ia64/xen-unstable

changeset 19074:b10fd9f4fe38

rombios: Simplify 32-bit gateway and avoid need for EBDA space.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jan 22 16:32:06 2009 +0000 (2009-01-22)
parents d52921c18c3d
children fe2957a376fe
files tools/firmware/rombios/32bitgateway.c tools/firmware/rombios/32bitgateway.h tools/firmware/rombios/rombios.c
line diff
     1.1 --- a/tools/firmware/rombios/32bitgateway.c	Thu Jan 22 11:21:43 2009 +0000
     1.2 +++ b/tools/firmware/rombios/32bitgateway.c	Thu Jan 22 16:32:06 2009 +0000
     1.3 @@ -19,8 +19,10 @@
     1.4   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
     1.5   *
     1.6   * Copyright (C) IBM Corporation, 2006
     1.7 + * Copyright (c) 2008, Citrix Systems, Inc.
     1.8   *
     1.9   * Author: Stefan Berger <stefanb@us.ibm.com>
    1.10 + * Author: Keir Fraser <keir.fraser@citrix.com>
    1.11   */
    1.12  
    1.13  /*
    1.14 @@ -34,384 +36,162 @@
    1.15   *  (4 bytes) even for uint16_t, so casting to 32bit from bcc is a good idea.
    1.16   */
    1.17  
    1.18 -#define SEGMENT_OFFSET  0xf0000
    1.19 -#define REAL_MODE_CODE_SEGMENT  0xf000
    1.20 +/* At most 32 bytes in argument list to a 32-bit function. */
    1.21 +#define MAX_ARG_BYTES 32
    1.22  
    1.23 -#define START_PM_CODE  USE32
    1.24 -#define END_PM_CODE    USE16
    1.25 +#define REAL_MODE_CODE_OFFSET  0xf0000
    1.26  
    1.27 -/* definition of used code/data segment descriptors */
    1.28 -#define PM_NORMAL_CS (gdt_entry_pm_cs       - gdt_base)
    1.29 +/* Definitions of code/data segment descriptors. */
    1.30 +#define PM_32BIT_CS  (gdt_entry_pm_32bit_cs - gdt_base)
    1.31  #define PM_16BIT_CS  (gdt_entry_pm_16bit_cs - gdt_base)
    1.32  #define PM_32BIT_DS  (gdt_entry_pm_32bit_ds - gdt_base)
    1.33 -
    1.34 -  ASM_START
    1.35 -
    1.36 -    ; Switch into protected mode to allow access to 32 bit addresses.
    1.37 -    ; This function allows switching into protected mode.
    1.38 -    ; (the specs says big real mode, but that will not work)
    1.39 -    ;
    1.40 -    ; preserves all registers and prepares cs, ds, es, ss for usage
    1.41 -    ; in protected mode; while in prot.mode interrupts remain disabled
    1.42 -switch_to_protmode:
    1.43 -    cli
    1.44 -
    1.45 -    ; have to fix the stack for proper return address in 32 bit mode
    1.46 -    push WORD #(REAL_MODE_CODE_SEGMENT>>12)	;extended return address
    1.47 -    push bp					;pop@A1
    1.48 -    mov bp, sp
    1.49 -    push eax					;pop@A2
    1.50 -    mov eax, 2[bp]				; fix return address
    1.51 -    rol eax, #16
    1.52 -    mov 2[bp], eax
    1.53 -
    1.54 -    mov eax, esp
    1.55 -    ror eax, #16				; hi(esp)
    1.56 -
    1.57 -    push bx					; preserve before function call
    1.58 -    push cx
    1.59 -    push dx
    1.60 -
    1.61 -    push ax					; prepare stack for
    1.62 -    push es					; call
    1.63 -    push ds
    1.64 -    push cs
    1.65 -    push ss
    1.66 -    call _store_segment_registers
    1.67 -    add sp, #10					; pop ax,es-ss
    1.68 +#define PM_16BIT_DS  (gdt_entry_pm_16bit_ds - gdt_base)
    1.69  
    1.70 -    pop dx					; restore after function call
    1.71 -    pop cx
    1.72 -    pop bx
    1.73 -
    1.74 -    ; calculate protected-mode esp from ss:sp
    1.75 -    and esp, #0xffff
    1.76 -    xor eax, eax
    1.77 -    mov ax, ss
    1.78 -    rol eax, #4
    1.79 -    add eax, esp
    1.80 -    mov esp, eax
    1.81 -
    1.82 -    seg cs
    1.83 -    lgdt my_gdtdesc				; switch to own table
    1.84 -
    1.85 -    mov eax, cr0
    1.86 -    or	al, #0x1				; protected mode 'on'
    1.87 -    mov cr0, eax
    1.88 -
    1.89 -    jmpf DWORD (SEGMENT_OFFSET | switch_to_protmode_goon_1), #PM_NORMAL_CS
    1.90 -
    1.91 -    START_PM_CODE
    1.92 -
    1.93 -switch_to_protmode_goon_1:
    1.94 -    mov ax, #PM_32BIT_DS			; 32 bit segment that allows
    1.95 -    mov ds, ax					; to reach all 32 bit
    1.96 -    mov es, ax					; addresses
    1.97 -    mov ss, ax
    1.98 -
    1.99 -    pop eax					;@A2
   1.100 -    pop bp					;@A1
   1.101 -    ret
   1.102 -
   1.103 -    END_PM_CODE
   1.104 -
   1.105 -
   1.106 +ASM_START
   1.107  
   1.108      .align 16
   1.109  gdt_base:
   1.110 -    ; see Intel SW Dev. Manuals section 3.4.5, Volume 3 for meaning of bits
   1.111      .word 0,0
   1.112      .byte 0,0,0,0
   1.113 -
   1.114 -gdt_entry_pm_cs:
   1.115 -    ; 32 bit code segment for protected mode
   1.116 +gdt_entry_pm_32bit_cs:
   1.117      .word 0xffff, 0x0000
   1.118      .byte 0x00, 0x9b, 0xcf, 0x00
   1.119 -
   1.120  gdt_entry_pm_16bit_cs:
   1.121 -    ; temp. 16 bit code segment used while in protected mode
   1.122      .word 0xffff, 0x0000
   1.123 -    .byte SEGMENT_OFFSET >> 16, 0x9b, 0x0, 0x0
   1.124 -
   1.125 +    .byte REAL_MODE_CODE_OFFSET >> 16, 0x9b, 0x0, 0x0
   1.126  gdt_entry_pm_32bit_ds:
   1.127 -    ; (32 bit) data segment (r/w) reaching all possible areas in 32bit memory
   1.128 -    ; 4kb granularity
   1.129      .word 0xffff, 0x0000
   1.130      .byte 0x0, 0x93, 0xcf, 0x0
   1.131 +gdt_entry_pm_16bit_ds:
   1.132 +    .word 0xffff, 0x0000
   1.133 +    .byte 0x0, 0x93, 0x0, 0x0
   1.134  gdt_entry_end:
   1.135  
   1.136 -my_gdtdesc:
   1.137 +protmode_gdtdesc:
   1.138      .word (gdt_entry_end - gdt_base) - 1
   1.139 -    .long gdt_base | SEGMENT_OFFSET
   1.140 +    .long gdt_base | REAL_MODE_CODE_OFFSET
   1.141  
   1.142 -
   1.143 -realmode_gdtdesc:				;to be used in real mode
   1.144 +realmode_gdtdesc:
   1.145      .word 0xffff
   1.146      .long 0x0
   1.147  
   1.148 -
   1.149 -
   1.150 -switch_to_realmode:
   1.151 -    ; Implementation of switching from protected mode to real mode
   1.152 -    ; prepares cs, es, ds, ss to be used in real mode
   1.153 -    ; spills   eax
   1.154 -    START_PM_CODE
   1.155 +Upcall:
   1.156 +    ; Do an upcall into 32 bit space
   1.157 +    ;
   1.158 +    ; Input:
   1.159 +    ; bx: index of function to call
   1.160 +    ; Ouput:
   1.161 +    ; dx, ax: 32 bit result of call (even if 'void' is expected)
   1.162  
   1.163 -    ; need to fix up the stack to return in 16 bit mode
   1.164 -    ; currently the 32 bit return address is on the stack
   1.165 -    pop eax
   1.166 -    push ax
   1.167 -
   1.168 -    push bx					;pop@1
   1.169 -    push si					;pop@2
   1.170 -
   1.171 -    call _ebda_ss_offset32			; get the offset of the ss
   1.172 -    mov bx, ax					; entry within the ebda.
   1.173 -
   1.174 -    jmpf switch_to_realmode_goon_1, #PM_16BIT_CS
   1.175 +    ; Save caller state, stack frame offsets listed below
   1.176 +#define esp_off     0
   1.177 +#define ss_off      4
   1.178 +#define es_off      6
   1.179 +#define ds_off      8
   1.180 +#define flags_off   10
   1.181 +#define retaddr_off 12
   1.182 +#define args_off    14
   1.183 +    pushf
   1.184 +    cli
   1.185 +    push ds
   1.186 +    push es
   1.187 +    push ss
   1.188 +    push esp
   1.189  
   1.190 -    END_PM_CODE
   1.191 -
   1.192 -switch_to_realmode_goon_1:
   1.193 -    mov eax, cr0
   1.194 -    and al, #0xfe				; protected mode 'off'
   1.195 -    mov cr0, eax
   1.196 -
   1.197 -    jmpf switch_to_realmode_goon_2, #REAL_MODE_CODE_SEGMENT
   1.198 -
   1.199 -switch_to_realmode_goon_2:
   1.200 +    ; Find the 32-bit function address via a table lookup
   1.201 +    push si
   1.202 +    rol bx, #2
   1.203 +    mov si, #jmptable
   1.204 +    seg cs
   1.205 +    mov eax, dword ptr [si+bx]
   1.206 +    pop si
   1.207 +    push eax
   1.208  
   1.209 -    ; get orig. 'ss' without using the stack (no 'call'!)
   1.210 -    xor eax, eax			; clear upper 16 bits (and lower)
   1.211 -    mov ax, #0x40			; where is the ebda located?
   1.212 +    ; Calculate protected-mode esp from ss:sp
   1.213 +    and esp, #0xffff
   1.214 +    xor eax, eax
   1.215 +    mov ax, ss
   1.216 +    shl eax, #4
   1.217 +    add esp, eax
   1.218 +
   1.219 +    ; Switch to protected mode
   1.220 +    seg cs
   1.221 +    lgdt protmode_gdtdesc
   1.222 +    mov eax, cr0
   1.223 +    or al, #0x1  ; protected mode on
   1.224 +    mov cr0, eax
   1.225 +    jmpf DWORD (REAL_MODE_CODE_OFFSET|upcall1), #PM_32BIT_CS
   1.226 +upcall1:
   1.227 +    USE32
   1.228 +    mov ax, #PM_32BIT_DS
   1.229      mov ds, ax
   1.230 -    mov si, #0xe
   1.231 -    seg ds
   1.232 -    mov ax, [si]			; ax = segment of ebda
   1.233 -
   1.234 -    mov ds, ax				; segment of ebda
   1.235 -    seg ds
   1.236 -    mov ax, [bx]			; stack segment - bx has been set above
   1.237 +    mov es, ax
   1.238      mov ss, ax
   1.239  
   1.240 -    ; from esp and ss calculate real-mode sp
   1.241 -    rol eax, #4
   1.242 -    sub esp, eax
   1.243 +    ; Marshal arguments and call 32-bit function
   1.244 +    pop eax
   1.245 +    mov ecx, #MAX_ARG_BYTES/4
   1.246 +upcall2:
   1.247 +    push MAX_ARG_BYTES-4+args_off[esp]
   1.248 +    loop upcall2
   1.249 +    call eax
   1.250 +    add esp, #MAX_ARG_BYTES
   1.251 +    mov ecx, eax  ; Result in ecx
   1.252  
   1.253 -    push dx				;preserve before call(s)
   1.254 -    push cx
   1.255 -    push bx
   1.256 +    ; Restore real-mode stack pointer
   1.257 +    xor eax, eax
   1.258 +    mov ax, ss_off[esp]
   1.259 +    shl eax, 4
   1.260 +    sub esp, eax
   1.261 +    mov bx, ax    ; Real-mode ss in bx
   1.262  
   1.263 -    call _get_register_ds		; get orig. 'ds'
   1.264 +    ; Return to real mode
   1.265 +    jmpf upcall3, #PM_16BIT_CS
   1.266 +upcall3:
   1.267 +    USE16
   1.268 +    mov ax, #PM_16BIT_DS
   1.269      mov ds, ax
   1.270 -    call _get_register_es		; get orig. 'es'
   1.271      mov es, ax
   1.272 -    call _get_register_esp_hi		; fix the upper 16 bits of esp
   1.273 -    ror esp, #16
   1.274 -    mov sp, ax
   1.275 -    rol esp, #16
   1.276 -
   1.277 -    pop bx
   1.278 -    pop cx
   1.279 -    pop dx
   1.280 -
   1.281 +    mov ss, ax
   1.282 +    mov eax, cr0
   1.283 +    and al, #0xfe ; protected mode off
   1.284 +    mov cr0, eax
   1.285 +    jmpf upcall4, #REAL_MODE_CODE_OFFSET>>4
   1.286 +upcall4:
   1.287      seg cs
   1.288      lgdt realmode_gdtdesc
   1.289  
   1.290 -    sti						; allow interrupts
   1.291 -
   1.292 -    pop si					;@2
   1.293 -    pop bx					;@1
   1.294 -
   1.295 -    ret
   1.296 -
   1.297 -    ASM_END
   1.298 -
   1.299 -/*
   1.300 - * Helper function to get the offset of the reg_ss within the ebda struct
   1.301 - * Only 'C' can tell the offset.
   1.302 - */
   1.303 -Bit16u
   1.304 -ebda_ss_offset32()
   1.305 -{
   1.306 -    ASM_START
   1.307 -    START_PM_CODE				// need to have this
   1.308 -    ASM_END					// compiled for protected mode
   1.309 -    return &EbdaData->upcall.reg_ss;		// 'C' knows the offset!
   1.310 -    ASM_START
   1.311 -    END_PM_CODE
   1.312 -    ASM_END
   1.313 -}
   1.314 -
   1.315 -/*
   1.316 - * Two often-used functions
   1.317 - */
   1.318 -Bit16u
   1.319 -read_word_from_ebda(offset)
   1.320 -    Bit16u offset;
   1.321 -{
   1.322 -	Bit16u ebda_seg = read_word(0x0040, 0x000E);
   1.323 -	return read_word(ebda_seg, offset);
   1.324 -}
   1.325 -
   1.326 -Bit32u
   1.327 -read_dword_from_ebda(offset)
   1.328 -    Bit16u offset;
   1.329 -{
   1.330 -	Bit16u ebda_seg = read_word(0x0040, 0x000E);
   1.331 -	return read_dword(ebda_seg, offset);
   1.332 -}
   1.333 -
   1.334 -/*
   1.335 - * Store registers in the EBDA; used to keep the registers'
   1.336 - * content in a well-defined place during protected mode execution
   1.337 - */
   1.338 -  void
   1.339 -store_segment_registers(ss, cs, ds, es, esp_hi)
   1.340 -  Bit16u ss, cs, ds, es, esp_hi;
   1.341 -{
   1.342 -	Bit16u ebda_seg = read_word(0x0040, 0x000E);
   1.343 -	write_word(ebda_seg, &EbdaData->upcall.reg_ss, ss);
   1.344 -	write_word(ebda_seg, &EbdaData->upcall.reg_cs, cs);
   1.345 -	write_word(ebda_seg, &EbdaData->upcall.reg_ds, ds);
   1.346 -	write_word(ebda_seg, &EbdaData->upcall.reg_es, es);
   1.347 -	write_word(ebda_seg, &EbdaData->upcall.esp_hi, esp_hi);
   1.348 -}
   1.349 -
   1.350 -
   1.351 -  void
   1.352 -store_returnaddress(retaddr)
   1.353 -   Bit16u retaddr;
   1.354 -{
   1.355 -	Bit16u ebda_seg = read_word(0x0040, 0x000E);
   1.356 -	write_word(ebda_seg, &EbdaData->upcall.retaddr, retaddr);
   1.357 -}
   1.358 -
   1.359 -Bit16u
   1.360 -get_returnaddress()
   1.361 -{
   1.362 -	return read_word_from_ebda(&EbdaData->upcall.retaddr);
   1.363 -}
   1.364 -
   1.365 -/*
   1.366 - * get the segment register 'cs' value from the EBDA
   1.367 - */
   1.368 -Bit16u
   1.369 -get_register_cs()
   1.370 -{
   1.371 -	return read_word_from_ebda(&EbdaData->upcall.reg_cs);
   1.372 -}
   1.373 +    ; Restore real-mode ss
   1.374 +    mov ss, bx
   1.375  
   1.376 -/*
   1.377 - * get the segment register 'ds' value from the EBDA
   1.378 - */
   1.379 -Bit16u
   1.380 -get_register_ds()
   1.381 -{
   1.382 -	return read_word_from_ebda(&EbdaData->upcall.reg_ds);
   1.383 -}
   1.384 -
   1.385 -/*
   1.386 - * get the segment register 'es' value from the EBDA
   1.387 - */
   1.388 -Bit16u
   1.389 -get_register_es()
   1.390 -{
   1.391 -	return read_word_from_ebda(&EbdaData->upcall.reg_es);
   1.392 -}
   1.393 -
   1.394 -/*
   1.395 - * get the upper 16 bits of the esp from the EBDA
   1.396 - */
   1.397 -Bit16u
   1.398 -get_register_esp_hi()
   1.399 -{
   1.400 -	return read_word_from_ebda(&EbdaData->upcall.esp_hi);
   1.401 -}
   1.402 -
   1.403 -
   1.404 -
   1.405 -/********************************************************/
   1.406 -
   1.407 -
   1.408 -ASM_START
   1.409 -
   1.410 -Upcall:
   1.411 -	; do the upcall into 32 bit space
   1.412 -	; clear the stack frame so that 32 bit space sees all the parameters
   1.413 -	; on the stack as if they were prepared for it
   1.414 -	; ---> take the 16 bit return address off the stack and remember it
   1.415 -	;
   1.416 -	; Input:
   1.417 -	; bx: index of function to call
   1.418 -	; Ouput:
   1.419 -	; dx, ax: 32 bit result of call (even if 'void' is expected)
   1.420 +    ; Convert result into dx:ax format
   1.421 +    mov eax, ecx
   1.422 +    ror eax, #16
   1.423 +    mov dx, ax
   1.424 +    ror eax, #16
   1.425  
   1.426 -	push bp				;pop @1
   1.427 -	mov bp, sp
   1.428 -	push si				;pop @2
   1.429 -
   1.430 -	mov ax, 2[bp]			; 16 bit return address
   1.431 -	push ax
   1.432 -	call _store_returnaddress	; store away
   1.433 -	pop ax
   1.434 -
   1.435 -	rol bx, #2
   1.436 -	mov si, #jmptable
   1.437 -	seg cs
   1.438 -	mov eax, dword ptr [si+bx]	; address to call from table
   1.439 -
   1.440 -	pop si				;@2
   1.441 -	pop bp				;@1
   1.442 -
   1.443 -	add sp, #2			; remove 16bit return address from stack
   1.444 -
   1.445 -	call switch_to_protmode
   1.446 -	START_PM_CODE
   1.447 -
   1.448 -	call eax			; call 32bit function
   1.449 -	push eax			; preserve result
   1.450 -
   1.451 -	call switch_to_realmode		; back to realmode
   1.452 -	END_PM_CODE
   1.453 -
   1.454 -	pop eax				; get result
   1.455 -
   1.456 -	push word 0x0000		; placeholder for 16 bit return address
   1.457 -	push bp
   1.458 -	mov bp,sp
   1.459 -	push eax			; preserve work register
   1.460 -
   1.461 -	call _get_returnaddress
   1.462 -	mov 2[bp], ax			; 16bit return address onto stack
   1.463 -
   1.464 -	pop eax
   1.465 -	pop bp
   1.466 -
   1.467 -	ror eax, #16			; result into dx/ax
   1.468 -	mov dx, ax			; hi(res) -> dx
   1.469 -	ror eax, #16
   1.470 -
   1.471 -	ret
   1.472 -
   1.473 +    ; Restore caller state and return
   1.474 +    pop esp
   1.475 +    pop bx ; skip ss
   1.476 +    pop es
   1.477 +    pop ds
   1.478 +    popf
   1.479 +    ret
   1.480  
   1.481  /* macro for functions to declare their call into 32bit space */
   1.482  MACRO DoUpcall
   1.483 -	mov bx, #?1
   1.484 -	jmp Upcall
   1.485 +    mov bx, #?1
   1.486 +    jmp Upcall
   1.487  MEND
   1.488  
   1.489 -
   1.490  ASM_END
   1.491  
   1.492  #include "32bitprotos.h"
   1.493 -#include "32bitgateway.h"
   1.494 -
   1.495  #include "tcgbios.c"
   1.496  
   1.497  Bit32u get_s3_waking_vector()
   1.498  {
   1.499 -	ASM_START
   1.500 -	DoUpcall(IDX_GET_S3_WAKING_VECTOR)
   1.501 -	ASM_END
   1.502 +    ASM_START
   1.503 +    DoUpcall(IDX_GET_S3_WAKING_VECTOR)
   1.504 +    ASM_END
   1.505  }
     2.1 --- a/tools/firmware/rombios/32bitgateway.h	Thu Jan 22 11:21:43 2009 +0000
     2.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.3 @@ -1,18 +0,0 @@
     2.4 -#ifndef GATEWAY
     2.5 -#define GATEWAY
     2.6 -
     2.7 -#include "32bitprotos.h"
     2.8 -
     2.9 -void test_gateway();
    2.10 -
    2.11 -/* extension for the EBDA */
    2.12 -typedef struct {
    2.13 -  Bit16u reg_ss;
    2.14 -  Bit16u reg_cs;
    2.15 -  Bit16u reg_ds;
    2.16 -  Bit16u reg_es;
    2.17 -  Bit16u esp_hi;
    2.18 -  Bit16u retaddr;
    2.19 -} upcall_t;
    2.20 -
    2.21 -#endif
     3.1 --- a/tools/firmware/rombios/rombios.c	Thu Jan 22 11:21:43 2009 +0000
     3.2 +++ b/tools/firmware/rombios/rombios.c	Thu Jan 22 16:32:06 2009 +0000
     3.3 @@ -726,7 +726,7 @@ typedef struct {
     3.4      } cdemu_t;
     3.5  #endif // BX_ELTORITO_BOOT
     3.6  
     3.7 -#include "32bitgateway.h"
     3.8 +#include "32bitprotos.h"
     3.9  
    3.10    // for access to EBDA area
    3.11    //     The EBDA structure should conform to
    3.12 @@ -752,8 +752,6 @@ typedef struct {
    3.13      // El Torito Emulation data
    3.14      cdemu_t cdemu;
    3.15  #endif // BX_ELTORITO_BOOT
    3.16 -
    3.17 -    upcall_t upcall;
    3.18      } ebda_data_t;
    3.19  
    3.20    #define EBDA_CMOS_SHUTDOWN_STATUS_OFFSET 1