aboutsummaryrefslogtreecommitdiffstats
path: root/tools/firmware/rombios/32bitgateway.c
blob: fc82e077252e3d8d9e284e91a93bd55d62c9f962 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/*
 *  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
 * Copyright (c) 2008, Citrix Systems, Inc.
 *
 * Author: Stefan Berger <stefanb@us.ibm.com>
 * Author: Keir Fraser <keir@xen.org>
 */

/*
 * 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.
 */

/* At most 32 bytes in argument list to a 32-bit function. */
#define MAX_ARG_BYTES 32

#define REAL_MODE_CODE_OFFSET  0xf0000

/* 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)

    .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, 0x8f, 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, 0x8f, 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
    ;
    ; 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

    ; Calculate protected-mode esp from ss:sp
    and esp, #0xffff
    xor eax, eax
    mov ax, ss
    shl eax, #4
    add esp, eax

    ; Switch to protected mode
    seg cs
    lgdt protmode_gdtdesc
    mov eax, cr0
    or al, #0x1  ; protected mode on
    mov cr0, eax
    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

    ; Marshal arguments and call 32-bit function
    mov ecx, #MAX_ARG_BYTES/4
upcall2:
    push MAX_ARG_BYTES-4+args_off[esp]
    loop upcall2
    mov eax, [BIOS_INFO_PHYSICAL_ADDRESS + BIOSINFO_OFF_bios32_entry]
    call eax
    add esp, #MAX_ARG_BYTES
    mov ecx, eax  ; Result in ecx

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

    ; 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
    mov cr0, eax
    jmpf upcall4, #REAL_MODE_CODE_OFFSET>>4
upcall4:
    seg cs
    lgdt realmode_gdtdesc

    ; Restore real-mode ss
    mov ss, bx

    ; 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

MACRO DoUpcall
    mov bx, #?1
    jmp Upcall
MEND

#define X(idx, ret, fn, args...) _ ## fn: DoUpcall(idx)
#include "32bitprotos.h"
#undef X