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