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