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, see <http://www.gnu.org/licenses/>.
19  *
20  * Copyright (C) IBM Corporation, 2006
21  * Copyright (c) 2008, Citrix Systems, Inc.
22  *
23  * Author: Stefan Berger <stefanb@us.ibm.com>
24  * Author: Keir Fraser <keir@xen.org>
25  */
26 
27 /*
28  * Note:
29  *  BCC's ABI does not require to preserve any 16bit registers ax, bx, cs, dx
30  *  by a called function. So these registers need not be preserved while
31  *  calling a function in 32bit space, either.
32  *
33  *  When bcc calls a function with 16bit parameters it pushes 2 bytes onto
34  *  the stack for such a parameter. GCC, however, expects 32bit parameters
35  *  (4 bytes) even for uint16_t, so casting to 32bit from bcc is a good idea.
36  */
37 
38 /* At most 32 bytes in argument list to a 32-bit function. */
39 #define MAX_ARG_BYTES 32
40 
41 #define REAL_MODE_CODE_OFFSET  0xf0000
42 
43 /* Definitions of code/data segment descriptors. */
44 #define PM_32BIT_CS  (gdt_entry_pm_32bit_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)
47 #define PM_16BIT_DS  (gdt_entry_pm_16bit_ds - gdt_base)
48 
49     .align 16
50 gdt_base:
51     .word 0,0
52     .byte 0,0,0,0
53 gdt_entry_pm_32bit_cs:
54     .word 0xffff, 0x0000
55     .byte 0x00, 0x9b, 0xcf, 0x00
56 gdt_entry_pm_16bit_cs:
57     .word 0xffff, 0x0000
58     .byte REAL_MODE_CODE_OFFSET >> 16, 0x9b, 0x8f, 0x0
59 gdt_entry_pm_32bit_ds:
60     .word 0xffff, 0x0000
61     .byte 0x0, 0x93, 0xcf, 0x0
62 gdt_entry_pm_16bit_ds:
63     .word 0xffff, 0x0000
64     .byte 0x0, 0x93, 0x8f, 0x0
65 gdt_entry_end:
66 
67 protmode_gdtdesc:
68     .word (gdt_entry_end - gdt_base) - 1
69     .long gdt_base | REAL_MODE_CODE_OFFSET
70 
71 realmode_gdtdesc:
72     .word 0xffff
73     .long 0x0
74 
75 Upcall:
76     ; Do an upcall into 32 bit space
77     ;
78     ; Input:
79     ; bx: index of function to call
80     ; Ouput:
81     ; dx, ax: 32 bit result of call (even if 'void' is expected)
82 
83     ; Save caller state, stack frame offsets listed below
84 #define esp_off     0
85 #define ss_off      4
86 #define es_off      6
87 #define ds_off      8
88 #define flags_off   10
89 #define retaddr_off 12
90 #define args_off    14
91     pushf
92     cli
93     push ds
94     push es
95     push ss
96     push esp
97 
98     ; Calculate protected-mode esp from ss:sp
99     and esp, #0xffff
100     xor eax, eax
101     mov ax, ss
102     shl eax, #4
103     add esp, eax
104 
105     ; Switch to protected mode
106     seg cs
107     lgdt protmode_gdtdesc
108     mov eax, cr0
109     or al, #0x1  ; protected mode on
110     mov cr0, eax
111     jmpf DWORD (REAL_MODE_CODE_OFFSET|upcall1), #PM_32BIT_CS
112 upcall1:
113     USE32
114     mov ax, #PM_32BIT_DS
115     mov ds, ax
116     mov es, ax
117     mov ss, ax
118 
119     ; Marshal arguments and call 32-bit function
120     mov ecx, #MAX_ARG_BYTES/4
121 upcall2:
122     push MAX_ARG_BYTES-4+args_off[esp]
123     loop upcall2
124     mov eax, [BIOS_INFO_PHYSICAL_ADDRESS + BIOSINFO_OFF_bios32_entry]
125     call eax
126     add esp, #MAX_ARG_BYTES
127     mov ecx, eax  ; Result in ecx
128 
129     ; Restore real-mode stack pointer
130     xor eax, eax
131     mov ax, ss_off[esp]
132     mov bx, ax    ; Real-mode ss in bx
133     shl eax, 4
134     sub esp, eax
135 
136     ; Return to real mode
137     jmpf upcall3, #PM_16BIT_CS
138 upcall3:
139     USE16
140     mov ax, #PM_16BIT_DS
141     mov ds, ax
142     mov es, ax
143     mov ss, ax
144     mov eax, cr0
145     and al, #0xfe ; protected mode off
146     mov cr0, eax
147     jmpf upcall4, #REAL_MODE_CODE_OFFSET>>4
148 upcall4:
149     seg cs
150     lgdt realmode_gdtdesc
151 
152     ; Restore real-mode ss
153     mov ss, bx
154 
155     ; Convert result into dx:ax format
156     mov eax, ecx
157     ror eax, #16
158     mov dx, ax
159     ror eax, #16
160 
161     ; Restore caller state and return
162     pop esp
163     pop bx ; skip ss
164     pop es
165     pop ds
166     popf
167     ret
168 
169 MACRO DoUpcall
170     mov bx, #?1
171     jmp Upcall
172 MEND
173 
174 #define X(idx, ret, fn, args...) _ ## fn: DoUpcall(idx)
175 #include "32bitprotos.h"
176 #undef X
177