diff --git a/src/arch/i386/firmware/pcbios/hidemem.c b/src/arch/i386/firmware/pcbios/hidemem.c index fa58135e..c372246c 100644 --- a/src/arch/i386/firmware/pcbios/hidemem.c +++ b/src/arch/i386/firmware/pcbios/hidemem.c @@ -128,6 +128,22 @@ void hide_etherboot ( void ) { * possible. */ void unhide_etherboot ( void ) { + + /* If we have more than one hooked interrupt at this point, it + * means that some other vector is still hooked, in which case + * we can't safely unhook INT 15 because we need to keep our + * memory protected. (We expect there to be at least one + * hooked interrupt, because INT 15 itself is still hooked). + */ + if ( hooked_bios_interrupts > 1 ) { + DBG ( "Cannot unhide: %d interrupt vectors still hooked\n", + hooked_bios_interrupts ); + return; + } + + /* Try to unhook INT 15. If it fails, then just leave it + * hooked; it takes care of protecting itself. :) + */ unhook_bios_interrupt ( 0x15, ( unsigned int ) int15, &int15_vector ); } diff --git a/src/arch/i386/prefix/libprefix.S b/src/arch/i386/prefix/libprefix.S index d1da0b00..02531211 100644 --- a/src/arch/i386/prefix/libprefix.S +++ b/src/arch/i386/prefix/libprefix.S @@ -230,7 +230,7 @@ install_highmem: * GDT for flat real mode * * We only ever use this GDT to set segment limits; the bases are - * unused. Also, we only flatten data segments, so we don't need to + * unused. Also, we only change data segments, so we don't need to * worry about the code or stack segments. This makes everything much * simpler. **************************************************************************** @@ -250,6 +250,11 @@ flat_ds: /* Flat real mode data segment */ .word 0xffff, 0 .byte 0, 0x93, 0xcf, 0 +real_ds: /* Normal real mode data segment */ + .equ REAL_DS, real_ds - gdt + .word 0xffff, 0 + .byte 0, 0x93, 0x00, 0 + gdt_end: .equ gdt_length, gdt_end - gdt .size gdt, . - gdt @@ -257,12 +262,12 @@ gdt_end: #endif /* KEEP_IT_REAL */ /**************************************************************************** - * flatten_real_mode (real-mode near call) + * set_real_mode_limits (real-mode near call) * - * Sets 4GB limits on the data segments %ds and %es. + * Sets limits on the data segments %ds and %es. * - * Parameters: - * none + * Parameters: + * %cx : segment type (FLAT_DS for 4GB or REAL_DS for 64kB) **************************************************************************** */ @@ -270,7 +275,7 @@ gdt_end: .section ".prefix.lib" .code16 -flatten_real_mode: +set_real_mode_limits: /* Preserve real-mode segment values and temporary registers */ pushw %es pushw %ds @@ -294,9 +299,8 @@ flatten_real_mode: movl %eax, %cr0 /* Set flat segment limits */ - movw $FLAT_DS, %ax - movw %ax, %ds - movw %ax, %es + movw %cx, %ds + movw %cx, %es /* Switch back to real mode */ movl %cr0, %eax @@ -309,7 +313,7 @@ flatten_real_mode: popw %ds popw %es ret - .size flatten_real_mode, . - flatten_real_mode + .size set_real_mode_limits, . - set_real_mode_limits #endif /* KEEP_IT_REAL */ @@ -369,7 +373,8 @@ install_prealloc: * prior to reading the E820 memory map and relocating * properly. */ - call flatten_real_mode + movw $FLAT_DS, %cx + call set_real_mode_limits movl $HIGHMEM_LOADPOINT, %edi call install_highmem @@ -383,19 +388,16 @@ install_prealloc: addw $4, %sp /* Move code to new location, set up new protected-mode GDT */ - call flatten_real_mode + movw $FLAT_DS, %cx + call set_real_mode_limits pushl %edi es rep addr32 movsb popl %edi lcall *init_librm_vector - - /* Hide Etherboot from BIOS memory map. Note that making this - * protected-mode call will also restore normal (non-flat) - * real mode, as part of the protected-to-real transition. - */ - pushl $hide_etherboot - lcall *prot_call_vector - addw $4, %sp + + /* Restore real-mode segment limits */ + movw $REAL_DS, %cx + call set_real_mode_limits /* Restore registers and interrupt status */ popl %ecx diff --git a/src/core/main.c b/src/core/main.c index 185e44b2..64e098ca 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -20,6 +20,7 @@ Literature dealing with the network protocols: #include #include #include +#include #include /** @@ -28,8 +29,9 @@ Literature dealing with the network protocols: * Call this function only once, before doing (almost) anything else. */ static void startup ( void ) { + hide_etherboot(); init_heap(); - call_init_fns (); + call_init_fns(); probe_devices(); } @@ -41,7 +43,8 @@ static void startup ( void ) { */ void shutdown ( void ) { remove_devices(); - call_exit_fns (); + call_exit_fns(); + unhide_etherboot(); } /** diff --git a/src/include/gpxe/hidemem.h b/src/include/gpxe/hidemem.h index 547f8881..db867f1c 100644 --- a/src/include/gpxe/hidemem.h +++ b/src/include/gpxe/hidemem.h @@ -17,6 +17,8 @@ enum hidemem_region_id { EXTMEM, }; +extern void hide_etherboot(); +extern void unhide_etherboot(); extern void hide_region ( unsigned int region_id, physaddr_t start, physaddr_t end );