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"
25 #include "hardware/cmos.h"
26 #include "hardware/pic.h"
27 #include "hardware/timer.h"
29 /* PRIVATE VARIABLES **********************************************************/
31 CALLBACK16 BiosContext
;
33 /* PRIVATE FUNCTIONS **********************************************************/
35 static VOID WINAPI
BiosException(LPWORD Stack
)
37 /* Get the exception number and call the emulator API */
38 BYTE ExceptionNumber
= LOBYTE(Stack
[STACK_INT_NUM
]);
39 EmulatorException(ExceptionNumber
, Stack
);
42 static VOID WINAPI
BiosMiscService(LPWORD Stack
)
50 * Interval in microseconds in CX:DX
51 * See Ralf Brown: http://www.ctyme.com/intr/rb-1525.htm
52 * for more information.
54 Sleep(MAKELONG(getDX(), getCX()));
57 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
62 /* Copy Extended Memory */
65 DWORD Count
= (DWORD
)getCX() * 2;
66 PFAST486_GDT_ENTRY Gdt
= (PFAST486_GDT_ENTRY
)SEG_OFF_TO_PTR(getES(), getSI());
67 DWORD SourceBase
= Gdt
[2].Base
+ (Gdt
[2].BaseMid
<< 16) + (Gdt
[2].BaseHigh
<< 24);
68 DWORD SourceLimit
= Gdt
[2].Limit
+ (Gdt
[2].LimitHigh
<< 16);
69 DWORD DestBase
= Gdt
[3].Base
+ (Gdt
[3].BaseMid
<< 16) + (Gdt
[3].BaseHigh
<< 24);
70 DWORD DestLimit
= Gdt
[3].Limit
+ (Gdt
[3].LimitHigh
<< 16);
73 if (Gdt
[2].Granularity
) SourceLimit
= (SourceLimit
<< 12) | 0xFFF;
74 if (Gdt
[3].Granularity
) DestLimit
= (DestLimit
<< 12) | 0xFFF;
76 if ((Count
> SourceLimit
) || (Count
> DestLimit
))
79 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
85 RtlMoveMemory((PVOID
)((ULONG_PTR
)BaseAddress
+ DestBase
),
86 (PVOID
)((ULONG_PTR
)BaseAddress
+ SourceBase
),
90 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
94 /* Get Extended Memory Size */
100 * Return the (usable) extended memory (after 1 MB)
101 * size in kB from CMOS.
103 IOWriteB(CMOS_ADDRESS_PORT
, CMOS_REG_ACTUAL_EXT_MEMORY_LOW
);
104 Low
= IOReadB(CMOS_DATA_PORT
);
105 IOWriteB(CMOS_ADDRESS_PORT
, CMOS_REG_ACTUAL_EXT_MEMORY_HIGH
);
106 High
= IOReadB(CMOS_DATA_PORT
);
107 setAX(MAKEWORD(Low
, High
));
110 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
115 /* Get Configuration */
118 /* Return the BIOS ROM Configuration Table address in ES:BX */
119 // The BCT is found at F000:E6F5 for 100% compatible BIOSes.
123 /* Call successful; clear CF */
125 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
132 DPRINT1("BIOS Function INT 15h, AH = 0x%02X NOT IMPLEMENTED\n",
138 static VOID WINAPI
BiosTimeService(LPWORD Stack
)
144 /* Set AL to 1 if midnight had passed, 0 otherwise */
145 setAL(Bda
->MidnightPassed
? 0x01 : 0x00);
147 /* Return the tick count in CX:DX */
148 setCX(HIWORD(Bda
->TickCounter
));
149 setDX(LOWORD(Bda
->TickCounter
));
151 /* Reset the midnight flag */
152 Bda
->MidnightPassed
= FALSE
;
159 /* Set the tick count to CX:DX */
160 Bda
->TickCounter
= MAKELONG(getDX(), getCX());
162 /* Reset the midnight flag */
163 Bda
->MidnightPassed
= FALSE
;
170 DPRINT1("BIOS Function INT 1Ah, AH = 0x%02X NOT IMPLEMENTED\n",
176 static VOID WINAPI
BiosSystemTimerInterrupt(LPWORD Stack
)
178 /* Increase the system tick count */
184 static VOID
PicSetIRQMask(USHORT off
, USHORT on
)
186 UCHAR pic1off
= off
, pic1on
= on
, pic2off
= off
>>8, pic2on
= on
>>8;
187 IOWriteB(PIC_MASTER_DATA
, (IOReadB(PIC_MASTER_DATA
) & ~pic1off
) | pic1on
);
188 IOWriteB(PIC_SLAVE_DATA
, (IOReadB(PIC_SLAVE_DATA
) & ~pic2off
) | pic2on
);
192 VOID
EnableHwIRQ(UCHAR hwirq
, EMULATOR_INT32_PROC func
)
196 PicSetIRQMask(1 << hwirq
, 0);
198 vector
= BIOS_PIC_MASTER_INT
+ hwirq
;
200 vector
= BIOS_PIC_SLAVE_INT
+ hwirq
- 8;
202 RegisterBiosInt32(vector
, func
);
206 VOID
PicIRQComplete(LPWORD Stack
)
208 /* Get the interrupt number */
209 BYTE IntNum
= LOBYTE(Stack
[STACK_INT_NUM
]);
212 * If this was a PIC IRQ, send an End-of-Interrupt to the PIC.
215 if (IntNum
>= BIOS_PIC_MASTER_INT
&& IntNum
< BIOS_PIC_MASTER_INT
+ 8)
217 /* It was an IRQ from the master PIC */
218 IOWriteB(PIC_MASTER_CMD
, PIC_OCW2_EOI
);
220 else if (IntNum
>= BIOS_PIC_SLAVE_INT
&& IntNum
< BIOS_PIC_SLAVE_INT
+ 8)
222 /* It was an IRQ from the slave PIC */
223 IOWriteB(PIC_SLAVE_CMD
, PIC_OCW2_EOI
);
224 IOWriteB(PIC_MASTER_CMD
, PIC_OCW2_EOI
);
228 static VOID WINAPI
BiosHandleMasterPicIRQ(LPWORD Stack
)
232 IOWriteB(PIC_MASTER_CMD
, PIC_OCW3_READ_ISR
/* == 0x0B */);
233 IrqNumber
= IOReadB(PIC_MASTER_CMD
);
235 DPRINT("Master - IrqNumber = 0x%x\n", IrqNumber
);
237 PicIRQComplete(Stack
);
240 static VOID WINAPI
BiosHandleSlavePicIRQ(LPWORD Stack
)
244 IOWriteB(PIC_SLAVE_CMD
, PIC_OCW3_READ_ISR
/* == 0x0B */);
245 IrqNumber
= IOReadB(PIC_SLAVE_CMD
);
247 DPRINT("Slave - IrqNumber = 0x%x\n", IrqNumber
);
249 PicIRQComplete(Stack
);
253 static VOID WINAPI
BiosTimerIrq(LPWORD Stack
)
256 * Perform the system timer interrupt.
258 * Do not call directly BiosSystemTimerInterrupt(Stack);
259 * because some programs may hook only BIOS_SYS_TIMER_INTERRUPT
260 * for their purpose...
262 /** EmulatorInterrupt(BIOS_SYS_TIMER_INTERRUPT); **/
263 Int32Call(&BiosContext
, BIOS_SYS_TIMER_INTERRUPT
);
264 PicIRQComplete(Stack
);
268 static VOID
BiosHwSetup(VOID
)
270 /* Initialize the master and the slave PICs (cascade mode) */
271 IOWriteB(PIC_MASTER_CMD
, PIC_ICW1
| PIC_ICW1_ICW4
);
272 IOWriteB(PIC_SLAVE_CMD
, PIC_ICW1
| PIC_ICW1_ICW4
);
275 * Set the interrupt vector offsets for each PIC
276 * (base IRQs: 0x08-0x0F for IRQ 0-7, 0x70-0x77 for IRQ 8-15)
278 IOWriteB(PIC_MASTER_DATA
, BIOS_PIC_MASTER_INT
);
279 IOWriteB(PIC_SLAVE_DATA
, BIOS_PIC_SLAVE_INT
);
281 /* Tell the master PIC that there is a slave PIC at IRQ 2 */
282 IOWriteB(PIC_MASTER_DATA
, 1 << 2);
283 /* Tell the slave PIC its cascade identity */
284 IOWriteB(PIC_SLAVE_DATA
, 2);
286 /* Make sure both PICs are in 8086 mode */
287 IOWriteB(PIC_MASTER_DATA
, PIC_ICW4_8086
);
288 IOWriteB(PIC_SLAVE_DATA
, PIC_ICW4_8086
);
290 /* Clear the masks for both PICs */
291 // IOWriteB(PIC_MASTER_DATA, 0x00);
292 // IOWriteB(PIC_SLAVE_DATA , 0x00);
293 /* Disable all IRQs */
294 IOWriteB(PIC_MASTER_DATA
, 0xFF);
295 IOWriteB(PIC_SLAVE_DATA
, 0xFF);
298 /* Initialize PIT Counter 0 */
299 IOWriteB(PIT_COMMAND_PORT
, 0x34);
300 IOWriteB(PIT_DATA_PORT(0), 0x00);
301 IOWriteB(PIT_DATA_PORT(0), 0x00);
303 /* Initialize PIT Counter 1 */
304 IOWriteB(PIT_COMMAND_PORT
, 0x74);
305 IOWriteB(PIT_DATA_PORT(1), 0x00);
306 IOWriteB(PIT_DATA_PORT(1), 0x00);
308 /* Initialize PIT Counter 2 */
309 IOWriteB(PIT_COMMAND_PORT
, 0xB4);
310 IOWriteB(PIT_DATA_PORT(2), 0x00);
311 IOWriteB(PIT_DATA_PORT(2), 0x00);
313 EnableHwIRQ(0, BiosTimerIrq
);
316 static VOID
InitializeBiosInt32(VOID
)
320 /* Initialize the callback context */
321 InitializeContext(&BiosContext
, BIOS_SEGMENT
, 0x0000);
323 /* Register the default BIOS 32-bit Interrupts */
324 for (i
= 0x00; i
<= 0xFF; i
++)
326 RegisterBiosInt32(i
, NULL
);
329 /* Initialize the exception vector interrupts to a default Exception handler */
330 for (i
= 0; i
< 8; i
++)
331 RegisterBiosInt32(i
, BiosException
);
333 /* Initialize HW vector interrupts to a default HW handler */
334 for (i
= BIOS_PIC_MASTER_INT
; i
< BIOS_PIC_MASTER_INT
+ 8; i
++)
335 RegisterBiosInt32(i
, BiosHandleMasterPicIRQ
);
336 for (i
= BIOS_PIC_SLAVE_INT
; i
< BIOS_PIC_SLAVE_INT
+ 8; i
++)
337 RegisterBiosInt32(i
, BiosHandleSlavePicIRQ
);
339 /* Initialize software vector handlers */
340 RegisterBiosInt32(BIOS_EQUIPMENT_INTERRUPT
, BiosEquipmentService
);
341 RegisterBiosInt32(BIOS_MEMORY_SIZE
, BiosGetMemorySize
);
342 RegisterBiosInt32(BIOS_MISC_INTERRUPT
, BiosMiscService
);
343 RegisterBiosInt32(BIOS_TIME_INTERRUPT
, BiosTimeService
);
344 RegisterBiosInt32(BIOS_SYS_TIMER_INTERRUPT
, BiosSystemTimerInterrupt
);
346 /* Some interrupts are in fact addresses to tables */
347 ((PULONG
)BaseAddress
)[0x1E] = (ULONG
)NULL
;
348 ((PULONG
)BaseAddress
)[0x41] = (ULONG
)NULL
;
349 ((PULONG
)BaseAddress
)[0x46] = (ULONG
)NULL
;
350 ((PULONG
)BaseAddress
)[0x48] = (ULONG
)NULL
;
351 ((PULONG
)BaseAddress
)[0x49] = (ULONG
)NULL
;
354 static VOID
InitializeBiosInfo(VOID
)
356 Bct
->Length
= sizeof(*Bct
);
357 Bct
->Model
= 0xFC; // PC-AT; see http://www.ctyme.com/intr/rb-1594.htm#Table515
358 Bct
->SubModel
= 0x00;
359 Bct
->BiosRevision
= 0x01;
360 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
361 Bct
->BiosFeature
[1] = 0x00; // We don't support anything from here; see http://www.ctyme.com/intr/rb-1594.htm#Table511
362 Bct
->BiosFeature
[2] = 0x00;
363 Bct
->BiosFeature
[3] = 0x00;
364 Bct
->BiosFeature
[4] = 0x00;
367 static VOID
InitializeBiosData(VOID
)
371 /* Initialize the BDA contents */
372 Bda
->EquipmentList
= BIOS_EQUIPMENT_LIST
;
375 * Retrieve the conventional memory size
376 * in kB from CMOS, typically 640 kB.
378 IOWriteB(CMOS_ADDRESS_PORT
, CMOS_REG_BASE_MEMORY_LOW
);
379 Low
= IOReadB(CMOS_DATA_PORT
);
380 IOWriteB(CMOS_ADDRESS_PORT
, CMOS_REG_BASE_MEMORY_HIGH
);
381 High
= IOReadB(CMOS_DATA_PORT
);
382 Bda
->MemorySize
= MAKEWORD(Low
, High
);
385 /* PUBLIC FUNCTIONS ***********************************************************/
388 * The BIOS POST (Power On-Self Test)
390 BOOLEAN
Bios32Initialize(VOID
)
394 /* Initialize the stack */
395 // That's what says IBM... (stack at 30:00FF going downwards)
398 setSS(0x0050); // Stack at 50:0400, going downwards
401 /* Set data segment */
404 /* Initialize the BDA and the BIOS ROM Information */
405 InitializeBiosData();
406 InitializeBiosInfo();
408 /* Register the BIOS 32-bit Interrupts */
409 InitializeBiosInt32();
411 /* Initialize platform hardware (PIC/PIT chips, ...) */
414 /* Initialize the Keyboard and Video BIOS */
415 if (!KbdBios32Initialize() || !VidBios32Initialize()) return FALSE
;
417 ///////////// MUST BE DONE AFTER IVT INITIALIZATION !! /////////////////////
420 Success
= LoadRom("boot.bin", (PVOID
)0xE0000, NULL
);
421 DPRINT1("Test ROM loading %s ; GetLastError() = %u\n", Success
? "succeeded" : "failed", GetLastError());
423 SearchAndInitRoms(&BiosContext
);
429 VOID
Bios32Cleanup(VOID
)