From 3050a9253437f4a4b5ad4bf3b3efdc3c660a5137 Mon Sep 17 00:00:00 2001 From: Sebastian Schmelzer Date: Mon, 25 Oct 2010 16:53:54 +0200 Subject: initial import of sc2010 scripts .. --- .../gpxe/src/arch/i386/prefix/bootpart.S | 218 ++++ .../gpxe/src/arch/i386/prefix/dskprefix.S | 381 +++++++ .../gpxe/src/arch/i386/prefix/hdprefix.S | 109 ++ .../gpxe/src/arch/i386/prefix/hromprefix.S | 12 + .../gpxe/src/arch/i386/prefix/kkpxeprefix.S | 13 + .../gpxe/src/arch/i386/prefix/kpxeprefix.S | 9 + .../gpxe/src/arch/i386/prefix/libprefix.S | 819 +++++++++++++++ .../gpxe/src/arch/i386/prefix/lkrnprefix.S | 216 ++++ .../syslinux-4.02/gpxe/src/arch/i386/prefix/mbr.S | 13 + .../gpxe/src/arch/i386/prefix/nbiprefix.S | 77 ++ .../gpxe/src/arch/i386/prefix/nullprefix.S | 13 + .../gpxe/src/arch/i386/prefix/pxeprefix.S | 761 ++++++++++++++ .../gpxe/src/arch/i386/prefix/romprefix.S | 1079 ++++++++++++++++++++ .../gpxe/src/arch/i386/prefix/undiloader.S | 49 + .../gpxe/src/arch/i386/prefix/unnrv2b.S | 184 ++++ .../gpxe/src/arch/i386/prefix/unnrv2b16.S | 9 + .../gpxe/src/arch/i386/prefix/usbdisk.S | 23 + .../gpxe/src/arch/i386/prefix/xromprefix.S | 9 + 18 files changed, 3994 insertions(+) create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/bootpart.S create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/dskprefix.S create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/hdprefix.S create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/hromprefix.S create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/kkpxeprefix.S create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/kpxeprefix.S create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/libprefix.S create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/lkrnprefix.S create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/mbr.S create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/nbiprefix.S create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/nullprefix.S create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/pxeprefix.S create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/romprefix.S create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/undiloader.S create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/unnrv2b.S create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/unnrv2b16.S create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/usbdisk.S create mode 100644 contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/xromprefix.S (limited to 'contrib/syslinux-4.02/gpxe/src/arch/i386/prefix') diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/bootpart.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/bootpart.S new file mode 100644 index 0000000..968da1a --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/bootpart.S @@ -0,0 +1,218 @@ +FILE_LICENCE ( GPL2_OR_LATER ) + +#define BOOT_SEG 0x07c0 +#define EXEC_SEG 0x0100 +#define STACK_SEG 0x0200 +#define STACK_SIZE 0x2000 + + .text + .arch i386 + .section ".prefix", "awx", @progbits + .code16 + +/* + * Find active partition + * + * Parameters: + * %dl : BIOS drive number + * %bp : Active partition handler routine + */ +find_active_partition: + /* Set up stack at STACK_SEG:STACK_SIZE */ + movw $STACK_SEG, %ax + movw %ax, %ss + movw $STACK_SIZE, %sp + + /* Relocate self to EXEC_SEG */ + pushw $BOOT_SEG + popw %ds + pushw $EXEC_SEG + popw %es + xorw %si, %si + xorw %di, %di + movw $0x200, %cx + rep movsb + ljmp $EXEC_SEG, $1f +1: pushw %ds + popw %es + pushw %cs + popw %ds + + /* Check for LBA extensions */ + movb $0x41, %ah + movw $0x55aa, %bx + stc + int $0x13 + jc 1f + cmpw $0xaa55, %bx + jne 1f + movw $read_lba, read_sectors +1: + /* Read and process root partition table */ + xorb %dh, %dh + movw $0x0001, %cx + xorl %esi, %esi + xorl %edi, %edi + call process_table + + /* Print failure message */ + movw $10f, %si + jmp boot_error +10: .asciz "Could not locate active partition\r\n" + +/* + * Print failure message and boot next device + * + * Parameters: + * %si : Failure string + */ +boot_error: + cld + movw $0x0007, %bx + movb $0x0e, %ah +1: lodsb + testb %al, %al + je 99f + int $0x10 + jmp 1b +99: /* Boot next device */ + int $0x18 + +/* + * Process partition table + * + * Parameters: + * %dl : BIOS drive number + * %dh : Head + * %cl : Sector (bits 0-5), high two bits of cylinder (bits 6-7) + * %ch : Low eight bits of cylinder + * %esi:%edi : LBA address + * %bp : Active partition handler routine + * + * Returns: + * CF set on error + */ +process_table: + pushal + call read_boot_sector + jc 99f + movw $446, %bx +1: call process_partition + addw $16, %bx + cmpw $510, %bx + jne 1b +99: popal + ret + +/* + * Process partition + * + * Parameters: + * %dl : BIOS drive number + * %dh : Head + * %cl : Sector (bits 0-5), high two bits of cylinder (bits 6-7) + * %ch : Low eight bits of cylinder + * %esi:%edi : LBA address + * %bx : Offset within partition table + * %bp : Active partition handler routine + */ +process_partition: + pushal + /* Load C/H/S values from partition entry */ + movb %es:1(%bx), %dh + movw %es:2(%bx), %cx + /* Update LBA address from partition entry */ + addl %es:8(%bx), %edi + adcl $0, %esi + /* Check active flag */ + testb $0x80, %es:(%bx) + jz 1f + call read_boot_sector + jc 99f + jmp *%bp +1: /* Check for extended partition */ + movb %es:4(%bx), %al + cmpb $0x05, %al + je 2f + cmpb $0x0f, %al + je 2f + cmpb $0x85, %al + jne 99f +2: call process_table +99: popal + /* Reload original partition table */ + call read_boot_sector + ret + +/* + * Read single sector to %es:0000 and verify 0x55aa signature + * + * Parameters: + * %dl : BIOS drive number + * %dh : Head + * %cl : Sector (bits 0-5), high two bits of cylinder (bits 6-7) + * %ch : Low eight bits of cylinder + * %esi:%edi : LBA address + * + * Returns: + * CF set on error + */ +read_boot_sector: + pushw %ax + movw $1, %ax + call *read_sectors + jc 99f + cmpw $0xaa55, %es:(510) + je 99f + stc +99: popw %ax + ret + +/* + * Read sectors to %es:0000 + * + * Parameters: + * %dl : BIOS drive number + * %dh : Head + * %cl : Sector (bits 0-5), high two bits of cylinder (bits 6-7) + * %ch : Low eight bits of cylinder + * %esi:%edi : LBA address + * %ax : Number of sectors (max 127) + * + * Returns: + * CF set on error + */ +read_sectors: .word read_chs + +read_chs: + /* Read sectors using C/H/S address */ + pushal + xorw %bx, %bx + movb $0x02, %ah + stc + int $0x13 + sti + popal + ret + +read_lba: + /* Read sectors using LBA address */ + pushal + movw %ax, (lba_desc + 2) + pushw %es + popw (lba_desc + 6) + movl %edi, (lba_desc + 8) + movl %esi, (lba_desc + 12) + movw $lba_desc, %si + movb $0x42, %ah + int $0x13 + popal + ret + +lba_desc: + .byte 0x10 + .byte 0 + .word 1 + .word 0x0000 + .word 0x0000 + .long 0, 0 diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/dskprefix.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/dskprefix.S new file mode 100644 index 0000000..60d351f --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/dskprefix.S @@ -0,0 +1,381 @@ +/* NOTE: this boot sector contains instructions that need at least an 80186. + * Yes, as86 has a bug somewhere in the valid instruction set checks. + * + */ + +/* floppyload.S Copyright (C) 1991, 1992 Linus Torvalds + * modified by Drew Eckhardt + * modified by Bruce Evans (bde) + * + * floppyprefix.S is loaded at 0x0000:0x7c00 by the bios-startup routines. + * + * It then loads the system at SYSSEG<<4, using BIOS interrupts. + * + * The loader has been made as simple as possible, and continuous read errors + * will result in a unbreakable loop. Reboot by hand. It loads pretty fast by + * getting whole tracks at a time whenever possible. + */ + +FILE_LICENCE ( GPL2_ONLY ) + +.equ BOOTSEG, 0x07C0 /* original address of boot-sector */ + +.equ SYSSEG, 0x1000 /* system loaded at SYSSEG<<4 */ + + .org 0 + .arch i386 + .text + .section ".prefix", "ax", @progbits + .code16 + + jmp $BOOTSEG, $go /* reload cs:ip to match relocation addr */ +go: + movw $0x2000-12, %di /* 0x2000 is arbitrary value >= length */ + /* of bootsect + room for stack + 12 for */ + /* saved disk parm block */ + + movw $BOOTSEG, %ax + movw %ax,%ds + movw %ax,%es + movw %ax,%ss /* put stack at BOOTSEG:0x4000-12. */ + movw %di,%sp + +/* Many BIOS's default disk parameter tables will not recognize multi-sector + * reads beyond the maximum sector number specified in the default diskette + * parameter tables - this may mean 7 sectors in some cases. + * + * Since single sector reads are slow and out of the question, we must take care + * of this by creating new parameter tables (for the first disk) in RAM. We + * will set the maximum sector count to 36 - the most we will encounter on an + * ED 2.88. High doesn't hurt. Low does. + * + * Segments are as follows: ds=es=ss=cs - BOOTSEG + */ + + xorw %cx,%cx + movw %cx,%es /* access segment 0 */ + movw $0x78, %bx /* 0:bx is parameter table address */ + pushw %ds /* save ds */ +/* 0:bx is parameter table address */ + ldsw %es:(%bx),%si /* loads ds and si */ + + movw %ax,%es /* ax is BOOTSECT (loaded above) */ + movb $6, %cl /* copy 12 bytes */ + cld + pushw %di /* keep a copy for later */ + rep + movsw /* ds:si is source, es:di is dest */ + popw %di + + movb $36,%es:4(%di) + + movw %cx,%ds /* access segment 0 */ + xchgw %di,(%bx) + movw %es,%si + xchgw %si,2(%bx) + popw %ds /* restore ds */ + movw %di, dpoff /* save old parameters */ + movw %si, dpseg /* to restore just before finishing */ + pushw %ds + popw %es /* reload es */ + +/* Note that es is already set up. Also cx is 0 from rep movsw above. */ + + xorb %ah,%ah /* reset FDC */ + xorb %dl,%dl + int $0x13 + +/* Get disk drive parameters, specifically number of sectors/track. + * + * It seems that there is no BIOS call to get the number of sectors. Guess + * 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read, + * 15 if sector 15 can be read. Otherwise guess 9. + */ + + movw $disksizes, %si /* table of sizes to try */ + +probe_loop: + lodsb + cbtw /* extend to word */ + movw %ax, sectors + cmpw $disksizes+4, %si + jae got_sectors /* if all else fails, try 9 */ + xchgw %cx,%ax /* cx = track and sector */ + xorw %dx,%dx /* drive 0, head 0 */ + movw $0x0200, %bx /* address after boot sector */ + /* (512 bytes from origin, es = cs) */ + movw $0x0201, %ax /* service 2, 1 sector */ + int $0x13 + jc probe_loop /* try next value */ + +got_sectors: + movw $msg1end-msg1, %cx + movw $msg1, %si + call print_str + +/* ok, we've written the Loading... message, now we want to load the system */ + + movw $SYSSEG, %ax + movw %ax,%es /* segment of SYSSEG<<4 */ + pushw %es + call read_it + +/* This turns off the floppy drive motor, so that we enter the kernel in a + * known state, and don't have to worry about it later. + */ + movw $0x3f2, %dx + xorb %al,%al + outb %al,%dx + + call print_nl + pop %es /* = SYSSEG */ + +/* Restore original disk parameters */ + movw $0x78, %bx + movw dpoff, %di + movw dpseg, %si + xorw %ax,%ax + movw %ax,%ds + movw %di,(%bx) + movw %si,2(%bx) + + /* Everything now loaded. %es = SYSSEG, so %es:0000 points to + * start of loaded image. + */ + + /* Jump to loaded copy */ + ljmp $SYSSEG, $start_runtime + +endseg: .word SYSSEG + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ + .ascii "ADDW" + .long endseg + .long 16 + .long 0 + .previous + +/* This routine loads the system at address SYSSEG<<4, making sure no 64kB + * boundaries are crossed. We try to load it as fast as possible, loading whole + * tracks whenever we can. + * + * in: es - starting address segment (normally SYSSEG) + */ +read_it: + movw $0,sread /* load whole image including prefix */ + movw %es,%ax + testw $0x0fff, %ax +die: jne die /* es must be at 64kB boundary */ + xorw %bx,%bx /* bx is starting address within segment */ +rp_read: + movw %es,%ax + movw %bx,%dx + movb $4, %cl + shrw %cl,%dx /* bx is always divisible by 16 */ + addw %dx,%ax + cmpw endseg, %ax /* have we loaded all yet? */ + jb ok1_read + ret +ok1_read: + movw sectors, %ax + subw sread, %ax + movw %ax,%cx + shlw $9, %cx + addw %bx,%cx + jnc ok2_read + je ok2_read + xorw %ax,%ax + subw %bx,%ax + shrw $9, %ax +ok2_read: + call read_track + movw %ax,%cx + addw sread, %ax + cmpw sectors, %ax + jne ok3_read + movw $1, %ax + subw head, %ax + jne ok4_read + incw track +ok4_read: + movw %ax, head + xorw %ax,%ax +ok3_read: + movw %ax, sread + shlw $9, %cx + addw %cx,%bx + jnc rp_read + movw %es,%ax + addb $0x10, %ah + movw %ax,%es + xorw %bx,%bx + jmp rp_read + +read_track: + pusha + pushw %ax + pushw %bx + pushw %bp /* just in case the BIOS is buggy */ + movw $0x0e2e, %ax /* 0x2e = . */ + movw $0x0007, %bx + int $0x10 + popw %bp + popw %bx + popw %ax + + movw track, %dx + movw sread, %cx + incw %cx + movb %dl,%ch + movw head, %dx + movb %dl,%dh + andw $0x0100, %dx + movb $2, %ah + + pushw %dx /* save for error dump */ + pushw %cx + pushw %bx + pushw %ax + + int $0x13 + jc bad_rt + addw $8, %sp + popa + ret + +bad_rt: pushw %ax /* save error code */ + call print_all /* ah = error, al = read */ + + xorb %ah,%ah + xorb %dl,%dl + int $0x13 + + addw $10, %sp + popa + jmp read_track + +/* print_all is for debugging purposes. It will print out all of the registers. + * The assumption is that this is called from a routine, with a stack frame like + * dx + * cx + * bx + * ax + * error + * ret <- sp + */ + +print_all: + call print_nl /* nl for readability */ + movw $5, %cx /* error code + 4 registers */ + movw %sp,%bp + +print_loop: + pushw %cx /* save count left */ + + cmpb $5, %cl + jae no_reg /* see if register name is needed */ + + movw $0x0007, %bx /* page 0, attribute 7 (normal) */ + movw $0xe05+0x41-1, %ax + subb %cl,%al + int $0x10 + + movb $0x58, %al /* 'X' */ + int $0x10 + + movb $0x3A, %al /* ':' */ + int $0x10 + +no_reg: + addw $2, %bp /* next register */ + call print_hex /* print it */ + movb $0x20, %al /* print a space */ + int $0x10 + popw %cx + loop print_loop + call print_nl /* nl for readability */ + ret + +print_str: + movw $0x0007, %bx /* page 0, attribute 7 (normal) */ + movb $0x0e, %ah /* write char, tty mode */ +prloop: + lodsb + int $0x10 + loop prloop + ret + +print_nl: + movw $0x0007, %bx /* page 0, attribute 7 (normal) */ + movw $0xe0d, %ax /* CR */ + int $0x10 + movb $0xa, %al /* LF */ + int $0x10 + ret + +/* print_hex prints the word pointed to by ss:bp in hexadecimal. */ + +print_hex: + movw (%bp),%dx /* load word into dx */ + movb $4, %cl + movb $0x0e, %ah /* write char, tty mode */ + movw $0x0007, %bx /* page 0, attribute 7 (normal) */ + call print_digit + call print_digit + call print_digit +/* fall through */ +print_digit: + rol %cl,%dx /* rotate so that lowest 4 bits are used */ + movb $0x0f, %al /* mask for nybble */ + andb %dl,%al + addb $0x90, %al /* convert al to ascii hex (four instructions) */ + daa + adcb $0x40, %al + daa + int $0x10 + ret + +sread: .word 0 /* sectors read of current track */ +head: .word 0 /* current head */ +track: .word 0 /* current track */ + +sectors: + .word 0 + +dpseg: .word 0 +dpoff: .word 0 + +disksizes: + .byte 36,18,15,9 + +msg1: + .ascii "Loading ROM image" +msg1end: + + .org 510, 0 + .word 0xAA55 + +start_runtime: + /* Install gPXE */ + call install + + /* Set up real-mode stack */ + movw %bx, %ss + movw $_estack16, %sp + + /* Jump to .text16 segment */ + pushw %ax + pushw $1f + lret + .section ".text16", "awx", @progbits +1: + pushl $main + pushw %cs + call prot_call + popl %ecx /* discard */ + + /* Uninstall gPXE */ + call uninstall + + /* Boot next device */ + int $0x18 + diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/hdprefix.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/hdprefix.S new file mode 100644 index 0000000..0576756 --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/hdprefix.S @@ -0,0 +1,109 @@ +FILE_LICENCE ( GPL2_OR_LATER ) + + .text + .arch i386 + .section ".prefix", "awx", @progbits + .code16 + .org 0 + + movw $load_image, %bp + jmp find_active_partition + +#include "bootpart.S" + +load_image: + /* Get disk geometry */ + pushal + pushw %es + movb $0x08, %ah + int $0x13 + jc load_failed + movb %cl, max_sector + movb %dh, max_head + popw %es + popal + +1: /* Read to end of current track */ + movb %cl, %al + negb %al + addb max_sector, %al + incb %al + andb $0x3f, %al + movzbl %al, %eax + call *read_sectors + jc load_failed + + /* Update %es */ + movw %es, %bx + shll $5, %eax + addw %ax, %bx + movw %bx, %es + shrl $5, %eax + + /* Update LBA address */ + addl %eax, %edi + adcl $0, %esi + + /* Update CHS address */ + andb $0xc0, %cl + orb $0x01, %cl + incb %dh + cmpb max_head, %dh + jbe 2f + xorb %dh, %dh + incb %ch + jnc 2f + addb $0xc0, %cl +2: + /* Loop until whole image is read */ + subl %eax, load_length + ja 1b + ljmp $BOOT_SEG, $start_image + +max_sector: + .byte 0 +max_head: + .byte 0 +load_length: + .long 0 + + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ + .ascii "ADDL" + .long load_length + .long 512 + .long 0 + .previous + + +load_failed: + movw $10f, %si + jmp boot_error +10: .asciz "Could not load gPXE\r\n" + + .org 510 + .byte 0x55, 0xaa + +start_image: + /* Install gPXE */ + call install + + /* Set up real-mode stack */ + movw %bx, %ss + movw $_estack16, %sp + + /* Jump to .text16 segment */ + pushw %ax + pushw $1f + lret + .section ".text16", "awx", @progbits +1: + pushl $main + pushw %cs + call prot_call + popl %ecx /* discard */ + + /* Uninstall gPXE */ + call uninstall + + /* Boot next device */ + int $0x18 diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/hromprefix.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/hromprefix.S new file mode 100644 index 0000000..03acf1e --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/hromprefix.S @@ -0,0 +1,12 @@ +/***************************************************************************** + * ROM prefix that relocates to HIGHMEM_LOADPOINT during POST if PMM allocation + * fails. Intended to be used, with caution, on BIOSes that support PCI3.00 but + * have limited PMM support, such as most AMI BIOSes. + ***************************************************************************** + */ + +FILE_LICENCE ( GPL2_OR_LATER ) + +#define SHRINK_WITHOUT_PMM + +#include "romprefix.S" diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/kkpxeprefix.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/kkpxeprefix.S new file mode 100644 index 0000000..02cc6fe --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/kkpxeprefix.S @@ -0,0 +1,13 @@ +/***************************************************************************** + * PXE prefix that keeps the whole PXE stack present + ***************************************************************************** + */ + +FILE_LICENCE ( GPL2_OR_LATER ) + +/* Since we have the whole stack, we can use cached DHCP information */ +REQUEST_OBJECT ( pxeparent_dhcp ) + +#define PXELOADER_KEEP_UNDI +#define PXELOADER_KEEP_PXE +#include "pxeprefix.S" diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/kpxeprefix.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/kpxeprefix.S new file mode 100644 index 0000000..923facc --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/kpxeprefix.S @@ -0,0 +1,9 @@ +/***************************************************************************** + * PXE prefix that keep the UNDI portion of the PXE stack present + ***************************************************************************** + */ + +FILE_LICENCE ( GPL2_OR_LATER ) + +#define PXELOADER_KEEP_UNDI +#include "pxeprefix.S" diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/libprefix.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/libprefix.S new file mode 100644 index 0000000..9e6ba6f --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/libprefix.S @@ -0,0 +1,819 @@ +/* + * Copyright (C) 2006 Michael Brown . + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ) + + .arch i386 + +/** + * High memory temporary load address + * + * Temporary buffer into which to copy (or decompress) our runtime + * image, prior to calling get_memmap() and relocate(). We don't + * actually leave anything here once install() has returned. + * + * 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 some PXE stack / PMM BIOS + * combinations are known to place data required by other UNDI ROMs + * loader around the 2MB mark. + */ + .globl HIGHMEM_LOADPOINT + .equ HIGHMEM_LOADPOINT, ( 4 << 20 ) + +/* Image compression enabled */ +#define COMPRESS 1 + +#define CR0_PE 1 + +/***************************************************************************** + * Utility function: print character (with LF -> LF,CR translation) + * + * Parameters: + * %al : character to print + * %ds:di : output buffer (or %di=0 to print to console) + * Returns: + * %ds:di : next character in output buffer (if applicable) + ***************************************************************************** + */ + .section ".prefix.lib", "awx", @progbits + .code16 + .globl print_character +print_character: + /* Preserve registers */ + pushw %ax + pushw %bx + pushw %bp + /* If %di is non-zero, write character to buffer and exit */ + testw %di, %di + jz 1f + movb %al, %ds:(%di) + incw %di + jmp 3f +1: /* Print character */ + movw $0x0007, %bx /* page 0, attribute 7 (normal) */ + movb $0x0e, %ah /* write char, tty mode */ + cmpb $0x0a, %al /* '\n'? */ + jne 2f + int $0x10 + movb $0x0d, %al +2: int $0x10 + /* Restore registers and return */ +3: popw %bp + popw %bx + popw %ax + ret + .size print_character, . - print_character + +/***************************************************************************** + * Utility function: print a NUL-terminated string + * + * Parameters: + * %ds:si : string to print + * %ds:di : output buffer (or %di=0 to print to console) + * Returns: + * %ds:si : character after terminating NUL + * %ds:di : next character in output buffer (if applicable) + ***************************************************************************** + */ + .section ".prefix.lib", "awx", @progbits + .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 + * %ds:di : output buffer (or %di=0 to print to console) + * Returns: + * %ds:di : next character in output buffer (if applicable) + ***************************************************************************** + */ + .section ".prefix.lib", "awx", @progbits + .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 + +/***************************************************************************** + * Utility function: print PCI bus:dev.fn + * + * Parameters: + * %ax : PCI bus:dev.fn to print + * %ds:di : output buffer (or %di=0 to print to console) + * Returns: + * %ds:di : next character in output buffer (if applicable) + ***************************************************************************** + */ + .section ".prefix.lib", "awx", @progbits + .code16 + .globl print_pci_busdevfn +print_pci_busdevfn: + /* Preserve registers */ + pushw %ax + /* Print bus */ + xchgb %al, %ah + call print_hex_byte + /* Print ":" */ + movb $( ':' ), %al + call print_character + /* Print device */ + movb %ah, %al + shrb $3, %al + call print_hex_byte + /* Print "." */ + movb $( '.' ), %al + call print_character + /* Print function */ + movb %ah, %al + andb $0x07, %al + call print_hex_nibble + /* Restore registers and return */ + popw %ax + ret + .size print_pci_busdevfn, . - print_pci_busdevfn + +/***************************************************************************** + * Utility function: clear current line + * + * Parameters: + * %ds:di : output buffer (or %di=0 to print to console) + * Returns: + * %ds:di : next character in output buffer (if applicable) + ***************************************************************************** + */ + .section ".prefix.lib", "awx", @progbits + .code16 + .globl print_kill_line +print_kill_line: + /* Preserve registers */ + pushw %ax + pushw %cx + /* Print CR */ + movb $( '\r' ), %al + call print_character + /* Print 79 spaces */ + movb $( ' ' ), %al + movw $79, %cx +1: call print_character + loop 1b + /* Print CR */ + movb $( '\r' ), %al + call print_character + /* Restore registers and return */ + popw %cx + popw %ax + ret + .size print_kill_line, . - print_kill_line + +/**************************************************************************** + * pm_call (real-mode near call) + * + * Call routine in 16-bit protected mode for access to extended memory + * + * Parameters: + * %ax : address of routine to call in 16-bit protected mode + * Returns: + * none + * Corrupts: + * %ax + * + * The specified routine is called in 16-bit protected mode, with: + * + * %cs : 16-bit code segment with base matching real-mode %cs + * %ss : 16-bit data segment with base matching real-mode %ss + * %ds,%es,%fs,%gs : 32-bit data segment with zero base and 4GB limit + * + **************************************************************************** + */ + +#ifndef KEEP_IT_REAL + + /* GDT for protected-mode calls */ + .section ".prefix.lib", "awx", @progbits + .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 */ + .equ PM_CS, pm_cs - gdt + .word 0xffff, 0 + .byte 0, 0x9b, 0x00, 0 +pm_ss: /* 16-bit protected-mode stack segment */ + .equ PM_SS, pm_ss - gdt + .word 0xffff, 0 + .byte 0, 0x93, 0x00, 0 +pm_ds: /* 32-bit protected-mode flat data segment */ + .equ PM_DS, pm_ds - gdt + .word 0xffff, 0 + .byte 0, 0x93, 0xcf, 0 +gdt_end: + .equ gdt_length, . - gdt + .size gdt, . - gdt + + .section ".prefix.lib", "awx", @progbits + .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", "awx", @progbits + .code16 +pm_call: + /* Preserve registers, flags, and RM return point */ + pushw %bp + movw %sp, %bp + subw $pm_call_vars_size, %sp + andw $0xfff0, %sp + pushfl + pushw %gs + pushw %fs + pushw %es + pushw %ds + pushw %ss + 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 + pushl %edi + xorl %eax, %eax + movw %ss, %ax + shll $4, %eax + movzwl %bp, %edi + addr32 leal PM_CALL_VAR(gdt)(%eax, %edi), %eax + movl %eax, PM_CALL_VAR(gdt_base)(%bp) + movw %cs, %ax + movw $PM_CALL_VAR(pm_cs), %di + call set_seg_base + movw %ss, %ax + movw $PM_CALL_VAR(pm_ss), %di + call set_seg_base + popl %edi + popl %eax + + /* Switch CPU to protected mode and load up segment registers */ + pushl %eax + cli + data32 lgdt PM_CALL_VAR(gdt)(%bp) + movl %cr0, %eax + orb $CR0_PE, %al + movl %eax, %cr0 + ljmp $PM_CS, $1f +1: movw $PM_SS, %ax + movw %ax, %ss + movw $PM_DS, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + popl %eax + + /* Call PM routine */ + call *%ax + + /* Set real-mode segment limits on %ds, %es, %fs and %gs */ + movw %ss, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + + /* Return CPU to real mode */ + movl %cr0, %eax + andb $0!CR0_PE, %al + movl %eax, %cr0 + + /* Restore registers and flags */ + lret /* will ljmp to 99f */ +99: popw %ss + popw %ds + popw %es + popw %fs + popw %gs + data32 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(%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 + +#endif /* KEEP_IT_REAL */ + +/**************************************************************************** + * copy_bytes (real-mode or 16-bit protected-mode near call) + * + * Copy bytes + * + * Parameters: + * %ds:esi : source address + * %es:edi : destination address + * %ecx : length + * Returns: + * %ds:esi : next source address + * %es:edi : next destination address + * Corrupts: + * None + **************************************************************************** + */ + .section ".prefix.lib", "awx", @progbits + .code16 +copy_bytes: + pushl %ecx + rep addr32 movsb + popl %ecx + ret + .size copy_bytes, . - copy_bytes + +/**************************************************************************** + * install_block (real-mode near call) + * + * Install block to specified address + * + * Parameters: + * %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: + * %esi : next source physical address (will be a multiple of 16) + * Corrupts: + * none + **************************************************************************** + */ + .section ".prefix.lib", "awx", @progbits + .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 +#else + /* Copy source to destination */ + call copy_bytes +#endif + + /* Zero .bss portion */ + negl %ecx + addl %edx, %ecx + pushw %ax + xorw %ax, %ax + rep addr32 stosb + popw %ax + + /* Round up %esi to start of next source 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 + +/**************************************************************************** + * alloc_basemem (real-mode near call) + * + * Allocate space for .text16 and .data16 from top of base memory. + * Memory is allocated using the BIOS free base memory counter at + * 0x40:13. + * + * Parameters: + * none + * Returns: + * %ax : .text16 segment address + * %bx : .data16 segment address + * Corrupts: + * none + **************************************************************************** + */ + .section ".prefix.lib", "awx", @progbits + .code16 + .globl alloc_basemem +alloc_basemem: + /* Preserve registers */ + pushw %fs + + /* FBMS => %ax as segment address */ + pushw $0x40 + popw %fs + movw %fs:0x13, %ax + shlw $6, %ax + + /* Calculate .data16 segment address */ + subw $_data16_memsz_pgh, %ax + pushw %ax + + /* Calculate .text16 segment address */ + subw $_text16_memsz_pgh, %ax + pushw %ax + + /* Update FBMS */ + shrw $6, %ax + movw %ax, %fs:0x13 + + /* Retrieve .text16 and .data16 segment addresses */ + popw %ax + popw %bx + + /* Restore registers and return */ + popw %fs + ret + .size alloc_basemem, . - alloc_basemem + +/**************************************************************************** + * free_basemem (real-mode near call) + * + * Free space allocated with alloc_basemem. + * + * Parameters: + * %ax : .text16 segment address + * %bx : .data16 segment address + * Returns: + * %ax : 0 if successfully freed + * Corrupts: + * none + **************************************************************************** + */ + .section ".text16", "ax", @progbits + .code16 + .globl free_basemem +free_basemem: + /* Preserve registers */ + pushw %fs + + /* Check FBMS counter */ + pushw %ax + shrw $6, %ax + pushw $0x40 + popw %fs + cmpw %ax, %fs:0x13 + popw %ax + jne 1f + + /* Check hooked interrupt count */ + cmpw $0, %cs:hooked_bios_interrupts + jne 1f + + /* OK to free memory */ + addw $_text16_memsz_pgh, %ax + addw $_data16_memsz_pgh, %ax + shrw $6, %ax + movw %ax, %fs:0x13 + xorw %ax, %ax + +1: /* Restore registers and return */ + popw %fs + ret + .size free_basemem, . - free_basemem + + .section ".text16.data", "aw", @progbits + .globl hooked_bios_interrupts +hooked_bios_interrupts: + .word 0 + .size hooked_bios_interrupts, . - hooked_bios_interrupts + +/**************************************************************************** + * install (real-mode near call) + * + * Install all text and data segments. + * + * Parameters: + * none + * Returns: + * %ax : .text16 segment address + * %bx : .data16 segment address + * Corrupts: + * none + **************************************************************************** + */ + .section ".prefix.lib", "awx", @progbits + .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", "awx", @progbits + .code16 + .globl install_prealloc +install_prealloc: + /* Save registers */ + pushal + pushw %ds + pushw %es + + /* Sanity: clear the direction flag asap */ + cld + + /* Calculate physical address of payload (i.e. first source) */ + testl %esi, %esi + jnz 1f + movw %cs, %si + shll $4, %esi +1: addl $_payload_lma, %esi + + /* Install .text16 and .data16 */ + pushl %edi + movzwl %ax, %edi + shll $4, %edi + movl $_text16_memsz, %ecx + movl %ecx, %edx + call install_block /* .text16 */ + movzwl %bx, %edi + shll $4, %edi + movl $_data16_filesz, %ecx + movl $_data16_memsz, %edx + call install_block /* .data16 */ + popl %edi + + /* Set up %ds for access to .data16 */ + movw %bx, %ds + +#ifdef KEEP_IT_REAL + /* Initialise libkir */ + movw %ax, (init_libkir_vector+2) + lcall *init_libkir_vector +#else + /* Install .text and .data to temporary area in high memory, + * prior to reading the E820 memory map and relocating + * properly. + */ + movl $_textdata_filesz, %ecx + movl $_textdata_memsz, %edx + call install_block + + /* Initialise librm at current location */ + movw %ax, (init_librm_vector+2) + lcall *init_librm_vector + + /* Call relocate() to determine target address for relocation. + * relocate() will return with %esi, %edi and %ecx set up + * ready for the copy to the new location. + */ + movw %ax, (prot_call_vector+2) + pushl $relocate + lcall *prot_call_vector + popl %edx /* discard */ + + /* Copy code to new location */ + pushl %edi + pushw %ax + movw $copy_bytes, %ax + call pm_call + popw %ax + popl %edi + + /* Initialise librm at new location */ + lcall *init_librm_vector + +#endif + /* Restore registers */ + popw %es + popw %ds + popal + ret + .size install_prealloc, . - install_prealloc + + /* Vectors for far calls to .text16 functions */ + .section ".data16", "aw", @progbits +#ifdef KEEP_IT_REAL +init_libkir_vector: + .word init_libkir + .word 0 + .size init_libkir_vector, . - init_libkir_vector +#else +init_librm_vector: + .word init_librm + .word 0 + .size init_librm_vector, . - init_librm_vector +prot_call_vector: + .word prot_call + .word 0 + .size prot_call_vector, . - prot_call_vector +#endif + +/**************************************************************************** + * uninstall (real-mode near call) + * + * Uninstall all text and data segments. + * + * Parameters: + * %ax : .text16 segment address + * %bx : .data16 segment address + * Returns: + * none + * Corrupts: + * none + **************************************************************************** + */ + .section ".text16", "ax", @progbits + .code16 + .globl uninstall +uninstall: + call free_basemem + ret + .size uninstall, . - uninstall + + + + /* File split information for the compressor */ +#if COMPRESS + .section ".zinfo", "a", @progbits + .ascii "COPY" + .long _prefix_lma + .long _prefix_filesz + .long _max_align + .ascii "PACK" + .long _text16_lma + .long _text16_filesz + .long _max_align + .ascii "PACK" + .long _data16_lma + .long _data16_filesz + .long _max_align + .ascii "PACK" + .long _textdata_lma + .long _textdata_filesz + .long _max_align +#else /* COMPRESS */ + .section ".zinfo", "a", @progbits + .ascii "COPY" + .long _prefix_lma + .long _filesz + .long _max_align +#endif /* COMPRESS */ diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/lkrnprefix.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/lkrnprefix.S new file mode 100644 index 0000000..101d038 --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/lkrnprefix.S @@ -0,0 +1,216 @@ +/* + Copyright (C) 2000, Entity Cyber, Inc. + + Authors: Gary Byers (gb@thinguin.org) + Marty Connor (mdc@thinguin.org) + + This software may be used and distributed according to the terms + of the GNU Public License (GPL), incorporated herein by reference. + + Description: + + This is just a little bit of code and data that can get prepended + to a ROM image in order to allow bootloaders to load the result + as if it were a Linux kernel image. + + A real Linux kernel image consists of a one-sector boot loader + (to load the image from a floppy disk), followed a few sectors + of setup code, followed by the kernel code itself. There's + a table in the first sector (starting at offset 497) that indicates + how many sectors of setup code follow the first sector and which + contains some other parameters that aren't interesting in this + case. + + When a bootloader loads the sectors that comprise a kernel image, + it doesn't execute the code in the first sector (since that code + would try to load the image from a floppy disk.) The code in the + first sector below doesn't expect to get executed (and prints an + error message if it ever -is- executed.) + + We don't require much in the way of setup code. Historically, the + Linux kernel required at least 4 sectors of setup code. + Therefore, at least 4 sectors must be present even though we don't + use them. + +*/ + +FILE_LICENCE ( GPL_ANY ) + +#define SETUPSECS 4 /* Minimal nr of setup-sectors */ +#define PREFIXSIZE ((SETUPSECS+1)*512) +#define PREFIXPGH (PREFIXSIZE / 16 ) +#define BOOTSEG 0x07C0 /* original address of boot-sector */ +#define INITSEG 0x9000 /* we move boot here - out of the way */ +#define SETUPSEG 0x9020 /* setup starts here */ +#define SYSSEG 0x1000 /* system loaded at 0x10000 (65536). */ + + .text + .code16 + .arch i386 + .org 0 + .section ".prefix", "ax", @progbits +/* + This is a minimal boot sector. If anyone tries to execute it (e.g., if + a .lilo file is dd'ed to a floppy), print an error message. +*/ + +bootsector: + jmp $BOOTSEG, $1f /* reload cs:ip to match relocation addr */ +1: + movw $0x2000, %di /* 0x2000 is arbitrary value >= length + of bootsect + room for stack */ + + movw $BOOTSEG, %ax + movw %ax,%ds + movw %ax,%es + + cli + movw %ax, %ss /* put stack at BOOTSEG:0x2000. */ + movw %di,%sp + sti + + movw $why_end-why, %cx + movw $why, %si + + movw $0x0007, %bx /* page 0, attribute 7 (normal) */ + movb $0x0e, %ah /* write char, tty mode */ +prloop: + lodsb + int $0x10 + loop prloop +freeze: jmp freeze + +why: .ascii "This image cannot be loaded from a floppy disk.\r\n" +why_end: + + +/* + The following header is documented in the Linux source code at + Documentation/i386/boot.txt +*/ + .org 497 +setup_sects: + .byte SETUPSECS +root_flags: + .word 0 +syssize: + .long -PREFIXPGH + + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ + .ascii "ADDL" + .long syssize + .long 16 + .long 0 + .previous + +ram_size: + .word 0 +vid_mode: + .word 0 +root_dev: + .word 0 +boot_flag: + .word 0xAA55 +jump: + /* Manually specify a two-byte jmp instruction here rather + * than leaving it up to the assembler. */ + .byte 0xeb + .byte setup_code - header +header: + .byte 'H', 'd', 'r', 'S' +version: + .word 0x0207 /* 2.07 */ +realmode_swtch: + .long 0 +start_sys: + .word 0 +kernel_version: + .word 0 +type_of_loader: + .byte 0 +loadflags: + .byte 0 +setup_move_size: + .word 0 +code32_start: + .long 0 +ramdisk_image: + .long 0 +ramdisk_size: + .long 0 +bootsect_kludge: + .long 0 +heap_end_ptr: + .word 0 +pad1: + .word 0 +cmd_line_ptr: + .long 0 +initrd_addr_max: + /* We don't use an initrd but some bootloaders (e.g. SYSLINUX) have + * been known to require this field. Set the value to 2 GB. This + * value is also used by the Linux kernel. */ + .long 0x7fffffff +kernel_alignment: + .long 0 +relocatable_kernel: + .byte 0 +pad2: + .byte 0, 0, 0 +cmdline_size: + .long 0 +hardware_subarch: + .long 0 +hardware_subarch_data: + .byte 0, 0, 0, 0, 0, 0, 0, 0 + +/* + We don't need to do too much setup. + + This code gets loaded at SETUPSEG:0. It wants to start + executing the image that's loaded at SYSSEG:0 and + whose entry point is SYSSEG:0. +*/ +setup_code: + /* We expect to be contiguous in memory once loaded. The Linux image + * boot process requires that setup code is loaded separately from + * "non-real code". Since we don't need any information that's left + * in the prefix, it doesn't matter: we just have to ensure that + * %cs:0000 is where the start of the image *would* be. + */ + ljmp $(SYSSEG-(PREFIXSIZE/16)), $run_gpxe + + + .org PREFIXSIZE +/* + We're now at the beginning of the kernel proper. + */ +run_gpxe: + /* Set up stack just below 0x7c00 */ + xorw %ax, %ax + movw %ax, %ss + movw $0x7c00, %sp + + /* Install gPXE */ + call install + + /* Set up real-mode stack */ + movw %bx, %ss + movw $_estack16, %sp + + /* Jump to .text16 segment */ + pushw %ax + pushw $1f + lret + .section ".text16", "awx", @progbits +1: + pushl $main + pushw %cs + call prot_call + popl %ecx /* discard */ + + /* Uninstall gPXE */ + call uninstall + + /* Boot next device */ + int $0x18 diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/mbr.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/mbr.S new file mode 100644 index 0000000..adfe204 --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/mbr.S @@ -0,0 +1,13 @@ + .text + .arch i386 + .section ".prefix", "awx", @progbits + .code16 + .org 0 + +mbr: + movw $exec_sector, %bp + jmp find_active_partition +exec_sector: + ljmp $0x0000, $0x7c00 + +#include "bootpart.S" diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/nbiprefix.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/nbiprefix.S new file mode 100644 index 0000000..607d80f --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/nbiprefix.S @@ -0,0 +1,77 @@ + .text + .arch i386 + .code16 + .section ".prefix", "ax", @progbits + .org 0 + +nbi_header: + +/***************************************************************************** + * NBI file header + ***************************************************************************** + */ +file_header: + .long 0x1b031336 /* Signature */ + .byte 0x04 /* 16 bytes header, no vendor info */ + .byte 0 + .byte 0 + .byte 0 /* No flags */ + .word 0x0000, 0x07c0 /* Load header to 0x07c0:0x0000 */ + .word entry, 0x07c0 /* Start execution at 0x07c0:entry */ + .size file_header, . - file_header + +/***************************************************************************** + * NBI segment header + ***************************************************************************** + */ +segment_header: + .byte 0x04 /* 16 bytes header, no vendor info */ + .byte 0 + .byte 0 + .byte 0x04 /* Last segment */ + .long 0x00007e00 +imglen: .long -512 +memlen: .long -512 + .size segment_header, . - segment_header + + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ + .ascii "ADDL" + .long imglen + .long 1 + .long 0 + .ascii "ADDL" + .long memlen + .long 1 + .long 0 + .previous + +/***************************************************************************** + * NBI entry point + ***************************************************************************** + */ +entry: + /* Install gPXE */ + call install + + /* Jump to .text16 segment */ + pushw %ax + pushw $1f + lret + .section ".text16", "awx", @progbits +1: + pushl $main + pushw %cs + call prot_call + popl %ecx /* discard */ + + /* Uninstall gPXE */ + call uninstall + + /* Reboot system */ + int $0x19 + + .previous + .size entry, . - entry + +nbi_header_end: + .org 512 diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/nullprefix.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/nullprefix.S new file mode 100644 index 0000000..032d41e --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/nullprefix.S @@ -0,0 +1,13 @@ + .org 0 + .text + .arch i386 + + .section ".prefix", "ax", @progbits + .code16 +_prefix: + + .section ".text16", "ax", @progbits +prefix_exit: + +prefix_exit_end: + .previous diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/pxeprefix.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/pxeprefix.S new file mode 100644 index 0000000..e728c48 --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/pxeprefix.S @@ -0,0 +1,761 @@ +FILE_LICENCE ( GPL2_OR_LATER ) + +#define PXENV_UNDI_SHUTDOWN 0x0005 +#define PXENV_UNDI_GET_NIC_TYPE 0x0012 +#define PXENV_UNDI_GET_IFACE_INFO 0x0013 +#define PXENV_STOP_UNDI 0x0015 +#define PXENV_UNLOAD_STACK 0x0070 + +#define PXE_HACK_EB54 0x0001 + + .text + .arch i386 + .org 0 + .code16 + +#include + +#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) ) +#define EB_MAGIC_1 ( 'E' + ( 't' << 8 ) + ( 'h' << 16 ) + ( 'e' << 24 ) ) +#define EB_MAGIC_2 ( 'r' + ( 'b' << 8 ) + ( 'o' << 16 ) + ( 'o' << 24 ) ) + +/***************************************************************************** + * Entry point: set operating context, print welcome message + ***************************************************************************** + */ + .section ".prefix", "ax", @progbits + jmp $0x7c0, $1f +1: + /* Preserve registers for possible return to PXE */ + pushfl + pushal + pushw %gs + pushw %fs + pushw %es + pushw %ds + + /* Store magic word on PXE stack and remember PXE %ss:esp */ + pushl $STACK_MAGIC + movw %ss, %cs:pxe_ss + movl %esp, %cs:pxe_esp + + /* Set up segments */ + movw %cs, %ax + movw %ax, %ds + movw $0x40, %ax /* BIOS data segment access */ + movw %ax, %fs + /* Set up stack just below 0x7c00 */ + xorw %ax, %ax + movw %ax, %ss + movl $0x7c00, %esp + /* Clear direction flag, for the sake of sanity */ + cld + /* Print welcome message */ + movw $10f, %si + xorw %di, %di + call print_message + .section ".prefix.data", "aw", @progbits +10: .asciz "PXE->EB:" + .previous + +/***************************************************************************** + * Find us a usable !PXE or PXENV+ entry point + ***************************************************************************** + */ +detect_pxe: + /* Plan A: !PXE pointer from the stack */ + lgsl pxe_esp, %ebp /* %gs:%bp -> original stack */ + lesw %gs:52(%bp), %bx + call is_valid_ppxe + je have_ppxe + + /* Plan B: PXENV+ pointer from initial ES:BX */ + movw %gs:32(%bp),%bx + movw %gs:8(%bp),%es + call is_valid_pxenv + je have_pxenv + + /* Plan C: PXENV+ structure via INT 1Ah */ + movw $0x5650, %ax + int $0x1a + jc 1f + cmpw $0x564e, %ax + jne 1f + call is_valid_pxenv + je have_pxenv +1: + /* Plan D: scan base memory for !PXE */ + call memory_scan_ppxe + je have_ppxe + + /* Plan E: scan base memory for PXENV+ */ + call memory_scan_pxenv + jne stack_not_found + +have_pxenv: + movw %bx, pxenv_offset + movw %es, pxenv_segment + + cmpw $0x201, %es:6(%bx) /* API version >= 2.01 */ + jb 1f + cmpb $0x2c, %es:8(%bx) /* ... and structure long enough */ + jb 2f + + lesw %es:0x28(%bx), %bx /* Find !PXE from PXENV+ */ + call is_valid_ppxe + je have_ppxe +2: + call memory_scan_ppxe /* We are *supposed* to have !PXE... */ + je have_ppxe +1: + lesw pxenv_segoff, %bx /* Nope, we're stuck with PXENV+ */ + + /* Record entry point and UNDI segments */ + pushl %es:0x0a(%bx) /* Entry point */ + pushw %es:0x24(%bx) /* UNDI code segment */ + pushw %es:0x26(%bx) /* UNDI code size */ + pushw %es:0x20(%bx) /* UNDI data segment */ + pushw %es:0x22(%bx) /* UNDI data size */ + + /* Print "PXENV+ at
" */ + movw $10f, %si + jmp check_have_stack + .section ".prefix.data", "aw", @progbits +10: .asciz " PXENV+ at " + .previous + +have_ppxe: + movw %bx, ppxe_offset + movw %es, ppxe_segment + + pushl %es:0x10(%bx) /* Entry point */ + pushw %es:0x30(%bx) /* UNDI code segment */ + pushw %es:0x36(%bx) /* UNDI code size */ + pushw %es:0x28(%bx) /* UNDI data segment */ + pushw %es:0x2e(%bx) /* UNDI data size */ + + /* Print "!PXE at
" */ + movw $10f, %si + jmp check_have_stack + .section ".prefix.data", "aw", @progbits +10: .asciz " !PXE at " + .previous + +is_valid_ppxe: + cmpl $0x45585021, %es:(%bx) + jne 1f + movzbw %es:4(%bx), %cx + cmpw $0x58, %cx + jae is_valid_checksum +1: + ret + +is_valid_pxenv: + cmpl $0x4e455850, %es:(%bx) + jne 1b + cmpw $0x2b56, %es:4(%bx) + jne 1b + movzbw %es:8(%bx), %cx + cmpw $0x28, %cx + jb 1b + +is_valid_checksum: + pushw %ax + movw %bx, %si + xorw %ax, %ax +2: + es lodsb + addb %al, %ah + loopw 2b + popw %ax + ret + +memory_scan_ppxe: + movw $is_valid_ppxe, %dx + jmp memory_scan_common + +memory_scan_pxenv: + movw $is_valid_pxenv, %dx + +memory_scan_common: + movw %fs:(0x13), %ax + shlw $6, %ax + decw %ax +1: incw %ax + cmpw $( 0xa000 - 1 ), %ax + ja 2f + movw %ax, %es + xorw %bx, %bx + call *%dx + jne 1b +2: ret + +/***************************************************************************** + * Sanity check: we must have an entry point + ***************************************************************************** + */ +check_have_stack: + /* Save common values pushed onto the stack */ + popl undi_data_segoff + popl undi_code_segoff + popl entry_segoff + + /* Print have !PXE/PXENV+ message; structure pointer in %es:%bx */ + call print_message + call print_segoff + movb $( ',' ), %al + call print_character + + /* Check for entry point */ + movl entry_segoff, %eax + testl %eax, %eax + jnz 99f + /* No entry point: print message and skip everything else */ +stack_not_found: + movw $10f, %si + call print_message + jmp finished + .section ".prefix.data", "aw", @progbits +10: .asciz " No PXE stack found!\n" + .previous +99: + +/***************************************************************************** + * Calculate base memory usage by UNDI + ***************************************************************************** + */ +find_undi_basemem_usage: + movw undi_code_segment, %ax + movw undi_code_size, %bx + movw undi_data_segment, %cx + movw undi_data_size, %dx + cmpw %ax, %cx + ja 1f + xchgw %ax, %cx + xchgw %bx, %dx +1: /* %ax:%bx now describes the lower region, %cx:%dx the higher */ + shrw $6, %ax /* Round down to nearest kB */ + movw %ax, undi_fbms_start + addw $0x0f, %dx /* Round up to next segment */ + shrw $4, %dx + addw %dx, %cx + addw $((1024 / 16) - 1), %cx /* Round up to next kB */ + shrw $6, %cx + movw %cx, undi_fbms_end + +/***************************************************************************** + * Print information about detected PXE stack + ***************************************************************************** + */ +print_structure_information: + /* Print entry point */ + movw $10f, %si + call print_message + les entry_segoff, %bx + call print_segoff + .section ".prefix.data", "aw", @progbits +10: .asciz " entry point at " + .previous + /* Print UNDI code segment */ + movw $10f, %si + call print_message + les undi_code_segoff, %bx + call print_segoff + .section ".prefix.data", "aw", @progbits +10: .asciz "\n UNDI code segment " + .previous + /* Print UNDI data segment */ + movw $10f, %si + call print_message + les undi_data_segoff, %bx + call print_segoff + .section ".prefix.data", "aw", @progbits +10: .asciz ", data segment " + .previous + /* Print UNDI memory usage */ + movw $10f, %si + call print_message + movw undi_fbms_start, %ax + call print_word + movb $( '-' ), %al + call print_character + movw undi_fbms_end, %ax + call print_word + movw $20f, %si + call print_message + .section ".prefix.data", "aw", @progbits +10: .asciz " (" +20: .asciz "kB)\n" + .previous + +/***************************************************************************** + * Determine physical device + ***************************************************************************** + */ +get_physical_device: + /* Issue PXENV_UNDI_GET_NIC_TYPE */ + movw $PXENV_UNDI_GET_NIC_TYPE, %bx + call pxe_call + jnc 1f + call print_pxe_error + jmp no_physical_device +1: /* Determine physical device type */ + movb ( pxe_parameter_structure + 0x02 ), %al + cmpb $2, %al + je pci_physical_device + jmp no_physical_device + +pci_physical_device: + /* Record PCI bus:dev.fn and vendor/device IDs */ + movl ( pxe_parameter_structure + 0x03 ), %eax + movl %eax, pci_vendor + movw ( pxe_parameter_structure + 0x0b ), %ax + movw %ax, pci_busdevfn + movw $10f, %si + call print_message + call print_pci_busdevfn + jmp 99f + .section ".prefix.data", "aw", @progbits +10: .asciz " UNDI device is PCI " + .previous + +no_physical_device: + /* No device found, or device type not understood */ + movw $10f, %si + call print_message + .section ".prefix.data", "aw", @progbits +10: .asciz " Unable to determine UNDI physical device" + .previous + +99: + +/***************************************************************************** + * Determine interface type + ***************************************************************************** + */ +get_iface_type: + /* Issue PXENV_UNDI_GET_IFACE_INFO */ + movw $PXENV_UNDI_GET_IFACE_INFO, %bx + call pxe_call + jnc 1f + call print_pxe_error + jmp 99f +1: /* Print interface type */ + movw $10f, %si + call print_message + leaw ( pxe_parameter_structure + 0x02 ), %si + call print_message + .section ".prefix.data", "aw", @progbits +10: .asciz ", type " + .previous + /* Check for "Etherboot" interface type */ + cmpl $EB_MAGIC_1, ( pxe_parameter_structure + 0x02 ) + jne 99f + cmpl $EB_MAGIC_2, ( pxe_parameter_structure + 0x06 ) + jne 99f + movw $10f, %si + call print_message + .section ".prefix.data", "aw", @progbits +10: .asciz " (workaround enabled)" + .previous + /* Flag Etherboot workarounds as required */ + orw $PXE_HACK_EB54, pxe_hacks + +99: movb $0x0a, %al + call print_character + +/***************************************************************************** + * Leave NIC in a safe state + ***************************************************************************** + */ +#ifndef PXELOADER_KEEP_PXE +shutdown_nic: + /* Issue PXENV_UNDI_SHUTDOWN */ + movw $PXENV_UNDI_SHUTDOWN, %bx + call pxe_call + jnc 1f + call print_pxe_error +1: +unload_base_code: + /* Etherboot treats PXENV_UNLOAD_STACK as PXENV_STOP_UNDI, so + * we must not issue this call if the underlying stack is + * Etherboot and we were not intending to issue a PXENV_STOP_UNDI. + */ +#ifdef PXELOADER_KEEP_UNDI + testw $PXE_HACK_EB54, pxe_hacks + jnz 99f +#endif /* PXELOADER_KEEP_UNDI */ + /* Issue PXENV_UNLOAD_STACK */ + movw $PXENV_UNLOAD_STACK, %bx + call pxe_call + jnc 1f + call print_pxe_error + jmp 99f +1: /* Free base memory used by PXE base code */ + movw undi_fbms_start, %ax + movw %fs:(0x13), %bx + call free_basemem +99: + andw $~( UNDI_FL_INITIALIZED | UNDI_FL_KEEP_ALL ), flags +#endif /* PXELOADER_KEEP_PXE */ + +/***************************************************************************** + * Unload UNDI driver + ***************************************************************************** + */ +#ifndef PXELOADER_KEEP_UNDI +unload_undi: + /* Issue PXENV_STOP_UNDI */ + movw $PXENV_STOP_UNDI, %bx + call pxe_call + jnc 1f + call print_pxe_error + jmp 99f +1: /* Free base memory used by UNDI */ + movw undi_fbms_end, %ax + movw undi_fbms_start, %bx + call free_basemem + /* Clear UNDI_FL_STARTED */ + andw $~UNDI_FL_STARTED, flags +99: +#endif /* PXELOADER_KEEP_UNDI */ + +/***************************************************************************** + * Print remaining free base memory + ***************************************************************************** + */ +print_free_basemem: + movw $10f, %si + call print_message + movw %fs:(0x13), %ax + call print_word + movw $20f, %si + call print_message + .section ".prefix.data", "aw", @progbits +10: .asciz " " +20: .asciz "kB free base memory after PXE unload\n" + .previous + +/***************************************************************************** + * Exit point + ***************************************************************************** + */ +finished: + jmp run_gpxe + +/***************************************************************************** + * Subroutine: print segment:offset address + * + * Parameters: + * %es:%bx : segment:offset address to print + * %ds:di : output buffer (or %di=0 to print to console) + * Returns: + * %ds:di : next character in output buffer (if applicable) + ***************************************************************************** + */ +print_segoff: + /* Preserve registers */ + pushw %ax + /* Print ":offset" */ + movw %es, %ax + call print_hex_word + movb $( ':' ), %al + call print_character + movw %bx, %ax + call print_hex_word + /* Restore registers and return */ + popw %ax + ret + +/***************************************************************************** + * Subroutine: print decimal word + * + * Parameters: + * %ax : word to print + * %ds:di : output buffer (or %di=0 to print to console) + * Returns: + * %ds:di : next character in output buffer (if applicable) + ***************************************************************************** + */ +print_word: + /* Preserve registers */ + pushw %ax + pushw %bx + pushw %cx + pushw %dx + /* Build up digit sequence on stack */ + movw $10, %bx + xorw %cx, %cx +1: xorw %dx, %dx + divw %bx, %ax + pushw %dx + incw %cx + testw %ax, %ax + jnz 1b + /* Print digit sequence */ +1: popw %ax + call print_hex_nibble + loop 1b + /* Restore registers and return */ + popw %dx + popw %cx + popw %bx + popw %ax + ret + +/***************************************************************************** + * Subroutine: zero 1kB block of base memory + * + * Parameters: + * %bx : block to zero (in kB) + * Returns: + * Nothing + ***************************************************************************** + */ +zero_kb: + /* Preserve registers */ + pushw %ax + pushw %cx + pushw %di + pushw %es + /* Zero block */ + movw %bx, %ax + shlw $6, %ax + movw %ax, %es + movw $0x400, %cx + xorw %di, %di + xorw %ax, %ax + rep stosb + /* Restore registers and return */ + popw %es + popw %di + popw %cx + popw %ax + ret + +/***************************************************************************** + * Subroutine: free and zero base memory + * + * Parameters: + * %ax : Desired new free base memory counter (in kB) + * %bx : Expected current free base memory counter (in kB) + * %fs : BIOS data segment (0x40) + * Returns: + * None + * + * The base memory from %bx kB to %ax kB is unconditionally zeroed. + * It will be freed if and only if the expected current free base + * memory counter (%bx) matches the actual current free base memory + * counter in 0x40:0x13; if this does not match then the memory will + * be leaked. + ***************************************************************************** + */ +free_basemem: + /* Zero base memory */ + pushw %bx +1: cmpw %bx, %ax + je 2f + call zero_kb + incw %bx + jmp 1b +2: popw %bx + /* Free base memory */ + cmpw %fs:(0x13), %bx /* Update FBMS only if "old" value */ + jne 1f /* is correct */ +1: movw %ax, %fs:(0x13) + ret + +/***************************************************************************** + * Subroutine: make a PXE API call. Works with either !PXE or PXENV+ API. + * + * Parameters: + * %bx : PXE API call number + * %ds:pxe_parameter_structure : Parameters for PXE API call + * Returns: + * %ax : PXE status code (not exit code) + * CF set if %ax is non-zero + ***************************************************************************** + */ +pxe_call: + /* Preserve registers */ + pushw %di + pushw %es + /* Set up registers for PXENV+ API. %bx already set up */ + pushw %ds + popw %es + movw $pxe_parameter_structure, %di + /* Set up stack for !PXE API */ + pushw %es + pushw %di + pushw %bx + /* Make the API call */ + lcall *entry_segoff + /* Reset the stack */ + addw $6, %sp + movw pxe_parameter_structure, %ax + clc + testw %ax, %ax + jz 1f + stc +1: /* Clear direction flag, for the sake of sanity */ + cld + /* Restore registers and return */ + popw %es + popw %di + ret + +/***************************************************************************** + * Subroutine: print PXE API call error message + * + * Parameters: + * %ax : PXE status code + * %bx : PXE API call number + * Returns: + * Nothing + ***************************************************************************** + */ +print_pxe_error: + pushw %si + movw $10f, %si + call print_message + xchgw %ax, %bx + call print_hex_word + movw $20f, %si + call print_message + xchgw %ax, %bx + call print_hex_word + movw $30f, %si + call print_message + popw %si + ret + .section ".prefix.data", "aw", @progbits +10: .asciz " UNDI API call " +20: .asciz " failed: status code " +30: .asciz "\n" + .previous + +/***************************************************************************** + * PXE data structures + ***************************************************************************** + */ + .section ".prefix.data" + +pxe_esp: .long 0 +pxe_ss: .word 0 + +pxe_parameter_structure: .fill 64 + +undi_code_segoff: +undi_code_size: .word 0 +undi_code_segment: .word 0 + +undi_data_segoff: +undi_data_size: .word 0 +undi_data_segment: .word 0 + +pxe_hacks: .word 0 + +/* The following fields are part of a struct undi_device */ + +undi_device: + +pxenv_segoff: +pxenv_offset: .word 0 +pxenv_segment: .word 0 + +ppxe_segoff: +ppxe_offset: .word 0 +ppxe_segment: .word 0 + +entry_segoff: +entry_offset: .word 0 +entry_segment: .word 0 + +undi_fbms_start: .word 0 +undi_fbms_end: .word 0 + +pci_busdevfn: .word UNDI_NO_PCI_BUSDEVFN +isapnp_csn: .word UNDI_NO_ISAPNP_CSN +isapnp_read_port: .word UNDI_NO_ISAPNP_READ_PORT + +pci_vendor: .word 0 +pci_device: .word 0 +flags: + .word ( UNDI_FL_INITIALIZED | UNDI_FL_STARTED | UNDI_FL_KEEP_ALL ) + + .equ undi_device_size, ( . - undi_device ) + +/***************************************************************************** + * Run gPXE main code + ***************************************************************************** + */ + .section ".prefix" +run_gpxe: + /* Install gPXE */ + call install + + /* Set up real-mode stack */ + movw %bx, %ss + movw $_estack16, %sp + +#ifdef PXELOADER_KEEP_UNDI + /* Copy our undi_device structure to the preloaded_undi variable */ + movw %bx, %es + movw $preloaded_undi, %di + movw $undi_device, %si + movw $undi_device_size, %cx + rep movsb +#endif + + /* Retrieve PXE %ss:esp */ + movw pxe_ss, %di + movl pxe_esp, %ebp + + /* Jump to .text16 segment with %ds pointing to .data16 */ + movw %bx, %ds + pushw %ax + pushw $1f + lret + .section ".text16", "ax", @progbits +1: + /* Update the exit hook */ + movw %cs,pxe_exit_hook+2 + push %ax + mov $2f,%ax + mov %ax,pxe_exit_hook + pop %ax + + /* Run main program */ + pushl $main + pushw %cs + call prot_call + popl %ecx /* discard */ + + /* Uninstall gPXE */ + call uninstall + + /* Restore PXE stack */ + movw %di, %ss + movl %ebp, %esp + + /* Jump to hook if applicable */ + ljmpw *pxe_exit_hook + +2: /* Check PXE stack magic */ + popl %eax + cmpl $STACK_MAGIC, %eax + jne 1f + + /* PXE stack OK: return to caller */ + popw %ds + popw %es + popw %fs + popw %gs + popal + popfl + xorw %ax, %ax /* Return success */ + lret + +1: /* PXE stack corrupt or removed: use INT 18 */ + int $0x18 + .previous diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/romprefix.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/romprefix.S new file mode 100644 index 0000000..02e5497 --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/romprefix.S @@ -0,0 +1,1079 @@ +/* At entry, the processor is in 16 bit real mode and the code is being + * executed from an address it was not linked to. Code must be pic and + * 32 bit sensitive until things are fixed up. + * + * Also be very careful as the stack is at the rear end of the interrupt + * table so using a noticeable amount of stack space is a no-no. + */ + +FILE_LICENCE ( GPL2_OR_LATER ) + +#include + +#define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) ) +#define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) ) +#define PCI_SIGNATURE ( 'P' + ( 'C' << 8 ) + ( 'I' << 16 ) + ( ' ' << 24 ) ) +#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) ) +#define PNP_GET_BBS_VERSION 0x60 +#define PMM_ALLOCATE 0x0000 +#define PMM_DEALLOCATE 0x0002 + +/* ROM banner timeout. Based on the configurable BANNER_TIMEOUT in + * config.h, but converted to a number of (18Hz) timer ticks, and + * doubled to allow for BIOSes that switch video modes immediately + * beforehand, so rendering the message almost invisible to the user. + */ +#define ROM_BANNER_TIMEOUT ( 2 * ( 18 * BANNER_TIMEOUT ) / 10 ) + +/* We can load a ROM in two ways: have the BIOS load all of it (.rom prefix) + * or have the BIOS load a stub that loads the rest using PCI (.xrom prefix). + * The latter is not as widely supported, but allows the use of large ROMs + * on some systems with crowded option ROM space. + */ + +#ifdef LOAD_ROM_FROM_PCI +#define ROM_SIZE_VALUE _prefix_filesz_sect /* Amount to load in BIOS */ +#else +#define ROM_SIZE_VALUE 0 /* Load amount (before compr. fixup) */ +#endif + + + .text + .code16 + .arch i386 + .section ".prefix", "ax", @progbits + + .org 0x00 +romheader: + .word 0xAA55 /* BIOS extension signature */ +romheader_size: .byte ROM_SIZE_VALUE /* Size in 512-byte blocks */ + jmp init /* Initialisation vector */ +checksum: + .byte 0, 0 +real_size: + .word 0 + .org 0x16 + .word undiheader + .org 0x18 + .word pciheader + .org 0x1a + .word pnpheader + .size romheader, . - romheader + + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ +#ifndef LOAD_ROM_FROM_PCI + .ascii "ADDB" + .long romheader_size + .long 512 + .long 0 +#endif + .ascii "ADDB" + .long real_size + .long 512 + .long 0 + .previous + +pciheader: + .ascii "PCIR" /* Signature */ + .word pci_vendor_id /* Vendor identification */ + .word pci_device_id /* Device identification */ + .word 0x0000 /* Device list pointer */ + .word pciheader_len /* PCI data structure length */ + .byte 0x03 /* PCI data structure revision */ + .byte 0x02, 0x00, 0x00 /* Class code */ +pciheader_image_length: + .word ROM_SIZE_VALUE /* Image length */ + .word 0x0001 /* Revision level */ + .byte 0x00 /* Code type */ + .byte 0x80 /* Last image indicator */ +pciheader_runtime_length: + .word ROM_SIZE_VALUE /* Maximum run-time image length */ + .word 0x0000 /* Configuration utility code header */ + .word 0x0000 /* DMTF CLP entry point */ + .equ pciheader_len, . - pciheader + .size pciheader, . - pciheader + +#ifndef LOAD_ROM_FROM_PCI + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ + .ascii "ADDW" + .long pciheader_image_length + .long 512 + .long 0 + .ascii "ADDW" + .long pciheader_runtime_length + .long 512 + .long 0 + .previous +#endif + +pnpheader: + .ascii "$PnP" /* Signature */ + .byte 0x01 /* Structure revision */ + .byte ( pnpheader_len / 16 ) /* Length (in 16 byte increments) */ + .word 0x0000 /* Offset of next header */ + .byte 0x00 /* Reserved */ + .byte 0x00 /* Checksum */ + .long 0x00000000 /* Device identifier */ + .word mfgstr /* Manufacturer string */ + .word prodstr /* Product name */ + .byte 0x02 /* Device base type code */ + .byte 0x00 /* Device sub-type code */ + .byte 0x00 /* Device interface type code */ + .byte 0xf4 /* Device indicator */ + .word 0x0000 /* Boot connection vector */ + .word 0x0000 /* Disconnect vector */ + .word bev_entry /* Boot execution vector */ + .word 0x0000 /* Reserved */ + .word 0x0000 /* Static resource information vector*/ + .equ pnpheader_len, . - pnpheader + .size pnpheader, . - pnpheader + +/* Manufacturer string */ +mfgstr: + .asciz "http://etherboot.org" + .size mfgstr, . - mfgstr + +/* Product string + * + * Defaults to PRODUCT_SHORT_NAME. If the ROM image is writable at + * initialisation time, it will be filled in to include the PCI + * bus:dev.fn number of the card as well. + */ +prodstr: + .ascii PRODUCT_SHORT_NAME +prodstr_separator: + .byte 0 + .ascii "(PCI " +prodstr_pci_id: + .asciz "xx:xx.x)" /* Filled in by init code */ + .size prodstr, . - prodstr + + .globl undiheader + .weak undiloader +undiheader: + .ascii "UNDI" /* Signature */ + .byte undiheader_len /* Length of structure */ + .byte 0 /* Checksum */ + .byte 0 /* Structure revision */ + .byte 0,1,2 /* PXE version: 2.1.0 */ + .word undiloader /* Offset to loader routine */ + .word _data16_memsz /* Stack segment size */ + .word _data16_memsz /* Data segment size */ + .word _text16_memsz /* Code segment size */ + .ascii "PCIR" /* Bus type */ + .equ undiheader_len, . - undiheader + .size undiheader, . - undiheader + +/* 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: + /* Preserve registers, clear direction flag, set %ds=%cs */ + pushaw + pushw %ds + pushw %es + pushw %fs + pushw %gs + cld + pushw %cs + popw %ds + + /* Shuffle some registers around. We need %di available for + * the print_xxx functions, and in a register that's + * addressable from %es, so shuffle as follows: + * + * %di (pointer to PnP structure) => %bx + * %bx (runtime segment address, for PCI 3.0) => %gs + */ + movw %bx, %gs + movw %di, %bx + + /* Print message as early as possible */ + movw $init_message, %si + xorw %di, %di + call print_message + call print_pci_busdevfn + +#ifdef LOAD_ROM_FROM_PCI + /* Save PCI bus:dev.fn for later use */ + movw %ax, pci_busdevfn +#endif + + /* Fill in product name string, if possible */ + movw $prodstr_pci_id, %di + call print_pci_busdevfn + movb $( ' ' ), prodstr_separator + + /* Print segment address */ + movb $( ' ' ), %al + xorw %di, %di + call print_character + movw %cs, %ax + call print_hex_word + + /* Check for PCI BIOS version */ + pushl %ebx + pushl %edx + pushl %edi + stc + movw $0xb101, %ax + int $0x1a + jc no_pci3 + cmpl $PCI_SIGNATURE, %edx + jne no_pci3 + testb %ah, %ah + jnz no_pci3 +#ifdef LOAD_ROM_FROM_PCI + incb pcibios_present +#endif + movw $init_message_pci, %si + xorw %di, %di + call print_message + movb %bh, %al + call print_hex_nibble + movb $( '.' ), %al + call print_character + movb %bl, %al + call print_hex_byte + cmpb $3, %bh + jb no_pci3 + /* PCI >=3.0: leave %gs as-is if sane */ + movw %gs, %ax + cmpw $0xa000, %ax /* Insane if %gs < 0xa000 */ + jb pci3_insane + movw %cs, %bx /* Sane if %cs == %gs */ + cmpw %bx, %ax + je 1f + movzbw romheader_size, %cx /* Sane if %cs+len <= %gs */ + shlw $5, %cx + addw %cx, %bx + cmpw %bx, %ax + jae 1f + movw %cs, %bx /* Sane if %gs+len <= %cs */ + addw %cx, %ax + cmpw %bx, %ax + jbe 1f +pci3_insane: /* PCI 3.0 with insane %gs value: print error and ignore %gs */ + movb $( '!' ), %al + call print_character + movw %gs, %ax + call print_hex_word +no_pci3: + /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */ + pushw %cs + popw %gs +1: popl %edi + popl %edx + popl %ebx + + /* Check for PnP BIOS. Although %es:di should point to the + * PnP BIOS signature on entry, some BIOSes fail to do this. + */ + movw $( 0xf000 - 1 ), %bx +pnp_scan: + incw %bx + jz no_pnp + movw %bx, %es + cmpl $PNP_SIGNATURE, %es:0 + jne pnp_scan + xorw %dx, %dx + xorw %si, %si + movzbw %es:5, %cx +1: es lodsb + addb %al, %dl + loop 1b + jnz pnp_scan + /* Is PnP: print PnP message */ + movw $init_message_pnp, %si + xorw %di, %di + call print_message + /* Check for BBS */ + pushw %es:0x1b /* Real-mode data segment */ + pushw %ds /* &(bbs_version) */ + pushw $bbs_version + pushw $PNP_GET_BBS_VERSION + lcall *%es:0xd + addw $8, %sp + testw %ax, %ax + je got_bbs +no_pnp: /* Not PnP-compliant - therefore cannot be BBS-compliant */ +no_bbs: /* Not BBS-compliant - must hook INT 19 */ + movw $init_message_int19, %si + xorw %di, %di + call print_message + xorw %ax, %ax + movw %ax, %es + pushl %es:( 0x19 * 4 ) + popl orig_int19 + pushw %gs /* %gs contains runtime %cs */ + pushw $int19_entry + popl %es:( 0x19 * 4 ) + jmp bbs_done +got_bbs: /* BBS compliant - no need to hook INT 19 */ + movw $init_message_bbs, %si + xorw %di, %di + call print_message +bbs_done: + + /* Check for PMM */ + movw $( 0xe000 - 1 ), %bx +pmm_scan: + incw %bx + jz no_pmm + movw %bx, %es + cmpl $PMM_SIGNATURE, %es:0 + jne pmm_scan + xorw %dx, %dx + xorw %si, %si + movzbw %es:5, %cx +1: es lodsb + addb %al, %dl + loop 1b + jnz pmm_scan + /* PMM found: print PMM message */ + movw $init_message_pmm, %si + xorw %di, %di + call print_message + /* We have PMM and so a 1kB stack: preserve upper register halves */ + pushal + /* Calculate required allocation size in %esi */ + movzwl real_size, %eax + shll $9, %eax + addl $_textdata_memsz, %eax + orw $0xffff, %ax /* Ensure allocation size is at least 64kB */ + bsrl %eax, %ecx + subw $15, %cx /* Round up and convert to 64kB count */ + movw $1, %si + shlw %cl, %si +pmm_loop: + /* Try to allocate block via PMM */ + pushw $0x0006 /* Aligned, extended memory */ + pushl $0xffffffff /* No handle */ + movzwl %si, %eax + shll $12, %eax + pushl %eax /* Allocation size in paragraphs */ + pushw $PMM_ALLOCATE + lcall *%es:7 + addw $12, %sp + /* Abort if allocation fails */ + testw %dx, %dx /* %ax==0 even on success, since align>=64kB */ + jz pmm_fail + /* If block has A20==1, free block and try again with twice + * the allocation size (and hence alignment). + */ + testw $0x0010, %dx + jz got_pmm + pushw %dx + pushw $0 + pushw $PMM_DEALLOCATE + lcall *%es:7 + addw $6, %sp + addw %si, %si + jmp pmm_loop +got_pmm: /* PMM allocation succeeded */ + movw %dx, ( image_source + 2 ) + movw %dx, %ax + xorw %di, %di + call print_hex_word + movb $( '@' ), %al + call print_character + movw %si, %ax + call print_hex_byte +pmm_copy: + /* Copy ROM to PMM block */ + xorw %ax, %ax + movw %ax, %es + movl image_source, %edi + 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 */ + movb $_prefix_memsz_sect, romheader_size +#if defined(SHRINK_WITHOUT_PMM) || defined(LOAD_ROM_FROM_PCI) + jmp pmm_done +pmm_fail: + /* Print marker and copy ourselves to high memory */ + movl $HIGHMEM_LOADPOINT, image_source + xorw %di, %di + movb $( '!' ), %al + call print_character + jmp pmm_copy +pmm_done: +#else +pmm_fail: +#endif + /* Restore upper register halves */ + popal +#if defined(LOAD_ROM_FROM_PCI) + call load_from_pci + jc load_err + jmp load_ok +no_pmm: + /* Cannot continue without PMM - print error message */ + xorw %di, %di + movw $init_message_no_pmm, %si + call print_message +load_err: + /* Wait for five seconds to let user see message */ + movw $90, %cx +1: call wait_for_tick + loop 1b + /* Mark environment as invalid and return */ + movl $0, decompress_to + jmp out + +load_ok: +#else +no_pmm: +#endif + /* Update checksum */ + xorw %bx, %bx + xorw %si, %si + movzbw romheader_size, %cx + shlw $9, %cx +1: lodsb + addb %al, %bl + loop 1b + subb %bl, checksum + + /* Copy self to option ROM space. Required for PCI3.0, which + * loads us to a temporary location in low memory. Will be a + * no-op for lower PCI versions. + */ + movb $( ' ' ), %al + xorw %di, %di + call print_character + movw %gs, %ax + call print_hex_word + movzbw romheader_size, %cx + shlw $9, %cx + movw %ax, %es + xorw %si, %si + xorw %di, %di + cs rep movsb + + /* Prompt for POST-time shell */ + movw $init_message_prompt, %si + xorw %di, %di + call print_message + movw $prodstr, %si + call print_message + movw $init_message_dots, %si + call print_message + /* Wait for Ctrl-B */ + movw $0xff02, %bx + call wait_for_key + /* Clear prompt */ + pushf + xorw %di, %di + call print_kill_line + movw $init_message_done, %si + call print_message + popf + jnz out + /* Ctrl-B was pressed: invoke gPXE. The keypress will be + * picked up by the initial shell prompt, and we will drop + * into a shell. + */ + pushw %cs + call exec +out: + /* Restore registers */ + popw %gs + popw %fs + popw %es + popw %ds + popaw + + /* Indicate boot capability to PnP BIOS, if present */ + movw $0x20, %ax + lret + .size init, . - init + +/* + * Note to hardware vendors: + * + * If you wish to brand this boot ROM, please do so by defining the + * strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/general.h. + * + * While nothing in the GPL prevents you from removing all references + * to gPXE or http://etherboot.org, we prefer you not to do so. + * + * If you have an OEM-mandated branding requirement that cannot be + * satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME, + * please contact us. + * + * [ Including an ASCII NUL in PRODUCT_NAME is considered to be + * bypassing the spirit of this request! ] + */ +init_message: + .ascii "\n" + .ascii PRODUCT_NAME + .ascii "\n" + .asciz "gPXE (http://etherboot.org) - " + .size init_message, . - init_message +init_message_pci: + .asciz " PCI" + .size init_message_pci, . - init_message_pci +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 +#ifdef LOAD_ROM_FROM_PCI +init_message_no_pmm: + .asciz "\nPMM required but not present!\n" + .size init_message_no_pmm, . - init_message_no_pmm +#endif +init_message_int19: + .asciz " INT19" + .size init_message_int19, . - init_message_int19 +init_message_prompt: + .asciz "\nPress Ctrl-B to configure " + .size init_message_prompt, . - init_message_prompt +init_message_dots: + .asciz "..." + .size init_message_dots, . - init_message_dots +init_message_done: + .asciz "\n\n" + .size init_message_done, . - init_message_done + +/* ROM image location + * + * May be either within option ROM space, or within PMM-allocated block. + */ + .globl image_source +image_source: + .long 0 + .size image_source, . - image_source + +/* Temporary decompression area + * + * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block. + * If a PCI ROM load fails, this will be set to zero. + */ + .globl decompress_to +decompress_to: + .long HIGHMEM_LOADPOINT + .size decompress_to, . - decompress_to + +#ifdef LOAD_ROM_FROM_PCI + +/* Set if the PCI BIOS is present, even <3.0 */ +pcibios_present: + .byte 0 + .byte 0 /* for alignment */ + .size pcibios_present, . - pcibios_present + +/* PCI bus:device.function word + * + * Filled in by init in the .xrom case, so the remainder of the ROM + * can be located. + */ +pci_busdevfn: + .word 0 + .size pci_busdevfn, . - pci_busdevfn + +#endif + +/* BBS version + * + * Filled in by BBS BIOS. We ignore the value. + */ +bbs_version: + .word 0 + .size bbs_version, . - bbs_version + +/* 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 + + +#ifdef LOAD_ROM_FROM_PCI + +#define PCI_ROM_ADDRESS 0x30 /* Bits 31:11 address, 10:1 reserved */ +#define PCI_ROM_ADDRESS_ENABLE 0x00000001 +#define PCI_ROM_ADDRESS_MASK 0xfffff800 + +#define PCIBIOS_READ_WORD 0xb109 +#define PCIBIOS_READ_DWORD 0xb10a +#define PCIBIOS_WRITE_WORD 0xb10c +#define PCIBIOS_WRITE_DWORD 0xb10d + +/* Determine size of PCI BAR + * + * %bx : PCI bus:dev.fn to probe + * %di : Address of BAR to find size of + * %edx : Mask of address bits within BAR + * + * %ecx : Size for a memory resource, + * 1 for an I/O resource (bit 0 set). + * CF : Set on error or nonexistent device (all-ones read) + * + * All other registers saved. + */ +pci_bar_size: + /* Save registers */ + pushw %ax + pushl %esi + pushl %edx + + /* Read current BAR value */ + movw $PCIBIOS_READ_DWORD, %ax + int $0x1a + + /* Check for device existence and save it */ + testb $1, %cl /* I/O bit? */ + jz 1f + andl $1, %ecx /* If so, exit with %ecx = 1 */ + jmp 99f +1: notl %ecx + testl %ecx, %ecx /* Set ZF iff %ecx was all-ones */ + notl %ecx + jnz 1f + stc /* All ones - exit with CF set */ + jmp 99f +1: movl %ecx, %esi /* Save in %esi */ + + /* Write all ones to BAR */ + movl %edx, %ecx + movw $PCIBIOS_WRITE_DWORD, %ax + int $0x1a + + /* Read back BAR */ + movw $PCIBIOS_READ_DWORD, %ax + int $0x1a + + /* Find decode size from least set bit in mask BAR */ + bsfl %ecx, %ecx /* Find least set bit, log2(decode size) */ + jz 1f /* Mask BAR should not be zero */ + xorl %edx, %edx + incl %edx + shll %cl, %edx /* %edx = decode size */ + jmp 2f +1: xorl %edx, %edx /* Return zero size for mask BAR zero */ + + /* Restore old BAR value */ +2: movl %esi, %ecx + movw $PCIBIOS_WRITE_DWORD, %ax + int $0x1a + + movl %edx, %ecx /* Return size in %ecx */ + + /* Restore registers and return */ +99: popl %edx + popl %esi + popw %ax + ret + + .size pci_bar_size, . - pci_bar_size + +/* PCI ROM loader + * + * Called from init in the .xrom case to load the non-prefix code + * using the PCI ROM BAR. + * + * Returns with carry flag set on error. All registers saved. + */ +load_from_pci: + /* + * Use PCI BIOS access to config space. The calls take + * + * %ah : 0xb1 %al : function + * %bx : bus/dev/fn + * %di : config space address + * %ecx : value to write (for writes) + * + * %ecx : value read (for reads) + * %ah : return code + * CF : error indication + * + * All registers not used for return are preserved. + */ + + /* Save registers and set up %es for big real mode */ + pushal + pushw %es + xorw %ax, %ax + movw %ax, %es + + /* Check PCI BIOS presence */ + cmpb $0, pcibios_present + jz err_pcibios + + /* Load existing PCI ROM BAR */ + movw $PCIBIOS_READ_DWORD, %ax + movw pci_busdevfn, %bx + movw $PCI_ROM_ADDRESS, %di + int $0x1a + + /* Maybe it's already enabled? */ + testb $PCI_ROM_ADDRESS_ENABLE, %cl + jz 1f + movb $1, %dl /* Flag indicating no deinit required */ + movl %ecx, %ebp + jmp check_rom + + /* Determine PCI BAR decode size */ +1: movl $PCI_ROM_ADDRESS_MASK, %edx + call pci_bar_size /* Returns decode size in %ecx */ + jc err_size_insane /* CF => no ROM BAR, %ecx == ffffffff */ + + /* Check sanity of decode size */ + xorl %eax, %eax + movw real_size, %ax + shll $9, %eax /* %eax = ROM size */ + cmpl %ecx, %eax + ja err_size_insane /* Insane if decode size < ROM size */ + cmpl $0x100000, %ecx + jae err_size_insane /* Insane if decode size >= 1MB */ + + /* Find a place to map the BAR + * In theory we should examine e820 and all PCI BARs to find a + * free region. However, we run at POST when e820 may not be + * available, and memory reads of an unmapped location are + * de facto standardized to return all-ones. Thus, we can get + * away with searching high memory (0xf0000000 and up) on + * multiples of the ROM BAR decode size for a sufficiently + * large all-ones region. + */ + movl %ecx, %edx /* Save ROM BAR size in %edx */ + movl $0xf0000000, %ebp + xorl %eax, %eax + notl %eax /* %eax = all ones */ +bar_search: + movl %ebp, %edi + movl %edx, %ecx + shrl $2, %ecx + addr32 repe scasl /* Scan %es:edi for anything not all-ones */ + jz bar_found + addl %edx, %ebp + testl $0x80000000, %ebp + jz err_no_bar + jmp bar_search + +bar_found: + movl %edi, %ebp + /* Save current BAR value on stack to restore later */ + movw $PCIBIOS_READ_DWORD, %ax + movw $PCI_ROM_ADDRESS, %di + int $0x1a + pushl %ecx + + /* Map the ROM */ + movw $PCIBIOS_WRITE_DWORD, %ax + movl %ebp, %ecx + orb $PCI_ROM_ADDRESS_ENABLE, %cl + int $0x1a + + xorb %dl, %dl /* %dl = 0 : ROM was not already mapped */ +check_rom: + /* Check and copy ROM - enter with %dl set to skip unmapping, + * %ebp set to mapped ROM BAR address. + * We check up to prodstr_separator for equality, since anything past + * that may have been modified. Since our check includes the checksum + * byte over the whole ROM stub, that should be sufficient. + */ + xorb %dh, %dh /* %dh = 0 : ROM did not fail integrity check */ + + /* Verify ROM integrity */ + xorl %esi, %esi + movl %ebp, %edi + movl $prodstr_separator, %ecx + addr32 repe cmpsb + jz copy_rom + incb %dh /* ROM failed integrity check */ + movl %ecx, %ebp /* Save number of bytes left */ + jmp skip_load + +copy_rom: + /* Print BAR address and indicate whether we mapped it ourselves */ + movb $( ' ' ), %al + xorw %di, %di + call print_character + movl %ebp, %eax + call print_hex_dword + movb $( '-' ), %al /* '-' for self-mapped */ + subb %dl, %al + subb %dl, %al /* '+' = '-' - 2 for BIOS-mapped */ + call print_character + + /* Copy ROM at %ebp to PMM or highmem block */ + movl %ebp, %esi + movl image_source, %edi + movzwl real_size, %ecx + shll $9, %ecx + addr32 es rep movsb + movl %edi, decompress_to +skip_load: + testb %dl, %dl /* Was ROM already mapped? */ + jnz skip_unmap + + /* Unmap the ROM by restoring old ROM BAR */ + movw $PCIBIOS_WRITE_DWORD, %ax + movw $PCI_ROM_ADDRESS, %di + popl %ecx + int $0x1a + +skip_unmap: + /* Error handling */ + testb %dh, %dh + jnz err_rom_invalid + clc + jmp 99f + +err_pcibios: /* No PCI BIOS available */ + movw $load_message_no_pcibios, %si + xorl %eax, %eax /* "error code" is zero */ + jmp 1f +err_size_insane: /* BAR has size (%ecx) that is insane */ + movw $load_message_size_insane, %si + movl %ecx, %eax + jmp 1f +err_no_bar: /* No space of sufficient size (%edx) found */ + movw $load_message_no_bar, %si + movl %edx, %eax + jmp 1f +err_rom_invalid: /* Loaded ROM does not match (%ebp bytes left) */ + movw $load_message_rom_invalid, %si + movzbl romheader_size, %eax + shll $9, %eax + subl %ebp, %eax + decl %eax /* %eax is now byte index of failure */ + +1: /* Error handler - print message at %si and dword in %eax */ + xorw %di, %di + call print_message + call print_hex_dword + stc +99: popw %es + popal + ret + + .size load_from_pci, . - load_from_pci + +load_message_no_pcibios: + .asciz "\nNo PCI BIOS found! " + .size load_message_no_pcibios, . - load_message_no_pcibios + +load_message_size_insane: + .asciz "\nROM resource has invalid size " + .size load_message_size_insane, . - load_message_size_insane + +load_message_no_bar: + .asciz "\nNo memory hole of sufficient size " + .size load_message_no_bar, . - load_message_no_bar + +load_message_rom_invalid: + .asciz "\nLoaded ROM is invalid at " + .size load_message_rom_invalid, . - load_message_rom_invalid + +#endif /* LOAD_ROM_FROM_PCI */ + + +/* INT19 entry point + * + * Called via the hooked INT 19 if we detected a non-PnP BIOS. We + * attempt to return via the original INT 19 vector (if we were able + * to store it). + */ +int19_entry: + pushw %cs + popw %ds + /* Prompt user to press B to boot */ + movw $int19_message_prompt, %si + xorw %di, %di + call print_message + movw $prodstr, %si + call print_message + movw $int19_message_dots, %si + call print_message + movw $0xdf4e, %bx + call wait_for_key + pushf + xorw %di, %di + call print_kill_line + movw $int19_message_done, %si + call print_message + popf + jz 1f + /* Leave keypress in buffer and start gPXE. The keypress will + * cause the usual initial Ctrl-B prompt to be skipped. + */ + pushw %cs + call exec +1: /* Try to call original INT 19 vector */ + movl %cs:orig_int19, %eax + testl %eax, %eax + je 2f + ljmp *%cs:orig_int19 +2: /* No chained vector: issue INT 18 as a last resort */ + int $0x18 + .size int19_entry, . - int19_entry +orig_int19: + .long 0 + .size orig_int19, . - orig_int19 + +int19_message_prompt: + .asciz "Press N to skip booting from " + .size int19_message_prompt, . - int19_message_prompt +int19_message_dots: + .asciz "..." + .size int19_message_dots, . - int19_message_dots +int19_message_done: + .asciz "\n\n" + .size int19_message_done, . - int19_message_done + +/* Execute as a boot device + * + */ +exec: /* Set %ds = %cs */ + pushw %cs + popw %ds + +#ifdef LOAD_ROM_FROM_PCI + /* Don't execute if load was invalid */ + cmpl $0, decompress_to + jne 1f + lret +1: +#endif + + /* Print message as soon as possible */ + movw $prodstr, %si + xorw %di, %di + call print_message + movw $exec_message, %si + call print_message + + /* 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 + movw $_estack16, %sp + + /* Jump to .text16 segment */ + pushw %ax + pushw $1f + lret + .section ".text16", "awx", @progbits +1: /* Call main() */ + pushl $main + pushw %cs + call prot_call + popl %ecx /* discard */ + + /* Uninstall gPXE */ + call uninstall + + /* Restore BIOS stack */ + movw %dx, %ss + movw %bp, %sp + + /* 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 " starting execution\n" + .size exec_message, . - exec_message + +/* Wait for key press specified by %bl (masked by %bh) + * + * Used by init and INT19 code when prompting user. If the specified + * key is pressed, it is left in the keyboard buffer. + * + * Returns with ZF set iff specified key is pressed. + */ +wait_for_key: + /* Preserve registers */ + pushw %cx + pushw %ax +1: /* Empty the keyboard buffer before waiting for input */ + movb $0x01, %ah + int $0x16 + jz 2f + xorw %ax, %ax + int $0x16 + jmp 1b +2: /* Wait for a key press */ + movw $ROM_BANNER_TIMEOUT, %cx +3: decw %cx + js 99f /* Exit with ZF clear */ + /* Wait for timer tick to be updated */ + call wait_for_tick + /* Check to see if a key was pressed */ + movb $0x01, %ah + int $0x16 + jz 3b + /* Check to see if key was the specified key */ + andb %bh, %al + cmpb %al, %bl + je 99f /* Exit with ZF set */ + /* Not the specified key: remove from buffer and stop waiting */ + pushfw + xorw %ax, %ax + int $0x16 + popfw /* Exit with ZF clear */ +99: /* Restore registers and return */ + popw %ax + popw %cx + ret + .size wait_for_key, . - wait_for_key + +/* Wait for timer tick + * + * Used by wait_for_key + */ +wait_for_tick: + pushl %eax + pushw %fs + movw $0x40, %ax + movw %ax, %fs + movl %fs:(0x6c), %eax +1: pushf + sti + hlt + popf + cmpl %fs:(0x6c), %eax + je 1b + popw %fs + popl %eax + ret + .size wait_for_tick, . - wait_for_tick diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/undiloader.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/undiloader.S new file mode 100644 index 0000000..36c1bef --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/undiloader.S @@ -0,0 +1,49 @@ + .text + .code16 + .arch i386 + .section ".prefix", "ax", @progbits + +/* UNDI loader + * + * Called by an external program to load our PXE stack. + */ + .globl undiloader +undiloader: + /* Save registers */ + pushl %esi + pushl %edi + pushw %ds + pushw %es + pushw %bx + /* ROM segment address to %ds */ + pushw %cs + popw %ds + /* UNDI loader parameter structure address into %es:%di */ + movw %sp, %bx + movw %ss:18(%bx), %di + movw %ss:20(%bx), %es + /* Install to specified real-mode addresses */ + pushw %di + movw %es:12(%di), %bx + movw %es:14(%di), %ax + movl image_source, %esi + movl decompress_to, %edi + call install_prealloc + popw %di + /* Call UNDI loader C code */ + pushl $pxe_loader_call + pushw %cs + pushw $1f + pushw %ax + pushw $prot_call + lret +1: popw %bx /* discard */ + popw %bx /* discard */ + /* Restore registers and return */ + popw %bx + popw %es + popw %ds + popl %edi + popl %esi + lret + .size undiloader, . - undiloader diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/unnrv2b.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/unnrv2b.S new file mode 100644 index 0000000..f5724c1 --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/unnrv2b.S @@ -0,0 +1,184 @@ +/* + * Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer + * + * This file 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 (at your option) any later version. + * + * Originally this code was part of ucl the data compression library + * for upx the ``Ultimate Packer of eXecutables''. + * + * - Converted to gas assembly, and refitted to work with etherboot. + * Eric Biederman 20 Aug 2002 + * + * - Structure modified to be a subroutine call rather than an + * executable prefix. + * Michael Brown 30 Mar 2004 + * + * - Modified to be compilable as either 16-bit or 32-bit code. + * Michael Brown 9 Mar 2005 + */ + +FILE_LICENCE ( GPL2_OR_LATER ) + +/**************************************************************************** + * This file provides the decompress() and decompress16() functions + * which can be called in order to decompress an image compressed with + * the nrv2b utility in src/util. + * + * These functions are designed to be called by the prefix. They are + * position-independent code. + * + * The same basic assembly code is used to compile both + * decompress() and decompress16(). + **************************************************************************** + */ + + .text + .arch i386 + .section ".prefix.lib", "ax", @progbits + +#ifdef CODE16 +/**************************************************************************** + * decompress16 (real-mode near call, position independent) + * + * Decompress data in 16-bit mode + * + * Parameters (passed via registers): + * %ds:%esi - Start of compressed input data + * %es:%edi - Start of output buffer + * Returns: + * %ds:%esi - End of compressed input data + * %es:%edi - End of decompressed output data + * All other registers are preserved + * + * NOTE: It would be possible to build a smaller version of the + * decompression code for -DKEEP_IT_REAL by using + * #define REG(x) x + * to use 16-bit registers where possible. This would impose limits + * that the compressed data size must be in the range [1,65533-%si] + * and the uncompressed data size must be in the range [1,65536-%di] + * (where %si and %di are the input values for those registers). Note + * particularly that the lower limit is 1, not 0, and that the upper + * limit on the input (compressed) data really is 65533, since the + * algorithm may read up to three bytes beyond the end of the input + * data, since it reads dwords. + **************************************************************************** + */ + +#define REG(x) e ## x +#define ADDR32 addr32 + + .code16 + .globl decompress16 +decompress16: + +#else /* CODE16 */ + +/**************************************************************************** + * decompress (32-bit protected-mode near call, position independent) + * + * Parameters (passed via registers): + * %ds:%esi - Start of compressed input data + * %es:%edi - Start of output buffer + * Returns: + * %ds:%esi - End of compressed input data + * %es:%edi - End of decompressed output data + * All other registers are preserved + **************************************************************************** + */ + +#define REG(x) e ## x +#define ADDR32 + + .code32 + .globl decompress +decompress: + +#endif /* CODE16 */ + +#define xAX REG(ax) +#define xCX REG(cx) +#define xBP REG(bp) +#define xSI REG(si) +#define xDI REG(di) + + /* Save registers */ + push %xAX + pushl %ebx + push %xCX + push %xBP + /* Do the decompression */ + cld + xor %xBP, %xBP + dec %xBP /* last_m_off = -1 */ + jmp dcl1_n2b + +decompr_literals_n2b: + ADDR32 movsb +decompr_loop_n2b: + addl %ebx, %ebx + jnz dcl2_n2b +dcl1_n2b: + call getbit32 +dcl2_n2b: + jc decompr_literals_n2b + xor %xAX, %xAX + inc %xAX /* m_off = 1 */ +loop1_n2b: + call getbit1 + adc %xAX, %xAX /* m_off = m_off*2 + getbit() */ + call getbit1 + jnc loop1_n2b /* while(!getbit()) */ + sub $3, %xAX + jb decompr_ebpeax_n2b /* if (m_off == 2) goto decompr_ebpeax_n2b ? */ + shl $8, %xAX + ADDR32 movb (%xSI), %al /* m_off = (m_off - 3)*256 + src[ilen++] */ + inc %xSI + xor $-1, %xAX + jz decompr_end_n2b /* if (m_off == 0xffffffff) goto decomp_end_n2b */ + mov %xAX, %xBP /* last_m_off = m_off ?*/ +decompr_ebpeax_n2b: + xor %xCX, %xCX + call getbit1 + adc %xCX, %xCX /* m_len = getbit() */ + call getbit1 + adc %xCX, %xCX /* m_len = m_len*2 + getbit()) */ + jnz decompr_got_mlen_n2b /* if (m_len == 0) goto decompr_got_mlen_n2b */ + inc %xCX /* m_len++ */ +loop2_n2b: + call getbit1 + adc %xCX, %xCX /* m_len = m_len*2 + getbit() */ + call getbit1 + jnc loop2_n2b /* while(!getbit()) */ + inc %xCX + inc %xCX /* m_len += 2 */ +decompr_got_mlen_n2b: + cmp $-0xd00, %xBP + adc $1, %xCX /* m_len = m_len + 1 + (last_m_off > 0xd00) */ + push %xSI + ADDR32 lea (%xBP,%xDI), %xSI /* m_pos = dst + olen + -m_off */ + rep + es ADDR32 movsb /* dst[olen++] = *m_pos++ while(m_len > 0) */ + pop %xSI + jmp decompr_loop_n2b + + +getbit1: + addl %ebx, %ebx + jnz 1f +getbit32: + ADDR32 movl (%xSI), %ebx + sub $-4, %xSI /* sets carry flag */ + adcl %ebx, %ebx +1: + ret + +decompr_end_n2b: + /* Restore registers and return */ + pop %xBP + pop %xCX + popl %ebx + pop %xAX + ret diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/unnrv2b16.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/unnrv2b16.S new file mode 100644 index 0000000..b24c284 --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/unnrv2b16.S @@ -0,0 +1,9 @@ +/* + * 16-bit version of the decompressor + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ) + +#define CODE16 +#include "unnrv2b.S" diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/usbdisk.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/usbdisk.S new file mode 100644 index 0000000..fa7d195 --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/usbdisk.S @@ -0,0 +1,23 @@ + .text + .arch i386 + .section ".prefix", "awx", @progbits + .code16 + .org 0 + +#include "mbr.S" + +/* Partition table: ZIP-compatible partition 4, 64 heads, 32 sectors/track */ + .org 446 + .space 16 + .space 16 + .space 16 + .byte 0x80, 0x01, 0x01, 0x00 + .byte 0xeb, 0x3f, 0x20, 0x01 + .long 0x00000020 + .long 0x00000fe0 + + .org 510 + .byte 0x55, 0xaa + +/* Skip to start of partition */ + .org 32 * 512 diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/xromprefix.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/xromprefix.S new file mode 100644 index 0000000..d7c861f --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/xromprefix.S @@ -0,0 +1,9 @@ +/* + * ROM prefix that loads the bulk of the ROM using direct PCI accesses, + * so as not to take up much option ROM space on PCI <3.0 systems. + */ + +FILE_LICENCE ( GPL2_OR_LATER ) + +#define LOAD_ROM_FROM_PCI +#include "romprefix.S" -- cgit v1.2.3-55-g7522