/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2020 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╠──────────────────────────────────────────────────────────────────────────────╣ │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░█▀█░█▀█░▀█▀░█░█░█▀█░█░░░█░░░█░█░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░█▀█░█░▄░░█░░█░█░█▀█░█░░░█░░░▀█▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░▀░▀░▀▀▀░░▀░░▀▀▀░▀░▀░▀▀▀░▀▀▀░░▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░█▀█░█▀█░█▀█░▀█▀░█▀█░█▀█░█░░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░█▀▀░█ █░██▀░░█░░█▀█░█▀█░█░░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░▀░░░▀▀▀░▀░▀░░▀░░▀░▀░▀▀▀░▀▀▀░▀▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░█▀▀░█░█░█▀▀░█▀█░█░█░▀█▀░█▀█░█▀█░█░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░▄▄░░░▐█░░│ │░░░░░░░█▀▀░▄▀▄░█▀▀░█░▄░█░█░░█░░█▀█░█▀█░█░░█▀▀░░░░░░░░░░░░▄▄▄░░░▄██▄░░█▀░░░█░▄░│ │░░░░░░░▀▀▀░▀░▀░▀▀▀░▀▀▀░▀▀▀░░▀░░▀░▀░▀▀▀░▀▀░▀▀▀░░░░░░░░░░▄██▀█▌░██▄▄░░▐█▀▄░▐█▀░░│ │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▐█▀▀▌░░░▄▀▌░▌░█░▌░░▌░▌░░│ ╠──────────────────────────────────────────────────────▌▀▄─▐──▀▄─▐▄─▐▄▐▄─▐▄─▐▄─│ │ αcτµαlly pδrταblε εxεcµταblε § ibm personal computer │ ╚─────────────────────────────────────────────────────────────────────────────*/ #ifndef COSMOPOLITAN_LIBC_RUNTIME_PC_H_ #define COSMOPOLITAN_LIBC_RUNTIME_PC_H_ #include "libc/runtime/e820.internal.h" #include "libc/runtime/mman.internal.h" #define BANE -140737488355328 #define BOOTSIG 0xaa55 /* master boot record signature */ #define PC_BIOS_DATA_AREA 0x400 #define kInterruptFlag (1u << 9) /* FPU Status Word (x87) @see Intel Manual V1 §8.1.3 IE: Invalid Operation ────────────────┐ DE: Denormalized Operand ────────────┐│ ZE: Zero Divide ────────────────────┐││ OE: Overflow Flag ─────────────────┐│││ UE: Underflow Flag ───────────────┐││││ PE: Precision Flag ──────────────┐│││││ SF: Stack Fault ────────────────┐││││││ ES: Exception Summary Status ──┐│││││││ C0-3: Condition Codes ──┬────┐ ││││││││ TOP of Stack Pointer ─────┐ │ ││││││││ B: FPU Busy ───────────┐│ │ │ ││││││││ ││┌┴┐┌┼┐││││││││ │↓│ │↓↓↓││││││││*/ #define FPU_IE 0b0000000000000000000000001 #define FPU_DE 0b0000000000000000000000010 #define FPU_ZE 0b0000000000000000000000100 #define FPU_OE 0b0000000000000000000001000 #define FPU_UE 0b0000000000000000000010000 #define FPU_PE 0b0000000000000000000100000 #define FPU_SF 0b0000000000000000001000000 #define FPU_C0 0b0000000000000000100000000 #define FPU_C1 0b0000000000000001000000000 #define FPU_C2 0b0000000000000010000000000 #define FPU_C3 0b0000000000100000000000000 #define CR0_PE 0x01 /* protected mode enabled */ #define CR0_MP 0x02 /* monitor coprocessor */ #define CR0_EM 0x04 /* no x87 fpu present if set */ #define CR0_TS 0x08 /* task switched x87 */ #define CR0_ET 0x10 /* extension type 287 or 387 */ #define CR0_NE 0x20 /* enable x87 error reporting */ #define CR0_WP 0x00010000 /* write protect read-only pages @pl0 */ #define CR0_AM 0x00040000 /* alignment mask */ #define CR0_NW 0x20000000 /* global write-through cache disable */ #define CR0_CD 0x40000000 /* global cache disable */ #define CR0_PG 0x80000000 /* paging enabled */ #define CR4_VME 0x01 /* virtual 8086 mode extension */ #define CR4_PVI 0x02 /* protected mode virtual interrupts */ #define CR4_TSD 0x04 /* time stamp disable (rdtsc) */ #define CR4_DE 0x08 /* debugging extensions */ #define CR4_PSE 0x10 /* page size extension */ #define CR4_PAE 0x20 /* physical address extension */ #define CR4_MCE 0x40 /* machine check exception */ #define CR4_PGE 0x80 /* page global enabled */ #define CR4_OSFXSR 0x0200 /* enable SSE and fxsave/fxrestor */ #define CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */ #define CR4_LA57 0x1000 /* enable level-5 paging */ #define CR4_VMXE 0x2000 /* enable VMX operations */ #define CR4_SMXE 0x4000 /* enable SMX operations */ #define CR4_FSGSBASE 0x00010000 /* enable *FSBASE and *GSBASE instructions */ #define CR4_PCIDE 0x00020000 /* enable process-context identifiers */ #define CR4_OSXSAVE 0x00040000 /* enable XSAVE */ #define XCR0_X87 0x01 #define XCR0_SSE 0x02 #define XCR0_AVX 0x04 #define XCR0_BNDREG 0x08 #define XCR0_BNDCSR 0x10 #define XCR0_OPMASK 0x20 #define XCR0_ZMM_HI256 0x40 #define XCR0_HI16_ZMM 0x80 #define EFER 0xc0000080 /* extended feature enable register */ #define EFER_SCE 0x01 /* system call extensions */ #define EFER_LME 0x0100 /* long mode enable */ #define EFER_LMA 0x0400 /* long mode active */ #define EFER_NXE 0x0800 /* no-execute enable */ #define GDT_REAL_CODE 8 #define GDT_REAL_DATA 16 #define GDT_LEGACY_CODE 24 #define GDT_LEGACY_DATA 32 #define GDT_LONG_CODE 40 #define GDT_LONG_DATA 48 #define GDT_LONG_TSS 56 #define PIC1 0x20 /* IO base address for master PIC */ #define PIC2 0xA0 /* IO base address for slave PIC */ #define PIC1_CMD PIC1 #define PIC1_DATA (PIC1 + 1) #define PIC2_CMD PIC2 #define PIC2_DATA (PIC2 + 1) #define PIC_EOI 0x20 /* End-of-interrupt command code */ #define PIC_READ_IRR 0x0a /* OCW3 irq ready next CMD read */ #define PIC_READ_ISR 0x0b /* OCW3 irq service next CMD read */ /* Long Mode Paging @see Intel Manual V.3A §4.1 §4.5 IsValid (ignored on CR3) V┐ ┌XD:No Inst. Fetches (if NXE) IsWritable (ignored on CR3) RW┐│ │ Permit User-Mode Access - u┐││ │ Page-level Write-Through - PWT┐│││ │ Page-level Cache Disable - PCD┐││││ │ Set if has been read - Accessed┐│││││ │ Set if has been written - Dirty┐││││││ │ IsPage 2MB/1GB (if PDPTE/PDE) or PAT (if PT)┐│││││││ │ (If this maps page and CR4.PGE) Global┐││││││││ │ (If IsPage 2MB/1GB, see Intel V3A § 11.12) PAT │││││││││ │ │ │││││││││ │ ┌─────────────────────────────────────┤ │││││││││ │ Must Be 0┐│ Next Page Table Address (!IsPage) │ │││││││││ │ │├─────────────────────────────────────┤ │││││││││ │ ││ Physical Address 4KB │ │││││││││ │┌──┐┌─────┐│├────────────────────────────┐ │ign│││││││││ ││PK││ ign │││ Physical Address 2MB │ │┌┴┐│││││││││ ││ ││ ││├───────────────────┐ │ ││ ││││││││││ ││ ││ │││ Phys. Addr. 1GB │ │ ││ ││││││││││ ││ ││ │││ │ │ ││ ││││││││││ 6666555555555544444444443333333333222222222211111111110000000000 3210987654321098765432109876543210987654321098765432109876543210*/ #define PAGE_V /* */ 0b000000000001 #define PAGE_RW /* */ 0b000000000010 #define PAGE_U /* */ 0b000000000100 #define PAGE_PCD /* */ 0b000000010000 #define PAGE_PS /* */ 0b000010000000 #define PAGE_G /* */ 0b000100000000 #define PAGE_IGN1 /* */ 0b111000000000 #define PAGE_RSRV /* blinkenlights/libc reservation */ 0b001000000000 #define PAGE_GROD /* blinkenlights MAP_GROWSDOWN */ 0b010000000000 #define PAGE_TA 0x00007ffffffff000 #define PAGE_PA2 0x00007fffffe00000 #define PAGE_IGN2 0x07f0000000000000 #define PAGE_REFC PAGE_IGN2 /* libc reference counting */ #define PAGE_1REF 0x0010000000000000 /* libc reference counting */ #define PAGE_XD 0x8000000000000000 #if !(__ASSEMBLER__ + __LINKER__ + 0) #define invlpg(p) asm volatile("invlpg\t(%0)" : : "r"(p) : "memory") struct IdtDescriptor { uint16_t offset_1; /* offset bits 0..15 */ uint16_t selector; /* a code segment selector in GDT or LDT */ uint8_t ist; /* bits 0..2 hold stack table offset, rest are zero */ uint8_t type_attr; /* type and attributes */ uint16_t offset_2; /* offset bits 16..31 */ uint32_t offset_3; /* offset bits 32..63 */ uint32_t zero; /* reserved */ }; uint64_t *__get_virtual(struct mman *, uint64_t *, int64_t, bool); uint64_t __clear_page(uint64_t); uint64_t __new_page(struct mman *); uint64_t *__invert_memory_area(struct mman *, uint64_t *, uint64_t, uint64_t, uint64_t); void __map_phdrs(struct mman *, uint64_t *, uint64_t, uint64_t); void __reclaim_boot_pages(struct mman *, uint64_t, uint64_t); void __ref_page(struct mman *, uint64_t *, uint64_t); void __ref_pages(struct mman *, uint64_t *, uint64_t, uint64_t); void __unref_page(struct mman *, uint64_t *, uint64_t); /** * Identity maps an area of physical memory to its negative address and * marks it as permanently referenced and unreclaimable (so that it will * never be added to the free list). This is useful for special-purpose * physical memory regions, such as video frame buffers and memory-mapped * I/O devices. */ forceinline void __invert_and_perm_ref_memory_area(struct mman *mm, uint64_t *pml4t, uint64_t ps, uint64_t size, uint64_t pte_flags) { __invert_memory_area(mm, pml4t, ps, size, pte_flags | PAGE_REFC); } forceinline unsigned char inb(unsigned short port) { unsigned char al; asm volatile("inb\t%1,%0" : "=a"(al) : "dN"(port)); return al; } forceinline void outb(unsigned short port, unsigned char byte) { asm volatile("outb\t%0,%1" : /* no inputs */ : "a"(byte), "dN"(port)); } #define __clear_page(page) \ ({ \ long di, cx; \ uintptr_t Page = (uintptr_t)(page); \ asm("rep stosb" \ : "=D"(di), "=c"(cx), "=m"(*(char(*)[4096])Page) \ : "0"(Page), "1"(4096), "a"(0)); \ Page; \ }) #define __get_pml4t() \ ({ \ intptr_t cr3; \ asm("mov\t%%cr3,%0" : "=r"(cr3)); \ (uint64_t *)(BANE + cr3); \ }) #define __get_mm() ((struct mman *)(BANE + 0x0500)) #define __get_mm_phy() ((struct mman *)0x0500) #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_RUNTIME_PC_H_ */