4c45004b10740645722cd48e365806cc97d23995
[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 PitWriteCommand(0x34);
80 PitWriteData(0, 0x00);
81 PitWriteData(0, 0x00);
82
83 return TRUE;
84 }
85
86 static COORD BiosVideoAddressToCoord(ULONG Address)
87 {
88 COORD Result = {0, 0};
89 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
90 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
91
92 if (!GetConsoleScreenBufferInfo(ConsoleOutput, &ConsoleInfo))
93 {
94 ASSERT(FALSE);
95 return Result;
96 }
97
98 Result.X = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) % ConsoleInfo.dwSize.X;
99 Result.Y = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) / ConsoleInfo.dwSize.X;
100
101 return Result;
102 }
103
104 VOID BiosUpdateConsole(ULONG StartAddress, ULONG EndAddress)
105 {
106 ULONG i;
107 COORD Coordinates;
108 DWORD CharsWritten;
109 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
110
111 /* Loop through all the addresses */
112 for (i = StartAddress; i < EndAddress; i++)
113 {
114 /* Get the coordinates */
115 Coordinates = BiosVideoAddressToCoord(i);
116
117 /* Check if this is a character byte or an attribute byte */
118 if ((i - CONSOLE_VIDEO_MEM_START) % 2 == 0)
119 {
120 /* This is a regular character */
121 FillConsoleOutputCharacterA(ConsoleOutput,
122 *(PCHAR)((ULONG_PTR)BaseAddress + i),
123 sizeof(CHAR),
124 Coordinates,
125 &CharsWritten);
126 }
127 else
128 {
129 /* This is an attribute */
130 FillConsoleOutputAttribute(ConsoleOutput,
131 *(PCHAR)((ULONG_PTR)BaseAddress + i),
132 sizeof(CHAR),
133 Coordinates,
134 &CharsWritten);
135 }
136 }
137 }
138
139 VOID BiosUpdateVideoMemory(ULONG StartAddress, ULONG EndAddress)
140 {
141 ULONG i;
142 COORD Coordinates;
143 WORD Attribute;
144 DWORD CharsWritten;
145 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
146
147 /* Loop through all the addresses */
148 for (i = StartAddress; i < EndAddress; i++)
149 {
150 /* Get the coordinates */
151 Coordinates = BiosVideoAddressToCoord(i);
152
153 /* Check if this is a character byte or an attribute byte */
154 if ((i - CONSOLE_VIDEO_MEM_START) % 2 == 0)
155 {
156 /* This is a regular character */
157 ReadConsoleOutputCharacterA(ConsoleOutput,
158 (LPSTR)((ULONG_PTR)BaseAddress + i),
159 sizeof(CHAR),
160 Coordinates,
161 &CharsWritten);
162 }
163 else
164 {
165 /* This is an attribute */
166 ReadConsoleOutputAttribute(ConsoleOutput,
167 &Attribute,
168 sizeof(CHAR),
169 Coordinates,
170 &CharsWritten);
171
172 *(PCHAR)((ULONG_PTR)BaseAddress + i) = LOBYTE(Attribute);
173 }
174 }
175 }
176
177 VOID BiosVideoService()
178 {
179 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
180 INT CursorHeight;
181 BOOLEAN Invisible = FALSE;
182 COORD Position;
183 CONSOLE_CURSOR_INFO CursorInfo;
184 CHAR_INFO Character;
185 SMALL_RECT Rect;
186 DWORD Eax = EmulatorGetRegister(EMULATOR_REG_AX);
187 DWORD Ecx = EmulatorGetRegister(EMULATOR_REG_CX);
188 DWORD Edx = EmulatorGetRegister(EMULATOR_REG_DX);
189 DWORD Ebx = EmulatorGetRegister(EMULATOR_REG_BX);
190
191 switch (HIBYTE(Eax))
192 {
193 /* Set Text-Mode Cursor Shape */
194 case 0x01:
195 {
196 /* Retrieve and validate the input */
197 Invisible = ((HIBYTE(Ecx) >> 5) & 0x03) ? TRUE : FALSE;
198 CursorHeight = (HIBYTE(Ecx) & 0x1F) - (LOBYTE(Ecx) & 0x1F);
199 if (CursorHeight < 1) CursorHeight = 1;
200 if (CursorHeight > 100) CursorHeight = 100;
201
202 /* Set the cursor */
203 CursorInfo.dwSize = (CursorHeight * 100) / CONSOLE_FONT_HEIGHT;
204 CursorInfo.bVisible = !Invisible;
205 SetConsoleCursorInfo(ConsoleOutput, &CursorInfo);
206
207 break;
208 }
209
210 /* Set Cursor Position */
211 case 0x02:
212 {
213 Position.X = LOBYTE(Edx);
214 Position.Y = HIBYTE(Edx);
215
216 SetConsoleCursorPosition(ConsoleOutput, Position);
217 break;
218 }
219
220 /* Scroll Up/Down Window */
221 case 0x06:
222 case 0x07:
223 {
224 Rect.Top = HIBYTE(Ecx);
225 Rect.Left = LOBYTE(Ecx);
226 Rect.Bottom = HIBYTE(Edx);
227 Rect.Right = LOBYTE(Edx);
228 Character.Char.UnicodeChar = L' ';
229 Character.Attributes = HIBYTE(Ebx);
230 Position.X = Rect.Left;
231 if (HIBYTE(Eax) == 0x06) Position.Y = Rect.Top - LOBYTE(Eax);
232 else Position.Y = Rect.Top + LOBYTE(Eax);
233
234 ScrollConsoleScreenBuffer(ConsoleOutput,
235 &Rect,
236 &Rect,
237 Position,
238 &Character);
239 break;
240 }
241
242 /* Read Character And Attribute At Cursor Position */
243 case 0x08:
244 {
245 break;
246 }
247
248 /* Write Character And Attribute At Cursor Position */
249 case 0x09:
250 {
251 break;
252 }
253
254 /* Write Character Only At Cursor Position */
255 case 0x0A:
256 {
257 break;
258 }
259 }
260 }
261
262 VOID BiosHandleIrq(BYTE IrqNumber)
263 {
264 PicWriteCommand(PIC_MASTER_CMD, PIC_OCW2_EOI);
265 }
266
267 /* EOF */