2dad12699c0373b0d03d201dfe233d1b6d365194
[reactos.git] / subsystems / ntvdm / bios.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: bios.c
5 * PURPOSE: VDM BIOS
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 #include "ntvdm.h"
10
11 BYTE CursorRow, CursorCol;
12 WORD ConsoleWidth, ConsoleHeight;
13
14 BOOLEAN BiosInitialize()
15 {
16 INT i;
17 WORD Offset = 0;
18 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
19 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
20 LPWORD IntVecTable = (LPWORD)((ULONG_PTR)BaseAddress);
21 LPBYTE BiosCode = (LPBYTE)((ULONG_PTR)BaseAddress + TO_LINEAR(BIOS_SEGMENT, 0));
22
23 /* Generate ISR stubs and fill the IVT */
24 for (i = 0; i < 256; i++)
25 {
26 IntVecTable[i * 2] = Offset;
27 IntVecTable[i * 2 + 1] = BIOS_SEGMENT;
28
29 if (i != SPECIAL_INT_NUM)
30 {
31 BiosCode[Offset++] = 0xFA; // cli
32
33 BiosCode[Offset++] = 0x6A; // push i
34 BiosCode[Offset++] = (BYTE)i;
35
36 BiosCode[Offset++] = 0xCD; // int SPECIAL_INT_NUM
37 BiosCode[Offset++] = SPECIAL_INT_NUM;
38
39 BiosCode[Offset++] = 0x83; // add sp, 2
40 BiosCode[Offset++] = 0xC4;
41 BiosCode[Offset++] = 0x02;
42 }
43
44 BiosCode[Offset++] = 0xCF; // iret
45 }
46
47 /* Get the console buffer info */
48 if (!GetConsoleScreenBufferInfo(ConsoleOutput, &ConsoleInfo))
49 {
50 return FALSE;
51 }
52
53 /* Set the initial cursor position and console size */
54 CursorCol = ConsoleInfo.dwCursorPosition.X;
55 CursorRow = ConsoleInfo.dwCursorPosition.Y;
56 ConsoleWidth = ConsoleInfo.dwSize.X;
57 ConsoleHeight = ConsoleInfo.dwSize.Y;
58
59 /* Initialize the PIC */
60 PicWriteCommand(PIC_MASTER_CMD, PIC_ICW1 | PIC_ICW1_ICW4);
61 PicWriteCommand(PIC_SLAVE_CMD, PIC_ICW1 | PIC_ICW1_ICW4);
62
63 /* Set the interrupt offsets */
64 PicWriteData(PIC_MASTER_DATA, BIOS_PIC_MASTER_INT);
65 PicWriteData(PIC_SLAVE_DATA, BIOS_PIC_SLAVE_INT);
66
67 /* Tell the master PIC there is a slave at IRQ 2 */
68 PicWriteData(PIC_MASTER_DATA, 1 << 2);
69 PicWriteData(PIC_SLAVE_DATA, 2);
70
71 /* Make sure the PIC is in 8086 mode */
72 PicWriteData(PIC_MASTER_DATA, PIC_ICW4_8086);
73 PicWriteData(PIC_SLAVE_DATA, PIC_ICW4_8086);
74
75 /* Clear the masks for both PICs */
76 PicWriteData(PIC_MASTER_DATA, 0x00);
77 PicWriteData(PIC_SLAVE_DATA, 0x00);
78
79 PitInitialize();
80
81 return TRUE;
82 }
83
84 static COORD BiosVideoAddressToCoord(ULONG Address)
85 {
86 COORD Result = {0, 0};
87 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
88 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
89
90 if (!GetConsoleScreenBufferInfo(ConsoleOutput, &ConsoleInfo))
91 {
92 assert(0);
93 return Result;
94 }
95
96 Result.X = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) % ConsoleInfo.dwSize.X;
97 Result.Y = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) / ConsoleInfo.dwSize.X;
98
99 return Result;
100 }
101
102 VOID BiosUpdateConsole(ULONG StartAddress, ULONG EndAddress)
103 {
104 ULONG i;
105 COORD Coordinates;
106 DWORD CharsWritten;
107 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
108
109 /* Loop through all the addresses */
110 for (i = StartAddress; i < EndAddress; i++)
111 {
112 /* Get the coordinates */
113 Coordinates = BiosVideoAddressToCoord(i);
114
115 /* Check if this is a character byte or an attribute byte */
116 if ((i - CONSOLE_VIDEO_MEM_START) % 2 == 0)
117 {
118 /* This is a regular character */
119 FillConsoleOutputCharacterA(ConsoleOutput,
120 *(PCHAR)((ULONG_PTR)BaseAddress + i),
121 sizeof(CHAR),
122 Coordinates,
123 &CharsWritten);
124 }
125 else
126 {
127 /* This is an attribute */
128 FillConsoleOutputAttribute(ConsoleOutput,
129 *(PCHAR)((ULONG_PTR)BaseAddress + i),
130 sizeof(CHAR),
131 Coordinates,
132 &CharsWritten);
133 }
134 }
135 }
136
137 VOID BiosUpdateVideoMemory(ULONG StartAddress, ULONG EndAddress)
138 {
139 ULONG i;
140 COORD Coordinates;
141 WORD Attribute;
142 DWORD CharsWritten;
143 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
144
145 /* Loop through all the addresses */
146 for (i = StartAddress; i < EndAddress; i++)
147 {
148 /* Get the coordinates */
149 Coordinates = BiosVideoAddressToCoord(i);
150
151 /* Check if this is a character byte or an attribute byte */
152 if ((i - CONSOLE_VIDEO_MEM_START) % 2 == 0)
153 {
154 /* This is a regular character */
155 ReadConsoleOutputCharacterA(ConsoleOutput,
156 (LPSTR)((ULONG_PTR)BaseAddress + i),
157 sizeof(CHAR),
158 Coordinates,
159 &CharsWritten);
160 }
161 else
162 {
163 /* This is an attribute */
164 ReadConsoleOutputAttribute(ConsoleOutput,
165 &Attribute,
166 sizeof(CHAR),
167 Coordinates,
168 &CharsWritten);
169
170 *(PCHAR)((ULONG_PTR)BaseAddress + i) = LOBYTE(Attribute);
171 }
172 }
173 }
174
175 VOID BiosVideoService()
176 {
177 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
178 INT CursorHeight;
179 BOOLEAN Invisible = FALSE;
180 COORD Position;
181 CONSOLE_CURSOR_INFO CursorInfo;
182 CHAR_INFO Character;
183 SMALL_RECT Rect;
184 DWORD Eax = EmulatorGetRegister(EMULATOR_REG_AX);
185 DWORD Ecx = EmulatorGetRegister(EMULATOR_REG_CX);
186 DWORD Edx = EmulatorGetRegister(EMULATOR_REG_DX);
187 DWORD Ebx = EmulatorGetRegister(EMULATOR_REG_BX);
188
189 switch (HIBYTE(Eax))
190 {
191 /* Set Text-Mode Cursor Shape */
192 case 0x01:
193 {
194 /* Retrieve and validate the input */
195 Invisible = ((HIBYTE(Ecx) >> 5) & 0x03) ? TRUE : FALSE;
196 CursorHeight = (HIBYTE(Ecx) & 0x1F) - (LOBYTE(Ecx) & 0x1F);
197 if (CursorHeight < 1) CursorHeight = 1;
198 if (CursorHeight > 100) CursorHeight = 100;
199
200 /* Set the cursor */
201 CursorInfo.dwSize = (CursorHeight * 100) / CONSOLE_FONT_HEIGHT;
202 CursorInfo.bVisible = !Invisible;
203 SetConsoleCursorInfo(ConsoleOutput, &CursorInfo);
204
205 break;
206 }
207
208 /* Set Cursor Position */
209 case 0x02:
210 {
211 Position.X = LOBYTE(Edx);
212 Position.Y = HIBYTE(Edx);
213
214 SetConsoleCursorPosition(ConsoleOutput, Position);
215 break;
216 }
217
218 /* Scroll Up/Down Window */
219 case 0x06:
220 case 0x07:
221 {
222 Rect.Top = HIBYTE(Ecx);
223 Rect.Left = LOBYTE(Ecx);
224 Rect.Bottom = HIBYTE(Edx);
225 Rect.Right = LOBYTE(Edx);
226 Character.Char.UnicodeChar = L' ';
227 Character.Attributes = HIBYTE(Ebx);
228 Position.X = Rect.Left;
229 if (HIBYTE(Eax) == 0x06) Position.Y = Rect.Top - LOBYTE(Eax);
230 else Position.Y = Rect.Top + LOBYTE(Eax);
231
232 ScrollConsoleScreenBuffer(ConsoleOutput,
233 &Rect,
234 &Rect,
235 Position,
236 &Character);
237 break;
238 }
239
240 /* Read Character And Attribute At Cursor Position */
241 case 0x08:
242 {
243 break;
244 }
245
246 /* Write Character And Attribute At Cursor Position */
247 case 0x09:
248 {
249 break;
250 }
251
252 /* Write Character Only At Cursor Position */
253 case 0x0A:
254 {
255 break;
256 }
257 }
258 }
259
260 VOID BiosHandleIrq(BYTE IrqNumber)
261 {
262 PicWriteCommand(PIC_MASTER_CMD, PIC_OCW2_EOI);
263 }
264
265 /* EOF */