diff options
Diffstat (limited to 'gpxe/src/arch/i386/firmware/pcbios')
-rw-r--r-- | gpxe/src/arch/i386/firmware/pcbios/e820mangler.S | 12 | ||||
-rw-r--r-- | gpxe/src/arch/i386/firmware/pcbios/gateA20.c | 13 | ||||
-rw-r--r-- | gpxe/src/arch/i386/firmware/pcbios/hidemem.c | 32 | ||||
-rw-r--r-- | gpxe/src/arch/i386/firmware/pcbios/memmap.c | 20 | ||||
-rw-r--r-- | gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c | 23 |
5 files changed, 63 insertions, 37 deletions
diff --git a/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S b/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S index 4fbd6563..53e2d7c5 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S +++ b/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S @@ -66,7 +66,7 @@ .align 16 .globl hidemem_base .globl hidemem_umalloc - .globl hidemem_text + .globl hidemem_textdata memory_windows: base_memory_window: .long 0x00000000, 0x00000000 /* Start of memory */ @@ -76,7 +76,7 @@ ext_memory_window: .long 0x000a0000, 0x00000000 /* 640kB mark */ hidemem_umalloc: .long 0xffffffff, 0xffffffff /* Changes at runtime */ .long 0xffffffff, 0xffffffff /* Changes at runtime */ -hidemem_text: .long 0xffffffff, 0xffffffff /* Changes at runtime */ +hidemem_textdata: .long 0xffffffff, 0xffffffff /* Changes at runtime */ .long 0xffffffff, 0xffffffff /* Changes at runtime */ .long 0xffffffff, 0xffffffff /* End of memory */ @@ -268,8 +268,10 @@ get_underlying_e820: pushl %ebx pushl %ecx pushl %edx + pushl %esi /* Some implementations corrupt %esi, so we */ + pushl %edi /* preserve %esi, %edi and %ebp to be paranoid */ + pushl %ebp pushw %es - pushw %di pushw %ds popw %es movw $underlying_e820_cache, %di @@ -280,8 +282,10 @@ get_underlying_e820: stc pushfw lcall *%cs:int15_vector - popw %di popw %es + popl %ebp + popl %edi + popl %esi /* Check for error return from underlying e820 call */ jc 2f /* CF set: error */ cmpl $SMAP, %eax diff --git a/gpxe/src/arch/i386/firmware/pcbios/gateA20.c b/gpxe/src/arch/i386/firmware/pcbios/gateA20.c index a14e3416..34e3ac52 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/gateA20.c +++ b/gpxe/src/arch/i386/firmware/pcbios/gateA20.c @@ -1,6 +1,7 @@ #include <stdio.h> #include <realmode.h> #include <bios.h> +#include <gpxe/io.h> #include <gpxe/timer.h> #define K_RDWR 0x60 /* keyboard data & cmds (read/write) */ @@ -48,9 +49,9 @@ static void empty_8042 ( void ) { time = currticks() + TICKS_PER_SEC; /* max wait of 1 second */ while ( ( inb ( K_CMD ) & ( K_IBUF_FUL | K_OBUF_FUL ) ) && currticks() < time ) { - SLOW_DOWN_IO; - ( void ) inb ( K_RDWR ); - SLOW_DOWN_IO; + iodelay(); + ( void ) inb_p ( K_RDWR ); + iodelay(); } } @@ -77,7 +78,7 @@ static int gateA20_is_set ( int retries ) { /* Avoid false negatives */ test_pattern++; - SLOW_DOWN_IO; + iodelay(); /* Always retry at least once, to avoid false negatives */ } while ( retries-- >= 0 ); @@ -145,9 +146,9 @@ void gateA20_set ( void ) { scp_a = inb ( SCP_A ); scp_a &= ~0x01; /* Avoid triggering a reset */ scp_a |= 0x02; /* Enable A20 */ - SLOW_DOWN_IO; + iodelay(); outb ( scp_a, SCP_A ); - SLOW_DOWN_IO; + iodelay(); if ( gateA20_is_set ( A20_SCPA_RETRIES ) ) { DBG ( "Enabled gate A20 using " "Fast Gate A20\n" ); diff --git a/gpxe/src/arch/i386/firmware/pcbios/hidemem.c b/gpxe/src/arch/i386/firmware/pcbios/hidemem.c index c9df7bd0..620b62e0 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/hidemem.c +++ b/gpxe/src/arch/i386/firmware/pcbios/hidemem.c @@ -55,8 +55,8 @@ extern struct hidden_region __data16 ( hidemem_umalloc ); #define hidemem_umalloc __use_data16 ( hidemem_umalloc ) /** Hidden text memory */ -extern struct hidden_region __data16 ( hidemem_text ); -#define hidemem_text __use_data16 ( hidemem_text ) +extern struct hidden_region __data16 ( hidemem_textdata ); +#define hidemem_textdata __use_data16 ( hidemem_textdata ) /** Assembly routine in e820mangler.S */ extern void int15(); @@ -66,12 +66,12 @@ extern struct segoff __text16 ( int15_vector ); #define int15_vector __use_text16 ( int15_vector ) /* The linker defines these symbols for us */ -extern char _text[]; -extern char _end[]; -extern char _text16_size[]; -#define _text16_size ( ( unsigned int ) _text16_size ) -extern char _data16_size[]; -#define _data16_size ( ( unsigned int ) _data16_size ) +extern char _textdata[]; +extern char _etextdata[]; +extern char _text16_memsz[]; +#define _text16_memsz ( ( unsigned int ) _text16_memsz ) +extern char _data16_memsz[]; +#define _data16_memsz ( ( unsigned int ) _data16_memsz ) /** * Hide region of memory from system memory map @@ -110,7 +110,7 @@ void hide_basemem ( void ) { * */ void hide_umalloc ( physaddr_t start, physaddr_t end ) { - assert ( end <= virt_to_phys ( _text ) ); + assert ( end <= virt_to_phys ( _textdata ) ); hide_region ( &hidemem_umalloc, start, end ); } @@ -118,9 +118,9 @@ void hide_umalloc ( physaddr_t start, physaddr_t end ) { * Hide .text and .data * */ -void hide_text ( void ) { - hide_region ( &hidemem_text, virt_to_phys ( _text ), - virt_to_phys ( _end ) ); +void hide_textdata ( void ) { + hide_region ( &hidemem_textdata, virt_to_phys ( _textdata ), + virt_to_phys ( _etextdata ) ); } /** @@ -148,8 +148,8 @@ static void hide_etherboot ( void ) { /* Initialise the hidden regions */ hide_basemem(); - hide_umalloc ( virt_to_phys ( _text ), virt_to_phys ( _text ) ); - hide_text(); + hide_umalloc ( virt_to_phys ( _textdata ), virt_to_phys ( _textdata ) ); + hide_textdata(); /* Some really moronic BIOSes bring up the PXE stack via the * UNDI loader entry point and then don't bother to unload it @@ -161,8 +161,8 @@ static void hide_etherboot ( void ) { * We use a heuristic to guess whether or not we are being * loaded sensibly. */ - rm_cs_top = ( ( ( rm_cs << 4 ) + _text16_size + 1024 - 1 ) >> 10 ); - rm_ds_top = ( ( ( rm_ds << 4 ) + _data16_size + 1024 - 1 ) >> 10 ); + rm_cs_top = ( ( ( rm_cs << 4 ) + _text16_memsz + 1024 - 1 ) >> 10 ); + rm_ds_top = ( ( ( rm_ds << 4 ) + _data16_memsz + 1024 - 1 ) >> 10 ); fbms = get_fbms(); if ( ( rm_cs_top < fbms ) && ( rm_ds_top < fbms ) ) { DBG ( "Detected potentially unsafe UNDI load at CS=%04x " diff --git a/gpxe/src/arch/i386/firmware/pcbios/memmap.c b/gpxe/src/arch/i386/firmware/pcbios/memmap.c index 9de10a7a..2e9627c0 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/memmap.c +++ b/gpxe/src/arch/i386/firmware/pcbios/memmap.c @@ -158,7 +158,7 @@ static int meme820 ( struct memory_map *memmap ) { uint32_t smap; size_t size; unsigned int flags; - unsigned int discard_d, discard_D; + unsigned int discard_D; /* Clear the E820 buffer. Do this once before starting, * rather than on each call; some BIOSes rely on the contents @@ -167,18 +167,24 @@ static int meme820 ( struct memory_map *memmap ) { memset ( &e820buf, 0, sizeof ( e820buf ) ); do { - __asm__ __volatile__ ( REAL_CODE ( "stc\n\t" + /* Some BIOSes corrupt %esi for fun. Guard against + * this by telling gcc that all non-output registers + * may be corrupted. + */ + __asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" + "stc\n\t" "int $0x15\n\t" "pushfw\n\t" - "popw %w0\n\t" ) - : "=r" ( flags ), "=a" ( smap ), - "=b" ( next ), "=D" ( discard_D ), - "=c" ( size ), "=d" ( discard_d ) + "popw %%dx\n\t" + "popl %%ebp\n\t" ) + : "=a" ( smap ), "=b" ( next ), + "=c" ( size ), "=d" ( flags ), + "=D" ( discard_D ) : "a" ( 0xe820 ), "b" ( next ), "D" ( __from_data16 ( &e820buf ) ), "c" ( sizeof ( e820buf ) ), "d" ( SMAP ) - : "memory" ); + : "esi", "memory" ); if ( smap != SMAP ) { DBG ( "INT 15,e820 failed SMAP signature check\n" ); diff --git a/gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c b/gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c index b088e51d..3238fb19 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c +++ b/gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c @@ -24,6 +24,16 @@ #include <gpxe/uuid.h> #include <smbios.h> +/** SMBIOS settings tag magic number */ +#define SMBIOS_TAG_MAGIC 0x5B /* "SmBios" */ + +/** + * Construct SMBIOS empty tag + * + * @ret tag SMBIOS setting tag + */ +#define SMBIOS_EMPTY_TAG ( SMBIOS_TAG_MAGIC << 24 ) + /** * Construct SMBIOS raw-data tag * @@ -33,7 +43,8 @@ * @ret tag SMBIOS setting tag */ #define SMBIOS_RAW_TAG( _type, _structure, _field ) \ - ( ( (_type) << 16 ) | \ + ( ( SMBIOS_TAG_MAGIC << 24 ) | \ + ( (_type) << 16 ) | \ ( offsetof ( _structure, _field ) << 8 ) | \ ( sizeof ( ( ( _structure * ) 0 )->_field ) ) ) @@ -46,7 +57,8 @@ * @ret tag SMBIOS setting tag */ #define SMBIOS_STRING_TAG( _type, _structure, _field ) \ - ( ( (_type) << 16 ) | \ + ( ( SMBIOS_TAG_MAGIC << 24 ) | \ + ( (_type) << 16 ) | \ ( offsetof ( _structure, _field ) << 8 ) ) /** @@ -78,16 +90,18 @@ static int smbios_fetch ( struct settings *settings __unused, struct setting *setting, void *data, size_t len ) { struct smbios_structure structure; + unsigned int tag_magic; unsigned int tag_type; unsigned int tag_offset; unsigned int tag_len; int rc; /* Split tag into type, offset and length */ - tag_type = ( setting->tag >> 16 ); + tag_magic = ( setting->tag >> 24 ); + tag_type = ( ( setting->tag >> 16 ) & 0xff ); tag_offset = ( ( setting->tag >> 8 ) & 0xff ); tag_len = ( setting->tag & 0xff ); - if ( ! tag_type ) + if ( tag_magic != SMBIOS_TAG_MAGIC ) return -ENOENT; /* Find SMBIOS structure */ @@ -127,6 +141,7 @@ static struct settings_operations smbios_settings_operations = { static struct settings smbios_settings = { .refcnt = NULL, .name = "smbios", + .tag_magic = SMBIOS_EMPTY_TAG, .siblings = LIST_HEAD_INIT ( smbios_settings.siblings ), .children = LIST_HEAD_INIT ( smbios_settings.children ), .op = &smbios_settings_operations, |