Mailing List Archive

[xen-unstable] rombios: Simplify 32-bit gateway and avoid need for EBDA space.
# HG changeset patch
# User Keir Fraser <keir.fraser@citrix.com>
# Date 1232641926 0
# Node ID b10fd9f4fe38c38069b140bf8689c5fc15cd595f
# Parent d52921c18c3d0171bccb4651cca8412f2fff2dd9
rombios: Simplify 32-bit gateway and avoid need for EBDA space.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
---
tools/firmware/rombios/32bitgateway.h | 18 -
tools/firmware/rombios/32bitgateway.c | 458 ++++++++--------------------------
tools/firmware/rombios/rombios.c | 4
3 files changed, 120 insertions(+), 360 deletions(-)

diff -r d52921c18c3d -r b10fd9f4fe38 tools/firmware/rombios/32bitgateway.c
--- a/tools/firmware/rombios/32bitgateway.c Thu Jan 22 11:21:43 2009 +0000
+++ b/tools/firmware/rombios/32bitgateway.c Thu Jan 22 16:32:06 2009 +0000
@@ -19,8 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Copyright (C) IBM Corporation, 2006
+ * Copyright (c) 2008, Citrix Systems, Inc.
*
* Author: Stefan Berger <stefanb@us.ibm.com>
+ * Author: Keir Fraser <keir.fraser@citrix.com>
*/

/*
@@ -34,384 +36,162 @@
* (4 bytes) even for uint16_t, so casting to 32bit from bcc is a good idea.
*/

-#define SEGMENT_OFFSET 0xf0000
-#define REAL_MODE_CODE_SEGMENT 0xf000
+/* At most 32 bytes in argument list to a 32-bit function. */
+#define MAX_ARG_BYTES 32

-#define START_PM_CODE USE32
-#define END_PM_CODE USE16
+#define REAL_MODE_CODE_OFFSET 0xf0000

-/* definition of used code/data segment descriptors */
-#define PM_NORMAL_CS (gdt_entry_pm_cs - gdt_base)
+/* Definitions of code/data segment descriptors. */
+#define PM_32BIT_CS (gdt_entry_pm_32bit_cs - gdt_base)
#define PM_16BIT_CS (gdt_entry_pm_16bit_cs - gdt_base)
#define PM_32BIT_DS (gdt_entry_pm_32bit_ds - gdt_base)
+#define PM_16BIT_DS (gdt_entry_pm_16bit_ds - gdt_base)

- ASM_START
+ASM_START

- ; Switch into protected mode to allow access to 32 bit addresses.
- ; This function allows switching into protected mode.
- ; (the specs says big real mode, but that will not work)
+ .align 16
+gdt_base:
+ .word 0,0
+ .byte 0,0,0,0
+gdt_entry_pm_32bit_cs:
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x9b, 0xcf, 0x00
+gdt_entry_pm_16bit_cs:
+ .word 0xffff, 0x0000
+ .byte REAL_MODE_CODE_OFFSET >> 16, 0x9b, 0x0, 0x0
+gdt_entry_pm_32bit_ds:
+ .word 0xffff, 0x0000
+ .byte 0x0, 0x93, 0xcf, 0x0
+gdt_entry_pm_16bit_ds:
+ .word 0xffff, 0x0000
+ .byte 0x0, 0x93, 0x0, 0x0
+gdt_entry_end:
+
+protmode_gdtdesc:
+ .word (gdt_entry_end - gdt_base) - 1
+ .long gdt_base | REAL_MODE_CODE_OFFSET
+
+realmode_gdtdesc:
+ .word 0xffff
+ .long 0x0
+
+Upcall:
+ ; Do an upcall into 32 bit space
;
- ; preserves all registers and prepares cs, ds, es, ss for usage
- ; in protected mode; while in prot.mode interrupts remain disabled
-switch_to_protmode:
+ ; Input:
+ ; bx: index of function to call
+ ; Ouput:
+ ; dx, ax: 32 bit result of call (even if 'void' is expected)
+
+ ; Save caller state, stack frame offsets listed below
+#define esp_off 0
+#define ss_off 4
+#define es_off 6
+#define ds_off 8
+#define flags_off 10
+#define retaddr_off 12
+#define args_off 14
+ pushf
cli
+ push ds
+ push es
+ push ss
+ push esp

- ; have to fix the stack for proper return address in 32 bit mode
- push WORD #(REAL_MODE_CODE_SEGMENT>>12) ;extended return address
- push bp ;pop@A1
- mov bp, sp
- push eax ;pop@A2
- mov eax, 2[bp] ; fix return address
- rol eax, #16
- mov 2[bp], eax
+ ; Find the 32-bit function address via a table lookup
+ push si
+ rol bx, #2
+ mov si, #jmptable
+ seg cs
+ mov eax, dword ptr [si+bx]
+ pop si
+ push eax

- mov eax, esp
- ror eax, #16 ; hi(esp)
-
- push bx ; preserve before function call
- push cx
- push dx
-
- push ax ; prepare stack for
- push es ; call
- push ds
- push cs
- push ss
- call _store_segment_registers
- add sp, #10 ; pop ax,es-ss
-
- pop dx ; restore after function call
- pop cx
- pop bx
-
- ; calculate protected-mode esp from ss:sp
+ ; Calculate protected-mode esp from ss:sp
and esp, #0xffff
xor eax, eax
mov ax, ss
- rol eax, #4
- add eax, esp
- mov esp, eax
+ shl eax, #4
+ add esp, eax

+ ; Switch to protected mode
seg cs
- lgdt my_gdtdesc ; switch to own table
-
+ lgdt protmode_gdtdesc
mov eax, cr0
- or al, #0x1 ; protected mode 'on'
+ or al, #0x1 ; protected mode on
mov cr0, eax
-
- jmpf DWORD (SEGMENT_OFFSET | switch_to_protmode_goon_1), #PM_NORMAL_CS
-
- START_PM_CODE
-
-switch_to_protmode_goon_1:
- mov ax, #PM_32BIT_DS ; 32 bit segment that allows
- mov ds, ax ; to reach all 32 bit
- mov es, ax ; addresses
+ jmpf DWORD (REAL_MODE_CODE_OFFSET|upcall1), #PM_32BIT_CS
+upcall1:
+ USE32
+ mov ax, #PM_32BIT_DS
+ mov ds, ax
+ mov es, ax
mov ss, ax

- pop eax ;@A2
- pop bp ;@A1
- ret
+ ; Marshal arguments and call 32-bit function
+ pop eax
+ mov ecx, #MAX_ARG_BYTES/4
+upcall2:
+ push MAX_ARG_BYTES-4+args_off[esp]
+ loop upcall2
+ call eax
+ add esp, #MAX_ARG_BYTES
+ mov ecx, eax ; Result in ecx

- END_PM_CODE
+ ; Restore real-mode stack pointer
+ xor eax, eax
+ mov ax, ss_off[esp]
+ shl eax, 4
+ sub esp, eax
+ mov bx, ax ; Real-mode ss in bx

-
-
- .align 16
-gdt_base:
- ; see Intel SW Dev. Manuals section 3.4.5, Volume 3 for meaning of bits
- .word 0,0
- .byte 0,0,0,0
-
-gdt_entry_pm_cs:
- ; 32 bit code segment for protected mode
- .word 0xffff, 0x0000
- .byte 0x00, 0x9b, 0xcf, 0x00
-
-gdt_entry_pm_16bit_cs:
- ; temp. 16 bit code segment used while in protected mode
- .word 0xffff, 0x0000
- .byte SEGMENT_OFFSET >> 16, 0x9b, 0x0, 0x0
-
-gdt_entry_pm_32bit_ds:
- ; (32 bit) data segment (r/w) reaching all possible areas in 32bit memory
- ; 4kb granularity
- .word 0xffff, 0x0000
- .byte 0x0, 0x93, 0xcf, 0x0
-gdt_entry_end:
-
-my_gdtdesc:
- .word (gdt_entry_end - gdt_base) - 1
- .long gdt_base | SEGMENT_OFFSET
-
-
-realmode_gdtdesc: ;to be used in real mode
- .word 0xffff
- .long 0x0
-
-
-
-switch_to_realmode:
- ; Implementation of switching from protected mode to real mode
- ; prepares cs, es, ds, ss to be used in real mode
- ; spills eax
- START_PM_CODE
-
- ; need to fix up the stack to return in 16 bit mode
- ; currently the 32 bit return address is on the stack
- pop eax
- push ax
-
- push bx ;pop@1
- push si ;pop@2
-
- call _ebda_ss_offset32 ; get the offset of the ss
- mov bx, ax ; entry within the ebda.
-
- jmpf switch_to_realmode_goon_1, #PM_16BIT_CS
-
- END_PM_CODE
-
-switch_to_realmode_goon_1:
+ ; Return to real mode
+ jmpf upcall3, #PM_16BIT_CS
+upcall3:
+ USE16
+ mov ax, #PM_16BIT_DS
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
mov eax, cr0
- and al, #0xfe ; protected mode 'off'
+ and al, #0xfe ; protected mode off
mov cr0, eax
-
- jmpf switch_to_realmode_goon_2, #REAL_MODE_CODE_SEGMENT
-
-switch_to_realmode_goon_2:
-
- ; get orig. 'ss' without using the stack (no 'call'!)
- xor eax, eax ; clear upper 16 bits (and lower)
- mov ax, #0x40 ; where is the ebda located?
- mov ds, ax
- mov si, #0xe
- seg ds
- mov ax, [si] ; ax = segment of ebda
-
- mov ds, ax ; segment of ebda
- seg ds
- mov ax, [bx] ; stack segment - bx has been set above
- mov ss, ax
-
- ; from esp and ss calculate real-mode sp
- rol eax, #4
- sub esp, eax
-
- push dx ;preserve before call(s)
- push cx
- push bx
-
- call _get_register_ds ; get orig. 'ds'
- mov ds, ax
- call _get_register_es ; get orig. 'es'
- mov es, ax
- call _get_register_esp_hi ; fix the upper 16 bits of esp
- ror esp, #16
- mov sp, ax
- rol esp, #16
-
- pop bx
- pop cx
- pop dx
-
+ jmpf upcall4, #REAL_MODE_CODE_OFFSET>>4
+upcall4:
seg cs
lgdt realmode_gdtdesc

- sti ; allow interrupts
+ ; Restore real-mode ss
+ mov ss, bx

- pop si ;@2
- pop bx ;@1
+ ; Convert result into dx:ax format
+ mov eax, ecx
+ ror eax, #16
+ mov dx, ax
+ ror eax, #16

+ ; Restore caller state and return
+ pop esp
+ pop bx ; skip ss
+ pop es
+ pop ds
+ popf
ret
-
- ASM_END
-
-/*
- * Helper function to get the offset of the reg_ss within the ebda struct
- * Only 'C' can tell the offset.
- */
-Bit16u
-ebda_ss_offset32()
-{
- ASM_START
- START_PM_CODE // need to have this
- ASM_END // compiled for protected mode
- return &EbdaData->upcall.reg_ss; // 'C' knows the offset!
- ASM_START
- END_PM_CODE
- ASM_END
-}
-
-/*
- * Two often-used functions
- */
-Bit16u
-read_word_from_ebda(offset)
- Bit16u offset;
-{
- Bit16u ebda_seg = read_word(0x0040, 0x000E);
- return read_word(ebda_seg, offset);
-}
-
-Bit32u
-read_dword_from_ebda(offset)
- Bit16u offset;
-{
- Bit16u ebda_seg = read_word(0x0040, 0x000E);
- return read_dword(ebda_seg, offset);
-}
-
-/*
- * Store registers in the EBDA; used to keep the registers'
- * content in a well-defined place during protected mode execution
- */
- void
-store_segment_registers(ss, cs, ds, es, esp_hi)
- Bit16u ss, cs, ds, es, esp_hi;
-{
- Bit16u ebda_seg = read_word(0x0040, 0x000E);
- write_word(ebda_seg, &EbdaData->upcall.reg_ss, ss);
- write_word(ebda_seg, &EbdaData->upcall.reg_cs, cs);
- write_word(ebda_seg, &EbdaData->upcall.reg_ds, ds);
- write_word(ebda_seg, &EbdaData->upcall.reg_es, es);
- write_word(ebda_seg, &EbdaData->upcall.esp_hi, esp_hi);
-}
-
-
- void
-store_returnaddress(retaddr)
- Bit16u retaddr;
-{
- Bit16u ebda_seg = read_word(0x0040, 0x000E);
- write_word(ebda_seg, &EbdaData->upcall.retaddr, retaddr);
-}
-
-Bit16u
-get_returnaddress()
-{
- return read_word_from_ebda(&EbdaData->upcall.retaddr);
-}
-
-/*
- * get the segment register 'cs' value from the EBDA
- */
-Bit16u
-get_register_cs()
-{
- return read_word_from_ebda(&EbdaData->upcall.reg_cs);
-}
-
-/*
- * get the segment register 'ds' value from the EBDA
- */
-Bit16u
-get_register_ds()
-{
- return read_word_from_ebda(&EbdaData->upcall.reg_ds);
-}
-
-/*
- * get the segment register 'es' value from the EBDA
- */
-Bit16u
-get_register_es()
-{
- return read_word_from_ebda(&EbdaData->upcall.reg_es);
-}
-
-/*
- * get the upper 16 bits of the esp from the EBDA
- */
-Bit16u
-get_register_esp_hi()
-{
- return read_word_from_ebda(&EbdaData->upcall.esp_hi);
-}
-
-
-
-/********************************************************/
-
-
-ASM_START
-
-Upcall:
- ; do the upcall into 32 bit space
- ; clear the stack frame so that 32 bit space sees all the parameters
- ; on the stack as if they were prepared for it
- ; ---> take the 16 bit return address off the stack and remember it
- ;
- ; Input:
- ; bx: index of function to call
- ; Ouput:
- ; dx, ax: 32 bit result of call (even if 'void' is expected)
-
- push bp ;pop @1
- mov bp, sp
- push si ;pop @2
-
- mov ax, 2[bp] ; 16 bit return address
- push ax
- call _store_returnaddress ; store away
- pop ax
-
- rol bx, #2
- mov si, #jmptable
- seg cs
- mov eax, dword ptr [si+bx] ; address to call from table
-
- pop si ;@2
- pop bp ;@1
-
- add sp, #2 ; remove 16bit return address from stack
-
- call switch_to_protmode
- START_PM_CODE
-
- call eax ; call 32bit function
- push eax ; preserve result
-
- call switch_to_realmode ; back to realmode
- END_PM_CODE
-
- pop eax ; get result
-
- push word 0x0000 ; placeholder for 16 bit return address
- push bp
- mov bp,sp
- push eax ; preserve work register
-
- call _get_returnaddress
- mov 2[bp], ax ; 16bit return address onto stack
-
- pop eax
- pop bp
-
- ror eax, #16 ; result into dx/ax
- mov dx, ax ; hi(res) -> dx
- ror eax, #16
-
- ret
-

/* macro for functions to declare their call into 32bit space */
MACRO DoUpcall
- mov bx, #?1
- jmp Upcall
+ mov bx, #?1
+ jmp Upcall
MEND
-

ASM_END

#include "32bitprotos.h"
-#include "32bitgateway.h"
-
#include "tcgbios.c"

Bit32u get_s3_waking_vector()
{
- ASM_START
- DoUpcall(IDX_GET_S3_WAKING_VECTOR)
- ASM_END
+ ASM_START
+ DoUpcall(IDX_GET_S3_WAKING_VECTOR)
+ ASM_END
}
diff -r d52921c18c3d -r b10fd9f4fe38 tools/firmware/rombios/32bitgateway.h
--- a/tools/firmware/rombios/32bitgateway.h Thu Jan 22 11:21:43 2009 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-#ifndef GATEWAY
-#define GATEWAY
-
-#include "32bitprotos.h"
-
-void test_gateway();
-
-/* extension for the EBDA */
-typedef struct {
- Bit16u reg_ss;
- Bit16u reg_cs;
- Bit16u reg_ds;
- Bit16u reg_es;
- Bit16u esp_hi;
- Bit16u retaddr;
-} upcall_t;
-
-#endif
diff -r d52921c18c3d -r b10fd9f4fe38 tools/firmware/rombios/rombios.c
--- a/tools/firmware/rombios/rombios.c Thu Jan 22 11:21:43 2009 +0000
+++ b/tools/firmware/rombios/rombios.c Thu Jan 22 16:32:06 2009 +0000
@@ -726,7 +726,7 @@ typedef struct {
} cdemu_t;
#endif // BX_ELTORITO_BOOT

-#include "32bitgateway.h"
+#include "32bitprotos.h"

// for access to EBDA area
// The EBDA structure should conform to
@@ -752,8 +752,6 @@ typedef struct {
// El Torito Emulation data
cdemu_t cdemu;
#endif // BX_ELTORITO_BOOT
-
- upcall_t upcall;
} ebda_data_t;

#define EBDA_CMOS_SHUTDOWN_STATUS_OFFSET 1

_______________________________________________
Xen-changelog mailing list
Xen-changelog@lists.xensource.com
http://lists.xensource.com/xen-changelog