aboutsummaryrefslogtreecommitdiffstats
path: root/gpxe/src/arch/i386
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2008-06-04 18:52:18 -0700
committerH. Peter Anvin <hpa@zytor.com>2008-06-04 18:52:18 -0700
commite63132bf03140d91ec74eca663f7bc2f16429fb0 (patch)
treeea5af9895146e85d3912584e699799863e0f8a29 /gpxe/src/arch/i386
parentbce8e1595ab30c828254038523e1e25c9fd9445f (diff)
downloadsyslinux.git-e63132bf03140d91ec74eca663f7bc2f16429fb0.tar.gz
syslinux.git-e63132bf03140d91ec74eca663f7bc2f16429fb0.tar.xz
syslinux.git-e63132bf03140d91ec74eca663f7bc2f16429fb0.zip
Update gPXE from gPXE git
Diffstat (limited to 'gpxe/src/arch/i386')
-rw-r--r--gpxe/src/arch/i386/Makefile2
-rw-r--r--gpxe/src/arch/i386/core/gdbidt.S209
-rw-r--r--gpxe/src/arch/i386/core/gdbsym.c33
-rw-r--r--gpxe/src/arch/i386/drivers/net/undinet.c3
-rw-r--r--gpxe/src/arch/i386/image/pxe_image.c8
-rw-r--r--gpxe/src/arch/i386/include/gdbmach.h51
-rw-r--r--gpxe/src/arch/i386/prefix/libprefix.S64
-rw-r--r--gpxe/src/arch/i386/prefix/pxeprefix.S117
-rw-r--r--gpxe/src/arch/i386/prefix/romprefix.S116
-rw-r--r--gpxe/src/arch/i386/transitions/librm.S43
10 files changed, 495 insertions, 151 deletions
diff --git a/gpxe/src/arch/i386/Makefile b/gpxe/src/arch/i386/Makefile
index da7976df..926daa1a 100644
--- a/gpxe/src/arch/i386/Makefile
+++ b/gpxe/src/arch/i386/Makefile
@@ -8,9 +8,7 @@ SRCDIRS += arch/i386/core arch/i386/transitions arch/i386/prefix
SRCDIRS += arch/i386/firmware/pcbios
SRCDIRS += arch/i386/image
SRCDIRS += arch/i386/drivers
-SRCDIRS += arch/i386/drivers/bus
SRCDIRS += arch/i386/drivers/net
-SRCDIRS += arch/i386/drivers/disk
SRCDIRS += arch/i386/interface/pcbios
SRCDIRS += arch/i386/interface/pxe
diff --git a/gpxe/src/arch/i386/core/gdbidt.S b/gpxe/src/arch/i386/core/gdbidt.S
new file mode 100644
index 00000000..45d079f6
--- /dev/null
+++ b/gpxe/src/arch/i386/core/gdbidt.S
@@ -0,0 +1,209 @@
+/*
+ * Interrupt Descriptor Table (IDT) setup and interrupt handlers for GDB stub.
+ */
+
+#include <virtaddr.h>
+
+#define SIZEOF_I386_REGS 32
+#define SIZEOF_I386_FLAGS 4
+
+/****************************************************************************
+ * Interrupt Descriptor Table
+ ****************************************************************************
+ */
+ .section ".data16"
+ .globl idtr
+idtr:
+idt_limit:
+ .word idt_length - 1
+idt_base:
+ .long 0
+
+/* IDT entries have the following format:
+ * offset_lo, segment selector, flags, offset_hi
+ *
+ * Since it is not possible to specify relocations in arbitrary
+ * expressions like (int_overflow & 0xffff), we initialise the
+ * IDT with entries in an incorrect format.
+ *
+ * The entries are shuffled into the correct format in init_librm().
+ */
+#define IDT_ENTRY_EMPTY(name) .word 0, 0, 0, 0
+#define IDT_ENTRY_PRESENT(name) \
+ .long int_##name; \
+ .word 0x8e00, VIRTUAL_CS
+
+.align 16
+idt:
+ IDT_ENTRY_PRESENT(divide_error)
+ IDT_ENTRY_PRESENT(debug_trap)
+ IDT_ENTRY_EMPTY(non_maskable_interrupt)
+ IDT_ENTRY_PRESENT(breakpoint)
+ IDT_ENTRY_PRESENT(overflow)
+ IDT_ENTRY_PRESENT(bound_range_exceeded)
+ IDT_ENTRY_PRESENT(invalid_opcode)
+ IDT_ENTRY_EMPTY(device_not_available)
+ IDT_ENTRY_PRESENT(double_fault)
+ IDT_ENTRY_EMPTY(coprocessor_segment_overrun)
+ IDT_ENTRY_PRESENT(invalid_tss)
+ IDT_ENTRY_PRESENT(segment_not_present)
+ IDT_ENTRY_PRESENT(stack_segment_fault)
+ IDT_ENTRY_PRESENT(general_protection)
+ IDT_ENTRY_PRESENT(page_fault)
+idt_end:
+ .equ idt_length, idt_end - idt
+
+/* The IDT entries are fixed up (once) in init_librm() */
+idt_fixed:
+ .byte 0
+
+/****************************************************************************
+ * idt_init (real-mode near call, 16-bit real-mode near return address)
+ *
+ * Initialise the IDT, called from init_librm.
+ *
+ * Parameters:
+ * %eax : IDT base address
+ *
+ * Destroys %ax, %bx, and %di.
+ ****************************************************************************
+ */
+ .section ".text16"
+ .code16
+ .globl idt_init
+idt_init:
+ movl %eax, idt_base
+ addl $idt, idt_base
+
+ /* IDT entries are only fixed up once */
+ movb idt_fixed, %al
+ orb %al, %al
+ jnz 2f
+ movb $1, idt_fixed
+
+ /* Shuffle IDT entries into the correct format */
+ movb $(idt_length / 8), %al
+ movw $idt, %bx
+ or %al, %al
+ jz 2f
+1:
+ movw 2(%bx), %di
+ xchg %di, 6(%bx)
+ movw %di, 2(%bx)
+ addw $8, %bx
+ dec %al
+ jnz 1b
+2:
+ ret
+
+/****************************************************************************
+ * Interrupt handlers
+ ****************************************************************************
+ */
+ .section ".text"
+ .code32
+
+/* POSIX signal numbers for reporting traps to GDB */
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGBUS 7
+#define SIGFPE 8
+#define SIGSEGV 11
+#define SIGSTKFLT 16
+
+int_divide_error:
+ pushl $SIGFPE
+ jmp do_interrupt
+
+int_debug_trap:
+int_breakpoint:
+ pushl $SIGTRAP
+ jmp do_interrupt
+
+int_overflow:
+int_bound_range_exceeded:
+ pushl $SIGSTKFLT
+ jmp do_interrupt
+
+int_invalid_opcode:
+ pushl $SIGILL
+ jmp do_interrupt
+
+int_double_fault:
+ movl $SIGBUS, (%esp)
+ jmp do_interrupt
+
+int_invalid_tss:
+int_segment_not_present:
+int_stack_segment_fault:
+int_general_protection:
+int_page_fault:
+ movl $SIGSEGV, (%esp)
+ jmp do_interrupt
+
+/* When invoked, the stack contains: eflags, cs, eip, signo. */
+#define IH_OFFSET_GDB_REGS ( 0 )
+#define IH_OFFSET_GDB_EIP ( IH_OFFSET_GDB_REGS + SIZEOF_I386_REGS )
+#define IH_OFFSET_GDB_EFLAGS ( IH_OFFSET_GDB_EIP + 4 )
+#define IH_OFFSET_GDB_SEG_REGS ( IH_OFFSET_GDB_EFLAGS + SIZEOF_I386_FLAGS )
+#define IH_OFFSET_GDB_END ( IH_OFFSET_GDB_SEG_REGS + 6 * 4 )
+#define IH_OFFSET_SIGNO ( IH_OFFSET_GDB_END )
+#define IH_OFFSET_OLD_EIP ( IH_OFFSET_SIGNO + 4 )
+#define IH_OFFSET_OLD_CS ( IH_OFFSET_OLD_EIP + 4 )
+#define IH_OFFSET_OLD_EFLAGS ( IH_OFFSET_OLD_CS + 4 )
+#define IH_OFFSET_END ( IH_OFFSET_OLD_EFLAGS + 4 )
+
+/* We also access the stack whilst still storing or restoring
+ * the register snapshot. Since ESP is in flux, we need
+ * special offsets.
+ */
+#define IH_OFFSET_FLUX_OLD_CS ( IH_OFFSET_OLD_CS - 44 )
+#define IH_OFFSET_FLUX_OLD_EFLAGS ( IH_OFFSET_OLD_EFLAGS - 40 )
+#define IH_OFFSET_FLUX_OLD_EIP ( IH_OFFSET_OLD_EIP - 36 )
+#define IH_OFFSET_FLUX_END ( IH_OFFSET_END - 20 )
+do_interrupt:
+ /* Store CPU state in GDB register snapshot */
+ pushl %gs
+ pushl %fs
+ pushl %es
+ pushl %ds
+ pushl %ss
+ pushl IH_OFFSET_FLUX_OLD_CS(%esp)
+ pushl IH_OFFSET_FLUX_OLD_EFLAGS(%esp)
+ pushl IH_OFFSET_FLUX_OLD_EIP(%esp)
+ pushl %edi
+ pushl %esi
+ pushl %ebp
+ leal IH_OFFSET_FLUX_END(%esp), %edi
+ pushl %edi /* old ESP */
+ pushl %ebx
+ pushl %edx
+ pushl %ecx
+ pushl %eax
+
+ /* Call GDB stub exception handler */
+ pushl %esp
+ pushl (IH_OFFSET_SIGNO + 4)(%esp)
+ call gdbstub_handler
+ addl $8, %esp
+
+ /* Restore CPU state from GDB register snapshot */
+ popl %eax
+ popl %ecx
+ popl %edx
+ popl %ebx
+ addl $4, %esp /* Changing ESP currently not supported */
+ popl %ebp
+ popl %esi
+ popl %edi
+ popl IH_OFFSET_FLUX_OLD_EIP(%esp)
+ popl IH_OFFSET_FLUX_OLD_EFLAGS(%esp)
+ popl IH_OFFSET_FLUX_OLD_CS(%esp)
+ popl %ss
+ popl %ds
+ popl %es
+ popl %fs
+ popl %gs
+
+ addl $4, %esp /* drop signo */
+ iret
diff --git a/gpxe/src/arch/i386/core/gdbsym.c b/gpxe/src/arch/i386/core/gdbsym.c
deleted file mode 100644
index 2da1a1bd..00000000
--- a/gpxe/src/arch/i386/core/gdbsym.c
+++ /dev/null
@@ -1,33 +0,0 @@
-#include <stdio.h>
-#include <gpxe/init.h>
-#include <console.h>
-#include <realmode.h>
-
-extern char __text[];
-extern char __rodata[];
-extern char __data[];
-extern char __bss[];
-extern char __text16[];
-extern char __data16[];
-
-
-static void gdb_symbol_line ( void ) {
- printf ( "Commands to start up gdb:\n\n" );
- printf ( "gdb\n" );
- printf ( "target remote localhost:1234\n" );
- printf ( "set confirm off\n" );
- printf ( "add-symbol-file symbols %#lx", virt_to_phys ( __text ) );
- printf ( " -s .rodata %#lx", virt_to_phys ( __rodata ) );
- printf ( " -s .data %#lx", virt_to_phys ( __data ) );
- printf ( " -s .bss %#lx", virt_to_phys ( __bss ) );
- printf ( " -s .text16 %#x", ( ( rm_cs << 4 ) + (int)__text16 ) );
- printf ( " -s .data16 %#x", ( ( rm_ds << 4 ) + (int)__data16 ) );
- printf ( "\n" );
- printf ( "add-symbol-file symbols 0\n" );
- printf ( "set confirm on\n" );
- getkey();
-}
-
-struct startup_fn gdb_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
- .startup = gdb_symbol_line,
-};
diff --git a/gpxe/src/arch/i386/drivers/net/undinet.c b/gpxe/src/arch/i386/drivers/net/undinet.c
index e3b9f85a..2c66c2f3 100644
--- a/gpxe/src/arch/i386/drivers/net/undinet.c
+++ b/gpxe/src/arch/i386/drivers/net/undinet.c
@@ -715,6 +715,9 @@ int undinet_probe ( struct undi_device *undi ) {
undinic->hacks |= UNDI_HACK_EB54;
}
+ /* Mark as link up; we don't handle link state */
+ netdev_link_up ( netdev );
+
/* Register network device */
if ( ( rc = register_netdev ( netdev ) ) != 0 )
goto err_register;
diff --git a/gpxe/src/arch/i386/image/pxe_image.c b/gpxe/src/arch/i386/image/pxe_image.c
index 9e634f14..77fa0469 100644
--- a/gpxe/src/arch/i386/image/pxe_image.c
+++ b/gpxe/src/arch/i386/image/pxe_image.c
@@ -84,6 +84,14 @@ int pxe_load ( struct image *image ) {
size_t memsz = image->len;
int rc;
+ /* Images too large to fit in base memory cannot be PXE
+ * images. We include this check to help prevent unrecognised
+ * images from being marked as PXE images, since PXE images
+ * have no signature we can check against.
+ */
+ if ( filesz > ( 0xa0000 - 0x7c00 ) )
+ return -ENOEXEC;
+
/* There are no signature checks for PXE; we will accept anything */
if ( ! image->type )
image->type = &pxe_image_type;
diff --git a/gpxe/src/arch/i386/include/gdbmach.h b/gpxe/src/arch/i386/include/gdbmach.h
new file mode 100644
index 00000000..9f6dc8f0
--- /dev/null
+++ b/gpxe/src/arch/i386/include/gdbmach.h
@@ -0,0 +1,51 @@
+#ifndef GDBMACH_H
+#define GDBMACH_H
+
+/** @file
+ *
+ * GDB architecture specifics
+ *
+ * This file declares functions for manipulating the machine state and
+ * debugging context.
+ *
+ */
+
+typedef uint32_t gdbreg_t;
+
+/* The register snapshot, this must be in sync with interrupt handler and the
+ * GDB protocol. */
+enum {
+ GDBMACH_EAX,
+ GDBMACH_ECX,
+ GDBMACH_EDX,
+ GDBMACH_EBX,
+ GDBMACH_ESP,
+ GDBMACH_EBP,
+ GDBMACH_ESI,
+ GDBMACH_EDI,
+ GDBMACH_EIP,
+ GDBMACH_EFLAGS,
+ GDBMACH_CS,
+ GDBMACH_SS,
+ GDBMACH_DS,
+ GDBMACH_ES,
+ GDBMACH_FS,
+ GDBMACH_GS,
+ GDBMACH_NREGS,
+ GDBMACH_SIZEOF_REGS = GDBMACH_NREGS * sizeof ( gdbreg_t )
+};
+
+static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) {
+ regs [ GDBMACH_EIP ] = pc;
+}
+
+static inline void gdbmach_set_single_step ( gdbreg_t *regs, int step ) {
+ regs [ GDBMACH_EFLAGS ] &= ~( 1 << 8 ); /* Trace Flag (TF) */
+ regs [ GDBMACH_EFLAGS ] |= ( step << 8 );
+}
+
+static inline void gdbmach_breakpoint ( void ) {
+ __asm__ __volatile__ ( "int $3\n" );
+}
+
+#endif /* GDBMACH_H */
diff --git a/gpxe/src/arch/i386/prefix/libprefix.S b/gpxe/src/arch/i386/prefix/libprefix.S
index deea5ab3..cb091112 100644
--- a/gpxe/src/arch/i386/prefix/libprefix.S
+++ b/gpxe/src/arch/i386/prefix/libprefix.S
@@ -48,10 +48,9 @@
*
* Parameters:
* %al : character to print
+ * %ds:di : output buffer (or %di=0 to print to console)
* Returns:
- * Nothing
- * Corrupts:
- * %ax
+ * %ds:di : next character in output buffer (if applicable)
*****************************************************************************
*/
.section ".prefix.lib"
@@ -59,19 +58,27 @@
.globl print_character
print_character:
/* Preserve registers */
+ pushw %ax
pushw %bx
pushw %bp
- /* Print character */
+ /* 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 1f
+ jne 2f
int $0x10
movb $0x0d, %al
-1: int $0x10
+2: int $0x10
/* Restore registers and return */
- popw %bp
+3: popw %bp
popw %bx
+ popw %ax
ret
.size print_character, . - print_character
@@ -80,8 +87,10 @@ print_character:
*
* 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"
@@ -109,8 +118,9 @@ print_message:
* %al : byte to print
* %ax : word to print
* %eax : dword to print
+ * %ds:di : output buffer (or %di=0 to print to console)
* Returns:
- * Nothing
+ * %ds:di : next character in output buffer (if applicable)
*****************************************************************************
*/
.section ".prefix.lib"
@@ -151,6 +161,44 @@ print_hex_nibble:
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"
+ .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
+
/****************************************************************************
* pm_call (real-mode near call)
*
diff --git a/gpxe/src/arch/i386/prefix/pxeprefix.S b/gpxe/src/arch/i386/prefix/pxeprefix.S
index d7125b61..302f8e5d 100644
--- a/gpxe/src/arch/i386/prefix/pxeprefix.S
+++ b/gpxe/src/arch/i386/prefix/pxeprefix.S
@@ -50,6 +50,7 @@
cld
/* Print welcome message */
movw $10f, %si
+ xorw %di, %di
call print_message
.section ".prefix.data"
10: .asciz "PXE->EB:"
@@ -61,24 +62,23 @@
*/
detect_pxenv:
/* Signature check */
- les pxenv_segoff, %di
- cmpl $0x4e455850, %es:(%di) /* 'PXEN' signature */
+ les pxenv_segoff, %bx
+ cmpl $0x4e455850, %es:(%bx) /* 'PXEN' signature */
jne no_pxenv
- cmpw $0x2b56, %es:4(%di) /* 'V+' signature */
+ cmpw $0x2b56, %es:4(%bx) /* 'V+' signature */
jne no_pxenv
/* Record entry point and UNDI segments */
- pushl %es:0x0a(%di) /* Entry point */
+ pushl %es:0x0a(%bx) /* Entry point */
popl entry_segoff
- pushw %es:0x24(%di) /* UNDI code segment */
- pushw %es:0x26(%di) /* UNDI code size */
+ pushw %es:0x24(%bx) /* UNDI code segment */
+ pushw %es:0x26(%bx) /* UNDI code size */
popl undi_code_segoff
- pushw %es:0x20(%di) /* UNDI data segment */
- pushw %es:0x22(%di) /* UNDI data size */
+ pushw %es:0x20(%bx) /* UNDI data segment */
+ pushw %es:0x22(%bx) /* UNDI data size */
popl undi_data_segoff
/* Print "PXENV+ at <address>" */
movw $10f, %si
call print_message
- movw %bx, %di
call print_segoff
movb $',', %al
call print_character
@@ -99,20 +99,20 @@ no_pxenv:
*/
detect_ppxe:
/* Signature check */
- les ppxe_segoff, %di
- cmpl $0x45585021, %es:(%di) /* '!PXE' signature */
+ les ppxe_segoff, %bx
+ cmpl $0x45585021, %es:(%bx) /* '!PXE' signature */
jne no_ppxe
/* Record structure address, entry point, and UNDI segments */
pushw %es
popw ppxe_segment
- movw %di, ppxe_offset
- pushl %es:0x10(%di) /* Entry point */
+ movw %bx, ppxe_offset
+ pushl %es:0x10(%bx) /* Entry point */
popl entry_segoff
- pushw %es:0x30(%di) /* UNDI code segment */
- pushw %es:0x36(%di) /* UNDI code size */
+ pushw %es:0x30(%bx) /* UNDI code segment */
+ pushw %es:0x36(%bx) /* UNDI code size */
popl undi_code_segoff
- pushw %es:0x28(%di) /* UNDI data segment */
- pushw %es:0x2e(%di) /* UNDI data size */
+ pushw %es:0x28(%bx) /* UNDI data segment */
+ pushw %es:0x2e(%bx) /* UNDI data size */
popl undi_data_segoff
/* Print "!PXE at <address>" */
movw $10f, %si
@@ -180,7 +180,7 @@ print_structure_information:
/* Print entry point */
movw $10f, %si
call print_message
- les entry_segoff, %di
+ les entry_segoff, %bx
call print_segoff
.section ".prefix.data"
10: .asciz " entry point at "
@@ -188,7 +188,7 @@ print_structure_information:
/* Print UNDI code segment */
movw $10f, %si
call print_message
- les undi_code_segoff, %di
+ les undi_code_segoff, %bx
call print_segoff
.section ".prefix.data"
10: .asciz "\n UNDI code segment "
@@ -196,7 +196,7 @@ print_structure_information:
/* Print UNDI data segment */
movw $10f, %si
call print_message
- les undi_data_segoff, %di
+ les undi_data_segoff, %bx
call print_segoff
.section ".prefix.data"
10: .asciz ", data segment "
@@ -285,8 +285,8 @@ unload_base_code:
call print_pxe_error
jmp 99f
1: /* Free base memory used by PXE base code */
- movw %fs:(0x13), %si
- movw undi_fbms_start, %di
+ movw undi_fbms_start, %ax
+ movw %fs:(0x13), %bx
call free_basemem
99:
@@ -303,8 +303,8 @@ unload_undi:
call print_pxe_error
jmp 99f
1: /* Free base memory used by UNDI */
- movw undi_fbms_start, %si
- movw undi_fbms_end, %di
+ movw undi_fbms_end, %ax
+ movw undi_fbms_start, %bx
call free_basemem
/* Clear UNDI_FL_STARTED */
andw $~UNDI_FL_STARTED, flags
@@ -338,9 +338,10 @@ finished:
* Subroutine: print segment:offset address
*
* Parameters:
- * %es:%di : segment:offset address to print
+ * %es:%bx : segment:offset address to print
+ * %ds:di : output buffer (or %di=0 to print to console)
* Returns:
- * Nothing
+ * %ds:di : next character in output buffer (if applicable)
*****************************************************************************
*/
print_segoff:
@@ -351,7 +352,7 @@ print_segoff:
call print_hex_word
movb $':', %al
call print_character
- movw %di, %ax
+ movw %bx, %ax
call print_hex_word
/* Restore registers and return */
popw %ax
@@ -362,8 +363,9 @@ print_segoff:
*
* Parameters:
* %ax : word to print
+ * %ds:di : output buffer (or %di=0 to print to console)
* Returns:
- * Nothing
+ * %ds:di : next character in output buffer (if applicable)
*****************************************************************************
*/
print_word:
@@ -393,43 +395,10 @@ print_word:
ret
/*****************************************************************************
- * Subroutine: print PCI bus:dev.fn
- *
- * Parameters:
- * %ax : PCI bus:dev.fn to print
- * Returns:
- * Nothing
- *****************************************************************************
- */
-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
-
-/*****************************************************************************
* Subroutine: zero 1kB block of base memory
*
* Parameters:
- * %si : block to zero (in kB)
+ * %bx : block to zero (in kB)
* Returns:
* Nothing
*****************************************************************************
@@ -441,7 +410,7 @@ zero_kb:
pushw %di
pushw %es
/* Zero block */
- movw %si, %ax
+ movw %bx, %ax
shlw $6, %ax
movw %ax, %es
movw $0x400, %cx
@@ -459,33 +428,31 @@ zero_kb:
* Subroutine: free and zero base memory
*
* Parameters:
- * %si : Expected current free base memory counter (in kB)
- * %di : Desired new free base memory counter (in kB)
+ * %ax : Desired new free base memory counter (in kB)
+ * %bx : Expected current free base memory counter (in kB)
* %fs : BIOS data segment (0x40)
* Returns:
- * %ax : Actual new free base memory counter (in kB)
+ * None
*
- * The base memory from %si kB to %di kB is unconditionally zeroed.
+ * 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 (%si) matches the actual current free base memory
+ * 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 %si
-1: cmpw %si, %di
+ pushw %bx
+1: cmpw %bx, %ax
je 2f
call zero_kb
- incw %si
+ incw %bx
jmp 1b
-2: popw %si
+2: popw %bx
/* Free base memory */
- movw %fs:(0x13), %ax /* Current FBMS to %ax */
- cmpw %ax, %si /* Update FBMS only if "old" value */
+ cmpw %fs:(0x13), %bx /* Update FBMS only if "old" value */
jne 1f /* is correct */
- movw %di, %ax
1: movw %ax, %fs:(0x13)
ret
diff --git a/gpxe/src/arch/i386/prefix/romprefix.S b/gpxe/src/arch/i386/prefix/romprefix.S
index d37cce94..19e6a9b3 100644
--- a/gpxe/src/arch/i386/prefix/romprefix.S
+++ b/gpxe/src/arch/i386/prefix/romprefix.S
@@ -85,11 +85,24 @@ pnpheader:
.equ pnpheader_len, . - pnpheader
.size pnpheader, . - pnpheader
+/* Manufacturer string */
mfgstr:
.asciz "http://etherboot.org"
.size mfgstr, . - mfgstr
+
+/* Product string
+ *
+ * Defaults to "gPXE". 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:
- .asciz "gPXE"
+ .ascii "gPXE"
+prodstr_separator:
+ .byte 0
+ .ascii "(PCI "
+prodstr_pci_id:
+ .asciz "xx:xx.x)" /* Filled in by init code */
.size prodstr, . - prodstr
undiheader:
@@ -117,27 +130,37 @@ init:
pushaw
pushw %ds
pushw %es
+ pushw %fs
cld
pushw %cs
popw %ds
+ pushw $0x40
+ popw %fs
+ movw %di, %bx
+ xorw %di, %di
/* Print message as early as possible */
movw $init_message, %si
call print_message
+ call print_pci_busdevfn
+ /* Fill in product name string, if possible */
+ movw $prodstr_pci_id, %di
+ call print_pci_busdevfn
+ movb $' ', prodstr_separator
+ xorw %di, %di
/* Check for PnP BIOS */
- testw $0x0f, %di /* PnP signature must be aligned - bochs */
+ testw $0x0f, %bx /* PnP signature must be aligned - bochs */
jnz hook_int19 /* uses unalignment to indicate 'fake' PnP. */
- cmpl $PNP_SIGNATURE, %es:0(%di)
+ cmpl $PNP_SIGNATURE, %es:0(%bx)
jne hook_int19
/* Is PnP: print PnP message */
movw $init_message_pnp, %si
call print_message
- xchgw %bx, %bx
/* Check for BBS */
- pushw %es:0x1b(%di) /* Real-mode data segment */
+ pushw %es:0x1b(%bx) /* Real-mode data segment */
pushw %ds /* &(bbs_version) */
pushw $bbs_version
pushw $PNP_GET_BBS_VERSION
- lcall *%es:0xd(%di)
+ lcall *%es:0xd(%bx)
addw $8, %sp
testw %ax, %ax
jne hook_int19
@@ -155,18 +178,18 @@ hook_int19:
popl %es:( 0x19 * 4 )
hook_bbs:
/* Check for PMM */
- movw $( 0xe000 - 1 ), %di
+ movw $( 0xe00 - 1 ), %bx
pmm_scan:
- incw %di
+ incw %bx
jz no_pmm
- movw %di, %es
+ movw %bx, %es
cmpl $PMM_SIGNATURE, %es:0
jne pmm_scan
- xorw %bx, %bx
+ xorw %dx, %dx
xorw %si, %si
movzbw %es:5, %cx
1: es lodsb
- addb %al, %bl
+ addb %al, %dl
loop 1b
jnz pmm_scan
/* PMM found: print PMM message */
@@ -207,11 +230,53 @@ gotpmm: /* PMM allocation succeeded: copy ROM to PMM block */
loop 1b
subb %bl, checksum
popal
-no_pmm:
- /* Print CRLF to terminate messages */
- movw $'\n', %ax
- call print_character
+no_pmm: /* Prompt for POST-time shell */
+ movw $init_message_prompt, %si
+ call print_message
+ /* Empty the keyboard buffer before waiting for input */
+empty_keyboard_buffer:
+ movb $0x01, %ah
+ int $0x16
+ jz 1f
+ xorw %ax, %ax
+ int $0x16
+ jmp empty_keyboard_buffer
+1: /* Wait for up to 3s for a key press */
+ movw $(18 * 3), %cx /* Approx 3s worth of timer ticks */
+wait_for_key:
+ decw %cx
+ jz no_key_pressed
+ /* Wait for timer tick to be updated */
+ movl %fs:(0x6c), %eax
+1: pushf
+ sti
+ hlt
+ popf
+ cmpl %fs:(0x6c), %eax
+ je 1b
+ /* Check to see if a key was pressed */
+ movb $0x01, %ah
+ int $0x16
+ jz wait_for_key
+ /* Check to see if key was Ctrl-B */
+ cmpb $0x02, %al
+ je 1f
+ /* Key was not Ctrl-B: remove from buffer and stop waiting */
+ xorw %ax, %ax
+ int $0x16
+ jmp no_key_pressed
+1: /* Key was Ctrl-B: leave in keyboard buffer and invoke gPXE.
+ * The keypress will be picked up by the initial shell
+ * prompt, and we will drop into a shell.
+ */
+ pushw %cs
+ call exec
+no_key_pressed:
+ /* Print blank lines to terminate messages */
+ movw $init_message_end, %si
+ call print_message
/* Restore registers */
+ popw %fs
popw %es
popw %ds
popaw
@@ -221,23 +286,29 @@ no_pmm:
.size init, . - init
init_message:
- .asciz "gPXE (http://etherboot.org) -"
+ .asciz "gPXE (http://etherboot.org) - PCI "
.size init_message, . - init_message
init_message_pnp:
.asciz " PnP"
- .size init_message_pnp, . - init_message_pnp
+ .size init_message_pnp, . - init_message_pnp
init_message_bbs:
.asciz " BBS"
- .size init_message_bbs, . - init_message_bbs
+ .size init_message_bbs, . - init_message_bbs
init_message_pmm:
.asciz " PMM"
- .size init_message_pmm, . - init_message_pmm
+ .size init_message_pmm, . - init_message_pmm
init_message_pmm_failed:
.asciz "(failed)"
- .size init_message_pmm_failed, . - init_message_pmm_failed
+ .size init_message_pmm_failed, . - init_message_pmm_failed
init_message_int19:
.asciz " INT19"
- .size init_message_int19, . - init_message_int19
+ .size init_message_int19, . - init_message_int19
+init_message_prompt:
+ .asciz "\nPress Ctrl-B to configure gPXE..."
+ .size init_message_prompt, . - init_message_prompt
+init_message_end:
+ .asciz "\n\n\n"
+ .size init_message_end, . - init_message_end
/* ROM image location
*
@@ -292,6 +363,7 @@ exec: /* Set %ds = %cs */
/* Print message as soon as possible */
movw $exec_message, %si
+ xorw %di, %di
call print_message
/* Store magic word on BIOS stack and remember BIOS %ss:sp */
@@ -340,7 +412,7 @@ exec: /* Set %ds = %cs */
.previous
exec_message:
- .asciz "gPXE starting boot\n"
+ .asciz "Entering gPXE\n"
.size exec_message, . - exec_message
/* UNDI loader
diff --git a/gpxe/src/arch/i386/transitions/librm.S b/gpxe/src/arch/i386/transitions/librm.S
index b1f9dd59..45e0d0ff 100644
--- a/gpxe/src/arch/i386/transitions/librm.S
+++ b/gpxe/src/arch/i386/transitions/librm.S
@@ -50,6 +50,7 @@
.section ".data16"
.align 16
gdt:
+gdtr: /* The first GDT entry is unused, the GDTR can fit here. */
gdt_limit: .word gdt_length - 1
gdt_base: .long 0
.word 0 /* padding */
@@ -127,7 +128,7 @@ init_librm:
addr32 leal (%eax, %edi), %ebx
movl %ebx, _text16
- /* Store rm_ds and _data16, set up real_ds segment and set GDT base */
+ /* Store rm_ds and _data16, set up real_ds segment */
xorl %eax, %eax
movw %ds, %ax
movw %ax, %cs:rm_ds
@@ -136,9 +137,12 @@ init_librm:
call set_seg_base
addr32 leal (%eax, %edi), %ebx
movl %ebx, _data16
- addl $gdt, %eax
+
+ /* Set GDT and IDT base */
movl %eax, gdt_base
-
+ addl $gdt, gdt_base
+ call idt_init
+
/* Restore registers */
negl %edi
popl %ebx
@@ -147,14 +151,16 @@ init_librm:
.section ".text16"
.code16
+ .weak idt_init
set_seg_base:
1: movw %ax, 2(%bx)
rorl $16, %eax
movb %al, 4(%bx)
movb %ah, 7(%bx)
roll $16, %eax
+idt_init: /* Reuse the return opcode here */
ret
-
+
/****************************************************************************
* real_to_prot (real-mode near call, 32-bit virtual return address)
*
@@ -197,7 +203,8 @@ real_to_prot:
/* Switch to protected mode */
cli
- data32 lgdt gdt
+ data32 lgdt gdtr
+ data32 lidt idtr
movl %cr0, %eax
orb $CR0_PE, %al
movl %eax, %cr0
@@ -232,6 +239,14 @@ real_to_prot:
/* Return to virtual address */
ret
+ /* Default IDTR with no interrupts */
+ .section ".data16"
+ .weak idtr
+idtr:
+rm_idtr:
+ .word 0xffff /* limit */
+ .long 0 /* base */
+
/****************************************************************************
* prot_to_real (protected-mode near call, 32-bit real-mode return address)
*
@@ -300,6 +315,9 @@ p2r_jump_target:
movw %bp, %ss
movl %edx, %esp
+ /* Reset IDTR to the real-mode defaults */
+ lidt rm_idtr
+
/* Return to real-mode address */
data32 ret
@@ -318,7 +336,7 @@ rm_cs: .word 0
.globl rm_ds
.section ".text16.data"
rm_ds: .word 0
-
+
/****************************************************************************
* prot_call (real-mode far call, 16-bit real-mode far return address)
*
@@ -354,7 +372,8 @@ rm_ds: .word 0
*/
#define PC_OFFSET_GDT ( 0 )
-#define PC_OFFSET_IX86 ( PC_OFFSET_GDT + 8 /* pad to 8 to keep alignment */ )
+#define PC_OFFSET_IDT ( PC_OFFSET_GDT + 8 /* pad to 8 to keep alignment */ )
+#define PC_OFFSET_IX86 ( PC_OFFSET_IDT + 8 /* pad to 8 to keep alignment */ )
#define PC_OFFSET_RETADDR ( PC_OFFSET_IX86 + SIZEOF_I386_ALL_REGS )
#define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 )
#define PC_OFFSET_END ( PC_OFFSET_FUNCTION + 4 )
@@ -372,8 +391,9 @@ prot_call:
pushw %ds
pushw %ss
pushw %cs
- subw $8, %sp
+ subw $16, %sp
movw %sp, %bp
+ sidt 8(%bp)
sgdt (%bp)
/* For sanity's sake, clear the direction flag as soon as possible */
@@ -402,10 +422,11 @@ prot_call:
.section ".text16"
.code16
1:
- /* Reload GDT, restore registers and flags and return */
+ /* Reload GDT and IDT, restore registers and flags and return */
movw %sp, %bp
lgdt (%bp)
- addw $12, %sp /* also skip %cs and %ss */
+ lidt 8(%bp)
+ addw $20, %sp /* also skip %cs and %ss */
popw %ds
popw %es
popw %fs
@@ -495,7 +516,7 @@ real_call:
*/
.section ".data16"
rc_function: .word 0, 0
-
+
/****************************************************************************
* Stored real-mode and protected-mode stack pointers
*