debuggers.hg

view tools/firmware/rombios/32bitgateway.c @ 13681:c07326324f8d

[HVM] Add TCG BIOS extensions to the high memory area along with
some often-used libc utility functions. The TCG extensions are
described here:

https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementationforBIOS_1-20_1-00.pdf

I have tried to keep the patching with rombios.c to a minimum, but
some amount of code needs to be inserted at various locations.

The code is currently deactivated, but can be activated by setting
BX_TCGBIOS to '1'.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author kaf24@localhost.localdomain
date Fri Jan 26 16:38:32 2007 +0000 (2007-01-26)
parents 480436ef6255
children edbff1762a55
line source
1 /*
2 * Implementation of a gateway into 32bit space. Stub functions
3 * can be called from Bochs BIOS which call functions with a compatible
4 * signature in 32bit space. All interrupts are disabled while in
5 * 32 bit mode.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * Copyright (C) IBM Corporation, 2006
22 *
23 * Author: Stefan Berger <stefanb@us.ibm.com>
24 */
26 /*
27 * Note:
28 * BCC's ABI does not require to preserve any 16bit registers ax, bx, cs, dx
29 * by a called function. So these registers need not be preserved while
30 * calling a function in 32bit space, either.
31 *
32 * When bcc calls a function with 16bit parameters it pushes 2 bytes onto
33 * the stack for such a parameter. GCC, however, expects 32bit parameters
34 * (4 bytes) even for uint16_t, so casting to 32bit from bcc is a good idea.
35 */
37 #define SEGMENT_OFFSET 0xf0000
38 #define REAL_MODE_CODE_SEGMENT 0xf000
40 #define START_PM_CODE USE32
41 #define END_PM_CODE USE16
43 /* definition of used code/data segment descriptors */
44 #define PM_NORMAL_CS (gdt_entry_pm_cs - gdt_base)
45 #define PM_16BIT_CS (gdt_entry_pm_16bit_cs - gdt_base)
46 #define PM_32BIT_DS (gdt_entry_pm_32bit_ds - gdt_base)
48 ASM_START
50 ; Switch into protected mode to allow access to 32 bit addresses.
51 ; This function allows switching into protected mode.
52 ; (the specs says big real mode, but that will not work)
53 ;
54 ; preserves all registers and prepares cs, ds, es, ss for usage
55 ; in protected mode; while in prot.mode interrupts remain disabled
56 switch_to_protmode:
57 cli
59 ; have to fix the stack for proper return address in 32 bit mode
60 push WORD #(REAL_MODE_CODE_SEGMENT>>12) ;extended return address
61 push bp ;pop@A1
62 mov bp, sp
63 push eax ;pop@A2
64 mov eax, 2[bp] ; fix return address
65 rol eax, #16
66 mov 2[bp], eax
68 mov eax, esp
69 ror eax, #16 ; hi(esp)
71 push bx ; preserve before function call
72 push cx
73 push dx
75 push ax ; prepare stack for
76 push es ; call
77 push ds
78 push cs
79 push ss
80 call _store_segment_registers
81 add sp, #10 ; pop ax,es-ss
83 pop dx ; restore after function call
84 pop cx
85 pop bx
87 ; calculate protected-mode esp from ss:sp
88 and esp, #0xffff
89 xor eax, eax
90 mov ax, ss
91 rol eax, #4
92 add eax, esp
93 mov esp, eax
95 seg cs
96 lgdt my_gdtdesc ; switch to own table
98 mov eax, cr0
99 or al, #0x1 ; protected mode 'on'
100 mov cr0, eax
102 jmpf DWORD (SEGMENT_OFFSET | switch_to_protmode_goon_1), #PM_NORMAL_CS
104 START_PM_CODE
106 switch_to_protmode_goon_1:
107 mov ax, #PM_32BIT_DS ; 32 bit segment that allows
108 mov ds, ax ; to reach all 32 bit
109 mov es, ax ; addresses
110 mov ss, ax
112 pop eax ;@A2
113 pop bp ;@A1
114 ret
116 END_PM_CODE
120 .align 16
121 gdt_base:
122 ; see Intel SW Dev. Manuals section 3.4.5, Volume 3 for meaning of bits
123 .word 0,0
124 .byte 0,0,0,0
126 gdt_entry_pm_cs:
127 ; 32 bit code segment for protected mode
128 .word 0xffff, 0x0000
129 .byte 0x00, 0x9a, 0xcf, 0x00
131 gdt_entry_pm_16bit_cs:
132 ; temp. 16 bit code segment used while in protected mode
133 .word 0xffff, 0x0000
134 .byte SEGMENT_OFFSET >> 16, 0x9a, 0x0, 0x0
136 gdt_entry_pm_32bit_ds:
137 ; (32 bit) data segment (r/w) reaching all possible areas in 32bit memory
138 ; 4kb granularity
139 .word 0xffff, 0x0000
140 .byte 0x0, 0x92, 0xcf, 0x0
141 gdt_entry_end:
143 my_gdtdesc:
144 .word (gdt_entry_end - gdt_base) - 1
145 .long gdt_base | SEGMENT_OFFSET
148 realmode_gdtdesc: ;to be used in real mode
149 .word 0xffff
150 .long 0x0
154 switch_to_realmode:
155 ; Implementation of switching from protected mode to real mode
156 ; restores all registers and prepares cs, es, ds, ss to be used
157 ; in real mode
158 START_PM_CODE
160 ; need to fix up the stack to return in 16 bit mode
161 ; currently the 32 bit return address is on the stack
162 push bp ;pop@A1
163 mov bp, sp
164 push eax ;pop@X
166 mov eax, [bp] ; return address low 16bits
167 ; and 'bp' are being moved
168 mov 2[bp], eax
170 pop eax ;@X
171 add sp, #2 ; adjust stack for 'lost' bytes
173 push eax ;pop@1
174 push bx ;pop@2
175 push si ;pop@3
177 call _ebda_ss_offset32 ; get the offset of the ss
178 mov bx, ax ; entry within the ebda.
180 jmpf switch_to_realmode_goon_1, #PM_16BIT_CS
182 END_PM_CODE
184 switch_to_realmode_goon_1:
185 mov eax, cr0
186 and al, #0xfe ; protected mode 'off'
187 mov cr0, eax
189 jmpf switch_to_realmode_goon_2, #REAL_MODE_CODE_SEGMENT
191 switch_to_realmode_goon_2:
193 ; get orig. 'ss' without using the stack (no 'call'!)
194 xor eax, eax ; clear upper 16 bits (and lower)
195 mov ax, #0x40 ; where is the ebda located?
196 mov ds, ax
197 mov si, #0xe
198 seg ds
199 mov ax, [si] ; ax = segment of ebda
201 mov ds, ax ; segment of ebda
202 seg ds
203 mov ax, [bx] ; stack segment - bx has been set above
204 mov ss, ax
206 ; from esp and ss calculate real-mode sp
207 rol eax, #4
208 sub esp, eax
210 push dx ;preserve before call(s)
211 push cx
212 push bx
214 call _get_register_ds ; get orig. 'ds'
215 mov ds, ax
216 call _get_register_es ; get orig. 'es'
217 mov es, ax
218 call _get_register_esp_hi ; fix the upper 16 bits of esp
219 ror esp, #16
220 mov sp, ax
221 rol esp, #16
223 pop bx
224 pop cx
225 pop dx
227 seg cs
228 lgdt realmode_gdtdesc
230 sti ; allow interrupts
232 pop si ;@3
233 pop bx ;@2
234 pop eax ;@1
235 pop bp ;@A1
237 ret
239 ASM_END
241 /*
242 * Helper function to get the offset of the reg_ss within the ebda struct
243 * Only 'C' can tell the offset.
244 */
245 Bit16u
246 ebda_ss_offset32()
247 {
248 ASM_START
249 START_PM_CODE // need to have this
250 ASM_END // compiled for protected mode
251 return &EbdaData->upcall.reg_ss; // 'C' knows the offset!
252 ASM_START
253 END_PM_CODE
254 ASM_END
255 }
257 /*
258 * Two often-used functions
259 */
260 Bit16u
261 read_word_from_ebda(offset)
262 Bit16u offset;
263 {
264 Bit16u ebda_seg = read_word(0x0040, 0x000E);
265 return read_word(ebda_seg, offset);
266 }
268 Bit32u
269 read_dword_from_ebda(offset)
270 Bit16u offset;
271 {
272 Bit16u ebda_seg = read_word(0x0040, 0x000E);
273 return read_dword(ebda_seg, offset);
274 }
276 /*
277 * Store registers in the EBDA; used to keep the registers'
278 * content in a well-defined place during protected mode execution
279 */
280 void
281 store_segment_registers(ss, cs, ds, es, esp_hi)
282 Bit16u ss, cs, ds, es, esp_hi;
283 {
284 Bit16u ebda_seg = read_word(0x0040, 0x000E);
285 write_word(ebda_seg, &EbdaData->upcall.reg_ss, ss);
286 write_word(ebda_seg, &EbdaData->upcall.reg_cs, cs);
287 write_word(ebda_seg, &EbdaData->upcall.reg_ds, ds);
288 write_word(ebda_seg, &EbdaData->upcall.reg_es, es);
289 write_word(ebda_seg, &EbdaData->upcall.esp_hi, esp_hi);
290 }
293 void
294 store_returnaddress(retaddr)
295 Bit16u retaddr;
296 {
297 Bit16u ebda_seg = read_word(0x0040, 0x000E);
298 write_word(ebda_seg, &EbdaData->upcall.retaddr, retaddr);
299 }
301 Bit16u
302 get_returnaddress()
303 {
304 return read_word_from_ebda(&EbdaData->upcall.retaddr);
305 }
307 /*
308 * get the segment register 'cs' value from the EBDA
309 */
310 Bit16u
311 get_register_cs()
312 {
313 return read_word_from_ebda(&EbdaData->upcall.reg_cs);
314 }
316 /*
317 * get the segment register 'ds' value from the EBDA
318 */
319 Bit16u
320 get_register_ds()
321 {
322 return read_word_from_ebda(&EbdaData->upcall.reg_ds);
323 }
325 /*
326 * get the segment register 'es' value from the EBDA
327 */
328 Bit16u
329 get_register_es()
330 {
331 return read_word_from_ebda(&EbdaData->upcall.reg_es);
332 }
334 /*
335 * get the upper 16 bits of the esp from the EBDA
336 */
337 Bit16u
338 get_register_esp_hi()
339 {
340 return read_word_from_ebda(&EbdaData->upcall.esp_hi);
341 }
345 /********************************************************/
348 ASM_START
350 Upcall:
351 ; do the upcall into 32 bit space
352 ; clear the stack frame so that 32 bit space sees all the parameters
353 ; on the stack as if they were prepared for it
354 ; ---> take the 16 bit return address off the stack and remember it
355 ;
356 ; Input:
357 ; bx: index of function to call
358 ; Ouput:
359 ; dx, ax: 32 bit result of call (even if 'void' is expected)
361 push bp ;pop @1
362 mov bp, sp
363 push si ;pop @2
365 mov ax, 2[bp] ; 16 bit return address
366 push ax
367 call _store_returnaddress ; store away
368 pop ax
370 rol bx, #2
371 mov si, #jmptable
372 seg cs
373 mov eax, dword ptr [si+bx] ; address to call from table
375 pop si ;@2
376 pop bp ;@1
378 add sp, #2 ; remove 16bit return address from stack
380 call switch_to_protmode
381 START_PM_CODE
383 call eax ; call 32bit function
384 push eax ; preserve result
386 call switch_to_realmode ; back to realmode
387 END_PM_CODE
389 pop eax ; get result
391 push word 0x0000 ; placeholder for 16 bit return address
392 push bp
393 mov bp,sp
394 push eax ; preserve work register
396 call _get_returnaddress
397 mov 2[bp], ax ; 16bit return address onto stack
399 pop eax
400 pop bp
402 ror eax, #16 ; result into dx/ax
403 mov dx, ax ; hi(res) -> dx
404 ror eax, #16
406 ret
409 /* macro for functions to declare their call into 32bit space */
410 MACRO DoUpcall
411 mov bx, #?1
412 jmp Upcall
413 MEND
416 ASM_END
418 #include "32bitprotos.h"
419 #include "32bitgateway.h"
421 /********************************************************************
422 Collection of stub functions for functions executed in 32bit space
423 *******************************************************************/
425 Bit32u multiply(a, b) /* for testing */
426 Bit32u a;
427 Bit32u b;
428 {
429 ASM_START
430 DoUpcall IDX_MULTIPLY
431 ASM_END
432 }
434 Bit32u add(a, b) /* for testing */
435 Bit32u a;
436 Bit32u b;
437 {
438 ASM_START
439 DoUpcall IDX_ADD
440 ASM_END
441 }
443 Bit32u set_static(a, b) /* for testing */
444 Bit32u a;
445 Bit32u b;
446 {
447 ASM_START
448 DoUpcall IDX_SET_STATIC
449 ASM_END
450 }
452 /* a function to test the gateway */
453 void
454 test_gateway()
455 {
456 Bit32u res;
457 Bit16u err = 0;
459 printf("32bit gateway ");
460 res = multiply(11111L,222L);
461 if (err = 0 && res != 11111L * 222L) {
462 printf("not working correctly: multiply\n");
463 err = 1;
464 }
466 res = add(111111L, 222222L);
467 if (err = 0 && res != 111111L + 222222L) {
468 printf("not working correctly: add\n");
469 err = 1;
470 }
472 res = set_static(0x12345678L);
473 if (err = 0 && res != 0x1L) {
474 printf("not working correctly: set_static (1)\n");
475 err = 1;
476 }
477 res = set_static(0x11111111L);
478 if (err = 0 && res != 0x12345678L) {
479 printf("not working correctly: set_static (2)\n");
480 err = 1;
481 }
483 if (err == 0) {
484 printf("working correctly\n");
485 }
486 }
488 #include "tcgbios.c"