xref: /reactos/drivers/setup/blue/font.c (revision e1605243)
1 /*
2  * PROJECT:     ReactOS Console Text-Mode Device Driver
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Loading specific fonts into VGA.
5  * COPYRIGHT:   Copyright 2008-2019 Aleksey Bragin (aleksey@reactos.org)
6  *              Copyright 2008-2019 Colin Finck (mail@colinfinck.de)
7  *              Copyright 2008-2019 Christoph von Wittich (christoph_vw@reactos.org)
8  */
9 
10 /* INCLUDES ***************************************************************/
11 
12 #include "blue.h"
13 #include <ndk/rtlfuncs.h>
14 
15 #define NDEBUG
16 #include <debug.h>
17 
18 NTSTATUS ExtractFont(_In_ ULONG CodePage, _In_ PUCHAR FontBitField);
19 VOID OpenBitPlane(VOID);
20 VOID CloseBitPlane(VOID);
21 VOID LoadFont(_In_ PUCHAR Bitplane, _In_ PUCHAR FontBitfield);
22 
23 /* FUNCTIONS ****************************************************************/
24 
25 VOID
26 ScrLoadFontTable(
27     _In_ ULONG CodePage)
28 {
29     PHYSICAL_ADDRESS BaseAddress;
30     PUCHAR Bitplane;
31     PUCHAR FontBitfield = NULL;
32     NTSTATUS Status = STATUS_SUCCESS;
33 
34     FontBitfield = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, 2048, TAG_BLUE);
35     if (FontBitfield == NULL)
36     {
37         DPRINT1("ExAllocatePoolWithTag failed\n");
38         return;
39     }
40 
41     /* open bit plane for font table access */
42     OpenBitPlane();
43 
44     /* get pointer to video memory */
45     BaseAddress.QuadPart = BITPLANE_BASE;
46     Bitplane = (PUCHAR)MmMapIoSpace(BaseAddress, 0xFFFF, MmNonCached);
47 
48     Status = ExtractFont(CodePage, FontBitfield);
49     if (NT_SUCCESS(Status))
50     {
51         LoadFont(Bitplane, FontBitfield);
52     }
53     else
54     {
55         DPRINT1("ExtractFont failed with Status 0x%lx\n", Status);
56     }
57 
58     MmUnmapIoSpace(Bitplane, 0xFFFF);
59     ExFreePoolWithTag(FontBitfield, TAG_BLUE);
60 
61     /* close bit plane */
62     CloseBitPlane();
63 }
64 
65 VOID
66 ScrSetFont(
67     _In_ PUCHAR FontBitfield)
68 {
69     PHYSICAL_ADDRESS BaseAddress;
70     PUCHAR Bitplane;
71 
72     /* open bit plane for font table access */
73     OpenBitPlane();
74 
75     /* get pointer to video memory */
76     BaseAddress.QuadPart = BITPLANE_BASE;
77     Bitplane = (PUCHAR)MmMapIoSpace(BaseAddress, 0xFFFF, MmNonCached);
78 
79     LoadFont(Bitplane, FontBitfield);
80 
81     MmUnmapIoSpace(Bitplane, 0xFFFF);
82 
83     /* close bit plane */
84     CloseBitPlane();
85 }
86 
87 /* PRIVATE FUNCTIONS *********************************************************/
88 
89 NTSTATUS
90 ExtractFont(
91     _In_ ULONG CodePage,
92     _In_ PUCHAR FontBitField)
93 {
94     BOOLEAN            bFoundFile = FALSE;
95     HANDLE             Handle;
96     NTSTATUS           Status;
97     CHAR               FileName[20];
98     IO_STATUS_BLOCK    IoStatusBlock;
99     OBJECT_ATTRIBUTES  ObjectAttributes;
100     UNICODE_STRING     LinkName;
101     UNICODE_STRING     SourceName;
102     CFHEADER           CabFileHeader;
103     CFFILE             CabFile;
104     ULONG              CabFileOffset = 0;
105     LARGE_INTEGER      ByteOffset;
106     WCHAR              SourceBuffer[MAX_PATH] = { L'\0' };
107     ULONG              ReadCP;
108 
109     if (KeGetCurrentIrql() != PASSIVE_LEVEL)
110         return STATUS_INVALID_DEVICE_STATE;
111 
112     RtlInitUnicodeString(&LinkName,
113                          L"\\SystemRoot");
114 
115     InitializeObjectAttributes(&ObjectAttributes,
116                                &LinkName,
117                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
118                                NULL,
119                                NULL);
120 
121     Status = ZwOpenSymbolicLinkObject(&Handle,
122                                       SYMBOLIC_LINK_ALL_ACCESS,
123                                       &ObjectAttributes);
124 
125     if (!NT_SUCCESS(Status))
126     {
127         DPRINT1("ZwOpenSymbolicLinkObject failed with Status 0x%lx\n", Status);
128         return Status;
129     }
130 
131     SourceName.Length = 0;
132     SourceName.MaximumLength = MAX_PATH * sizeof(WCHAR);
133     SourceName.Buffer = SourceBuffer;
134 
135     Status = ZwQuerySymbolicLinkObject(Handle,
136                                        &SourceName,
137                                        NULL);
138     ZwClose(Handle);
139 
140     if (!NT_SUCCESS(Status))
141     {
142         DPRINT1("ZwQuerySymbolicLinkObject failed with Status 0x%lx\n", Status);
143         return Status;
144     }
145 
146     Status = RtlAppendUnicodeToString(&SourceName, L"\\vgafonts.cab");
147     if (!NT_SUCCESS(Status))
148     {
149         DPRINT1("RtlAppendUnicodeToString failed with Status 0x%lx\n", Status);
150         return Status;
151     }
152 
153     InitializeObjectAttributes(&ObjectAttributes,
154                                &SourceName,
155                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
156                                NULL,
157                                NULL);
158 
159     Status = ZwCreateFile(&Handle,
160                           GENERIC_READ,
161                           &ObjectAttributes,
162                           &IoStatusBlock,
163                           NULL,
164                           FILE_ATTRIBUTE_NORMAL,
165                           0,
166                           FILE_OPEN,
167                           FILE_SYNCHRONOUS_IO_NONALERT,
168                           NULL,
169                           0);
170     if (!NT_SUCCESS(Status))
171     {
172         DPRINT1("Error: Cannot open vgafonts.cab (0x%lx)\n", Status);
173         return Status;
174     }
175 
176     ByteOffset.QuadPart = 0;
177     Status = ZwReadFile(Handle,
178                         NULL,
179                         NULL,
180                         NULL,
181                         &IoStatusBlock,
182                         &CabFileHeader,
183                         sizeof(CabFileHeader),
184                         &ByteOffset,
185                         NULL);
186 
187     if (!NT_SUCCESS(Status))
188     {
189         DPRINT1("Error: Cannot read from file (0x%lx)\n", Status);
190         goto Exit;
191     }
192 
193     if (CabFileHeader.Signature != CAB_SIGNATURE)
194     {
195         DPRINT1("Invalid CAB signature: 0x%lx!\n", CabFileHeader.Signature);
196         Status = STATUS_UNSUCCESSFUL;
197         goto Exit;
198     }
199 
200     // We have a valid CAB file!
201     // Read the file table now and decrement the file count on every file. When it's zero, we read the complete table.
202     ByteOffset.QuadPart = CabFileHeader.FileTableOffset;
203 
204     while (CabFileHeader.FileCount)
205     {
206         Status = ZwReadFile(Handle,
207                             NULL,
208                             NULL,
209                             NULL,
210                             &IoStatusBlock,
211                             &CabFile,
212                             sizeof(CabFile),
213                             &ByteOffset,
214                             NULL);
215 
216         if (NT_SUCCESS(Status))
217         {
218             ByteOffset.QuadPart += sizeof(CabFile);
219 
220             // We assume here that the file name is max. 19 characters (+ 1 NULL character) long.
221             // This should be enough for our purpose.
222             Status = ZwReadFile(Handle,
223                                 NULL,
224                                 NULL,
225                                 NULL,
226                                 &IoStatusBlock,
227                                 FileName,
228                                 sizeof(FileName),
229                                 &ByteOffset,
230                                 NULL);
231 
232             if (NT_SUCCESS(Status))
233             {
234                 if (!bFoundFile)
235                 {
236                     Status = RtlCharToInteger(FileName, 0, &ReadCP);
237                     if (NT_SUCCESS(Status) && ReadCP == CodePage)
238                     {
239                         // We got the correct file.
240                         // Save the offset and loop through the rest of the file table to find the position, where the actual data starts.
241                         CabFileOffset = CabFile.FileOffset;
242                         bFoundFile = TRUE;
243                     }
244                 }
245 
246                 ByteOffset.QuadPart += strlen(FileName) + 1;
247             }
248         }
249 
250         CabFileHeader.FileCount--;
251     }
252 
253     // 8 = Size of a CFFOLDER structure (see cabman). As we don't need the values of that structure, just increase the offset here.
254     ByteOffset.QuadPart += 8;
255     ByteOffset.QuadPart += CabFileOffset;
256 
257     // ByteOffset now contains the offset of the actual data, so we can read the RAW font
258     Status = ZwReadFile(Handle,
259                         NULL,
260                         NULL,
261                         NULL,
262                         &IoStatusBlock,
263                         FontBitField,
264                         2048,
265                         &ByteOffset,
266                         NULL);
267     if (!NT_SUCCESS(Status))
268     {
269         DPRINT1("ZwReadFile failed with Status 0x%lx\n", Status);
270     }
271 
272 Exit:
273 
274     ZwClose(Handle);
275     return Status;
276 }
277 
278 /* Font-load specific funcs */
279 VOID
280 OpenBitPlane(VOID)
281 {
282     /* disable interrupts */
283     _disable();
284 
285     /* sequence reg */
286     WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_RESET); WRITE_PORT_UCHAR(SEQ_DATA, 0x01);
287     WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_ENABLE_WRT_PLANE); WRITE_PORT_UCHAR(SEQ_DATA, 0x04);
288     WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_MEM_MODE); WRITE_PORT_UCHAR(SEQ_DATA, 0x07);
289     WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_RESET); WRITE_PORT_UCHAR(SEQ_DATA, 0x03);
290 
291     /* graphic reg */
292     WRITE_PORT_UCHAR(GCT_COMMAND, GCT_READ_PLANE); WRITE_PORT_UCHAR(GCT_DATA, 0x02);
293     WRITE_PORT_UCHAR(GCT_COMMAND, GCT_RW_MODES); WRITE_PORT_UCHAR(GCT_DATA, 0x00);
294     WRITE_PORT_UCHAR(GCT_COMMAND, GCT_GRAPH_MODE); WRITE_PORT_UCHAR(GCT_DATA, 0x00);
295 
296     /* enable interrupts */
297     _enable();
298 }
299 
300 VOID
301 CloseBitPlane(VOID)
302 {
303     /* disable interrupts */
304     _disable();
305 
306     /* sequence reg */
307     WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_RESET); WRITE_PORT_UCHAR(SEQ_DATA, 0x01);
308     WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_ENABLE_WRT_PLANE); WRITE_PORT_UCHAR(SEQ_DATA, 0x03);
309     WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_MEM_MODE); WRITE_PORT_UCHAR(SEQ_DATA, 0x03);
310     WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_RESET); WRITE_PORT_UCHAR(SEQ_DATA, 0x03);
311 
312     /* graphic reg */
313     WRITE_PORT_UCHAR(GCT_COMMAND, GCT_READ_PLANE); WRITE_PORT_UCHAR(GCT_DATA, 0x00);
314     WRITE_PORT_UCHAR(GCT_COMMAND, GCT_RW_MODES); WRITE_PORT_UCHAR(GCT_DATA, 0x10);
315     WRITE_PORT_UCHAR(GCT_COMMAND, GCT_GRAPH_MODE); WRITE_PORT_UCHAR(GCT_DATA, 0x0e);
316 
317     /* enable interrupts */
318     _enable();
319 }
320 
321 VOID
322 LoadFont(
323     _In_ PUCHAR Bitplane,
324     _In_ PUCHAR FontBitfield)
325 {
326     UINT32 i, j;
327 
328     for (i = 0; i < 256; i++)
329     {
330         for (j = 0; j < 8; j++)
331         {
332             *Bitplane = FontBitfield[i * 8 + j];
333             Bitplane++;
334         }
335 
336         // padding
337         for (j = 8; j < 32; j++)
338         {
339             *Bitplane = 0;
340             Bitplane++;
341         }
342     }
343 }
344