2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
17 #include "hardware/cmos.h"
18 #include "hardware/pic.h"
19 #include "hardware/timer.h"
23 /* PRIVATE VARIABLES **********************************************************/
27 /* PRIVATE FUNCTIONS **********************************************************/
29 static VOID WINAPI
BiosException(LPWORD Stack
)
31 /* Get the exception number and call the emulator API */
32 BYTE ExceptionNumber
= LOBYTE(Stack
[STACK_INT_NUM
]);
33 EmulatorException(ExceptionNumber
, Stack
);
36 static VOID WINAPI
BiosEquipmentService(LPWORD Stack
)
38 /* Return the equipment list */
39 setAX(Bda
->EquipmentList
);
42 static VOID WINAPI
BiosGetMemorySize(LPWORD Stack
)
44 /* Return the conventional memory size in kB, typically 640 kB */
45 setAX(Bda
->MemorySize
);
48 static VOID WINAPI
BiosMiscService(LPWORD Stack
)
52 /* Copy Extended Memory */
55 DWORD Count
= (DWORD
)getCX() * 2;
56 PFAST486_GDT_ENTRY Gdt
= (PFAST486_GDT_ENTRY
)SEG_OFF_TO_PTR(getES(), getSI());
57 DWORD SourceBase
= Gdt
[2].Base
+ (Gdt
[2].BaseMid
<< 16) + (Gdt
[2].BaseHigh
<< 24);
58 DWORD SourceLimit
= Gdt
[2].Limit
+ (Gdt
[2].LimitHigh
<< 16);
59 DWORD DestBase
= Gdt
[3].Base
+ (Gdt
[3].BaseMid
<< 16) + (Gdt
[3].BaseHigh
<< 24);
60 DWORD DestLimit
= Gdt
[3].Limit
+ (Gdt
[3].LimitHigh
<< 16);
63 if (Gdt
[2].Granularity
) SourceLimit
= (SourceLimit
<< 12) | 0xFFF;
64 if (Gdt
[3].Granularity
) DestLimit
= (DestLimit
<< 12) | 0xFFF;
66 if ((Count
> SourceLimit
) || (Count
> DestLimit
))
69 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
75 RtlMoveMemory((PVOID
)((ULONG_PTR
)BaseAddress
+ DestBase
),
76 (PVOID
)((ULONG_PTR
)BaseAddress
+ SourceBase
),
80 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
84 /* Get Extended Memory Size */
90 * Return the (usable) extended memory (after 1 MB)
91 * size in kB from CMOS.
93 IOWriteB(CMOS_ADDRESS_PORT
, CMOS_REG_ACTUAL_EXT_MEMORY_LOW
);
94 Low
= IOReadB(CMOS_DATA_PORT
);
95 IOWriteB(CMOS_ADDRESS_PORT
, CMOS_REG_ACTUAL_EXT_MEMORY_HIGH
);
96 High
= IOReadB(CMOS_DATA_PORT
);
97 setAX(MAKEWORD(Low
, High
));
100 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
107 DPRINT1("BIOS Function INT 15h, AH = 0x%02X NOT IMPLEMENTED\n",
113 static VOID WINAPI
BiosTimeService(LPWORD Stack
)
119 /* Set AL to 1 if midnight had passed, 0 otherwise */
120 setAL(Bda
->MidnightPassed
? 0x01 : 0x00);
122 /* Return the tick count in CX:DX */
123 setCX(HIWORD(Bda
->TickCounter
));
124 setDX(LOWORD(Bda
->TickCounter
));
126 /* Reset the midnight flag */
127 Bda
->MidnightPassed
= FALSE
;
134 /* Set the tick count to CX:DX */
135 Bda
->TickCounter
= MAKELONG(getDX(), getCX());
137 /* Reset the midnight flag */
138 Bda
->MidnightPassed
= FALSE
;
145 DPRINT1("BIOS Function INT 1Ah, AH = 0x%02X NOT IMPLEMENTED\n",
151 static VOID WINAPI
BiosSystemTimerInterrupt(LPWORD Stack
)
153 /* Increase the system tick count */
159 static VOID
PicSetIRQMask(USHORT off
, USHORT on
)
161 UCHAR pic1off
= off
, pic1on
= on
, pic2off
= off
>>8, pic2on
= on
>>8;
162 IOWriteB(PIC_MASTER_DATA
, (IOReadB(PIC_MASTER_DATA
) & ~pic1off
) | pic1on
);
163 IOWriteB(PIC_SLAVE_DATA
, (IOReadB(PIC_SLAVE_DATA
) & ~pic2off
) | pic2on
);
167 VOID
EnableHwIRQ(UCHAR hwirq
, EMULATOR_INT32_PROC func
)
171 PicSetIRQMask(1 << hwirq
, 0);
173 vector
= BIOS_PIC_MASTER_INT
+ hwirq
;
175 vector
= BIOS_PIC_SLAVE_INT
+ hwirq
- 8;
177 RegisterInt32(vector
, func
);
181 VOID
PicIRQComplete(LPWORD Stack
)
183 /* Get the interrupt number */
184 BYTE IntNum
= LOBYTE(Stack
[STACK_INT_NUM
]);
187 * If this was a PIC IRQ, send an End-of-Interrupt to the PIC.
190 if (IntNum
>= BIOS_PIC_MASTER_INT
&& IntNum
< BIOS_PIC_MASTER_INT
+ 8)
192 /* It was an IRQ from the master PIC */
193 IOWriteB(PIC_MASTER_CMD
, PIC_OCW2_EOI
);
195 else if (IntNum
>= BIOS_PIC_SLAVE_INT
&& IntNum
< BIOS_PIC_SLAVE_INT
+ 8)
197 /* It was an IRQ from the slave PIC */
198 IOWriteB(PIC_SLAVE_CMD
, PIC_OCW2_EOI
);
199 IOWriteB(PIC_MASTER_CMD
, PIC_OCW2_EOI
);
203 static VOID WINAPI
BiosHandleMasterPicIRQ(LPWORD Stack
)
207 IOWriteB(PIC_MASTER_CMD
, PIC_OCW3_READ_ISR
/* == 0x0B */);
208 IrqNumber
= IOReadB(PIC_MASTER_CMD
);
210 DPRINT1("Master - IrqNumber = 0x%x\n", IrqNumber
);
212 PicIRQComplete(Stack
);
215 static VOID WINAPI
BiosHandleSlavePicIRQ(LPWORD Stack
)
219 IOWriteB(PIC_SLAVE_CMD
, PIC_OCW3_READ_ISR
/* == 0x0B */);
220 IrqNumber
= IOReadB(PIC_SLAVE_CMD
);
222 DPRINT1("Slave - IrqNumber = 0x%x\n", IrqNumber
);
224 PicIRQComplete(Stack
);
228 static VOID WINAPI
BiosTimerIrq(LPWORD Stack
)
231 * Perform the system timer interrupt.
233 * Do not call directly BiosSystemTimerInterrupt(Stack);
234 * because some programs may hook only BIOS_SYS_TIMER_INTERRUPT
235 * for their purpose...
237 EmulatorInterrupt(BIOS_SYS_TIMER_INTERRUPT
);
238 PicIRQComplete(Stack
);
242 static VOID
BiosHwSetup(VOID
)
244 /* Initialize the master and the slave PICs (cascade mode) */
245 IOWriteB(PIC_MASTER_CMD
, PIC_ICW1
| PIC_ICW1_ICW4
);
246 IOWriteB(PIC_SLAVE_CMD
, PIC_ICW1
| PIC_ICW1_ICW4
);
249 * Set the interrupt vector offsets for each PIC
250 * (base IRQs: 0x08-0x0F for IRQ 0-7, 0x70-0x77 for IRQ 8-15)
252 IOWriteB(PIC_MASTER_DATA
, BIOS_PIC_MASTER_INT
);
253 IOWriteB(PIC_SLAVE_DATA
, BIOS_PIC_SLAVE_INT
);
255 /* Tell the master PIC that there is a slave PIC at IRQ 2 */
256 IOWriteB(PIC_MASTER_DATA
, 1 << 2);
257 /* Tell the slave PIC its cascade identity */
258 IOWriteB(PIC_SLAVE_DATA
, 2);
260 /* Make sure both PICs are in 8086 mode */
261 IOWriteB(PIC_MASTER_DATA
, PIC_ICW4_8086
);
262 IOWriteB(PIC_SLAVE_DATA
, PIC_ICW4_8086
);
264 /* Clear the masks for both PICs */
265 // IOWriteB(PIC_MASTER_DATA, 0x00);
266 // IOWriteB(PIC_SLAVE_DATA , 0x00);
267 /* Disable all IRQs */
268 IOWriteB(PIC_MASTER_DATA
, 0xFF);
269 IOWriteB(PIC_SLAVE_DATA
, 0xFF);
272 /* Initialize the PIT */
273 IOWriteB(PIT_COMMAND_PORT
, 0x34);
274 IOWriteB(PIT_DATA_PORT(0), 0x00);
275 IOWriteB(PIT_DATA_PORT(0), 0x00);
277 EnableHwIRQ(0, BiosTimerIrq
);
280 /* PUBLIC FUNCTIONS ***********************************************************/
283 * The BIOS POST (Power On-Self Test)
285 BOOLEAN
BiosInitialize(HANDLE ConsoleInput
, HANDLE ConsoleOutput
)
290 /* Initialize the BDA */
291 Bda
= (PBIOS_DATA_AREA
)SEG_OFF_TO_PTR(BDA_SEGMENT
, 0);
292 Bda
->EquipmentList
= BIOS_EQUIPMENT_LIST
;
295 * Retrieve the conventional memory size
296 * in kB from CMOS, typically 640 kB.
298 IOWriteB(CMOS_ADDRESS_PORT
, CMOS_REG_BASE_MEMORY_LOW
);
299 Low
= IOReadB(CMOS_DATA_PORT
);
300 IOWriteB(CMOS_ADDRESS_PORT
, CMOS_REG_BASE_MEMORY_HIGH
);
301 High
= IOReadB(CMOS_DATA_PORT
);
302 Bda
->MemorySize
= MAKEWORD(Low
, High
);
304 /* Initialize the 32-bit Interrupt system */
305 InitializeInt32(BIOS_SEGMENT
);
307 /* Register the BIOS 32-bit Interrupts */
309 /* Initialize the exception vector interrupts to a default Exception handler */
310 for (i
= 0; i
< 8; i
++)
311 RegisterInt32(i
, BiosException
);
313 /* Initialize HW vector interrupts to a default HW handler */
314 for (i
= BIOS_PIC_MASTER_INT
; i
< BIOS_PIC_MASTER_INT
+ 8; i
++)
315 RegisterInt32(i
, BiosHandleMasterPicIRQ
);
316 for (i
= BIOS_PIC_SLAVE_INT
; i
< BIOS_PIC_SLAVE_INT
+ 8; i
++)
317 RegisterInt32(i
, BiosHandleSlavePicIRQ
);
319 /* Initialize software vector handlers */
320 RegisterInt32(BIOS_EQUIPMENT_INTERRUPT
, BiosEquipmentService
);
321 RegisterInt32(BIOS_MEMORY_SIZE
, BiosGetMemorySize
);
322 RegisterInt32(BIOS_MISC_INTERRUPT
, BiosMiscService
);
323 RegisterInt32(BIOS_TIME_INTERRUPT
, BiosTimeService
);
324 RegisterInt32(BIOS_SYS_TIMER_INTERRUPT
, BiosSystemTimerInterrupt
);
326 /* Some interrupts are in fact addresses to tables */
327 ((PDWORD
)BaseAddress
)[0x1E] = (DWORD
)NULL
;
328 ((PDWORD
)BaseAddress
)[0x41] = (DWORD
)NULL
;
329 ((PDWORD
)BaseAddress
)[0x46] = (DWORD
)NULL
;
330 ((PDWORD
)BaseAddress
)[0x48] = (DWORD
)NULL
;
331 ((PDWORD
)BaseAddress
)[0x49] = (DWORD
)NULL
;
333 /* Initialize platform hardware (PIC/PIT chips, ...) */
336 /* Initialize the Keyboard BIOS */
337 if (!KbdBiosInitialize(ConsoleInput
)) return FALSE
;
339 /* Set the console input mode */
340 SetConsoleMode(ConsoleInput
, ENABLE_MOUSE_INPUT
| ENABLE_PROCESSED_INPUT
);
342 /* Initialize the Video BIOS */
343 if (!VidBiosInitialize(ConsoleOutput
)) return FALSE
;
348 VOID
BiosCleanup(VOID
)