2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: VDM 32-bit BIOS
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
21 #include "kbdbios32.h"
22 #include "vidbios32.h"
23 #include "moubios32.h"
26 #include "hardware/cmos.h"
27 #include "hardware/pic.h"
28 #include "hardware/timer.h"
30 /* PRIVATE VARIABLES **********************************************************/
32 CALLBACK16 BiosContext
;
34 /* PRIVATE FUNCTIONS **********************************************************/
36 static VOID WINAPI
BiosException(LPWORD Stack
)
38 /* Get the exception number and call the emulator API */
39 BYTE ExceptionNumber
= LOBYTE(Stack
[STACK_INT_NUM
]);
40 EmulatorException(ExceptionNumber
, Stack
);
43 static VOID WINAPI
BiosMiscService(LPWORD Stack
)
51 * Interval in microseconds in CX:DX
52 * See Ralf Brown: http://www.ctyme.com/intr/rb-1525.htm
53 * for more information.
55 Sleep(MAKELONG(getDX(), getCX()));
58 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
63 /* Copy Extended Memory */
66 DWORD Count
= (DWORD
)getCX() * 2;
67 PFAST486_GDT_ENTRY Gdt
= (PFAST486_GDT_ENTRY
)SEG_OFF_TO_PTR(getES(), getSI());
68 DWORD SourceBase
= Gdt
[2].Base
+ (Gdt
[2].BaseMid
<< 16) + (Gdt
[2].BaseHigh
<< 24);
69 DWORD SourceLimit
= Gdt
[2].Limit
+ (Gdt
[2].LimitHigh
<< 16);
70 DWORD DestBase
= Gdt
[3].Base
+ (Gdt
[3].BaseMid
<< 16) + (Gdt
[3].BaseHigh
<< 24);
71 DWORD DestLimit
= Gdt
[3].Limit
+ (Gdt
[3].LimitHigh
<< 16);
74 if (Gdt
[2].Granularity
) SourceLimit
= (SourceLimit
<< 12) | 0xFFF;
75 if (Gdt
[3].Granularity
) DestLimit
= (DestLimit
<< 12) | 0xFFF;
77 if ((Count
> SourceLimit
) || (Count
> DestLimit
))
80 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
86 RtlMoveMemory((PVOID
)((ULONG_PTR
)BaseAddress
+ DestBase
),
87 (PVOID
)((ULONG_PTR
)BaseAddress
+ SourceBase
),
91 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
95 /* Get Extended Memory Size */
101 * Return the (usable) extended memory (after 1 MB)
102 * size in kB from CMOS.
104 IOWriteB(CMOS_ADDRESS_PORT
, CMOS_REG_ACTUAL_EXT_MEMORY_LOW
);
105 Low
= IOReadB(CMOS_DATA_PORT
);
106 IOWriteB(CMOS_ADDRESS_PORT
, CMOS_REG_ACTUAL_EXT_MEMORY_HIGH
);
107 High
= IOReadB(CMOS_DATA_PORT
);
108 setAX(MAKEWORD(Low
, High
));
111 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
116 /* Get Configuration */
119 /* Return the BIOS ROM Configuration Table address in ES:BX */
120 // The BCT is found at F000:E6F5 for 100% compatible BIOSes.
124 /* Call successful; clear CF */
126 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
134 DPRINT1("INT 15h, AH = 0x%02X must be implemented in order to support vendor mouse drivers\n");
140 DPRINT1("BIOS Function INT 15h, AH = 0x%02X NOT IMPLEMENTED\n",
146 static VOID WINAPI
BiosTimeService(LPWORD Stack
)
152 /* Set AL to 1 if midnight had passed, 0 otherwise */
153 setAL(Bda
->MidnightPassed
? 0x01 : 0x00);
155 /* Return the tick count in CX:DX */
156 setCX(HIWORD(Bda
->TickCounter
));
157 setDX(LOWORD(Bda
->TickCounter
));
159 /* Reset the midnight flag */
160 Bda
->MidnightPassed
= FALSE
;
167 /* Set the tick count to CX:DX */
168 Bda
->TickCounter
= MAKELONG(getDX(), getCX());
170 /* Reset the midnight flag */
171 Bda
->MidnightPassed
= FALSE
;
178 DPRINT1("BIOS Function INT 1Ah, AH = 0x%02X NOT IMPLEMENTED\n",
184 static VOID WINAPI
BiosSystemTimerInterrupt(LPWORD Stack
)
186 /* Increase the system tick count */
192 static VOID
PicSetIRQMask(USHORT off
, USHORT on
)
194 UCHAR pic1off
= off
, pic1on
= on
, pic2off
= off
>>8, pic2on
= on
>>8;
195 IOWriteB(PIC_MASTER_DATA
, (IOReadB(PIC_MASTER_DATA
) & ~pic1off
) | pic1on
);
196 IOWriteB(PIC_SLAVE_DATA
, (IOReadB(PIC_SLAVE_DATA
) & ~pic2off
) | pic2on
);
200 VOID
EnableHwIRQ(UCHAR hwirq
, EMULATOR_INT32_PROC func
)
204 PicSetIRQMask(1 << hwirq
, 0);
206 vector
= BIOS_PIC_MASTER_INT
+ hwirq
;
208 vector
= BIOS_PIC_SLAVE_INT
+ hwirq
- 8;
210 RegisterBiosInt32(vector
, func
);
214 VOID
PicIRQComplete(LPWORD Stack
)
216 /* Get the interrupt number */
217 BYTE IntNum
= LOBYTE(Stack
[STACK_INT_NUM
]);
220 * If this was a PIC IRQ, send an End-of-Interrupt to the PIC.
223 if (IntNum
>= BIOS_PIC_MASTER_INT
&& IntNum
< BIOS_PIC_MASTER_INT
+ 8)
225 /* It was an IRQ from the master PIC */
226 IOWriteB(PIC_MASTER_CMD
, PIC_OCW2_EOI
);
228 else if (IntNum
>= BIOS_PIC_SLAVE_INT
&& IntNum
< BIOS_PIC_SLAVE_INT
+ 8)
230 /* It was an IRQ from the slave PIC */
231 IOWriteB(PIC_SLAVE_CMD
, PIC_OCW2_EOI
);
232 IOWriteB(PIC_MASTER_CMD
, PIC_OCW2_EOI
);
236 static VOID WINAPI
BiosHandleMasterPicIRQ(LPWORD Stack
)
240 IOWriteB(PIC_MASTER_CMD
, PIC_OCW3_READ_ISR
/* == 0x0B */);
241 IrqNumber
= IOReadB(PIC_MASTER_CMD
);
243 DPRINT("Master - IrqNumber = 0x%x\n", IrqNumber
);
245 PicIRQComplete(Stack
);
248 static VOID WINAPI
BiosHandleSlavePicIRQ(LPWORD Stack
)
252 IOWriteB(PIC_SLAVE_CMD
, PIC_OCW3_READ_ISR
/* == 0x0B */);
253 IrqNumber
= IOReadB(PIC_SLAVE_CMD
);
255 DPRINT("Slave - IrqNumber = 0x%x\n", IrqNumber
);
257 PicIRQComplete(Stack
);
261 static VOID WINAPI
BiosTimerIrq(LPWORD Stack
)
264 * Perform the system timer interrupt.
266 * Do not call directly BiosSystemTimerInterrupt(Stack);
267 * because some programs may hook only BIOS_SYS_TIMER_INTERRUPT
268 * for their purpose...
270 /** EmulatorInterrupt(BIOS_SYS_TIMER_INTERRUPT); **/
271 Int32Call(&BiosContext
, BIOS_SYS_TIMER_INTERRUPT
);
272 PicIRQComplete(Stack
);
276 static VOID
BiosHwSetup(VOID
)
278 /* Initialize the master and the slave PICs (cascade mode) */
279 IOWriteB(PIC_MASTER_CMD
, PIC_ICW1
| PIC_ICW1_ICW4
);
280 IOWriteB(PIC_SLAVE_CMD
, PIC_ICW1
| PIC_ICW1_ICW4
);
283 * Set the interrupt vector offsets for each PIC
284 * (base IRQs: 0x08-0x0F for IRQ 0-7, 0x70-0x77 for IRQ 8-15)
286 IOWriteB(PIC_MASTER_DATA
, BIOS_PIC_MASTER_INT
);
287 IOWriteB(PIC_SLAVE_DATA
, BIOS_PIC_SLAVE_INT
);
289 /* Tell the master PIC that there is a slave PIC at IRQ 2 */
290 IOWriteB(PIC_MASTER_DATA
, 1 << 2);
291 /* Tell the slave PIC its cascade identity */
292 IOWriteB(PIC_SLAVE_DATA
, 2);
294 /* Make sure both PICs are in 8086 mode */
295 IOWriteB(PIC_MASTER_DATA
, PIC_ICW4_8086
);
296 IOWriteB(PIC_SLAVE_DATA
, PIC_ICW4_8086
);
298 /* Clear the masks for both PICs */
299 // IOWriteB(PIC_MASTER_DATA, 0x00);
300 // IOWriteB(PIC_SLAVE_DATA , 0x00);
301 /* Disable all IRQs */
302 IOWriteB(PIC_MASTER_DATA
, 0xFF);
303 IOWriteB(PIC_SLAVE_DATA
, 0xFF);
306 /* Initialize PIT Counter 0 */
307 IOWriteB(PIT_COMMAND_PORT
, 0x34);
308 IOWriteB(PIT_DATA_PORT(0), 0x00);
309 IOWriteB(PIT_DATA_PORT(0), 0x00);
311 /* Initialize PIT Counter 1 */
312 IOWriteB(PIT_COMMAND_PORT
, 0x74);
313 IOWriteB(PIT_DATA_PORT(1), 0x00);
314 IOWriteB(PIT_DATA_PORT(1), 0x00);
316 /* Initialize PIT Counter 2 */
317 IOWriteB(PIT_COMMAND_PORT
, 0xB4);
318 IOWriteB(PIT_DATA_PORT(2), 0x00);
319 IOWriteB(PIT_DATA_PORT(2), 0x00);
321 EnableHwIRQ(0, BiosTimerIrq
);
324 static VOID
InitializeBiosInt32(VOID
)
328 /* Initialize the callback context */
329 InitializeContext(&BiosContext
, BIOS_SEGMENT
, 0x0000);
331 /* Register the default BIOS 32-bit Interrupts */
332 for (i
= 0x00; i
<= 0xFF; i
++)
334 RegisterBiosInt32(i
, NULL
);
337 /* Initialize the exception vector interrupts to a default Exception handler */
338 for (i
= 0; i
< 8; i
++)
339 RegisterBiosInt32(i
, BiosException
);
341 /* Initialize HW vector interrupts to a default HW handler */
342 for (i
= BIOS_PIC_MASTER_INT
; i
< BIOS_PIC_MASTER_INT
+ 8; i
++)
343 RegisterBiosInt32(i
, BiosHandleMasterPicIRQ
);
344 for (i
= BIOS_PIC_SLAVE_INT
; i
< BIOS_PIC_SLAVE_INT
+ 8; i
++)
345 RegisterBiosInt32(i
, BiosHandleSlavePicIRQ
);
347 /* Initialize software vector handlers */
348 RegisterBiosInt32(BIOS_EQUIPMENT_INTERRUPT
, BiosEquipmentService
);
349 RegisterBiosInt32(BIOS_MEMORY_SIZE
, BiosGetMemorySize
);
350 RegisterBiosInt32(BIOS_MISC_INTERRUPT
, BiosMiscService
);
351 RegisterBiosInt32(BIOS_TIME_INTERRUPT
, BiosTimeService
);
352 RegisterBiosInt32(BIOS_SYS_TIMER_INTERRUPT
, BiosSystemTimerInterrupt
);
354 /* Some interrupts are in fact addresses to tables */
355 ((PULONG
)BaseAddress
)[0x1E] = (ULONG
)NULL
;
356 ((PULONG
)BaseAddress
)[0x41] = (ULONG
)NULL
;
357 ((PULONG
)BaseAddress
)[0x46] = (ULONG
)NULL
;
358 ((PULONG
)BaseAddress
)[0x48] = (ULONG
)NULL
;
359 ((PULONG
)BaseAddress
)[0x49] = (ULONG
)NULL
;
362 static VOID
InitializeBiosInfo(VOID
)
364 Bct
->Length
= sizeof(*Bct
);
365 Bct
->Model
= 0xFC; // PC-AT; see http://www.ctyme.com/intr/rb-1594.htm#Table515
366 Bct
->SubModel
= 0x00;
367 Bct
->BiosRevision
= 0x01;
368 Bct
->BiosFeature
[0] = 0x64; // At the moment we don't support "INT 15/AH=4Fh called upon INT 09h" nor "wait for external event (INT 15/AH=41h) supported"; see http://www.ctyme.com/intr/rb-1594.htm#Table510
369 Bct
->BiosFeature
[1] = 0x00; // We don't support anything from here; see http://www.ctyme.com/intr/rb-1594.htm#Table511
370 Bct
->BiosFeature
[2] = 0x00;
371 Bct
->BiosFeature
[3] = 0x00;
372 Bct
->BiosFeature
[4] = 0x00;
375 static VOID
InitializeBiosData(VOID
)
379 /* Initialize the BDA contents */
380 Bda
->EquipmentList
= BIOS_EQUIPMENT_LIST
;
383 * Retrieve the conventional memory size
384 * in kB from CMOS, typically 640 kB.
386 IOWriteB(CMOS_ADDRESS_PORT
, CMOS_REG_BASE_MEMORY_LOW
);
387 Low
= IOReadB(CMOS_DATA_PORT
);
388 IOWriteB(CMOS_ADDRESS_PORT
, CMOS_REG_BASE_MEMORY_HIGH
);
389 High
= IOReadB(CMOS_DATA_PORT
);
390 Bda
->MemorySize
= MAKEWORD(Low
, High
);
393 /* PUBLIC FUNCTIONS ***********************************************************/
396 * The BIOS POST (Power On-Self Test)
398 BOOLEAN
Bios32Initialize(VOID
)
402 /* Initialize the stack */
403 // That's what says IBM... (stack at 30:00FF going downwards)
406 setSS(0x0050); // Stack at 50:0400, going downwards
409 /* Set data segment */
412 /* Initialize the BDA and the BIOS ROM Information */
413 InitializeBiosData();
414 InitializeBiosInfo();
416 /* Register the BIOS 32-bit Interrupts */
417 InitializeBiosInt32();
419 /* Initialize platform hardware (PIC/PIT chips, ...) */
422 /* Initialize the Keyboard, Video and Mouse BIOS */
423 if (!KbdBios32Initialize() || !VidBios32Initialize() || !MouseBios32Initialize())
426 ///////////// MUST BE DONE AFTER IVT INITIALIZATION !! /////////////////////
429 Success
= LoadRom("boot.bin", (PVOID
)0xE0000, NULL
);
430 DPRINT1("Test ROM loading %s ; GetLastError() = %u\n", Success
? "succeeded" : "failed", GetLastError());
432 SearchAndInitRoms(&BiosContext
);
438 VOID
Bios32Cleanup(VOID
)
440 MouseBios32Cleanup();