summaryrefslogtreecommitdiffstats
path: root/src/arch/x86/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/x86/core')
-rw-r--r--src/arch/x86/core/cpuid.c5
-rw-r--r--src/arch/x86/core/cpuid_settings.c20
-rw-r--r--src/arch/x86/core/debugcon.c1
-rw-r--r--src/arch/x86/core/gdbmach.c1
-rw-r--r--src/arch/x86/core/pci_autoboot.c1
-rw-r--r--src/arch/x86/core/pcidirect.c4
-rw-r--r--src/arch/x86/core/rdrand.c1
-rw-r--r--src/arch/x86/core/relocate.c96
-rw-r--r--src/arch/x86/core/runtime.c17
-rw-r--r--src/arch/x86/core/video_subr.c1
-rw-r--r--src/arch/x86/core/vram_settings.c5
-rw-r--r--src/arch/x86/core/x86_bigint.c100
-rw-r--r--src/arch/x86/core/x86_io.c69
-rw-r--r--src/arch/x86/core/x86_string.c1
-rw-r--r--src/arch/x86/core/x86_tcpip.c1
-rw-r--r--src/arch/x86/core/x86_uart.c60
16 files changed, 183 insertions, 200 deletions
diff --git a/src/arch/x86/core/cpuid.c b/src/arch/x86/core/cpuid.c
index 1a7c93e83..0461b846e 100644
--- a/src/arch/x86/core/cpuid.c
+++ b/src/arch/x86/core/cpuid.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <string.h>
#include <errno.h>
@@ -84,8 +85,8 @@ int cpuid_supported ( uint32_t function ) {
return rc;
/* Find highest supported function number within this family */
- cpuid ( ( function & CPUID_EXTENDED ), 0, &max_function, &discard_b,
- &discard_c, &discard_d );
+ cpuid ( ( function & ( CPUID_EXTENDED | CPUID_HYPERVISOR ) ), 0,
+ &max_function, &discard_b, &discard_c, &discard_d );
/* Fail if maximum function number is meaningless (e.g. if we
* are attempting to call an extended function on a CPU which
diff --git a/src/arch/x86/core/cpuid_settings.c b/src/arch/x86/core/cpuid_settings.c
index 0b67ee91d..ef0164069 100644
--- a/src/arch/x86/core/cpuid_settings.c
+++ b/src/arch/x86/core/cpuid_settings.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <string.h>
#include <errno.h>
@@ -38,7 +39,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
* Bit 31 Extended function
* Bits 30-24 (bit 22 = 1) Subfunction number
- * (bit 22 = 0) Number of consecutive functions to call, minus one
+ * Bit 30 (bit 22 = 0) Hypervisor function
+ * Bits 29-24 (bit 22 = 0) Number of consecutive functions to call, minus one
* Bit 23 Return result as little-endian (used for strings)
* Bit 22 Interpret bits 30-24 as a subfunction number
* Bits 21-18 Unused
@@ -98,7 +100,7 @@ enum cpuid_flags {
* @v tag Setting tag
* @ret function Starting function number
*/
-#define CPUID_FUNCTION( tag ) ( (tag) & 0x800000ffUL )
+#define CPUID_FUNCTION( tag ) ( (tag) & 0xc00000ffUL )
/**
* Extract subfunction number from CPUID setting tag
@@ -109,6 +111,14 @@ enum cpuid_flags {
#define CPUID_SUBFUNCTION( tag ) ( ( (tag) >> 24 ) & 0x7f )
/**
+ * Extract number of consecutive functions from CPUID setting tag
+ *
+ * @v tag Setting tag
+ * @ret num_functions Number of consecutive functions
+ */
+#define CPUID_NUM_FUNCTIONS( tag ) ( ( ( (tag) >> 24 ) & 0x3f ) + 1 )
+
+/**
* Extract register array from CPUID setting tag
*
* @v tag Setting tag
@@ -165,12 +175,13 @@ static int cpuid_settings_fetch ( struct settings *settings,
/* Call each function in turn */
function = CPUID_FUNCTION ( setting->tag );
- subfunction = CPUID_SUBFUNCTION ( setting->tag );
if ( setting->tag & CPUID_USE_SUBFUNCTION ) {
+ function &= ~CPUID_HYPERVISOR;
+ subfunction = CPUID_SUBFUNCTION ( setting->tag );
num_functions = 1;
} else {
- num_functions = ( subfunction + 1 );
subfunction = 0;
+ num_functions = CPUID_NUM_FUNCTIONS ( setting->tag );
}
for ( ; num_functions-- ; function++ ) {
@@ -240,6 +251,7 @@ static void cpuid_settings_init ( void ) {
/** CPUID settings initialiser */
struct init_fn cpuid_settings_init_fn __init_fn ( INIT_NORMAL ) = {
+ .name = "cpuid",
.initialise = cpuid_settings_init,
};
diff --git a/src/arch/x86/core/debugcon.c b/src/arch/x86/core/debugcon.c
index 60de61f55..0e3a5dfc7 100644
--- a/src/arch/x86/core/debugcon.c
+++ b/src/arch/x86/core/debugcon.c
@@ -86,5 +86,6 @@ static void debugcon_init ( void ) {
* Debug port console initialisation function
*/
struct init_fn debugcon_init_fn __init_fn ( INIT_EARLY ) = {
+ .name = "debugcon",
.initialise = debugcon_init,
};
diff --git a/src/arch/x86/core/gdbmach.c b/src/arch/x86/core/gdbmach.c
index af6abfedd..d4d187e35 100644
--- a/src/arch/x86/core/gdbmach.c
+++ b/src/arch/x86/core/gdbmach.c
@@ -31,7 +31,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/uaccess.h>
#include <ipxe/gdbstub.h>
#include <librm.h>
-#include <gdbmach.h>
/** @file
*
diff --git a/src/arch/x86/core/pci_autoboot.c b/src/arch/x86/core/pci_autoboot.c
index 337598091..243e45026 100644
--- a/src/arch/x86/core/pci_autoboot.c
+++ b/src/arch/x86/core/pci_autoboot.c
@@ -44,5 +44,6 @@ static void pci_autoboot_init ( void ) {
/** PCI autoboot device initialisation function */
struct init_fn pci_autoboot_init_fn __init_fn ( INIT_NORMAL ) = {
+ .name = "autoboot",
.initialise = pci_autoboot_init,
};
diff --git a/src/arch/x86/core/pcidirect.c b/src/arch/x86/core/pcidirect.c
index f4659a1ac..887b78a0b 100644
--- a/src/arch/x86/core/pcidirect.c
+++ b/src/arch/x86/core/pcidirect.c
@@ -45,6 +45,7 @@ void pcidirect_prepare ( struct pci_device *pci, int where ) {
PCIDIRECT_CONFIG_ADDRESS );
}
+PROVIDE_PCIAPI_INLINE ( direct, pci_can_probe );
PROVIDE_PCIAPI_INLINE ( direct, pci_discover );
PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_byte );
PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_word );
@@ -53,5 +54,4 @@ PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_byte );
PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_word );
PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_dword );
PROVIDE_PCIAPI_INLINE ( direct, pci_ioremap );
-
-struct pci_api pcidirect_api = PCIAPI_RUNTIME ( direct );
+PROVIDE_PCIAPI_RUNTIME ( direct, PCIAPI_PRIORITY_DIRECT );
diff --git a/src/arch/x86/core/rdrand.c b/src/arch/x86/core/rdrand.c
index 850ab1f11..05fc3cd23 100644
--- a/src/arch/x86/core/rdrand.c
+++ b/src/arch/x86/core/rdrand.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
diff --git a/src/arch/x86/core/relocate.c b/src/arch/x86/core/relocate.c
index 765d46560..3cdc53c2e 100644
--- a/src/arch/x86/core/relocate.c
+++ b/src/arch/x86/core/relocate.c
@@ -1,4 +1,5 @@
-#include <ipxe/io.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/memmap.h>
#include <registers.h>
/*
@@ -41,82 +42,73 @@ extern char _etextdata[];
* to the prefix in %edi.
*/
__asmcall void relocate ( struct i386_all_regs *ix86 ) {
- struct memory_map memmap;
- uint32_t start, end, size, padded_size, max;
- uint32_t new_start, new_end;
- unsigned i;
+ struct memmap_region region;
+ physaddr_t start, end, max;
+ physaddr_t new_start, new_end;
+ physaddr_t r_start, r_end;
+ size_t size, padded_size;
- /* Get memory map and current location */
- get_memmap ( &memmap );
+ /* Show whole memory map (for debugging) */
+ memmap_dump_all ( 0 );
+
+ /* Get current location */
start = virt_to_phys ( _textdata );
end = virt_to_phys ( _etextdata );
size = ( end - start );
padded_size = ( size + ALIGN - 1 );
- DBG ( "Relocate: currently at [%x,%x)\n"
- "...need %x bytes for %d-byte alignment\n",
- start, end, padded_size, ALIGN );
+ DBGC ( &region, "Relocate: currently at [%#08lx,%#08lx)\n"
+ "...need %#zx bytes for %d-byte alignment\n",
+ start, end, padded_size, ALIGN );
/* Determine maximum usable address */
max = MAX_ADDR;
if ( ix86->regs.ebp < max ) {
max = ix86->regs.ebp;
- DBG ( "Limiting relocation to [0,%x)\n", max );
+ DBGC ( &region, "Limiting relocation to [0,%#08lx)\n", max );
}
/* Walk through the memory map and find the highest address
- * below 4GB that iPXE will fit into.
+ * above the current iPXE and below 4GB that iPXE will fit
+ * into.
*/
new_end = end;
- for ( i = 0 ; i < memmap.count ; i++ ) {
- struct memory_region *region = &memmap.regions[i];
- uint32_t r_start, r_end;
+ for_each_memmap_from ( &region, end, 0 ) {
- DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
-
/* Truncate block to maximum address. This will be
- * less than 4GB, which means that we can get away
- * with using just 32-bit arithmetic after this stage.
+ * strictly less than 4GB, which means that we can get
+ * away with using just 32-bit arithmetic after this
+ * stage.
*/
- if ( region->start > max ) {
- DBG ( "...starts after max=%x\n", max );
+ DBGC_MEMMAP ( &region, &region );
+ if ( region.min > max ) {
+ DBGC ( &region, "...starts after max=%#08lx\n", max );
+ break;
+ }
+ r_start = region.min;
+ if ( ! memmap_is_usable ( &region ) ) {
+ DBGC ( &region, "...not usable\n" );
continue;
}
- r_start = region->start;
- if ( region->end > max ) {
- DBG ( "...end truncated to max=%x\n", max );
+ r_end = ( r_start + memmap_size ( &region ) );
+ if ( ( r_end == 0 ) || ( r_end > max ) ) {
+ DBGC ( &region, "...end truncated to max=%#08lx\n",
+ max );
r_end = max;
- } else {
- r_end = region->end;
- }
- DBG ( "...usable portion is [%x,%x)\n", r_start, r_end );
-
- /* If we have rounded down r_end below r_ start, skip
- * this block.
- */
- if ( r_end < r_start ) {
- DBG ( "...truncated to negative size\n" );
- continue;
}
+ DBGC ( &region, "...usable portion is [%#08lx,%#08lx)\n",
+ r_start, r_end );
/* Check that there is enough space to fit in iPXE */
- if ( ( r_end - r_start ) < size ) {
- DBG ( "...too small (need %x bytes)\n", size );
+ if ( ( r_end - r_start ) < padded_size ) {
+ DBGC ( &region, "...too small (need %#zx bytes)\n",
+ padded_size );
continue;
}
- /* If the start address of the iPXE we would
- * place in this block is higher than the end address
- * of the current highest block, use this block.
- *
- * Note that this avoids overlaps with the current
- * iPXE, as well as choosing the highest of all viable
- * blocks.
- */
- if ( ( r_end - size ) > new_end ) {
- new_end = r_end;
- DBG ( "...new best block found.\n" );
- }
+ /* Use highest block with enough space */
+ new_end = r_end;
+ DBGC ( &region, "...new best block found.\n" );
}
/* Calculate new location of iPXE, and align it to the
@@ -126,9 +118,9 @@ __asmcall void relocate ( struct i386_all_regs *ix86 ) {
new_start += ( ( start - new_start ) & ( ALIGN - 1 ) );
new_end = new_start + size;
- DBG ( "Relocating from [%x,%x) to [%x,%x)\n",
- start, end, new_start, new_end );
-
+ DBGC ( &region, "Relocating from [%#08lx,%#08lx) to [%#08lx,%#08lx)\n",
+ start, end, new_start, new_end );
+
/* Let prefix know what to copy */
ix86->regs.esi = start;
ix86->regs.edi = new_start;
diff --git a/src/arch/x86/core/runtime.c b/src/arch/x86/core/runtime.c
index 02072b5bf..86083b1f9 100644
--- a/src/arch/x86/core/runtime.c
+++ b/src/arch/x86/core/runtime.c
@@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
+#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <assert.h>
@@ -69,6 +70,7 @@ static void cmdline_image_free ( struct refcnt *refcnt ) {
struct image *image = container_of ( refcnt, struct image, refcnt );
DBGC ( image, "RUNTIME freeing command line\n" );
+ free_image ( refcnt );
free ( cmdline_copy );
}
@@ -76,6 +78,7 @@ static void cmdline_image_free ( struct refcnt *refcnt ) {
static struct image cmdline_image = {
.refcnt = REF_INIT ( cmdline_image_free ),
.name = "<CMDLINE>",
+ .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ),
.type = &script_image_type,
};
@@ -114,9 +117,7 @@ static void cmdline_strip ( char *cmdline, const char *cruft ) {
* @ret rc Return status code
*/
static int cmdline_init ( void ) {
- userptr_t cmdline_user;
char *cmdline;
- size_t len;
int rc;
/* Do nothing if no command line was specified */
@@ -124,19 +125,15 @@ static int cmdline_init ( void ) {
DBGC ( colour, "RUNTIME found no command line\n" );
return 0;
}
- cmdline_user = phys_to_user ( cmdline_phys );
- len = ( strlen_user ( cmdline_user, 0 ) + 1 /* NUL */ );
/* Allocate and copy command line */
- cmdline_copy = malloc ( len );
+ cmdline_copy = strdup ( phys_to_virt ( cmdline_phys ) );
if ( ! cmdline_copy ) {
- DBGC ( colour, "RUNTIME could not allocate %zd bytes for "
- "command line\n", len );
+ DBGC ( colour, "RUNTIME could not allocate command line\n" );
rc = -ENOMEM;
goto err_alloc_cmdline_copy;
}
cmdline = cmdline_copy;
- copy_from_user ( cmdline, cmdline_user, 0, len );
DBGC ( colour, "RUNTIME found command line \"%s\" at %08x\n",
cmdline, cmdline_phys );
@@ -151,7 +148,7 @@ static int cmdline_init ( void ) {
DBGC ( colour, "RUNTIME using command line \"%s\"\n", cmdline );
/* Prepare and register image */
- cmdline_image.data = virt_to_user ( cmdline );
+ cmdline_image.data = cmdline;
cmdline_image.len = strlen ( cmdline );
if ( cmdline_image.len ) {
if ( ( rc = register_image ( &cmdline_image ) ) != 0 ) {
@@ -193,7 +190,7 @@ static int initrd_init ( void ) {
initrd_phys, ( initrd_phys + initrd_len ) );
/* Create initrd image */
- image = image_memory ( "<INITRD>", phys_to_user ( initrd_phys ),
+ image = image_memory ( "<INITRD>", phys_to_virt ( initrd_phys ),
initrd_len );
if ( ! image ) {
DBGC ( colour, "RUNTIME could not create initrd image\n" );
diff --git a/src/arch/x86/core/video_subr.c b/src/arch/x86/core/video_subr.c
index f5cc4cdd4..4e9ef466f 100644
--- a/src/arch/x86/core/video_subr.c
+++ b/src/arch/x86/core/video_subr.c
@@ -109,5 +109,6 @@ struct console_driver vga_console __console_driver = {
};
struct init_fn video_init_fn __init_fn ( INIT_EARLY ) = {
+ .name = "video",
.initialise = video_init,
};
diff --git a/src/arch/x86/core/vram_settings.c b/src/arch/x86/core/vram_settings.c
index 9c169b40c..a97a463fe 100644
--- a/src/arch/x86/core/vram_settings.c
+++ b/src/arch/x86/core/vram_settings.c
@@ -23,6 +23,7 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+#include <string.h>
#include <ipxe/uaccess.h>
#include <ipxe/settings.h>
@@ -47,12 +48,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* @ret len Length of setting data, or negative error
*/
static int vram_fetch ( void *data, size_t len ) {
- userptr_t vram = phys_to_user ( VRAM_BASE );
+ const void *vram = phys_to_virt ( VRAM_BASE );
/* Copy video RAM */
if ( len > VRAM_LEN )
len = VRAM_LEN;
- copy_from_user ( data, vram, 0, len );
+ memcpy ( data, vram, len );
return VRAM_LEN;
}
diff --git a/src/arch/x86/core/x86_bigint.c b/src/arch/x86/core/x86_bigint.c
deleted file mode 100644
index 74e5da9a2..000000000
--- a/src/arch/x86/core/x86_bigint.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- * You can also choose to distribute this program under the terms of
- * the Unmodified Binary Distribution Licence (as given in the file
- * COPYING.UBDL), provided that you have satisfied its requirements.
- */
-
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-
-#include <stdint.h>
-#include <string.h>
-#include <ipxe/bigint.h>
-
-/** @file
- *
- * Big integer support
- */
-
-/**
- * Multiply big integers
- *
- * @v multiplicand0 Element 0 of big integer to be multiplied
- * @v multiplicand_size Number of elements in multiplicand
- * @v multiplier0 Element 0 of big integer to be multiplied
- * @v multiplier_size Number of elements in multiplier
- * @v result0 Element 0 of big integer to hold result
- */
-void bigint_multiply_raw ( const uint32_t *multiplicand0,
- unsigned int multiplicand_size,
- const uint32_t *multiplier0,
- unsigned int multiplier_size,
- uint32_t *result0 ) {
- unsigned int result_size = ( multiplicand_size + multiplier_size );
- const bigint_t ( multiplicand_size ) __attribute__ (( may_alias ))
- *multiplicand = ( ( const void * ) multiplicand0 );
- const bigint_t ( multiplier_size ) __attribute__ (( may_alias ))
- *multiplier = ( ( const void * ) multiplier0 );
- bigint_t ( result_size ) __attribute__ (( may_alias ))
- *result = ( ( void * ) result0 );
- unsigned int i;
- unsigned int j;
- uint32_t multiplicand_element;
- uint32_t multiplier_element;
- uint32_t *result_elements;
- uint32_t discard_a;
- uint32_t discard_d;
- long index;
-
- /* Zero result */
- memset ( result, 0, sizeof ( *result ) );
-
- /* Multiply integers one element at a time */
- for ( i = 0 ; i < multiplicand_size ; i++ ) {
- multiplicand_element = multiplicand->element[i];
- for ( j = 0 ; j < multiplier_size ; j++ ) {
- multiplier_element = multiplier->element[j];
- result_elements = &result->element[ i + j ];
- /* Perform a single multiply, and add the
- * resulting double-element into the result,
- * carrying as necessary. The carry can
- * never overflow beyond the end of the
- * result, since:
- *
- * a < 2^{n}, b < 2^{m} => ab < 2^{n+m}
- */
- __asm__ __volatile__ ( "mull %5\n\t"
- "addl %%eax, (%6,%2,4)\n\t"
- "adcl %%edx, 4(%6,%2,4)\n\t"
- "\n1:\n\t"
- "adcl $0, 8(%6,%2,4)\n\t"
- "inc %2\n\t"
- /* Does not affect CF */
- "jc 1b\n\t"
- : "=&a" ( discard_a ),
- "=&d" ( discard_d ),
- "=&r" ( index ),
- "+m" ( *result )
- : "0" ( multiplicand_element ),
- "g" ( multiplier_element ),
- "r" ( result_elements ),
- "2" ( 0 ) );
- }
- }
-}
diff --git a/src/arch/x86/core/x86_io.c b/src/arch/x86/core/x86_io.c
index 6c6b6e1e7..270ed7bef 100644
--- a/src/arch/x86/core/x86_io.c
+++ b/src/arch/x86/core/x86_io.c
@@ -32,6 +32,69 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
+/** Threshold for port I/O-mapped addresses
+ *
+ * On x86, port I/O instructions (inb/outb/etc) can take only an 8-bit
+ * or 16-bit address (in %dx). All I/O ports must therefore have a
+ * value in the first 64kB of the address space.
+ *
+ * Virtual addresses below 64kB can never be MMIO addresses:
+ *
+ * - In the UEFI memory model and x86_64 BIOS memory model, virtual
+ * addresses below 64kB are identity-mapped to the corresponding
+ * physical address. Since the first 64kB of address space is
+ * always RAM, no MMIO device can exist within this region.
+ *
+ * - In the i386 BIOS memory model, virtual addresses below 64kB cover
+ * the iPXE binary itself (which starts at address zero). Since the
+ * size of .textdata can never realistically be below 64kB (not
+ * least since the heap alone is 512kB), and since iPXE is placed
+ * into RAM as a contiguous block, no MMIO device can exist within
+ * this region.
+ *
+ * We therefore know that any (virtual) address returned by ioremap()
+ * must be outside the first 64kB of the address space. We can
+ * therefore use this as a threshold to determine whether a given
+ * address is a port I/O address or an MMIO address.
+ */
+#define PIO_THRESHOLD 0x10000
+
+/**
+ * Read from I/O-mapped or memory-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+#define X86_IOREADX( _api_func, _suffix, _type ) \
+static _type x86_ ## _api_func ( volatile _type *io_addr ) { \
+ if ( ( ( intptr_t ) io_addr ) < PIO_THRESHOLD ) { \
+ return in ## _suffix ( io_addr ); \
+ } else { \
+ return read ## _suffix ( io_addr ); \
+ } \
+}
+X86_IOREADX ( ioread8, b, uint8_t );
+X86_IOREADX ( ioread16, w, uint16_t );
+X86_IOREADX ( ioread32, l, uint32_t );
+
+/**
+ * Write to I/O-mapped or memory-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+#define X86_IOWRITEX( _api_func, _suffix, _type ) \
+static void x86_ ## _api_func ( _type data, volatile _type *io_addr ) { \
+ if ( ( ( intptr_t ) io_addr ) < PIO_THRESHOLD ) { \
+ out ## _suffix ( data, io_addr ); \
+ } else { \
+ write ## _suffix ( data, io_addr ); \
+ } \
+}
+X86_IOWRITEX ( iowrite8, b, uint8_t );
+X86_IOWRITEX ( iowrite16, w, uint16_t );
+X86_IOWRITEX ( iowrite32, l, uint32_t );
+
/**
* Read 64-bit qword from memory-mapped device
*
@@ -101,3 +164,9 @@ PROVIDE_IOAPI_INLINE ( x86, writeq );
PROVIDE_IOAPI ( x86, readq, i386_readq );
PROVIDE_IOAPI ( x86, writeq, i386_writeq );
#endif
+PROVIDE_IOAPI ( x86, ioread8, x86_ioread8 );
+PROVIDE_IOAPI ( x86, ioread16, x86_ioread16 );
+PROVIDE_IOAPI ( x86, ioread32, x86_ioread32 );
+PROVIDE_IOAPI ( x86, iowrite8, x86_iowrite8 );
+PROVIDE_IOAPI ( x86, iowrite16, x86_iowrite16 );
+PROVIDE_IOAPI ( x86, iowrite32, x86_iowrite32 );
diff --git a/src/arch/x86/core/x86_string.c b/src/arch/x86/core/x86_string.c
index 1a1e79dac..923552f66 100644
--- a/src/arch/x86/core/x86_string.c
+++ b/src/arch/x86/core/x86_string.c
@@ -28,6 +28,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <string.h>
#include <config/defaults.h>
diff --git a/src/arch/x86/core/x86_tcpip.c b/src/arch/x86/core/x86_tcpip.c
index ed323d5d0..b3bfe2546 100644
--- a/src/arch/x86/core/x86_tcpip.c
+++ b/src/arch/x86/core/x86_tcpip.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
diff --git a/src/arch/x86/core/x86_uart.c b/src/arch/x86/core/x86_uart.c
index e455775bf..03809ff9b 100644
--- a/src/arch/x86/core/x86_uart.c
+++ b/src/arch/x86/core/x86_uart.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
+ * Copyright (C) 2025 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -29,41 +29,47 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
-#include <errno.h>
-#include <ipxe/uart.h>
+#include <string.h>
+#include <ipxe/serial.h>
+#include <ipxe/ns16550.h>
-/** UART port bases */
-static uint16_t uart_base[] = {
- [COM1] = 0x3f8,
- [COM2] = 0x2f8,
- [COM3] = 0x3e8,
- [COM4] = 0x2e8,
-};
+/** Define a fixed ISA UART */
+#define ISA_UART( NAME, BASE ) \
+ static struct ns16550_uart ns16550_ ## NAME = { \
+ .base = ( ( void * ) (BASE) ), \
+ .clock = NS16550_CLK_DEFAULT, \
+ }; \
+ struct uart NAME = { \
+ .refcnt = REF_INIT ( ref_no_free ), \
+ .name = #NAME, \
+ .op = &ns16550_operations, \
+ .priv = &ns16550_ ## NAME, \
+ }
+
+/* Fixed ISA UARTs */
+ISA_UART ( com1, COM1_BASE );
+ISA_UART ( com2, COM2_BASE );
+ISA_UART ( com3, COM3_BASE );
+ISA_UART ( com4, COM4_BASE );
/**
- * Select UART port
+ * Register fixed ISA UARTs
*
- * @v uart UART
- * @v port Port number, or 0 to disable
* @ret rc Return status code
*/
-int uart_select ( struct uart *uart, unsigned int port ) {
+int uart_register_fixed ( void ) {
+ static struct uart *ports[] = { COM1, COM2, COM3, COM4 };
+ unsigned int i;
int rc;
- /* Set new UART base */
- if ( port >= ( sizeof ( uart_base ) / sizeof ( uart_base[0] ) ) ) {
- rc = -ENODEV;
- goto err;
+ /* Register all fixed ISA UARTs */
+ for ( i = 0 ; i < ( sizeof ( ports ) / sizeof ( ports[0] ) ) ; i++ ) {
+ if ( ( rc = uart_register ( ports[i] ) ) != 0 ) {
+ DBGC ( ports[i], "UART could not register %s: %s\n",
+ ports[i]->name, strerror ( rc ) );
+ return rc;
+ }
}
- uart->base = ( ( void * ) ( intptr_t ) uart_base[port] );
-
- /* Check that UART exists */
- if ( ( rc = uart_exists ( uart ) ) != 0 )
- goto err;
return 0;
-
- err:
- uart->base = NULL;
- return rc;
}