├── plan9.ini ├── 9bootproto ├── mkfile ├── README ├── LICENSE ├── kern.c ├── mem.h └── l.s /plan9.ini: -------------------------------------------------------------------------------- 1 | bootfile=/amd64/9pc64 2 | -------------------------------------------------------------------------------- /9bootproto: -------------------------------------------------------------------------------- 1 | uid=sys 2 | gid=sys 3 | 386 d775 4 | 9bootfat 664 5 | 9boothyb 664 6 | 9bootiso 664 7 | mbr 664 8 | pbs 664 9 | 10 | cfg d775 11 | plan9.ini 664 12 | 13 | amd64 d775 14 | 9pc64 664 15 | -------------------------------------------------------------------------------- /mkfile: -------------------------------------------------------------------------------- 1 | objtype=amd64 2 | 2 | #include "mem.h" 3 | 4 | enum { 5 | VGA_COLOR_BLACK = 0, 6 | VGA_COLOR_BLUE = 1, 7 | VGA_COLOR_GREEN = 2, 8 | VGA_COLOR_CYAN = 3, 9 | VGA_COLOR_RED = 4, 10 | VGA_COLOR_MAGENTA = 5, 11 | VGA_COLOR_BROWN = 6, 12 | VGA_COLOR_LIGHT_GREY = 7, 13 | VGA_COLOR_DARK_GREY = 8, 14 | VGA_COLOR_LIGHT_BLUE = 9, 15 | VGA_COLOR_LIGHT_GREEN = 10, 16 | VGA_COLOR_LIGHT_CYAN = 11, 17 | VGA_COLOR_LIGHT_RED = 12, 18 | VGA_COLOR_LIGHT_MAGENTA = 13, 19 | VGA_COLOR_LIGHT_BROWN = 14, 20 | VGA_COLOR_WHITE = 15, 21 | }; 22 | 23 | u32int MemMin; 24 | u16int *terminal; 25 | 26 | u8int 27 | mkcolor(int fg, int bg) 28 | { 29 | return fg | bg << 4; 30 | } 31 | 32 | u16int 33 | mkchar(uchar c, u8int color) 34 | { 35 | return (u16int) c | (u16int) color << 8; 36 | } 37 | 38 | void 39 | writestr(char *s, int len, u8int color) 40 | { 41 | int i; 42 | for(i=0;i (b)? (a): (b)) 13 | 14 | #define ALIGNED(p, a) (!(((uintptr)(p)) & ((a)-1))) 15 | 16 | /* 17 | * Sizes 18 | */ 19 | #define BI2BY 8 /* bits per byte */ 20 | #define BI2WD 32 /* bits per word */ 21 | #define BY2WD 8 /* bytes per word */ 22 | #define BY2V 8 /* bytes per double word */ 23 | #define BY2PG (0x1000ull) /* bytes per page */ 24 | #define WD2PG (BY2PG/BY2WD) /* words per page */ 25 | #define PGSHIFT 12 /* log(BY2PG) */ 26 | #define ROUND(s, sz) (((s)+((sz)-1))&~((sz)-1)) 27 | #define PGROUND(s) ROUND(s, BY2PG) 28 | #define BLOCKALIGN 8 29 | #define FPalign 16 30 | 31 | #define MAXMACH 128 /* max # cpus system can run */ 32 | 33 | #define KSTACK (16*KiB) /* Size of Proc kernel stack */ 34 | 35 | /* 36 | * Time 37 | */ 38 | #define HZ (100) /* clock frequency */ 39 | #define MS2HZ (1000/HZ) /* millisec per clock tick */ 40 | #define TK2SEC(t) ((t)/HZ) /* ticks to seconds */ 41 | 42 | /* 43 | * Address spaces. User: 44 | */ 45 | #define UTZERO (0x0000000000200000ull) /* first address in user text */ 46 | #define UADDRMASK (0x00007fffffffffffull) /* canonical address mask */ 47 | #define USTKTOP (0x00007ffffffff000ull) 48 | #define USTKSIZE (16*MiB) /* size of user stack */ 49 | 50 | /* 51 | * Address spaces. Kernel, sorted by address. 52 | */ 53 | #define KZERO (0xffffffff80000000ull) 54 | #define KTZERO (KZERO+1*MiB+64*KiB) 55 | 56 | #define VMAP (0xffffff0000000000ull) 57 | #define VMAPSIZE (512ull*GiB) 58 | 59 | #define KMAP (0xfffffe8000000000ull) 60 | #define KMAPSIZE (2*MiB) 61 | 62 | /* 63 | * Fundamental addresses - bottom 64kB saved for return to real mode 64 | */ 65 | #define CONFADDR (KZERO+0x1200ull) /* info passed from boot loader */ 66 | #define APBOOTSTRAP (KZERO+0x7000ull) /* AP bootstrap code */ 67 | #define IDTADDR (KZERO+0x10000ull) /* idt */ 68 | #define REBOOTADDR (0x11000) /* reboot code - physical address */ 69 | 70 | #define CPU0PML4 (KZERO+0x13000ull) 71 | #define CPU0PDP (KZERO+0x14000ull) 72 | #define CPU0PD0 (KZERO+0x15000ull) /* KZERO */ 73 | #define CPU0PD1 (KZERO+0x16000ull) /* KZERO+1GB */ 74 | 75 | #define CPU0GDT (KZERO+0x17000ull) /* bootstrap processor GDT */ 76 | 77 | #define CPU0MACH (KZERO+0x18000ull) /* Mach for bootstrap processor */ 78 | #define CPU0END (CPU0MACH+MACHSIZE) 79 | 80 | #define MACHSIZE (2*KSTACK) 81 | 82 | /* 83 | * Where configuration info is left for the loaded programme. 84 | * There are 24064 bytes available at CONFADDR. 85 | */ 86 | #define BOOTLINE ((char*)CONFADDR) 87 | #define BOOTLINELEN 64 88 | #define BOOTARGS ((char*)(CONFADDR+BOOTLINELEN)) 89 | #define BOOTARGSLEN (0x6000-0x200-BOOTLINELEN) 90 | 91 | /* 92 | * known x86 segments (in GDT) and their selectors 93 | */ 94 | #define NULLSEG 0 /* null segment */ 95 | #define KESEG 1 /* kernel executable */ 96 | #define KDSEG 2 /* kernel data */ 97 | #define UE32SEG 3 /* user executable 32bit */ 98 | #define UDSEG 4 /* user data/stack */ 99 | #define UESEG 5 /* user executable 64bit */ 100 | #define TSSSEG 8 /* task segment (two descriptors) */ 101 | 102 | #define NGDT 10 /* number of GDT entries required */ 103 | 104 | #define SELGDT (0<<2) /* selector is in gdt */ 105 | #define SELLDT (1<<2) /* selector is in ldt */ 106 | 107 | #define SELECTOR(i, t, p) (((i)<<3) | (t) | (p)) 108 | 109 | #define NULLSEL SELECTOR(NULLSEG, SELGDT, 0) 110 | #define KDSEL NULLSEL 111 | #define KESEL SELECTOR(KESEG, SELGDT, 0) 112 | #define UE32SEL SELECTOR(UE32SEG, SELGDT, 3) 113 | #define UDSEL SELECTOR(UDSEG, SELGDT, 3) 114 | #define UESEL SELECTOR(UESEG, SELGDT, 3) 115 | #define TSSSEL SELECTOR(TSSSEG, SELGDT, 0) 116 | 117 | /* 118 | * fields in segment descriptors 119 | */ 120 | #define SEGDATA (0x10<<8) /* data/stack segment */ 121 | #define SEGEXEC (0x18<<8) /* executable segment */ 122 | #define SEGTSS (0x9<<8) /* TSS segment */ 123 | #define SEGCG (0x0C<<8) /* call gate */ 124 | #define SEGIG (0x0E<<8) /* interrupt gate */ 125 | #define SEGTG (0x0F<<8) /* trap gate */ 126 | #define SEGLDT (0x02<<8) /* local descriptor table */ 127 | #define SEGTYPE (0x1F<<8) 128 | 129 | #define SEGP (1<<15) /* segment present */ 130 | #define SEGPL(x) ((x)<<13) /* priority level */ 131 | #define SEGB (1<<22) /* granularity 1==4k (for expand-down) */ 132 | #define SEGD (1<<22) /* default 1==32bit (for code) */ 133 | #define SEGE (1<<10) /* expand down */ 134 | #define SEGW (1<<9) /* writable (for data/stack) */ 135 | #define SEGR (1<<9) /* readable (for code) */ 136 | #define SEGL (1<<21) /* 64 bit */ 137 | #define SEGG (1<<23) /* granularity 1==4k (for other) */ 138 | 139 | /* 140 | * virtual MMU 141 | */ 142 | #define PTEMAPMEM (1ull*MiB) 143 | #define PTEPERTAB (PTEMAPMEM/BY2PG) 144 | #define SEGMAPSIZE 65536 145 | #define SSEGMAPSIZE 16 146 | #define PPN(x) ((x)&~(1ull<<63 | BY2PG-1)) 147 | 148 | /* 149 | * physical MMU 150 | */ 151 | #define PTEVALID (1ull<<0) 152 | #define PTEWT (1ull<<3) 153 | #define PTEUNCACHED (1ull<<4) 154 | #define PTECACHED (0ull<<4) 155 | #define PTEWRITE (1ull<<1) 156 | #define PTERONLY (0ull<<1) 157 | #define PTEKERNEL (0ull<<2) 158 | #define PTEUSER (1ull<<2) 159 | #define PTESIZE (1ull<<7) 160 | #define PTEGLOBAL (1ull<<8) 161 | #define PTENOEXEC ((uvlong)m->havenx<<63) 162 | 163 | /* 164 | * Hierarchical Page Tables. 165 | * For example, traditional IA-32 paging structures have 2 levels, 166 | * level 1 is the PD, and level 0 the PT pages; with IA-32e paging, 167 | * level 3 is the PML4(!), level 2 the PDP, level 1 the PD, 168 | * and level 0 the PT pages. The PTLX macro gives an index into the 169 | * page-table page at level 'l' for the virtual address 'v'. 170 | */ 171 | #define PTSZ (4*KiB) /* page table page size */ 172 | #define PTSHIFT 9 /* */ 173 | 174 | #define PTLX(v, l) (((v)>>(((l)*PTSHIFT)+PGSHIFT)) & ((1< */ 180 | #define RUSER R14 /* up-> */ 181 | -------------------------------------------------------------------------------- /l.s: -------------------------------------------------------------------------------- 1 | #include "mem.h" 2 | 3 | MODE $32 4 | 5 | #define DELAY BYTE $0xEB; BYTE $0x00 /* JMP .+2 */ 6 | 7 | #define pFARJMP32(s, o) BYTE $0xea; /* far jump to ptr32:16 */\ 8 | LONG $o; WORD $s 9 | 10 | /* 11 | * Enter here in 32-bit protected mode. Welcome to 1982. 12 | * Make sure the GDT is set as it should be: 13 | * disable interrupts; 14 | * load the GDT with the table in _gdt32p; 15 | * load all the data segments 16 | * load the code segment via a far jump. 17 | */ 18 | TEXT _protected<>(SB), 1, $-4 19 | CLI 20 | 21 | MOVL $_gdtptr32p<>-KZERO(SB), AX 22 | MOVL (AX), GDTR 23 | 24 | MOVL $SELECTOR(2, SELGDT, 0), AX 25 | MOVW AX, DS 26 | MOVW AX, ES 27 | MOVW AX, FS 28 | MOVW AX, GS 29 | MOVW AX, SS 30 | 31 | pFARJMP32(SELECTOR(3, SELGDT, 0), _warp64<>-KZERO(SB)) 32 | 33 | BYTE $0x90 /* align */ 34 | 35 | /* 36 | * Must be 4-byte aligned. 37 | */ 38 | TEXT _multibootheader<>(SB), 1, $-4 39 | LONG $0x1BADB002 /* magic */ 40 | LONG $0x00010007 /* flags */ 41 | LONG $-(0x1BADB002 + 0x00010007) /* checksum */ 42 | LONG $_multibootheader<>-KZERO(SB) /* header_addr */ 43 | LONG $_protected<>-KZERO(SB) /* load_addr */ 44 | LONG $edata-KZERO(SB) /* load_end_addr */ 45 | LONG $end-KZERO(SB) /* bss_end_addr */ 46 | LONG $_multibootentry<>-KZERO(SB) /* entry_addr */ 47 | LONG $0 /* mode_type */ 48 | LONG $0 /* width */ 49 | LONG $0 /* height */ 50 | LONG $32 /* depth */ 51 | 52 | /* 53 | * the kernel expects the data segment to be page-aligned 54 | * multiboot bootloaders put the data segment right behind text 55 | */ 56 | TEXT _multibootentry<>(SB), 1, $-4 57 | MOVL $etext-KZERO(SB), SI 58 | MOVL SI, DI 59 | ADDL $(BY2PG-1), DI 60 | ANDL $~(BY2PG-1), DI 61 | MOVL $edata-KZERO(SB), CX 62 | SUBL DI, CX 63 | ADDL CX, SI 64 | ADDL CX, DI 65 | INCL CX /* one more for post decrement */ 66 | STD 67 | REP; MOVSB 68 | MOVL BX, multibootptr-KZERO(SB) 69 | MOVL $_protected<>-KZERO(SB), AX 70 | JMP* AX 71 | 72 | /* multiboot structure pointer (physical address) */ 73 | TEXT multibootptr(SB), 1, $-4 74 | LONG $0 75 | 76 | TEXT _gdt<>(SB), 1, $-4 77 | /* null descriptor */ 78 | LONG $0 79 | LONG $0 80 | 81 | /* (KESEG) 64 bit long mode exec segment */ 82 | LONG $(0xFFFF) 83 | LONG $(SEGL|SEGG|SEGP|(0xF<<16)|SEGPL(0)|SEGEXEC|SEGR) 84 | 85 | /* 32 bit data segment descriptor for 4 gigabytes (PL 0) */ 86 | LONG $(0xFFFF) 87 | LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW) 88 | 89 | /* 32 bit exec segment descriptor for 4 gigabytes (PL 0) */ 90 | LONG $(0xFFFF) 91 | LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR) 92 | 93 | 94 | TEXT _gdtptr32p<>(SB), 1, $-4 95 | WORD $(4*8-1) 96 | LONG $_gdt<>-KZERO(SB) 97 | 98 | TEXT _gdtptr64p<>(SB), 1, $-4 99 | WORD $(4*8-1) 100 | QUAD $_gdt<>-KZERO(SB) 101 | 102 | TEXT _gdtptr64v<>(SB), 1, $-4 103 | WORD $(4*8-1) 104 | QUAD $_gdt<>(SB) 105 | 106 | /* 107 | * Macros for accessing page table entries; change the 108 | * C-style array-index macros into a page table byte offset 109 | */ 110 | #define PML4O(v) ((PTLX((v), 3))<<3) 111 | #define PDPO(v) ((PTLX((v), 2))<<3) 112 | #define PDO(v) ((PTLX((v), 1))<<3) 113 | #define PTO(v) ((PTLX((v), 0))<<3) 114 | 115 | TEXT _warp64<>(SB), 1, $-4 116 | 117 | /* clear mach and page tables */ 118 | MOVL $((CPU0END-CPU0PML4)>>2), CX 119 | MOVL $(CPU0PML4-KZERO), SI 120 | MOVL SI, DI 121 | XORL AX, AX 122 | CLD 123 | REP; STOSL 124 | 125 | MOVL SI, AX /* PML4 */ 126 | MOVL AX, DX 127 | ADDL $(PTSZ|PTEWRITE|PTEVALID), DX /* PDP at PML4 + PTSZ */ 128 | MOVL DX, PML4O(0)(AX) /* PML4E for double-map */ 129 | MOVL DX, PML4O(KZERO)(AX) /* PML4E for KZERO */ 130 | 131 | ADDL $PTSZ, AX /* PDP at PML4 + PTSZ */ 132 | ADDL $PTSZ, DX /* PD0 at PML4 + 2*PTSZ */ 133 | MOVL DX, PDPO(0)(AX) /* PDPE for double-map */ 134 | MOVL DX, PDPO(KZERO)(AX) /* PDPE for KZERO */ 135 | 136 | /* 137 | * add PDPE for KZERO+1GB early as Vmware 138 | * hangs when modifying kernel PDP 139 | */ 140 | ADDL $PTSZ, DX /* PD1 */ 141 | MOVL DX, PDPO(KZERO+GiB)(AX) 142 | 143 | ADDL $PTSZ, AX /* PD0 at PML4 + 2*PTSZ */ 144 | MOVL $(PTESIZE|PTEGLOBAL|PTEWRITE|PTEVALID), DX 145 | MOVL DX, PDO(0)(AX) /* PDE for double-map */ 146 | 147 | /* 148 | * map from KZERO to end using 2MB pages 149 | */ 150 | ADDL $PDO(KZERO), AX 151 | MOVL $end-KZERO(SB), CX 152 | 153 | ADDL $(16*1024), CX /* qemu puts multiboot data after the kernel */ 154 | 155 | ADDL $(PGLSZ(1)-1), CX 156 | ANDL $~(PGLSZ(1)-1), CX 157 | MOVL CX, MemMin-KZERO(SB) /* see memory.c */ 158 | SHRL $(1*PTSHIFT+PGSHIFT), CX 159 | memloop: 160 | MOVL DX, (AX) 161 | ADDL $PGLSZ(1), DX 162 | ADDL $8, AX 163 | LOOP memloop 164 | 165 | /* 166 | * Enable and activate Long Mode. From the manual: 167 | * make sure Page Size Extentions are off, and Page Global 168 | * Extensions and Physical Address Extensions are on in CR4; 169 | * set Long Mode Enable in the Extended Feature Enable MSR; 170 | * set Paging Enable in CR0; 171 | * make an inter-segment jump to the Long Mode code. 172 | * It's all in 32-bit mode until the jump is made. 173 | */ 174 | TEXT _lme<>(SB), 1, $-4 175 | MOVL SI, CR3 /* load the mmu */ 176 | DELAY 177 | 178 | MOVL CR4, AX 179 | ANDL $~0x00000010, AX /* Page Size */ 180 | ORL $0x000000A0, AX /* Page Global, Phys. Address */ 181 | MOVL AX, CR4 182 | 183 | MOVL $0xc0000080, CX /* Extended Feature Enable */ 184 | RDMSR 185 | ORL $0x00000100, AX /* Long Mode Enable */ 186 | WRMSR 187 | 188 | MOVL CR0, DX 189 | ANDL $~0x6000000a, DX 190 | ORL $0x80010000, DX /* Paging Enable, Write Protect */ 191 | MOVL DX, CR0 192 | 193 | pFARJMP32(SELECTOR(KESEG, SELGDT, 0), _identity<>-KZERO(SB)) 194 | 195 | /* 196 | * Long mode. Welcome to 2003. 197 | * Jump out of the identity map space; 198 | * load a proper long mode GDT. 199 | */ 200 | MODE $64 201 | 202 | TEXT _identity<>(SB), 1, $-4 203 | MOVQ $_start64v<>(SB), AX 204 | JMP* AX 205 | 206 | TEXT _start64v<>(SB), 1, $-4 207 | MOVQ $_gdtptr64v<>(SB), AX 208 | MOVL (AX), GDTR 209 | 210 | XORQ AX, AX 211 | MOVW AX, DS /* not used in long mode */ 212 | MOVW AX, ES /* not used in long mode */ 213 | MOVW AX, FS 214 | MOVW AX, GS 215 | MOVW AX, SS /* not used in long mode */ 216 | 217 | MOVW AX, LDTR 218 | 219 | MOVQ $(CPU0MACH+MACHSIZE), SP 220 | MOVQ $(CPU0MACH), RMACH 221 | MOVQ AX, RUSER /* up = 0; */ 222 | 223 | _clearbss: 224 | MOVQ $edata(SB), DI 225 | MOVQ $end(SB), CX 226 | SUBQ DI, CX /* end-edata bytes */ 227 | SHRQ $2, CX /* end-edata doublewords */ 228 | 229 | CLD 230 | REP; STOSL /* clear BSS */ 231 | 232 | PUSHQ AX /* clear flags */ 233 | POPFQ 234 | 235 | CALL main(SB) 236 | 237 | /* 238 | * Park a processor. Should never fall through a return from main to here, 239 | * should only be called by application processors when shutting down. 240 | */ 241 | TEXT idle(SB), 1, $-4 242 | _idle: 243 | STI 244 | HLT 245 | JMP _idle 246 | 247 | /* 248 | * The CPUID instruction is always supported on the amd64. 249 | */ 250 | TEXT cpuid(SB), $-4 251 | MOVL RARG, AX /* function in AX */ 252 | CPUID 253 | 254 | MOVQ info+8(FP), BP 255 | MOVL AX, 0(BP) 256 | MOVL BX, 4(BP) 257 | MOVL CX, 8(BP) 258 | MOVL DX, 12(BP) 259 | RET 260 | 261 | /* 262 | * Port I/O. 263 | */ 264 | TEXT inb(SB), 1, $-4 265 | MOVL RARG, DX /* MOVL port+0(FP), DX */ 266 | XORL AX, AX 267 | INB 268 | RET 269 | 270 | TEXT insb(SB), 1, $-4 271 | MOVL RARG, DX /* MOVL port+0(FP), DX */ 272 | MOVQ address+8(FP), DI 273 | MOVL count+16(FP), CX 274 | CLD 275 | REP; INSB 276 | RET 277 | 278 | TEXT ins(SB), 1, $-4 279 | MOVL RARG, DX /* MOVL port+0(FP), DX */ 280 | XORL AX, AX 281 | INW 282 | RET 283 | 284 | TEXT inss(SB), 1, $-4 285 | MOVL RARG, DX /* MOVL port+0(FP), DX */ 286 | MOVQ address+8(FP), DI 287 | MOVL count+16(FP), CX 288 | CLD 289 | REP; INSW 290 | RET 291 | 292 | TEXT inl(SB), 1, $-4 293 | MOVL RARG, DX /* MOVL port+0(FP), DX */ 294 | INL 295 | RET 296 | 297 | TEXT insl(SB), 1, $-4 298 | MOVL RARG, DX /* MOVL port+0(FP), DX */ 299 | MOVQ address+8(FP), DI 300 | MOVL count+16(FP), CX 301 | CLD 302 | REP; INSL 303 | RET 304 | 305 | TEXT outb(SB), 1, $-1 306 | MOVL RARG, DX /* MOVL port+0(FP), DX */ 307 | MOVL byte+8(FP), AX 308 | OUTB 309 | RET 310 | 311 | TEXT outsb(SB), 1, $-4 312 | MOVL RARG, DX /* MOVL port+0(FP), DX */ 313 | MOVQ address+8(FP), SI 314 | MOVL count+16(FP), CX 315 | CLD 316 | REP; OUTSB 317 | RET 318 | 319 | TEXT outs(SB), 1, $-4 320 | MOVL RARG, DX /* MOVL port+0(FP), DX */ 321 | MOVL short+8(FP), AX 322 | OUTW 323 | RET 324 | 325 | TEXT outss(SB), 1, $-4 326 | MOVL RARG, DX /* MOVL port+0(FP), DX */ 327 | MOVQ address+8(FP), SI 328 | MOVL count+16(FP), CX 329 | CLD 330 | REP; OUTSW 331 | RET 332 | 333 | TEXT outl(SB), 1, $-4 334 | MOVL RARG, DX /* MOVL port+0(FP), DX */ 335 | MOVL long+8(FP), AX 336 | OUTL 337 | RET 338 | 339 | TEXT outsl(SB), 1, $-4 340 | MOVL RARG, DX /* MOVL port+0(FP), DX */ 341 | MOVQ address+8(FP), SI 342 | MOVL count+16(FP), CX 343 | CLD 344 | REP; OUTSL 345 | RET 346 | 347 | TEXT getgdt(SB), 1, $-4 348 | MOVQ RARG, AX 349 | MOVL GDTR, (AX) /* Note: 10 bytes returned */ 350 | RET 351 | 352 | TEXT lgdt(SB), $0 /* GDTR - global descriptor table */ 353 | MOVQ RARG, AX 354 | MOVL (AX), GDTR 355 | RET 356 | 357 | TEXT lidt(SB), $0 /* IDTR - interrupt descriptor table */ 358 | MOVQ RARG, AX 359 | MOVL (AX), IDTR 360 | RET 361 | 362 | TEXT ltr(SB), 1, $-4 363 | MOVW RARG, AX 364 | MOVW AX, TASK 365 | RET 366 | --------------------------------------------------------------------------------