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 *******************************************************************/
19 #include "hardware/cmos.h"
20 #include "hardware/pic.h"
21 #include "hardware/timer.h"
23 /* PRIVATE VARIABLES **********************************************************/
25 CALLBACK16 BiosContext
;
28 /* PRIVATE FUNCTIONS **********************************************************/
30 static VOID WINAPI
BiosException(LPWORD Stack
)
32 /* Get the exception number and call the emulator API */
33 BYTE ExceptionNumber
= LOBYTE(Stack
[STACK_INT_NUM
]);
34 EmulatorException(ExceptionNumber
, Stack
);
37 static VOID WINAPI
BiosEquipmentService(LPWORD Stack
)
39 /* Return the equipment list */
40 setAX(Bda
->EquipmentList
);
43 static VOID WINAPI
BiosGetMemorySize(LPWORD Stack
)
45 /* Return the conventional memory size in kB, typically 640 kB */
46 setAX(Bda
->MemorySize
);
49 static VOID WINAPI
BiosMiscService(LPWORD Stack
)
57 * Interval in microseconds in CX:DX
58 * See Ralf Brown: http://www.ctyme.com/intr/rb-1525.htm
59 * for more information.
61 Sleep(MAKELONG(getDX(), getCX()));
64 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
69 /* Copy Extended Memory */
72 DWORD Count
= (DWORD
)getCX() * 2;
73 PFAST486_GDT_ENTRY Gdt
= (PFAST486_GDT_ENTRY
)SEG_OFF_TO_PTR(getES(), getSI());
74 DWORD SourceBase
= Gdt
[2].Base
+ (Gdt
[2].BaseMid
<< 16) + (Gdt
[2].BaseHigh
<< 24);
75 DWORD SourceLimit
= Gdt
[2].Limit
+ (Gdt
[2].LimitHigh
<< 16);
76 DWORD DestBase
= Gdt
[3].Base
+ (Gdt
[3].BaseMid
<< 16) + (Gdt
[3].BaseHigh
<< 24);
77 DWORD DestLimit
= Gdt
[3].Limit
+ (Gdt
[3].LimitHigh
<< 16);
80 if (Gdt
[2].Granularity
) SourceLimit
= (SourceLimit
<< 12) | 0xFFF;
81 if (Gdt
[3].Granularity
) DestLimit
= (DestLimit
<< 12) | 0xFFF;
83 if ((Count
> SourceLimit
) || (Count
> DestLimit
))
86 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
92 RtlMoveMemory((PVOID
)((ULONG_PTR
)BaseAddress
+ DestBase
),
93 (PVOID
)((ULONG_PTR
)BaseAddress
+ SourceBase
),
97 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
101 /* Get Extended Memory Size */
107 * Return the (usable) extended memory (after 1 MB)
108 * size in kB from CMOS.
110 IOWriteB(CMOS_ADDRESS_PORT
, CMOS_REG_ACTUAL_EXT_MEMORY_LOW
);
111 Low
= IOReadB(CMOS_DATA_PORT
);
112 IOWriteB(CMOS_ADDRESS_PORT
, CMOS_REG_ACTUAL_EXT_MEMORY_HIGH
);
113 High
= IOReadB(CMOS_DATA_PORT
);
114 setAX(MAKEWORD(Low
, High
));
117 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
124 DPRINT1("BIOS Function INT 15h, AH = 0x%02X NOT IMPLEMENTED\n",
130 static VOID WINAPI
BiosTimeService(LPWORD Stack
)
136 /* Set AL to 1 if midnight had passed, 0 otherwise */
137 setAL(Bda
->MidnightPassed
? 0x01 : 0x00);
139 /* Return the tick count in CX:DX */
140 setCX(HIWORD(Bda
->TickCounter
));
141 setDX(LOWORD(Bda
->TickCounter
));
143 /* Reset the midnight flag */
144 Bda
->MidnightPassed
= FALSE
;
151 /* Set the tick count to CX:DX */
152 Bda
->TickCounter
= MAKELONG(getDX(), getCX());
154 /* Reset the midnight flag */
155 Bda
->MidnightPassed
= FALSE
;
162 DPRINT1("BIOS Function INT 1Ah, AH = 0x%02X NOT IMPLEMENTED\n",
168 static VOID WINAPI
BiosSystemTimerInterrupt(LPWORD Stack
)
170 /* Increase the system tick count */
176 static VOID
PicSetIRQMask(USHORT off
, USHORT on
)
178 UCHAR pic1off
= off
, pic1on
= on
, pic2off
= off
>>8, pic2on
= on
>>8;
179 IOWriteB(PIC_MASTER_DATA
, (IOReadB(PIC_MASTER_DATA
) & ~pic1off
) | pic1on
);
180 IOWriteB(PIC_SLAVE_DATA
, (IOReadB(PIC_SLAVE_DATA
) & ~pic2off
) | pic2on
);
184 VOID
EnableHwIRQ(UCHAR hwirq
, EMULATOR_INT32_PROC func
)
188 PicSetIRQMask(1 << hwirq
, 0);
190 vector
= BIOS_PIC_MASTER_INT
+ hwirq
;
192 vector
= BIOS_PIC_SLAVE_INT
+ hwirq
- 8;
194 RegisterBiosInt32(vector
, func
);
198 VOID
PicIRQComplete(LPWORD Stack
)
200 /* Get the interrupt number */
201 BYTE IntNum
= LOBYTE(Stack
[STACK_INT_NUM
]);
204 * If this was a PIC IRQ, send an End-of-Interrupt to the PIC.
207 if (IntNum
>= BIOS_PIC_MASTER_INT
&& IntNum
< BIOS_PIC_MASTER_INT
+ 8)
209 /* It was an IRQ from the master PIC */
210 IOWriteB(PIC_MASTER_CMD
, PIC_OCW2_EOI
);
212 else if (IntNum
>= BIOS_PIC_SLAVE_INT
&& IntNum
< BIOS_PIC_SLAVE_INT
+ 8)
214 /* It was an IRQ from the slave PIC */
215 IOWriteB(PIC_SLAVE_CMD
, PIC_OCW2_EOI
);
216 IOWriteB(PIC_MASTER_CMD
, PIC_OCW2_EOI
);
220 static VOID WINAPI
BiosHandleMasterPicIRQ(LPWORD Stack
)
224 IOWriteB(PIC_MASTER_CMD
, PIC_OCW3_READ_ISR
/* == 0x0B */);
225 IrqNumber
= IOReadB(PIC_MASTER_CMD
);
227 DPRINT("Master - IrqNumber = 0x%x\n", IrqNumber
);
229 PicIRQComplete(Stack
);
232 static VOID WINAPI
BiosHandleSlavePicIRQ(LPWORD Stack
)
236 IOWriteB(PIC_SLAVE_CMD
, PIC_OCW3_READ_ISR
/* == 0x0B */);
237 IrqNumber
= IOReadB(PIC_SLAVE_CMD
);
239 DPRINT("Slave - IrqNumber = 0x%x\n", IrqNumber
);
241 PicIRQComplete(Stack
);
245 static VOID WINAPI
BiosTimerIrq(LPWORD Stack
)
248 * Perform the system timer interrupt.
250 * Do not call directly BiosSystemTimerInterrupt(Stack);
251 * because some programs may hook only BIOS_SYS_TIMER_INTERRUPT
252 * for their purpose...
254 /** EmulatorInterrupt(BIOS_SYS_TIMER_INTERRUPT); **/
255 Int32Call(&BiosContext
, BIOS_SYS_TIMER_INTERRUPT
);
256 PicIRQComplete(Stack
);
260 static VOID
BiosHwSetup(VOID
)
262 /* Initialize the master and the slave PICs (cascade mode) */
263 IOWriteB(PIC_MASTER_CMD
, PIC_ICW1
| PIC_ICW1_ICW4
);
264 IOWriteB(PIC_SLAVE_CMD
, PIC_ICW1
| PIC_ICW1_ICW4
);
267 * Set the interrupt vector offsets for each PIC
268 * (base IRQs: 0x08-0x0F for IRQ 0-7, 0x70-0x77 for IRQ 8-15)
270 IOWriteB(PIC_MASTER_DATA
, BIOS_PIC_MASTER_INT
);
271 IOWriteB(PIC_SLAVE_DATA
, BIOS_PIC_SLAVE_INT
);
273 /* Tell the master PIC that there is a slave PIC at IRQ 2 */
274 IOWriteB(PIC_MASTER_DATA
, 1 << 2);
275 /* Tell the slave PIC its cascade identity */
276 IOWriteB(PIC_SLAVE_DATA
, 2);
278 /* Make sure both PICs are in 8086 mode */
279 IOWriteB(PIC_MASTER_DATA
, PIC_ICW4_8086
);
280 IOWriteB(PIC_SLAVE_DATA
, PIC_ICW4_8086
);
282 /* Clear the masks for both PICs */
283 // IOWriteB(PIC_MASTER_DATA, 0x00);
284 // IOWriteB(PIC_SLAVE_DATA , 0x00);
285 /* Disable all IRQs */
286 IOWriteB(PIC_MASTER_DATA
, 0xFF);
287 IOWriteB(PIC_SLAVE_DATA
, 0xFF);
290 /* Initialize PIT Counter 0 */
291 IOWriteB(PIT_COMMAND_PORT
, 0x34);
292 IOWriteB(PIT_DATA_PORT(0), 0x00);
293 IOWriteB(PIT_DATA_PORT(0), 0x00);
295 /* Initialize PIT Counter 1 */
296 IOWriteB(PIT_COMMAND_PORT
, 0x74);
297 IOWriteB(PIT_DATA_PORT(1), 0x00);
298 IOWriteB(PIT_DATA_PORT(1), 0x00);
300 /* Initialize PIT Counter 2 */
301 IOWriteB(PIT_COMMAND_PORT
, 0xB4);
302 IOWriteB(PIT_DATA_PORT(2), 0x00);
303 IOWriteB(PIT_DATA_PORT(2), 0x00);
305 EnableHwIRQ(0, BiosTimerIrq
);
308 static VOID
InitializeBiosInt32(VOID
)
311 // USHORT Offset = 0;
313 /* Initialize the callback context */
314 InitializeContext(&BiosContext
, BIOS_SEGMENT
, 0x0000);
316 /* Register the BIOS 32-bit Interrupts */
317 for (i
= 0x00; i
<= 0xFF; i
++)
319 // Offset += RegisterInt32(MAKELONG(Offset, BIOS_SEGMENT), i, NULL, NULL);
320 BiosContext
.NextOffset
+= RegisterInt32(MAKELONG(BiosContext
.NextOffset
,
321 BiosContext
.Segment
),
325 /* Initialize the exception vector interrupts to a default Exception handler */
326 for (i
= 0; i
< 8; i
++)
327 RegisterBiosInt32(i
, BiosException
);
329 /* Initialize HW vector interrupts to a default HW handler */
330 for (i
= BIOS_PIC_MASTER_INT
; i
< BIOS_PIC_MASTER_INT
+ 8; i
++)
331 RegisterBiosInt32(i
, BiosHandleMasterPicIRQ
);
332 for (i
= BIOS_PIC_SLAVE_INT
; i
< BIOS_PIC_SLAVE_INT
+ 8; i
++)
333 RegisterBiosInt32(i
, BiosHandleSlavePicIRQ
);
335 /* Initialize software vector handlers */
336 RegisterBiosInt32(BIOS_EQUIPMENT_INTERRUPT
, BiosEquipmentService
);
337 RegisterBiosInt32(BIOS_MEMORY_SIZE
, BiosGetMemorySize
);
338 RegisterBiosInt32(BIOS_MISC_INTERRUPT
, BiosMiscService
);
339 RegisterBiosInt32(BIOS_TIME_INTERRUPT
, BiosTimeService
);
340 RegisterBiosInt32(BIOS_SYS_TIMER_INTERRUPT
, BiosSystemTimerInterrupt
);
342 /* Some interrupts are in fact addresses to tables */
343 ((PULONG
)BaseAddress
)[0x1E] = (ULONG
)NULL
;
344 ((PULONG
)BaseAddress
)[0x41] = (ULONG
)NULL
;
345 ((PULONG
)BaseAddress
)[0x46] = (ULONG
)NULL
;
346 ((PULONG
)BaseAddress
)[0x48] = (ULONG
)NULL
;
347 ((PULONG
)BaseAddress
)[0x49] = (ULONG
)NULL
;
350 /* PUBLIC FUNCTIONS ***********************************************************/
353 * The BIOS POST (Power On-Self Test)
355 BOOLEAN
Bios32Initialize(IN HANDLE ConsoleInput
,
356 IN HANDLE ConsoleOutput
)
360 /* Initialize the BDA */
361 Bda
= (PBIOS_DATA_AREA
)SEG_OFF_TO_PTR(BDA_SEGMENT
, 0);
362 Bda
->EquipmentList
= BIOS_EQUIPMENT_LIST
;
365 * Retrieve the conventional memory size
366 * in kB from CMOS, typically 640 kB.
368 IOWriteB(CMOS_ADDRESS_PORT
, CMOS_REG_BASE_MEMORY_LOW
);
369 Low
= IOReadB(CMOS_DATA_PORT
);
370 IOWriteB(CMOS_ADDRESS_PORT
, CMOS_REG_BASE_MEMORY_HIGH
);
371 High
= IOReadB(CMOS_DATA_PORT
);
372 Bda
->MemorySize
= MAKEWORD(Low
, High
);
374 /* Register the BIOS 32-bit Interrupts */
375 InitializeBiosInt32();
377 /* Initialize platform hardware (PIC/PIT chips, ...) */
380 /* Initialize the Keyboard BIOS */
381 if (!KbdBios32Initialize(ConsoleInput
)) return FALSE
;
383 /* Set the console input mode */
384 SetConsoleMode(ConsoleInput
, ENABLE_MOUSE_INPUT
| ENABLE_PROCESSED_INPUT
);
386 /* Initialize the Video BIOS */
387 if (!VidBios32Initialize(ConsoleOutput
)) return FALSE
;
389 /* Enable interrupts */
396 VOID
Bios32Cleanup(VOID
)