diff --git a/src/arch/i386/prefix/libprefix.S b/src/arch/i386/prefix/libprefix.S index 12cf9184..deea5ab3 100644 --- a/src/arch/i386/prefix/libprefix.S +++ b/src/arch/i386/prefix/libprefix.S @@ -17,6 +17,10 @@ * */ + .arch i386 + .section ".prefix.lib", "awx", @progbits + .section ".data16", "aw", @progbits + /** * High memory temporary load address * @@ -27,24 +31,125 @@ * We use the start of an even megabyte so that we don't have to worry * about the current state of the A20 line. * - * We use 4MB rather than 2MB because there is at least one commercial - * PXE ROM ("Broadcom UNDI, PXE-2.1 (build 082) v2.0.4") which stores - * data required by the UNDI ROM loader (yes, the ROM loader; that's - * the component which should be impossible to damage short of - * screwing with the MMU) around the 2MB mark. Sadly, this is not a - * joke. - * + * We use 4MB rather than 2MB because some PXE stack / PMM BIOS + * combinations are known to place data required by other UNDI ROMs + * loader around the 2MB mark. */ -#define HIGHMEM_LOADPOINT ( 4 << 20 ) + .globl HIGHMEM_LOADPOINT + .equ HIGHMEM_LOADPOINT, ( 4 << 20 ) /* Image compression enabled */ #define COMPRESS 1 #define CR0_PE 1 - .arch i386 - .section ".prefix.lib", "awx", @progbits - .section ".data16", "aw", @progbits +/***************************************************************************** + * Utility function: print character (with LF -> LF,CR translation) + * + * Parameters: + * %al : character to print + * Returns: + * Nothing + * Corrupts: + * %ax + ***************************************************************************** + */ + .section ".prefix.lib" + .code16 + .globl print_character +print_character: + /* Preserve registers */ + pushw %bx + pushw %bp + /* Print character */ + movw $0x0007, %bx /* page 0, attribute 7 (normal) */ + movb $0x0e, %ah /* write char, tty mode */ + cmpb $0x0a, %al /* '\n'? */ + jne 1f + int $0x10 + movb $0x0d, %al +1: int $0x10 + /* Restore registers and return */ + popw %bp + popw %bx + ret + .size print_character, . - print_character + +/***************************************************************************** + * Utility function: print a NUL-terminated string + * + * Parameters: + * %ds:si : string to print + * Returns: + * %ds:si : character after terminating NUL + ***************************************************************************** + */ + .section ".prefix.lib" + .code16 + .globl print_message +print_message: + /* Preserve registers */ + pushw %ax + /* Print string */ +1: lodsb + testb %al, %al + je 2f + call print_character + jmp 1b +2: /* Restore registers and return */ + popw %ax + ret + .size print_message, . - print_message + +/***************************************************************************** + * Utility functions: print hex digit/byte/word/dword + * + * Parameters: + * %al (low nibble) : digit to print + * %al : byte to print + * %ax : word to print + * %eax : dword to print + * Returns: + * Nothing + ***************************************************************************** + */ + .section ".prefix.lib" + .code16 + .globl print_hex_dword +print_hex_dword: + rorl $16, %eax + call print_hex_word + rorl $16, %eax + /* Fall through */ + .size print_hex_dword, . - print_hex_dword + .globl print_hex_word +print_hex_word: + xchgb %al, %ah + call print_hex_byte + xchgb %al, %ah + /* Fall through */ + .size print_hex_word, . - print_hex_word + .globl print_hex_byte +print_hex_byte: + rorb $4, %al + call print_hex_nibble + rorb $4, %al + /* Fall through */ + .size print_hex_byte, . - print_hex_byte + .globl print_hex_nibble +print_hex_nibble: + /* Preserve registers */ + pushw %ax + /* Print digit (technique by Norbert Juffa */ + andb $0x0f, %al + cmpb $10, %al + sbbb $0x69, %al + das + call print_character + /* Restore registers and return */ + popw %ax + ret + .size print_hex_nibble, . - print_hex_nibble /**************************************************************************** * pm_call (real-mode near call) @@ -70,13 +175,14 @@ #ifndef KEEP_IT_REAL /* GDT for protected-mode calls */ - .section ".data16" + .section ".prefix.lib" .align 16 +pm_call_vars: gdt: gdt_limit: .word gdt_length - 1 gdt_base: .long 0 .word 0 /* padding */ -pm_cs: /* 16-bit protected-mode code segment */ +pm_cs: /* 16-bit protected-mode code segment */ .equ PM_CS, pm_cs - gdt .word 0xffff, 0 .byte 0, 0x9b, 0x00, 0 @@ -92,18 +198,24 @@ gdt_end: .equ gdt_length, . - gdt .size gdt, . - gdt - .section ".data16" + .section ".prefix.lib" .align 16 pm_saved_gdt: .long 0, 0 .size pm_saved_gdt, . - pm_saved_gdt + .equ pm_call_vars_size, . - pm_call_vars +#define PM_CALL_VAR(x) ( -pm_call_vars_size + ( (x) - pm_call_vars ) ) + .section ".prefix.lib" .code16 pm_call: - /* Preserve registers, flags, GDT, and RM return point */ + /* Preserve registers, flags, and RM return point */ + pushw %bp + movw %sp, %bp + subw $pm_call_vars_size, %sp + andw $0xfff0, %sp pushfl - sgdt pm_saved_gdt pushw %gs pushw %fs pushw %es @@ -112,27 +224,43 @@ pm_call: pushw %cs pushw $99f + /* Set up local variable block, and preserve GDT */ + pushw %cx + pushw %si + pushw %di + pushw %ss + popw %es + movw $pm_call_vars, %si + leaw PM_CALL_VAR(pm_call_vars)(%bp), %di + movw $pm_call_vars_size, %cx + cs rep movsb + popw %di + popw %si + popw %cx + sgdt PM_CALL_VAR(pm_saved_gdt)(%bp) + /* Set up GDT bases */ pushl %eax - pushw %bx + pushl %edi xorl %eax, %eax - movw %ds, %ax + movw %ss, %ax shll $4, %eax - addl $gdt, %eax - movl %eax, gdt_base + movzwl %bp, %edi + leal PM_CALL_VAR(gdt)(%eax, %edi), %eax + movl %eax, PM_CALL_VAR(gdt_base)(%bp) movw %cs, %ax - movw $pm_cs, %bx + movw $PM_CALL_VAR(pm_cs), %di call set_seg_base movw %ss, %ax - movw $pm_ss, %bx + movw $PM_CALL_VAR(pm_ss), %di call set_seg_base - popw %bx + popl %edi popl %eax /* Switch CPU to protected mode and load up segment registers */ pushl %eax cli - lgdt gdt + lgdt PM_CALL_VAR(gdt)(%bp) movl %cr0, %eax orb $CR0_PE, %al movl %eax, %cr0 @@ -168,18 +296,19 @@ pm_call: popw %es popw %fs popw %gs - lgdt pm_saved_gdt + lgdt PM_CALL_VAR(pm_saved_gdt)(%bp) popfl - + movw %bp, %sp + popw %bp ret .size pm_call, . - pm_call set_seg_base: rolw $4, %ax - movw %ax, 2(%bx) - andw $0xfff0, 2(%bx) - movb %al, 4(%bx) - andb $0x0f, 4(%bx) + movw %ax, 2(%bp,%di) + andw $0xfff0, 2(%bp,%di) + movb %al, 4(%bp,%di) + andb $0x0f, 4(%bp,%di) ret .size set_seg_base, . - set_seg_base @@ -196,7 +325,7 @@ set_seg_base: * %ecx : length * Returns: * %ds:esi : next source address - * %ds:esi : next destination address + * %es:edi : next destination address * Corrupts: * None **************************************************************************** @@ -211,24 +340,57 @@ copy_bytes: .size copy_bytes, . - copy_bytes /**************************************************************************** - * install_block (real-mode or 16-bit protected-mode near call) + * install_block (real-mode near call) * * Install block to specified address * * Parameters: - * %ds:esi : source address (must be a multiple of 16) - * %es:edi : destination address + * %esi : source physical address (must be a multiple of 16) + * %edi : destination physical address (must be a multiple of 16) * %ecx : length of (decompressed) data * %edx : total length of block (including any uninitialised data portion) * Returns: - * %ds:esi : next source address (will be a multiple of 16) + * %esi : next source physical address (will be a multiple of 16) * Corrupts: - * %edi, %ecx, %edx + * none **************************************************************************** */ .section ".prefix.lib" .code16 install_block: + +#ifdef KEEP_IT_REAL + + /* Preserve registers */ + pushw %ds + pushw %es + pushl %ecx + pushl %edi + + /* Convert %esi and %edi to segment registers */ + shrl $4, %esi + movw %si, %ds + xorw %si, %si + shrl $4, %edi + movw %di, %es + xorw %di, %di + +#else /* KEEP_IT_REAL */ + + /* Call self in protected mode */ + pushw %ax + movw $1f, %ax + call pm_call + popw %ax + ret +1: + /* Preserve registers */ + pushl %ecx + pushl %edi + +#endif /* KEEP_IT_REAL */ + + #if COMPRESS /* Decompress source to destination */ call decompress16 @@ -249,6 +411,28 @@ install_block: addl $0xf, %esi andl $~0xf, %esi + +#ifdef KEEP_IT_REAL + + /* Convert %ds:esi back to a physical address */ + movzwl %ds, %cx + shll $4, %ecx + addl %ecx, %esi + + /* Restore registers */ + popl %edi + popl %ecx + popw %es + popw %ds + +#else /* KEEP_IT_REAL */ + + /* Restore registers */ + popl %edi + popl %ecx + +#endif + ret .size install_block, . - install_block @@ -270,6 +454,7 @@ install_block: */ .section ".prefix.lib" .code16 + .globl alloc_basemem alloc_basemem: /* FBMS => %ax as segment address */ movw $0x40, %ax @@ -295,98 +480,16 @@ alloc_basemem: ret .size alloc_basemem, . - alloc_basemem -/**************************************************************************** - * install_basemem (real-mode near call) - * - * Install source block into base memory - * - * Parameters: - * %esi : source physical address (must be a multiple of 16) - * %es : destination segment address - * %cx : length of (decompressed) data - * %dx : total length of block (including any uninitialised data portion) - * Returns: - * %esi : next source physical address (will be a multiple of 16) - * Corrupts: - * %edi, %ecx, %edx - **************************************************************************** - */ - .section ".prefix.lib" - .code16 -install_basemem: - /* Preserve registers */ - pushw %ds - - /* Preserve original %esi */ - pushl %esi - - /* Install to specified address */ - shrl $4, %esi - movw %si, %ds - xorw %si, %si - xorl %edi, %edi - movzwl %cx, %ecx - movzwl %dx, %edx - call install_block - - /* Fix up %esi for return */ - popl %ecx - addl %ecx, %esi - - /* Restore registers */ - popw %ds - ret - .size install_basemem, . - install_basemem - -/**************************************************************************** - * install_highmem (real-mode near call) - * - * Install source block into high memory - * - * Parameters: - * %esi : source physical address (must be a multiple of 16) - * %edi : destination physical address - * %ecx : length of (decompressed) data - * %edx : total length of block (including any uninitialised data portion) - * Returns: - * %esi : next source physical address (will be a multiple of 16) - * Corrupts: - * %edi, %ecx, %edx - **************************************************************************** - */ - -#ifndef KEEP_IT_REAL - - .section ".prefix.lib" - .code16 -install_highmem: - /* Preserve registers */ - pushw %ax - - /* Install to specified address */ - movw $install_block, %ax - call pm_call - - /* Restore registers */ - popw %ax - ret - .size install_highmem, . - install_highmem - -#endif /* KEEP_IT_REAL */ - /**************************************************************************** * install (real-mode near call) - * install_prealloc (real-mode near call) * * Install all text and data segments. * * Parameters: - * %ax : .text16 segment address (install_prealloc only) - * %bx : .data16 segment address (install_prealloc only) + * none * Returns: - * %ax : .text16 segment address - * %bx : .data16 segment address - * %edi : .text physical address (if applicable) + * %ax : .text16 segment address + * %bx : .data16 segment address * Corrupts: * none **************************************************************************** @@ -395,38 +498,69 @@ install_highmem: .code16 .globl install install: + /* Preserve registers */ + pushl %esi + pushl %edi /* Allocate space for .text16 and .data16 */ call alloc_basemem + /* Image source = %cs:0000 */ + xorl %esi, %esi + /* Image destination = HIGHMEM_LOADPOINT */ + movl $HIGHMEM_LOADPOINT, %edi + /* Install text and data segments */ + call install_prealloc + /* Restore registers and return */ + popl %edi + popl %esi + ret .size install, . - install + +/**************************************************************************** + * install_prealloc (real-mode near call) + * + * Install all text and data segments. + * + * Parameters: + * %ax : .text16 segment address + * %bx : .data16 segment address + * %esi : Image source physical address (or zero for %cs:0000) + * %edi : Decompression temporary area physical address + * Corrupts: + * none + **************************************************************************** + */ + .section ".prefix.lib" + .code16 .globl install_prealloc install_prealloc: /* Save registers */ + pushal pushw %ds pushw %es - pushl %esi - pushl %ecx - pushl %edx /* Sanity: clear the direction flag asap */ cld /* Calculate physical address of payload (i.e. first source) */ - xorl %esi, %esi + testl %esi, %esi + jnz 1f movw %cs, %si shll $4, %esi - addl $_payload_offset, %esi +1: addl $_payload_offset, %esi - /* Install .text16 */ - movw %ax, %es - movw $_text16_size, %cx - movw %cx, %dx - call install_basemem - - /* Install .data16 */ - movw %bx, %es - movw $_data16_progbits_size, %cx - movw $_data16_size, %dx - call install_basemem + /* Install .text16 and .data16 */ + pushl %edi + movzwl %ax, %edi + shll $4, %edi + movl $_text16_size, %ecx + movl %ecx, %edx + call install_block /* .text16 */ + movzwl %bx, %edi + shll $4, %edi + movl $_data16_progbits_size, %ecx + movl $_data16_size, %edx + call install_block /* .data16 */ + popl %edi /* Set up %ds for access to .data16 */ movw %bx, %ds @@ -440,12 +574,9 @@ install_prealloc: * prior to reading the E820 memory map and relocating * properly. */ - movl $HIGHMEM_LOADPOINT, %edi movl $_textdata_progbits_size, %ecx movl $_textdata_size, %edx - pushl %edi - call install_highmem - popl %edi + call install_block /* Initialise librm at current location */ movw %ax, (init_librm_vector+2) @@ -473,11 +604,9 @@ install_prealloc: #endif /* Restore registers */ - popl %edx - popl %ecx - popl %esi popw %es popw %ds + popal ret .size install_prealloc, . - install_prealloc diff --git a/src/arch/i386/prefix/pxeprefix.S b/src/arch/i386/prefix/pxeprefix.S index 31b2102f..6a8aeb3a 100644 --- a/src/arch/i386/prefix/pxeprefix.S +++ b/src/arch/i386/prefix/pxeprefix.S @@ -320,112 +320,6 @@ print_free_basemem: finished: jmp run_etherboot -/***************************************************************************** - * Subroutine: print character (with LF -> LF,CR translation) - * - * Parameters: - * %al : character to print - * Returns: - * Nothing - ***************************************************************************** - */ -print_character: - /* Preserve registers */ - pushw %ax - pushw %bx - pushw %bp - /* Print character */ - movw $0x0007, %bx /* page 0, attribute 7 (normal) */ - movb $0x0e, %ah /* write char, tty mode */ - cmpb $0x0a, %al /* '\n'? */ - jne 1f - int $0x10 - movb $0x0d, %al -1: int $0x10 - /* Restore registers and return */ - popw %bp - popw %bx - popw %ax - ret - -/***************************************************************************** - * Subroutine: print a NUL-terminated string - * - * Parameters: - * %ds:%si : string to print - * Returns: - * Nothing - ***************************************************************************** - */ -print_message: - /* Preserve registers */ - pushw %ax - pushw %si - /* Print string */ -1: lodsb - testb %al, %al - je 2f - call print_character - jmp 1b -2: /* Restore registers and return */ - popw %si - popw %ax - ret - -/***************************************************************************** - * Subroutine: print hex digit - * - * Parameters: - * %al (low nibble) : digit to print - * Returns: - * Nothing - ***************************************************************************** - */ -print_hex_nibble: - /* Preserve registers */ - pushw %ax - /* Print digit (technique by Norbert Juffa */ - andb $0x0f, %al - cmpb $10, %al - sbbb $0x69, %al - das - call print_character - /* Restore registers and return */ - popw %ax - ret - -/***************************************************************************** - * Subroutine: print hex byte - * - * Parameters: - * %al : byte to print - * Returns: - * Nothing - ***************************************************************************** - */ -print_hex_byte: - rorb $4, %al - call print_hex_nibble - rorb $4, %al - call print_hex_nibble - ret - -/***************************************************************************** - * Subroutine: print hex word - * - * Parameters: - * %ax : word to print - * Returns: - * Nothing - ***************************************************************************** - */ -print_hex_word: - xchgb %al, %ah - call print_hex_byte - xchgb %al, %ah - call print_hex_byte - ret - /***************************************************************************** * Subroutine: print segment:offset address * diff --git a/src/arch/i386/prefix/romprefix.S b/src/arch/i386/prefix/romprefix.S index 167641c6..d37cce94 100644 --- a/src/arch/i386/prefix/romprefix.S +++ b/src/arch/i386/prefix/romprefix.S @@ -6,6 +6,11 @@ * table so using a noticeable amount of stack space is a no-no. */ +#define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) ) +#define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) ) +#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) ) +#define PNP_GET_BBS_VERSION 0x60 + .text .code16 .arch i386 @@ -15,7 +20,9 @@ romheader: .word 0xAA55 /* BIOS extension signature */ romheader_size: .byte _load_size_sect /* Size in 512-byte blocks */ - jmp init_vector /* Initialisation vector */ + jmp init /* Initialisation vector */ +checksum: + .byte 0 .org 0x16 .word undiheader .org 0x18 @@ -72,7 +79,7 @@ pnpheader: .byte 0x54 /* Device indicator */ .word 0x0000 /* Boot connection vector */ .word 0x0000 /* Disconnect vector */ - .word exec_vector /* Boot execution vector */ + .word bev_entry /* Boot execution vector */ .word 0x0000 /* Reserved */ .word 0x0000 /* Static resource information vector*/ .equ pnpheader_len, . - pnpheader @@ -98,60 +105,210 @@ undiheader: .equ undiheader_len, . - undiheader .size undiheader, . - undiheader -/* Initialisation vector +/* Initialisation (called once during POST) * * Determine whether or not this is a PnP system via a signature * check. If it is PnP, return to the PnP BIOS indicating that we are * a boot-capable device; the BIOS will call our boot execution vector * if it wants to boot us. If it is not PnP, hook INT 19. */ -init_vector: - pushw %si - cmpw $'$'+'P'*256, %es:0(%di) - jne notpnp - cmpw $'n'+'P'*256, %es:2(%di) - jne notpnp -ispnp: - movw $ispnp_message, %si - jmp 99f -notpnp: +init: + /* Preserve registers, clear direction flag, set %ds=%cs */ + pushaw pushw %ds - pushw $0 - popw %ds + pushw %es + cld pushw %cs - pushw $exec_vector - popl ( 0x19 * 4 ) popw %ds - movw $notpnp_message, %si -99: + /* Print message as early as possible */ + movw $init_message, %si + call print_message + /* Check for PnP BIOS */ + testw $0x0f, %di /* PnP signature must be aligned - bochs */ + jnz hook_int19 /* uses unalignment to indicate 'fake' PnP. */ + cmpl $PNP_SIGNATURE, %es:0(%di) + jne hook_int19 + /* Is PnP: print PnP message */ + movw $init_message_pnp, %si + call print_message + xchgw %bx, %bx + /* Check for BBS */ + pushw %es:0x1b(%di) /* Real-mode data segment */ + pushw %ds /* &(bbs_version) */ + pushw $bbs_version + pushw $PNP_GET_BBS_VERSION + lcall *%es:0xd(%di) + addw $8, %sp + testw %ax, %ax + jne hook_int19 + movw $init_message_bbs, %si + call print_message + jmp hook_bbs + /* Not BBS-compliant - must hook INT 19 */ +hook_int19: + movw $init_message_int19, %si call print_message - movw $0x20, %ax - popw %si - lret - .size init_vector, . - init_vector - -ispnp_message: - .asciz "gPXE detected PnP BIOS\r\n" - .size ispnp_message, . - ispnp_message -notpnp_message: - .asciz "gPXE detected non-PnP BIOS\r\n" - .size notpnp_message, . - notpnp_message - -/* Boot execution vector - *pciheader_size - * Called by the PnP BIOS when it wants to boot us, or via the hooked - * INT 19 if we detected a non-PnP BIOS. - */ -exec_vector: - /* Obtain a reasonably-sized stack */ xorw %ax, %ax - movw %ax, %ss - movw $0x7c00, %sp - + movw %ax, %es + pushw %cs + pushw $int19_entry + popl %es:( 0x19 * 4 ) +hook_bbs: + /* Check for PMM */ + movw $( 0xe000 - 1 ), %di +pmm_scan: + incw %di + jz no_pmm + movw %di, %es + cmpl $PMM_SIGNATURE, %es:0 + jne pmm_scan + xorw %bx, %bx + xorw %si, %si + movzbw %es:5, %cx +1: es lodsb + addb %al, %bl + loop 1b + jnz pmm_scan + /* PMM found: print PMM message */ + movw $init_message_pmm, %si + call print_message + /* Try to allocate 2MB block via PMM */ + pushw $0x0006 /* Aligned, extended memory */ + pushl $0xffffffff /* No handle */ + pushl $( 0x00200000 / 16 ) /* 2MB in paragraphs */ + pushw $0x0000 /* pmmAllocate */ + lcall *%es:7 + addw $12, %sp + testw %dx, %dx /* %ax==0 even on success, since align=2MB */ + jnz gotpmm + movw $init_message_pmm_failed, %si + call print_message + jmp no_pmm +gotpmm: /* PMM allocation succeeded: copy ROM to PMM block */ + pushal /* PMM presence implies 1kB stack */ + movw %ax, %es /* %ax=0 already - see above */ + pushw %dx + pushw %ax + popl %edi + movl %edi, image_source + xorl %esi, %esi + movzbl romheader_size, %ecx + shll $9, %ecx + addr32 rep movsb /* PMM presence implies flat real mode */ + movl %edi, decompress_to + /* Shrink ROM and update checksum */ + xorw %bx, %bx + xorw %si, %si + movw $_prefix_size_sect, %cx + movb %cl, romheader_size + shlw $9, %cx +1: lodsb + addb %al, %bl + loop 1b + subb %bl, checksum + popal +no_pmm: + /* Print CRLF to terminate messages */ + movw $'\n', %ax + call print_character + /* Restore registers */ + popw %es + popw %ds + popaw + /* Indicate boot capability to PnP BIOS, if present */ + movw $0x20, %ax + lret + .size init, . - init + +init_message: + .asciz "gPXE (http://etherboot.org) -" + .size init_message, . - init_message +init_message_pnp: + .asciz " PnP" + .size init_message_pnp, . - init_message_pnp +init_message_bbs: + .asciz " BBS" + .size init_message_bbs, . - init_message_bbs +init_message_pmm: + .asciz " PMM" + .size init_message_pmm, . - init_message_pmm +init_message_pmm_failed: + .asciz "(failed)" + .size init_message_pmm_failed, . - init_message_pmm_failed +init_message_int19: + .asciz " INT19" + .size init_message_int19, . - init_message_int19 + +/* ROM image location + * + * May be either within option ROM space, or within PMM-allocated block. + */ +image_source: + .long 0 + .size image_source, . - image_source + +/* Temporary decompression area + * + * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block. + */ +decompress_to: + .long HIGHMEM_LOADPOINT + .size decompress_to, . - decompress_to + +/* BBS version + * + * Filled in by BBS BIOS. We ignore the value. + */ +bbs_version: + .word 0 + +/* Boot Execution Vector entry point + * + * Called by the PnP BIOS when it wants to boot us. + */ +bev_entry: + pushw %cs + call exec + lret + .size bev_entry, . - bev_entry + +/* INT19 entry point + * + * Called via the hooked INT 19 if we detected a non-PnP BIOS. + */ +int19_entry: + pushw %cs + call exec + /* No real way to return from INT19 */ + int $0x18 + .size int19_entry, . - int19_entry + +/* Execute as a boot device + * + */ +exec: /* Set %ds = %cs */ + pushw %cs + popw %ds + + /* Print message as soon as possible */ movw $exec_message, %si call print_message - call install + /* Store magic word on BIOS stack and remember BIOS %ss:sp */ + pushl $STACK_MAGIC + movw %ss, %dx + movw %sp, %bp + + /* Obtain a reasonably-sized temporary stack */ + xorw %ax, %ax + movw %ax, %ss + movw $0x7c00, %sp + + /* Install gPXE */ + movl image_source, %esi + movl decompress_to, %edi + call alloc_basemem + call install_prealloc /* Set up real-mode stack */ movw %bx, %ss @@ -162,18 +319,28 @@ exec_vector: pushw $1f lret .section ".text16", "awx", @progbits -1: +1: /* Call main() */ pushl $main pushw %cs call prot_call - popl %eax /* discard */ + /* No need to clean up stack; we are about to reload %ss:sp */ + + /* Restore BIOS stack */ + movw %dx, %ss + movw %bp, %sp - /* Boot next device */ + /* Check magic word on BIOS stack */ + popl %eax + cmpl $STACK_MAGIC, %eax + jne 1f + /* BIOS stack OK: return to caller */ + lret +1: /* BIOS stack corrupt: use INT 18 */ int $0x18 .previous exec_message: - .asciz "gPXE starting boot\r\n" + .asciz "gPXE starting boot\n" .size exec_message, . - exec_message /* UNDI loader @@ -182,6 +349,7 @@ exec_message: */ undiloader: /* Save registers */ + pushl %esi pushl %edi pushw %es pushw %bx @@ -193,6 +361,8 @@ undiloader: pushw %di movw %es:12(%di), %bx movw %es:14(%di), %ax + movl %cs:image_source, %esi + movl %cs:decompress_to, %edi call install_prealloc popw %di /* Call UNDI loader C code */ @@ -208,24 +378,6 @@ undiloader: popw %bx popw %es popl %edi + popl %esi lret .size undiloader, . - undiloader - -/* Utility function: print string - */ -print_message: - pushw %ax - pushw %bx - pushw %bp - movw $0x0007, %bx -1: cs lodsb - testb %al, %al - je 2f - movb $0x0e, %ah /* write char, tty mode */ - int $0x10 - jmp 1b -2: popw %bp - popw %bx - popw %ax - ret - .size print_message, . - print_message diff --git a/src/arch/i386/scripts/i386.lds b/src/arch/i386/scripts/i386.lds index d481db0f..a5a01056 100644 --- a/src/arch/i386/scripts/i386.lds +++ b/src/arch/i386/scripts/i386.lds @@ -257,6 +257,8 @@ SECTIONS { /* * Values calculated to save code from doing it */ + _prefix_size_pgh = ( ( _prefix_size + 15 ) / 16 ); + _prefix_size_sect = ( ( _prefix_size + 511 ) / 512 ); _text16_size_pgh = ( ( _text16_size + 15 ) / 16 ); _data16_size_pgh = ( ( _data16_size + 15 ) / 16 );