mirror of
				https://github.com/jart/cosmopolitan.git
				synced 2025-10-25 02:30:57 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			220 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			220 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*-*- 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 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 (if PDPTE/PDE) or PAT (if PT)┐│││││││
 | ||
|      │        (If this maps 2MB/1GB 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│││││││││
 | ||
|      ││PKE││ ign │││ Physical Address 2MB      │        │┌┴┐│││││││││
 | ||
|      ││   ││     ││├──────────────────┐        │        ││ ││││││││││
 | ||
|      ││   ││     │││ Phys. Addr. 1GB  │        │        ││ ││││││││││
 | ||
|      ││   ││     │││                  │        │        ││ ││││││││││
 | ||
|      6666555555555544444444443333333333222222222211111111110000000000
 | ||
|      3210987654321098765432109876543210987654321098765432109876543210*/
 | ||
| #define PAGE_V    /*                                */ 0b000000000001
 | ||
| #define PAGE_RW   /*                                */ 0b000000000010
 | ||
| #define PAGE_U    /*                                */ 0b000000000100
 | ||
| #define PAGE_4KB  /*                                */ 0b000010000000
 | ||
| #define PAGE_2MB  /*                                */ 0b000110000000
 | ||
| #define PAGE_1GB  /*                                */ 0b000110000000
 | ||
| #define PAGE_IGN1 /*                                */ 0b111000000000
 | ||
| #define PAGE_RSRV /* blinkenlights reservation      */ 0b001000000000
 | ||
| #define PAGE_GROD /* blinkenlights MAP_GROWSDOWN    */ 0b010000000000
 | ||
| #define PAGE_TA   0x00007ffffffff000
 | ||
| #define PAGE_PA2  0x00007fffffe00000
 | ||
| #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 *);
 | ||
| void __map_phdrs(struct mman *, uint64_t *, uint64_t);
 | ||
| 
 | ||
| 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);         \
 | ||
|   })
 | ||
| 
 | ||
| #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
 | ||
| #endif /* COSMOPOLITAN_LIBC_RUNTIME_PC_H_ */
 |