-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathbga.asm
316 lines (270 loc) · 8.24 KB
/
bga.asm
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
; bga.asm - Code for handling the Bochs Graphics Adapter
;
; Many virtualization programs including Bochs, VirtualBox and QEMU provide this
; VESA BIOS extension as a convenient way to configure VESA modes.
; Due to the large amount of port I/O and low-level calls, this module is
; implemented in assembly language.
.MODEL MEDIUM
.386
INCLUDE vflatd.inc
;-------------------------------------------------------------------------------
; Imports
;-------------------------------------------------------------------------------
EXTERN _dwFrameBufSize : DWORD
EXTERN _dwVideoMemSize : DWORD
EXTERN _wXResolution : WORD
EXTERN _wYResolution : WORD
EXTERN _wBPP : WORD
EXTERN _wFrameBufSelector : WORD
EXTERN pci_config_read_dword : NEAR
EXTERN pci_config_write_dword : NEAR
EXTERN pci_get_device_config_base : NEAR
;-------------------------------------------------------------------------------
; Defines
;-------------------------------------------------------------------------------
GET_DEVICE_API_ENTRY_POINT EQU 1684h
VFLATD_VXD EQU 11Fh
; Bochs Graphics Adapter ports
VBE_DISPI_IOPORT_INDEX EQU 01CEh
VBE_DISPI_IOPORT_DATA EQU 01CFh
; Bochs Graphics Adapter register indexes
VBE_DISPI_INDEX_ID EQU 0000h
VBE_DISPI_INDEX_XRES EQU 0001h
VBE_DISPI_INDEX_YRES EQU 0002h
VBE_DISPI_INDEX_BPP EQU 0003h
VBE_DISPI_INDEX_ENABLE EQU 0004h
VBE_DISPI_INDEX_BANK EQU 0005h
;-------------------------------------------------------------------------------
; Variables
;-------------------------------------------------------------------------------
PUBLIC _vflatdEntry
PUBLIC _dwFrameBufAddr
_DATA_BSS SEGMENT PUBLIC 'FAR_DATA'
_vflatdEntry DD 0 ; vflatd.vxd entry point
_dwFrameBufAddr DD 0
dwPhysFrameBufAddr DD 0 ; physical address of the linear frame buffer
_DATA_BSS ENDS
ASSUME ds:_DATA_BSS
;-------------------------------------------------------------------------------
; Code (16-bit)
;-------------------------------------------------------------------------------
_INIT SEGMENT WORD PUBLIC USE16 'CODE'
; Detects the Bochs Graphics adapter and the size and location of its VRAM
; Called from the DriverInit on startup
; Returns
; 1 on success, 0 on failure
bga_hardware_detect_ PROC FAR PUBLIC
push esi
cli ; disable interrupts so we don't get preempted while manipulating ports
; check ID of adapter (must be between 0xB0C0 and 0xB0C5)
mov ax, VBE_DISPI_INDEX_ID
call bga_read_reg
cmp ax, 0B0C0h
jb failure
cmp ax, 0B0C5h
ja failure
; probe for PCI device
mov eax, 11111234h
call pci_get_device_config_base
cmp eax, -1
jne found_pci
mov eax, 01001B36h ; QEMU QXL also supports this
call pci_get_device_config_base
cmp eax, -1
je failure
found_pci:
mov al, 10h
mov esi, eax ; save config address of BAR0
; Read the frame buffer address from BAR0
call pci_config_read_dword
push eax ; save original BAR0
and al, 0F0h ; clear lower 4 bits to get the actual address
mov dwPhysFrameBufAddr, eax
; Get the size of the frame buffer by writing all 1s, then reading it back
; to see what is masked
mov eax, esi
xor ebx, ebx
not ebx
call pci_config_write_dword
mov eax, esi
call pci_config_read_dword
and al, 0F0h
not eax
inc eax
mov _dwVideoMemSize, eax
; Restore original BAR0 value
mov eax, esi
pop ebx
call pci_config_write_dword
success:
mov ax, 1
jmp done
failure:
xor ax, ax
done:
sti ; re-enable interrupts
pop esi
retf
bga_hardware_detect_ ENDP
; Enables the Bochs Graphics Adapter hardware
; Returns:
; 1 on success, 0 on failure
bga_phys_enable_ PROC FAR PUBLIC
call bga_phys_reset
test ax, ax
jz done ; failed
call bga_vflatd_init
done:
retf
bga_phys_enable_ ENDP
; Resets the Bochs Graphics Adapter hardware and applies the current resolution
; settings
; Returns:
; 1 on success, 0 on failure
bga_phys_reset PROC NEAR
cli ; disable interrupts so we don't get preempted while manipulating ports
; temporarily disable VBE extensions
mov ax, VBE_DISPI_INDEX_ENABLE
xor bx, bx
call bga_write_reg
; set X resolution
mov ax, VBE_DISPI_INDEX_XRES
mov bx, _wXResolution
call bga_write_reg
; set Y resolution
mov ax, VBE_DISPI_INDEX_YRES
mov bx, _wYResolution
call bga_write_reg
; set bits per pixel
mov ax, VBE_DISPI_INDEX_BPP
mov bx, _wBPP
call bga_write_reg
; re-enable VBE extensions
mov ax, VBE_DISPI_INDEX_ENABLE
mov bx, 1
call bga_write_reg
mov ax, 1
sti ; re-enable interrupts
ret
bga_phys_reset ENDP
; Initializes the VflatD device, which simulates flat memory access to the framebuffer
; Returns:
; 1 on success, 0 on failure
bga_vflatd_init PROC NEAR
push bp
push si
push di
mov eax, _vflatdEntry
test eax, eax
jnz success ; already initialized
; Get VFLATD entry point
mov ax, GET_DEVICE_API_ENTRY_POINT
mov bx, VFLATD_VXD
int 2Fh
mov WORD PTR _vflatdEntry, di
mov WORD PTR _vflatdEntry+2, es
; Call VflatD_Query to register driver
mov dx, VflatD_Query
call DWORD PTR _vflatdEntry
mov eax, dwPhysFrameBufAddr
test eax, eax ; can we use the linear framebuffer
jz no_linear_fb
; Get a selector for the linear framebuffer
; dl = function number
; dh = flags (must be zero)
; eax = physical address of frame buffer
; ecx = size of frame buffer
mov dx, VflatD_Create_Physical_Frame_Buffer
mov ecx, _dwVideoMemSize
call DWORD PTR _vflatdEntry
jc no_linear_fb ; couldn't do it. maybe the virtual framebuffer works instead?
mov _wFrameBufSelector, ax
mov _dwFrameBufAddr, edx
jmp success
no_linear_fb:
; Get a selector for the virtual bank-switched framebuffer
; dl = function number
; dh = flags (must be zero)
; eax = size of frame buffer
; ebx = bank size
; esi = physical address of bank
; es:di = bank switch code
; cx = size of bank switch code
xor edi, edi
lea di, OFFSET BankSwitchRoutine ; di = bank switch code offset
mov ax, _INIT32
mov es, ax ; es = bank switch code segment
mov ecx, BankSwitchRoutineSize
mov eax, _dwFrameBufSize ; eax = frame buffer size
mov ebx, 10000h ; ebx = bank size
mov esi, 0A0000h ; esi = physical memory address of bank
mov dx, VflatD_Create_Virtual_Frame_Buffer
call DWORD PTR _vflatdEntry
jc failure
mov _wFrameBufSelector, ax
mov _dwFrameBufAddr, edx
success:
mov ax, 1
jmp done
failure:
xor ax, ax
done:
pop di
pop si
pop bp
ret
bga_vflatd_init ENDP
; Reads a Bochs Graphics Adapter register
; Parameters:
; ax = register index
; Returns:
; value of register
bga_read_reg PROC NEAR
; select register to read
mov dx, VBE_DISPI_IOPORT_INDEX
out dx, ax
; read value
mov dx, VBE_DISPI_IOPORT_DATA
in ax, dx
ret
bga_read_reg ENDP
; Writes a Bochs Graphics Adapter register
; Parameters:
; ax = register index
; bx = value
bga_write_reg PROC NEAR
; select register to write
mov dx, VBE_DISPI_IOPORT_INDEX
out dx, ax
; write value
mov ax, bx
mov dx, VBE_DISPI_IOPORT_DATA
out dx, ax
ret
bga_write_reg ENDP
_INIT ENDS
;-------------------------------------------------------------------------------
; Code (32-bit)
;-------------------------------------------------------------------------------
_INIT32 SEGMENT PUBLIC USE32 'CODE'
; Framebuffer bank switching routine
; When calling VflatD_Create_Virtual_Frame_Buffer, this routine is copied
; inline and is run in 32-bit ring 0 as a page fault handler by VFLATD. Hence
; there is no "ret" at the end. All registers must be saved except for EAX, EDX,
; and Flags.
; Parameters:
; eax = bank to be swapped in
PUBLIC BankSwitchRoutine
BankSwitchRoutine:
shl eax, 16 ; save bank number
; Select register index
mov dx, 01CEh ; VBE_DISPI_IOPORT_INDEX (0x01CE)
mov ax, 0005h ; VBE_DISPI_INDEX_BANK (0x005)
out dx, ax
; Write bank number
shr eax, 16
inc edx ; VBE_DISPI_IOPORT_DATA (0x01CF)
out dx, ax
BankSwitchRoutineSize = $ - BankSwitchRoutine
_INIT32 ENDS
END