From b6f9a644a780fda73e0f6f9c6bf3518abd01bba2 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 30 Mar 2023 19:21:14 +0300 Subject: [PATCH] Map the kernel too --- .../amd64/Bootstrap/Multiboot2/Entry.asm | 19 +- .../Bootstrap/Multiboot2/MB2MemoryMapper.cpp | 281 ++++++++++++++++++ .../amd64/Bootstrap/Multiboot2/Multiboot2.cpp | 75 +++-- .../amd64/Bootstrap/Multiboot2/PageTable.asm | 90 ++---- Core/Memory/Memory.cpp | 4 +- include/boot/binfo.h | 14 +- 6 files changed, 373 insertions(+), 110 deletions(-) create mode 100644 Architecture/amd64/Bootstrap/Multiboot2/MB2MemoryMapper.cpp diff --git a/Architecture/amd64/Bootstrap/Multiboot2/Entry.asm b/Architecture/amd64/Bootstrap/Multiboot2/Entry.asm index ddcf1df..6c7c0d9 100644 --- a/Architecture/amd64/Bootstrap/Multiboot2/Entry.asm +++ b/Architecture/amd64/Bootstrap/Multiboot2/Entry.asm @@ -16,10 +16,22 @@ global MB2_start extern MB2_start_c [bits 32] + +section .bootstrap.data +global MB2_HeaderMagic +MB2_HeaderMagic: + times (0x64) dq 0 + +global MB2_HeaderInfo +MB2_HeaderInfo: + times (0x64) dq 0 + section .bootstrap.text MB2_start: cli mov word [0xb8F00], 0x072E ; . + mov [MB2_HeaderMagic], eax + mov [MB2_HeaderInfo], ebx ; We need to check if the CPU supports 64-bit mode call DetectCPUID @@ -88,10 +100,11 @@ HigherHalfStart: mov word [0xb8F08], 0x072E ; . mov rsp, (KernelStack + KERNEL_STACK_SIZE) + mov rbp, (KernelStack + KERNEL_STACK_SIZE) + + cld + cli - push rax ; Multiboot2 Magic - add rbx, KERNEL_VIRTUAL_BASE - push rbx ; Multiboot2 Header call Multiboot2Entry .Loop: hlt diff --git a/Architecture/amd64/Bootstrap/Multiboot2/MB2MemoryMapper.cpp b/Architecture/amd64/Bootstrap/Multiboot2/MB2MemoryMapper.cpp new file mode 100644 index 0000000..a128b49 --- /dev/null +++ b/Architecture/amd64/Bootstrap/Multiboot2/MB2MemoryMapper.cpp @@ -0,0 +1,281 @@ +#include + +union __attribute__((packed)) PageTableEntry +{ + struct + { + bool Present : 1; // 0 + bool ReadWrite : 1; // 1 + bool UserSupervisor : 1; // 2 + bool WriteThrough : 1; // 3 + bool CacheDisable : 1; // 4 + bool Accessed : 1; // 5 + bool Dirty : 1; // 6 + bool PageAttributeTable : 1; // 7 + bool Global : 1; // 8 + uint8_t Available0 : 3; // 9-11 + uint64_t Address : 40; // 12-51 + uint32_t Available1 : 7; // 52-58 + uint8_t ProtectionKey : 4; // 59-62 + bool ExecuteDisable : 1; // 63 + }; + uint64_t raw; + + __always_inline inline SafeFunction NIF void SetAddress(uintptr_t _Address) + { + _Address &= 0x000000FFFFFFFFFF; + this->raw &= 0xFFF0000000000FFF; + this->raw |= (_Address << 12); + } + + __always_inline inline SafeFunction NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; } +}; + +struct __attribute__((packed)) PageTableEntryPtr +{ + PageTableEntry Entries[511]; +}; + +union __attribute__((packed)) PageDirectoryEntry +{ + struct + { + bool Present : 1; // 0 + bool ReadWrite : 1; // 1 + bool UserSupervisor : 1; // 2 + bool WriteThrough : 1; // 3 + bool CacheDisable : 1; // 4 + bool Accessed : 1; // 5 + bool Available0 : 1; // 6 + bool PageSize : 1; // 7 + uint8_t Available1 : 4; // 8-11 + uint64_t Address : 40; // 12-51 + uint32_t Available2 : 11; // 52-62 + bool ExecuteDisable : 1; // 63 + }; + uint64_t raw; + + __always_inline inline SafeFunction NIF void SetAddress(uintptr_t _Address) + { + _Address &= 0x000000FFFFFFFFFF; + this->raw &= 0xFFF0000000000FFF; + this->raw |= (_Address << 12); + } + + __always_inline inline SafeFunction NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; } +}; + +struct __attribute__((packed)) PageDirectoryEntryPtr +{ + PageDirectoryEntry Entries[511]; +}; + +union __attribute__((packed)) PageDirectoryPointerTableEntry +{ + struct + { + bool Present : 1; // 0 + bool ReadWrite : 1; // 1 + bool UserSupervisor : 1; // 2 + bool WriteThrough : 1; // 3 + bool CacheDisable : 1; // 4 + bool Accessed : 1; // 5 + bool Available0 : 1; // 6 + bool PageSize : 1; // 7 + uint8_t Available1 : 4; // 8-11 + uint64_t Address : 40; // 12-51 + uint32_t Available2 : 11; // 52-62 + bool ExecuteDisable : 1; // 63 + }; + uint64_t raw; + + __always_inline inline SafeFunction NIF void SetAddress(uintptr_t _Address) + { + _Address &= 0x000000FFFFFFFFFF; + this->raw &= 0xFFF0000000000FFF; + this->raw |= (_Address << 12); + } + + __always_inline inline SafeFunction NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; } +}; + +struct __attribute__((packed)) PageDirectoryPointerTableEntryPtr +{ + PageDirectoryPointerTableEntry Entries[511]; +}; + +union __attribute__((packed)) PageMapLevel4 +{ + struct + { + bool Present : 1; // 0 + bool ReadWrite : 1; // 1 + bool UserSupervisor : 1; // 2 + bool WriteThrough : 1; // 3 + bool CacheDisable : 1; // 4 + bool Accessed : 1; // 5 + bool Available0 : 1; // 6 + bool Reserved0 : 1; // 7 + uint8_t Available1 : 4; // 8-11 + uint64_t Address : 40; // 12-51 + uint32_t Available2 : 11; // 52-62 + bool ExecuteDisable : 1; // 63 + }; + uint64_t raw; + + __always_inline inline SafeFunction NIF void SetAddress(uintptr_t _Address) + { + _Address &= 0x000000FFFFFFFFFF; + this->raw &= 0xFFF0000000000FFF; + this->raw |= (_Address << 12); + } + + __always_inline inline SafeFunction NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; } +}; + +struct PageTable4 +{ + PageMapLevel4 Entries[511]; +} __attribute__((aligned(0x1000))); + +extern "C" char BootPageTable[]; +extern uintptr_t _kernel_start, _kernel_end; + +__attribute__((section(".bootstrap.data"))) static PageTable4 *BPTable = (PageTable4 *)BootPageTable; +__attribute__((section(".bootstrap.data"))) static size_t BPT_Allocated = 0x4000; + +__always_inline inline SafeFunction NIF void *RequestPage() +{ + void *Page = (void *)(BootPageTable + BPT_Allocated); + BPT_Allocated += 0x1000; + if (BPT_Allocated >= 0x10000) /* The length of BootPageTable */ + { + while (true) + ; + } + return Page; +} + +class PageMapIndexer +{ +public: + uintptr_t PMLIndex = 0; + uintptr_t PDPTEIndex = 0; + uintptr_t PDEIndex = 0; + uintptr_t PTEIndex = 0; + __always_inline inline SafeFunction NIF PageMapIndexer(uintptr_t VirtualAddress) + { + uintptr_t Address = VirtualAddress; + Address >>= 12; + this->PTEIndex = Address & 0x1FF; + Address >>= 9; + this->PDEIndex = Address & 0x1FF; + Address >>= 9; + this->PDPTEIndex = Address & 0x1FF; + Address >>= 9; + this->PMLIndex = Address & 0x1FF; + } +}; + +__always_inline inline SafeFunction NIF void Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags) +{ + PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress); + // Clear any flags that are not 1 << 0 (Present) - 1 << 5 (Accessed) because rest are for page table entries only + uint64_t DirectoryFlags = Flags & 0x3F; + + PageMapLevel4 PML4 = BPTable->Entries[Index.PMLIndex]; + PageDirectoryPointerTableEntryPtr *PDPTEPtr = nullptr; + if (!PML4.Present) + { + PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)RequestPage(); + { + void *ptr = PDPTEPtr; + int value = 0; + size_t num = 0x1000; + uint8_t *p = (uint8_t *)ptr; + for (size_t i = 0; i < num; i++) + p[i] = value; + } + PML4.Present = true; + PML4.SetAddress((uintptr_t)PDPTEPtr >> 12); + } + else + PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12); + PML4.raw |= DirectoryFlags; + BPTable->Entries[Index.PMLIndex] = PML4; + + PageDirectoryPointerTableEntry PDPTE = PDPTEPtr->Entries[Index.PDPTEIndex]; + PageDirectoryEntryPtr *PDEPtr = nullptr; + if (!PDPTE.Present) + { + PDEPtr = (PageDirectoryEntryPtr *)RequestPage(); + { + void *ptr = PDEPtr; + int value = 0; + size_t num = 0x1000; + uint8_t *p = (uint8_t *)ptr; + for (size_t i = 0; i < num; i++) + p[i] = value; + } + PDPTE.Present = true; + PDPTE.SetAddress((uintptr_t)PDEPtr >> 12); + } + else + PDEPtr = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE.GetAddress() << 12); + PDPTE.raw |= DirectoryFlags; + PDPTEPtr->Entries[Index.PDPTEIndex] = PDPTE; + + PageDirectoryEntry PDE = PDEPtr->Entries[Index.PDEIndex]; + PageTableEntryPtr *PTEPtr = nullptr; + if (!PDE.Present) + { + PTEPtr = (PageTableEntryPtr *)RequestPage(); + { + void *ptr = PTEPtr; + int value = 0; + size_t num = 0x1000; + uint8_t *p = (uint8_t *)ptr; + for (size_t i = 0; i < num; i++) + p[i] = value; + } + PDE.Present = true; + PDE.SetAddress((uintptr_t)PTEPtr >> 12); + } + else + PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE.GetAddress() << 12); + PDE.raw |= DirectoryFlags; + PDEPtr->Entries[Index.PDEIndex] = PDE; + + PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex]; + PTE.Present = true; + PTE.raw |= Flags; + PTE.SetAddress((uintptr_t)PhysicalAddress >> 12); + PTEPtr->Entries[Index.PTEIndex] = PTE; + asmv("invlpg (%0)" + : + : "r"(VirtualAddress) + : "memory"); +} + +EXTERNC __attribute__((section(".bootstrap.text"))) SafeFunction NIF __attribute__((section(".bootstrap.text"))) void UpdatePageTable64() +{ + BPTable = (PageTable4 *)BootPageTable; + + // for (size_t i = 0; i < 0x10000000; i += 0x1000) + // Map((void *)i, (void *)i, 0x3); + + uintptr_t KernelStart = (uintptr_t)&_kernel_start; + uintptr_t KernelEnd = (uintptr_t)&_kernel_end; + uintptr_t PhysicalStart = KernelStart - 0xFFFFFFFF80000000; + for (uintptr_t i = KernelStart; i < KernelEnd; i += 0x1000) + { + Map((void *)i, (void *)PhysicalStart, 0x3); + PhysicalStart += 0x1000; + } + + asmv("mov %%cr3, %%rax\n" + "mov %%rax, %%cr3\n" + : + : + : "rax"); +} diff --git a/Architecture/amd64/Bootstrap/Multiboot2/Multiboot2.cpp b/Architecture/amd64/Bootstrap/Multiboot2/Multiboot2.cpp index f85ac3b..f7748b9 100644 --- a/Architecture/amd64/Bootstrap/Multiboot2/Multiboot2.cpp +++ b/Architecture/amd64/Bootstrap/Multiboot2/Multiboot2.cpp @@ -6,8 +6,6 @@ #include "../../../../kernel.h" -BootInfo mb2binfo; - enum VideoType { VIDEO_TYPE_NONE = 0x00, @@ -50,9 +48,37 @@ void GetSMBIOS() } } -void ProcessMB2(unsigned long Info) +extern "C" unsigned int MB2_HeaderMagic; +extern "C" unsigned long MB2_HeaderInfo; + +EXTERNC void Multiboot2Entry() { - uint8_t *VideoBuffer = (uint8_t *)0xB8F00 + 0xC0000000; + unsigned long Info = MB2_HeaderInfo; + unsigned int Magic = MB2_HeaderMagic; + if (Info == NULL || Magic == NULL) + { + if (Magic == NULL) + error("Multiboot magic is NULL"); + if (Info == NULL) + error("Multiboot info is NULL"); + CPU::Stop(); + } + else if (Magic != MULTIBOOT2_BOOTLOADER_MAGIC) + { + error("Multiboot magic is invalid (%#x != %#x)", Magic, MULTIBOOT2_BOOTLOADER_MAGIC); + CPU::Stop(); + } + + uint64_t div = 1193180 / 1000; + outb(0x43, 0xB6); + outb(0x42, (uint8_t)div); + outb(0x42, (uint8_t)(div >> 8)); + uint8_t tmp = inb(0x61); + if (tmp != (tmp | 3)) + outb(0x61, tmp | 3); + + BootInfo mb2binfo; + uint8_t *VideoBuffer = (uint8_t *)0xB8F00; int pos = 0; auto InfoAddress = Info; for (auto Tag = (struct multiboot_tag *)((uint8_t *)InfoAddress + 8); @@ -90,7 +116,7 @@ void ProcessMB2(unsigned long Info) { multiboot_tag_module *module = (multiboot_tag_module *)Tag; static int module_count = 0; - mb2binfo.Modules[module_count++].Address = (void *)module->mod_start; + mb2binfo.Modules[module_count++].Address = (void *)(uint64_t)module->mod_start; mb2binfo.Modules[module_count++].Size = module->size; strncpy(mb2binfo.Modules[module_count++].Path, "(null)", 6); strncpy(mb2binfo.Modules[module_count++].CommandLine, module->cmdline, @@ -187,11 +213,12 @@ void ProcessMB2(unsigned long Info) { case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED: { - fixme("indexed"); + mb2binfo.Framebuffer[fb_count].Type = Indexed; break; } case MULTIBOOT_FRAMEBUFFER_TYPE_RGB: { + mb2binfo.Framebuffer[fb_count].Type = RGB; mb2binfo.Framebuffer[fb_count].RedMaskSize = fb->framebuffer_red_mask_size; mb2binfo.Framebuffer[fb_count].RedMaskShift = fb->framebuffer_red_field_position; mb2binfo.Framebuffer[fb_count].GreenMaskSize = fb->framebuffer_green_mask_size; @@ -202,11 +229,11 @@ void ProcessMB2(unsigned long Info) } case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT: { - fixme("ega_text"); + mb2binfo.Framebuffer[fb_count].Type = EGA; break; } } - debug("Framebuffer %d: %dx%d %d bpp", Tag, fb->common.framebuffer_width, fb->common.framebuffer_height, fb->common.framebuffer_bpp); + debug("Framebuffer %d: %dx%d %d bpp", fb_count, fb->common.framebuffer_width, fb->common.framebuffer_height, fb->common.framebuffer_bpp); debug("More info:\nAddress: %p\nPitch: %lld\nMemoryModel: %d\nRedMaskSize: %d\nRedMaskShift: %d\nGreenMaskSize: %d\nGreenMaskShift: %d\nBlueMaskSize: %d\nBlueMaskShift: %d", fb->common.framebuffer_addr, fb->common.framebuffer_pitch, fb->common.framebuffer_type, fb->framebuffer_red_mask_size, fb->framebuffer_red_field_position, fb->framebuffer_green_mask_size, @@ -291,8 +318,8 @@ void ProcessMB2(unsigned long Info) case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR: { multiboot_tag_load_base_addr *load_base_addr = (multiboot_tag_load_base_addr *)Tag; - mb2binfo.Kernel.PhysicalBase = (void *)load_base_addr->load_base_addr; - mb2binfo.Kernel.VirtualBase = (void *)(load_base_addr->load_base_addr + 0xC0000000); + mb2binfo.Kernel.PhysicalBase = (void *)(uint64_t)load_base_addr->load_base_addr; + mb2binfo.Kernel.VirtualBase = (void *)(uint64_t)(load_base_addr->load_base_addr + 0xFFFFFFFF80000000); debug("Kernel base: %p (physical) %p (virtual)", mb2binfo.Kernel.PhysicalBase, mb2binfo.Kernel.VirtualBase); break; } @@ -303,37 +330,9 @@ void ProcessMB2(unsigned long Info) } } } -} - -EXTERNC void Multiboot2Entry(unsigned long Info, unsigned int Magic) -{ - if (Info == NULL || Magic == NULL) - { - if (Magic == NULL) - error("Multiboot magic is NULL"); - if (Info == NULL) - error("Multiboot info is NULL"); - CPU::Stop(); - } - else if (Magic != MULTIBOOT2_BOOTLOADER_MAGIC) - { - error("Multiboot magic is invalid (%#x != %#x)", Magic, MULTIBOOT2_BOOTLOADER_MAGIC); - CPU::Stop(); - } - - uint64_t div = 1193180 / 1000; - outb(0x43, 0xB6); - outb(0x42, (uint8_t)div); - outb(0x42, (uint8_t)(div >> 8)); - uint8_t tmp = inb(0x61); - if (tmp != (tmp | 3)) - outb(0x61, tmp | 3); - - ProcessMB2(Info); tmp = inb(0x61) & 0xFC; outb(0x61, tmp); - CPU::Stop(); Entry(&mb2binfo); } diff --git a/Architecture/amd64/Bootstrap/Multiboot2/PageTable.asm b/Architecture/amd64/Bootstrap/Multiboot2/PageTable.asm index f6525d5..eba5546 100644 --- a/Architecture/amd64/Bootstrap/Multiboot2/PageTable.asm +++ b/Architecture/amd64/Bootstrap/Multiboot2/PageTable.asm @@ -10,76 +10,36 @@ BootPageTable: section .bootstrap.text global UpdatePageTable UpdatePageTable: - mov edi, (BootPageTable + 0x0000) + mov edi, (BootPageTable + 0x0000) ; First PML4E + mov eax, (BootPageTable + 0x1000) ; First PDPTE + or eax, 11b ; Bitwise OR on rax (PDPTE) with 11b (Present, Write) + mov dword [edi], eax ; Write 11b to PML4E - mov eax, (BootPageTable + 0x1000) - or eax, 0x3 - mov dword [edi], eax - - mov ecx, PAGE_TABLE_SIZE - mov edi, (BootPageTable + 0x1000) - mov eax, (BootPageTable + 0x2000) - or eax, 0x3 - mov ebx, 0x0 + mov edi, (BootPageTable + 0x1000) ; First PDPTE + mov eax, (BootPageTable + 0x2000) ; First PDE + or eax, 11b ; Bitwise OR on rax (PDE) with 11b (Present, Write) + mov ecx, PAGE_TABLE_SIZE ; For loop instruction + mov ebx, 0x0 ; Value to store in the next 4 bytes .FillPageTableLevel3: - mov dword [edi], eax - mov dword [edi + 4], ebx - add eax, 1 << 12 - adc ebx, 0 - add edi, 8 - loop .FillPageTableLevel3 + mov dword [edi], eax ; Store modified PDE in PDPTE + mov dword [edi + 4], ebx ; Store the rbx value in the next 4 bytes + add eax, 0x1000 ; Increment (page size) + adc ebx, 0 ; Add 0 to carry flag + add edi, 8 ; Add 8 to rdi (next PDE) + loop .FillPageTableLevel3 ; Loop until rcx is 0 - mov ecx, (512 * PAGE_TABLE_SIZE) - mov edi, (BootPageTable + 0x2000) - mov eax, 0x0 | 0x3 | 1 << 7 - mov ebx, 0x0 + mov edi, (BootPageTable + 0x2000) ; First PDE + mov eax, 11b | 10000000b ; Present, Write, Large Page + mov ecx, (512 * PAGE_TABLE_SIZE) ; For loop instruction + mov ebx, 0x0 ; Value to store in the next 4 bytes .FillPageTableLevel2: - mov dword [edi], eax - mov dword [edi + 4], ebx - add eax, 1 << 21 - adc ebx, 0 - add edi, 8 - loop .FillPageTableLevel2 - - ret - -[bits 64] -section .bootstrap.text -global UpdatePageTable64 -UpdatePageTable64: - mov rdi, (BootPageTable + 0x0000) - - mov rax, (BootPageTable + 0x1000) - or rax, 0x3 - mov [rdi], rax - - mov rcx, PAGE_TABLE_SIZE - mov rdi, (BootPageTable + 0x1000) - mov rax, (BootPageTable + 0x2000) - or rax, 0x3 - mov rbx, 0x0 - - .FillPageTableLevel3: - mov [rdi], rax - mov [rdi + 4], rbx - add rax, 1 << 12 - adc rbx, 0 - add rdi, 8 - loop .FillPageTableLevel3 - - mov rcx, (512 * PAGE_TABLE_SIZE) - mov rdi, (BootPageTable + 0x2000) - mov rax, 0x0 | 0x3 | 1 << 7 - mov rbx, 0x0 - - .FillPageTableLevel2: - mov [rdi], rax - mov [rdi + 4], rbx - add rax, 1 << 21 - adc rbx, 0 - add rdi, 8 - loop .FillPageTableLevel2 + mov dword [edi], eax ; Store modified PDE in PDPTE + mov dword [edi + 4], ebx ; Store the rbx value in the next 4 bytes + add eax, 1 << 21 ; Increment (page size) + adc ebx, 0 ; Add 0 (carry flag) to rbx to increment if there was a carry + add edi, 8 ; Add 8 to rdi (next PDE) + loop .FillPageTableLevel2 ; Loop until rcx is 0 ret diff --git a/Core/Memory/Memory.cpp b/Core/Memory/Memory.cpp index 968072e..1dca2f7 100644 --- a/Core/Memory/Memory.cpp +++ b/Core/Memory/Memory.cpp @@ -71,8 +71,8 @@ NIF void MapFromZero(PageTable4 *PT, BootInfo *Info) for (size_t t = 0; t < MemSize; t += PAGE_SIZE) { va.Map((void *)t, (void *)t, PTFlag::RW /* | PTFlag::US */); - va.Map((void *)VirtualOffsetNormalVMA, (void *)t, PTFlag::RW /* | PTFlag::US */); - VirtualOffsetNormalVMA += PAGE_SIZE; + // va.Map((void *)VirtualOffsetNormalVMA, (void *)t, PTFlag::RW /* | PTFlag::US */); + // VirtualOffsetNormalVMA += PAGE_SIZE; } } else diff --git a/include/boot/binfo.h b/include/boot/binfo.h index 944b7f0..01947c7 100644 --- a/include/boot/binfo.h +++ b/include/boot/binfo.h @@ -3,7 +3,7 @@ enum MemoryType { - Unknown, + Unknown_Memory_Type, Usable, Reserved, ACPIReclaimable, @@ -11,7 +11,16 @@ enum MemoryType BadMemory, BootloaderReclaimable, KernelAndModules, - Framebuffer + Framebuffer, + Unknown +}; + +enum FramebufferType +{ + Unknown_Framebuffer_Type, + Indexed, + RGB, + EGA }; #define MAX_FRAMEBUFFERS 16 @@ -22,6 +31,7 @@ struct BootInfo { struct FramebufferInfo { + enum FramebufferType Type; void *BaseAddress; __UINT64_TYPE__ Width; __UINT64_TYPE__ Height;