Call option roms in "big real mode".
authorKevin O'Connor <kevin@koconnor.net>
Sat, 6 Dec 2008 18:03:52 +0000 (13:03 -0500)
committerKevin O'Connor <kevin@koconnor.net>
Sat, 6 Dec 2008 18:03:52 +0000 (13:03 -0500)
src/config.h
src/optionroms.c
src/romlayout.S
src/util.c
src/util.h

index f6280a5e71ab2021a54a23c4bd98334dfd4676a1..4308342a193cae1778f619a69c89c680abc70330 100644 (file)
 #define SEG_EBDA     0x9fc0
 #define SEG_BDA      0x0000
 
-// Segment definitions in 32bit mode.
-#define SEG32_MODE32_CS (2 << 3) // 0x10
-#define SEG32_MODE32_DS (3 << 3) // 0x18
-#define SEG32_MODE16_CS (4 << 3) // 0x20
-#define SEG32_MODE16_DS (5 << 3) // 0x28
+// Segment definitions in protected mode (see rombios32_gdt in romlayout.S)
+#define SEG32_MODE32_CS    (2 << 3)
+#define SEG32_MODE32_DS    (3 << 3)
+#define SEG32_MODE16_CS    (4 << 3)
+#define SEG32_MODE16_DS    (5 << 3)
+#define SEG32_MODE16BIG_CS (6 << 3)
+#define SEG32_MODE16BIG_DS (7 << 3)
 
 // Debugging levels.  If non-zero and CONFIG_DEBUG_LEVEL is greater
 // than the specified value, then the corresponding irq handler will
index 7783f8467180e277b7d70ecd8cdc08243daba1d4..0f99c2ee739e3b291e5aed456cfd6f3028f26bf6 100644 (file)
@@ -96,8 +96,7 @@ callrom(struct rom_header *rom, u16 offset, u16 bdf)
     br.di = (u32)pnp_string - BUILD_BIOS_ADDR;
     br.cs = seg;
     br.ip = offset;
-    // XXX - should call option rom in "big real mode".
-    call16(&br);
+    call16big(&br);
 
     debug_serial_setup();
 
index 4249d4471f69f5695311e6389cfa979d362a2226..a9788f437bda46d5c817f3af7bdcfe83f04aa134 100644 (file)
@@ -153,15 +153,15 @@ transition32:
         outb %al, $PORT_A20
 
         // Set segment descriptors
-        lidt %cs:pmode_IDT_info
-        lgdt %cs:rombios32_gdt_48
+        lidtw %cs:pmode_IDT_info
+        lgdtw %cs:rombios32_gdt_48
 
         // Enable protected mode
         movl %cr0, %eax
         orl $CR0_PE, %eax
         movl %eax, %cr0
 
-        // start protected mode code
+        // start 32bit protected mode code
         ljmpl $SEG32_MODE32_CS, $(BUILD_BIOS_ADDR + 1f)
 
         .code32
@@ -171,7 +171,6 @@ transition32:
         movw %ax, %ds
         movw %ax, %es
         movw %ax, %ss
-        xorl %eax, %eax
         movw %ax, %fs
         movw %ax, %gs
 
@@ -180,12 +179,12 @@ transition32:
 // Call a 16bit function from 32bit mode.
 // %eax = address of struct bregs
 // Clobbers: all gp registers, flags, stack registers, cr0, idt/gdt
-        .global __call16_from32
+        .global __call16_from32, __call16big_from32
 __call16_from32:
         pushl %eax
 
         // restore data segment limits to 0xffff
-        movw $SEG32_MODE16_DS, %ax
+        movl $SEG32_MODE16_DS, %eax
         movw %ax, %ds
         movw %ax, %es
         movw %ax, %ss
@@ -200,6 +199,18 @@ __call16_from32:
         // Jump to 16bit mode
         ljmpw $SEG32_MODE16_CS, $1f
 
+__call16big_from32:
+        pushl %eax
+
+        movl $SEG32_MODE16BIG_DS, %eax
+        movw %ax, %ds
+        movw %ax, %es
+        movw %ax, %ss
+        movw %ax, %fs
+        movw %ax, %gs
+
+        ljmpl $SEG32_MODE16BIG_CS, $(BUILD_BIOS_ADDR + 1f)
+
         .code16gcc
 1:
         // Disable protected mode
@@ -212,7 +223,7 @@ __call16_from32:
 
 2:
         // restore IDT to normal real-mode defaults
-        lidt %cs:rmode_IDT_info
+        lidtw %cs:rmode_IDT_info
 
         // Clear segment registers
         xorw %ax, %ax
@@ -366,9 +377,8 @@ rmode_IDT_info:
         .long 0       // base 16:47
 
 rombios32_gdt_48:
-        .word 0x30
-        .word rombios32_gdt
-        .word 0x000f
+        .word (rombios32_gdt_end - rombios32_gdt)
+        .long (BUILD_BIOS_ADDR + rombios32_gdt)
 
         .balign 8
 rombios32_gdt:
@@ -382,6 +392,11 @@ rombios32_gdt:
         .word 0xffff, 0, 0x9b0f, 0x0000
         // 16 bit data segment base=0x0 limit=0xffff (SEG32_MODE16_DS)
         .word 0xffff, 0, 0x9300, 0x0000
+        // 16 bit code segment base=0 limit=0xffffffff (SEG32_MODE16BIG_CS)
+        .word 0xffff, 0, 0x9b00, 0x008f
+        // 16 bit data segment base=0 limit=0xffffffff (SEG32_MODE16BIG_DS)
+        .word 0xffff, 0, 0x9300, 0x008f
+rombios32_gdt_end:
 
 // We need a copy of this string in the 0xf000 segment, but we are not
 // actually a PnP BIOS, so make sure it is *not* aligned, so OSes will
index b85a1a52b695ec9ed20bf844c539f29f933d8c14..1237cd1d717d0252fbda00074838e71b27e50c53 100644 (file)
@@ -25,6 +25,20 @@ call16(struct bregs *callregs)
         : "ebx", "ecx", "edx", "esi", "edi", "ebp", "cc");
 }
 
+inline void
+call16big(struct bregs *callregs)
+{
+#if MODE16 == 1
+    extern void __force_link_error__only_in_32bit_mode();
+    __force_link_error__only_in_32bit_mode();
+#endif
+    asm volatile(
+        "calll __call16big_from32\n"
+        : "+a" (callregs), "+m" (*callregs)
+        :
+        : "ebx", "ecx", "edx", "esi", "edi", "ebp", "cc");
+}
+
 inline void
 __call16_int(struct bregs *callregs, u16 offset)
 {
index b356c4ed31e556283d54ab81885b1daaebce9ffe..ef7933276561b8d1f81bac243d6ab38b37238b96 100644 (file)
@@ -72,6 +72,7 @@ void *memmove(void *d, const void *s, size_t len);
 
 struct bregs;
 inline void call16(struct bregs *callregs);
+inline void call16big(struct bregs *callregs);
 inline void __call16_int(struct bregs *callregs, u16 offset);
 #define call16_int(nr, callregs) do {                           \
         extern void irq_trampoline_ ##nr ();                    \