xref: /reactos/drivers/setup/blue/font.c (revision f7cab5a1)
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 /* PRIVATE FUNCTIONS *********************************************************/
66 
67 NTSTATUS
68 ExtractFont(
69     _In_ ULONG CodePage,
70     _In_ PUCHAR FontBitField)
71 {
72     BOOLEAN            bFoundFile = FALSE;
73     HANDLE             Handle;
74     NTSTATUS           Status;
75     CHAR               FileName[20];
76     IO_STATUS_BLOCK    IoStatusBlock;
77     OBJECT_ATTRIBUTES  ObjectAttributes;
78     UNICODE_STRING     LinkName;
79     UNICODE_STRING     SourceName;
80     CFHEADER           CabFileHeader;
81     CFFILE             CabFile;
82     ULONG              CabFileOffset = 0;
83     LARGE_INTEGER      ByteOffset;
84     WCHAR              SourceBuffer[MAX_PATH] = { L'\0' };
85     ULONG              ReadCP;
86 
87     if (KeGetCurrentIrql() != PASSIVE_LEVEL)
88         return STATUS_INVALID_DEVICE_STATE;
89 
90     RtlInitUnicodeString(&LinkName,
91                          L"\\SystemRoot");
92 
93     InitializeObjectAttributes(&ObjectAttributes,
94                                &LinkName,
95                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
96                                NULL,
97                                NULL);
98 
99     Status = ZwOpenSymbolicLinkObject(&Handle,
100                                       SYMBOLIC_LINK_ALL_ACCESS,
101                                       &ObjectAttributes);
102 
103     if (!NT_SUCCESS(Status))
104     {
105         DPRINT1("ZwOpenSymbolicLinkObject failed with Status 0x%lx\n", Status);
106         return Status;
107     }
108 
109     SourceName.Length = 0;
110     SourceName.MaximumLength = MAX_PATH * sizeof(WCHAR);
111     SourceName.Buffer = SourceBuffer;
112 
113     Status = ZwQuerySymbolicLinkObject(Handle,
114                                        &SourceName,
115                                        NULL);
116     ZwClose(Handle);
117 
118     if (!NT_SUCCESS(Status))
119     {
120         DPRINT1("ZwQuerySymbolicLinkObject failed with Status 0x%lx\n", Status);
121         return Status;
122     }
123 
124     Status = RtlAppendUnicodeToString(&SourceName, L"\\vgafonts.cab");
125     if (!NT_SUCCESS(Status))
126     {
127         DPRINT1("RtlAppendUnicodeToString failed with Status 0x%lx\n", Status);
128         return Status;
129     }
130 
131     InitializeObjectAttributes(&ObjectAttributes,
132                                &SourceName,
133                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
134                                NULL,
135                                NULL);
136 
137     Status = ZwCreateFile(&Handle,
138                           GENERIC_READ,
139                           &ObjectAttributes,
140                           &IoStatusBlock,
141                           NULL,
142                           FILE_ATTRIBUTE_NORMAL,
143                           0,
144                           FILE_OPEN,
145                           FILE_SYNCHRONOUS_IO_NONALERT,
146                           NULL,
147                           0);
148     if (!NT_SUCCESS(Status))
149     {
150         DPRINT1("Error: Cannot open vgafonts.cab (0x%lx)\n", Status);
151         return Status;
152     }
153 
154     ByteOffset.QuadPart = 0;
155     Status = ZwReadFile(Handle,
156                         NULL,
157                         NULL,
158                         NULL,
159                         &IoStatusBlock,
160                         &CabFileHeader,
161                         sizeof(CabFileHeader),
162                         &ByteOffset,
163                         NULL);
164 
165     if (!NT_SUCCESS(Status))
166     {
167         DPRINT1("Error: Cannot read from file (0x%lx)\n", Status);
168         goto Exit;
169     }
170 
171     if (CabFileHeader.Signature != CAB_SIGNATURE)
172     {
173         DPRINT1("Invalid CAB signature: 0x%lx!\n", CabFileHeader.Signature);
174         Status = STATUS_UNSUCCESSFUL;
175         goto Exit;
176     }
177 
178     // We have a valid CAB file!
179     // Read the file table now and decrement the file count on every file. When it's zero, we read the complete table.
180     ByteOffset.QuadPart = CabFileHeader.FileTableOffset;
181 
182     while (CabFileHeader.FileCount)
183     {
184         Status = ZwReadFile(Handle,
185                             NULL,
186                             NULL,
187                             NULL,
188                             &IoStatusBlock,
189                             &CabFile,
190                             sizeof(CabFile),
191                             &ByteOffset,
192                             NULL);
193 
194         if (NT_SUCCESS(Status))
195         {
196             ByteOffset.QuadPart += sizeof(CabFile);
197 
198             // We assume here that the file name is max. 19 characters (+ 1 NULL character) long.
199             // This should be enough for our purpose.
200             Status = ZwReadFile(Handle,
201                                 NULL,
202                                 NULL,
203                                 NULL,
204                                 &IoStatusBlock,
205                                 FileName,
206                                 sizeof(FileName),
207                                 &ByteOffset,
208                                 NULL);
209 
210             if (NT_SUCCESS(Status))
211             {
212                 if (!bFoundFile)
213                 {
214                     Status = RtlCharToInteger(FileName, 0, &ReadCP);
215                     if (NT_SUCCESS(Status) && ReadCP == CodePage)
216                     {
217                         // We got the correct file.
218                         // Save the offset and loop through the rest of the file table to find the position, where the actual data starts.
219                         CabFileOffset = CabFile.FileOffset;
220                         bFoundFile = TRUE;
221                     }
222                 }
223 
224                 ByteOffset.QuadPart += strlen(FileName) + 1;
225             }
226         }
227 
228         CabFileHeader.FileCount--;
229     }
230 
231     // 8 = Size of a CFFOLDER structure (see cabman). As we don't need the values of that structure, just increase the offset here.
232     ByteOffset.QuadPart += 8;
233     ByteOffset.QuadPart += CabFileOffset;
234 
235     // ByteOffset now contains the offset of the actual data, so we can read the RAW font
236     Status = ZwReadFile(Handle,
237                         NULL,
238                         NULL,
239                         NULL,
240                         &IoStatusBlock,
241                         FontBitField,
242                         2048,
243                         &ByteOffset,
244                         NULL);
245     if (!NT_SUCCESS(Status))
246     {
247         DPRINT1("ZwReadFile failed with Status 0x%lx\n", Status);
248     }
249 
250 Exit:
251 
252     ZwClose(Handle);
253     return Status;
254 }
255 
256 /* Font-load specific funcs */
257 VOID
258 OpenBitPlane(VOID)
259 {
260     /* disable interrupts */
261     _disable();
262 
263     /* sequence reg */
264     WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_RESET); WRITE_PORT_UCHAR(SEQ_DATA, 0x01);
265     WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_ENABLE_WRT_PLANE); WRITE_PORT_UCHAR(SEQ_DATA, 0x04);
266     WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_MEM_MODE); WRITE_PORT_UCHAR(SEQ_DATA, 0x07);
267     WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_RESET); WRITE_PORT_UCHAR(SEQ_DATA, 0x03);
268 
269     /* graphic reg */
270     WRITE_PORT_UCHAR(GCT_COMMAND, GCT_READ_PLANE); WRITE_PORT_UCHAR(GCT_DATA, 0x02);
271     WRITE_PORT_UCHAR(GCT_COMMAND, GCT_RW_MODES); WRITE_PORT_UCHAR(GCT_DATA, 0x00);
272     WRITE_PORT_UCHAR(GCT_COMMAND, GCT_GRAPH_MODE); WRITE_PORT_UCHAR(GCT_DATA, 0x00);
273 
274     /* enable interrupts */
275     _enable();
276 }
277 
278 VOID
279 CloseBitPlane(VOID)
280 {
281     /* disable interrupts */
282     _disable();
283 
284     /* sequence reg */
285     WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_RESET); WRITE_PORT_UCHAR(SEQ_DATA, 0x01);
286     WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_ENABLE_WRT_PLANE); WRITE_PORT_UCHAR(SEQ_DATA, 0x03);
287     WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_MEM_MODE); WRITE_PORT_UCHAR(SEQ_DATA, 0x03);
288     WRITE_PORT_UCHAR(SEQ_COMMAND, SEQ_RESET); WRITE_PORT_UCHAR(SEQ_DATA, 0x03);
289 
290     /* graphic reg */
291     WRITE_PORT_UCHAR(GCT_COMMAND, GCT_READ_PLANE); WRITE_PORT_UCHAR(GCT_DATA, 0x00);
292     WRITE_PORT_UCHAR(GCT_COMMAND, GCT_RW_MODES); WRITE_PORT_UCHAR(GCT_DATA, 0x10);
293     WRITE_PORT_UCHAR(GCT_COMMAND, GCT_GRAPH_MODE); WRITE_PORT_UCHAR(GCT_DATA, 0x0e);
294 
295     /* enable interrupts */
296     _enable();
297 }
298 
299 VOID
300 LoadFont(
301     _In_ PUCHAR Bitplane,
302     _In_ PUCHAR FontBitfield)
303 {
304     UINT32 i, j;
305 
306     for (i = 0; i < 256; i++)
307     {
308         for (j = 0; j < 8; j++)
309         {
310             *Bitplane = FontBitfield[i * 8 + j];
311             Bitplane++;
312         }
313 
314         // padding
315         for (j = 8; j < 32; j++)
316         {
317             *Bitplane = 0;
318             Bitplane++;
319         }
320     }
321 }
322