📄 32bitgateway.c
字号:
/* * Implementation of a gateway into 32bit space. Stub functions * can be called from Bochs BIOS which call functions with a compatible * signature in 32bit space. All interrupts are disabled while in * 32 bit mode. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright (C) IBM Corporation, 2006 * * Author: Stefan Berger <stefanb@us.ibm.com> *//* * Note: * BCC's ABI does not require to preserve any 16bit registers ax, bx, cs, dx * by a called function. So these registers need not be preserved while * calling a function in 32bit space, either. * * When bcc calls a function with 16bit parameters it pushes 2 bytes onto * the stack for such a parameter. GCC, however, expects 32bit parameters * (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#define START_PM_CODE USE32#define END_PM_CODE USE16/* definition of used code/data segment descriptors */#define PM_NORMAL_CS (gdt_entry_pm_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) 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) ; ; preserves all registers and prepares cs, ds, es, ss for usage ; in protected mode; while in prot.mode interrupts remain disabledswitch_to_protmode: cli ; 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 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 and esp, #0xffff xor eax, eax mov ax, ss rol eax, #4 add eax, esp mov esp, eax seg cs lgdt my_gdtdesc ; switch to own table mov eax, cr0 or al, #0x1 ; protected mode 'on' mov cr0, eax jmpf DWORD (SEGMENT_OFFSET | switch_to_protmode_goon_1), #PM_NORMAL_CS START_PM_CODEswitch_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 mov ss, ax pop eax ;@A2 pop bp ;@A1 ret END_PM_CODE .align 16gdt_base: ; see Intel SW Dev. Manuals section 3.4.5, Volume 3 for meaning of bits .word 0,0 .byte 0,0,0,0gdt_entry_pm_cs: ; 32 bit code segment for protected mode .word 0xffff, 0x0000 .byte 0x00, 0x9a, 0xcf, 0x00gdt_entry_pm_16bit_cs: ; temp. 16 bit code segment used while in protected mode .word 0xffff, 0x0000 .byte SEGMENT_OFFSET >> 16, 0x9a, 0x0, 0x0gdt_entry_pm_32bit_ds: ; (32 bit) data segment (r/w) reaching all possible areas in 32bit memory ; 4kb granularity .word 0xffff, 0x0000 .byte 0x0, 0x92, 0xcf, 0x0gdt_entry_end:my_gdtdesc: .word (gdt_entry_end - gdt_base) - 1 .long gdt_base | SEGMENT_OFFSETrealmode_gdtdesc: ;to be used in real mode .word 0xffff .long 0x0switch_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_CODEswitch_to_realmode_goon_1: mov eax, cr0 and al, #0xfe ; protected mode 'off' mov cr0, eax jmpf switch_to_realmode_goon_2, #REAL_MODE_CODE_SEGMENTswitch_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 seg cs lgdt realmode_gdtdesc sti ; allow interrupts pop si ;@2 pop bx ;@1 ret ASM_END/* * Helper function to get the offset of the reg_ss within the ebda struct * Only 'C' can tell the offset. */Bit16uebda_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 */Bit16uread_word_from_ebda(offset) Bit16u offset;{ Bit16u ebda_seg = read_word(0x0040, 0x000E); return read_word(ebda_seg, offset);}Bit32uread_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 */ voidstore_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);} voidstore_returnaddress(retaddr) Bit16u retaddr;{ Bit16u ebda_seg = read_word(0x0040, 0x000E); write_word(ebda_seg, &EbdaData->upcall.retaddr, retaddr);}Bit16uget_returnaddress(){ return read_word_from_ebda(&EbdaData->upcall.retaddr);}/* * get the segment register 'cs' value from the EBDA */Bit16uget_register_cs(){ return read_word_from_ebda(&EbdaData->upcall.reg_cs);}/* * get the segment register 'ds' value from the EBDA */Bit16uget_register_ds(){ return read_word_from_ebda(&EbdaData->upcall.reg_ds);}/* * get the segment register 'es' value from the EBDA */Bit16uget_register_es(){ return read_word_from_ebda(&EbdaData->upcall.reg_es);}/* * get the upper 16 bits of the esp from the EBDA */Bit16uget_register_esp_hi(){ return read_word_from_ebda(&EbdaData->upcall.esp_hi);}/********************************************************/ASM_STARTUpcall: ; 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 ; XXX GDT munging requires ROM to be writable! call _enable_rom_write_access 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 _disable_rom_write_access 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 UpcallMENDASM_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}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -