├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── boot └── x86_64 │ ├── Makefile │ ├── entry64.S │ ├── entryother.S │ ├── include │ ├── asm.h │ ├── defs.h │ ├── memlayout.h │ ├── mmu.h │ ├── param.h │ ├── proc.h │ ├── syscall.h │ ├── traps.h │ ├── types.h │ └── x86.h │ ├── initcode64.S │ ├── kernel64.ld │ └── main.c ├── console.nim ├── consts.nim ├── kalloc.nim ├── main.nim ├── memlayout.nim ├── mmu.nim ├── panicoverride.nim ├── procs.nim ├── spinlock.nim ├── stdlib.nim ├── types.nim ├── uart.nim ├── vm64.nim └── x86asm.nim /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | \#* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Kashyap 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | make -C boot/x86_64 3 | $(NIM) c --noLinking --os:standalone --deadCodeElim:on --noMain --parallelBuild:1 --gcc.exe:$(GCC) --passC:"-I$(NIM)/tinyc/win32/include" --passC:"-w" --passC:"-O2" --passC:"-Wall" --passC:"-Wextra" --passC:"-ffreestanding" --passC:"-mcmodel=kernel" --threads:on main.nim 4 | $(LD) -m elf_x86_64 -nodefaultlibs -nostdlib -T boot/x86_64/kernel64.ld -o kernel.elf boot/x86_64/entry64.o boot/x86_64/main.o nimcache/*.o -b binary boot/x86_64/initcode boot/x86_64/entryother 5 | 6 | 7 | run: kernel.elf 8 | $(QEMU) -kernel kernel.elf -vnc :1 -s -serial stdio 9 | 10 | clean: 11 | rm -rf nimcache/ 12 | rm -f kernel.elf 13 | make -C boot/x86_64 clean 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nim-xv6 2 | Translate xv6 to nim 3 | 4 | 5 | ## Build 6 | Build depends on a devel version of Nim (0.10.3) and a C compiler that can emit x86_64 7 | 8 | ```bash 9 | export GCC=gcc 10 | export LD=ld 11 | export OBJCOPY=objcopy 12 | export NIM=nim 13 | export QEMU=qemu-system-x86_64 14 | make 15 | 16 | 17 | While working on this I realized that instead of trying to build up 18 | the kernel from scratch in Nim, a potentially better approach could be 19 | to "infuse" Nim into working kernel. This way, I could have a "working 20 | kernel" all the time. So I started 21 | git@github.com:ckkashyap/nimxv6.git - and looks like the idea is 22 | working. I took a working 64bit C version of xv6 and replaced uart.c 23 | with uart.nim and it works! So, essentially, I have a working kernel 24 | that has Nim source in it. Now, it's a matter of replacing more and 25 | more of the C source with Nim - but always having the pleasure of a 26 | working unix kernel. 27 | -------------------------------------------------------------------------------- /boot/x86_64/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | $(GCC) -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -MD -ggdb -fno-omit-frame-pointer -ffreestanding -fno-common -nostdlib -Iinclude -gdwarf-2 -m64 -DX64 -mcmodel=kernel -mtls-direct-seg-refs -mno-red-zone -O0 -fno-stack-protector -nostdinc -I. -o initcode.o -c initcode64.S 3 | $(LD) -m elf_x86_64 -nodefaultlibs -N -e start -Ttext 0 -o initcode.out initcode.o 4 | $(OBJCOPY) -S -O binary initcode.out initcode 5 | $(GCC) -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -MD -ggdb -fno-omit-frame-pointer -ffreestanding -fno-common -nostdlib -Iinclude -gdwarf-2 -m64 -DX64 -mcmodel=kernel -mtls-direct-seg-refs -mno-red-zone -O0 -fno-stack-protector -fno-pic -nostdinc -I. -o entryother.o -c entryother.S 6 | $(LD) -m elf_x86_64 -nodefaultlibs -N -e start -Ttext 0x7000 -o bootblockother.o entryother.o 7 | $(OBJCOPY) -S -O binary -j .text bootblockother.o entryother 8 | $(GCC) -gdwarf-2 -Wa,-divide -Iinclude -m64 -DX64 -mcmodel=kernel -mtls-direct-seg-refs -mno-red-zone -c -o entry64.o entry64.S 9 | $(GCC) -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -MD -ggdb -fno-omit-frame-pointer -ffreestanding -fno-common -nostdlib -Iinclude -gdwarf-2 -m64 -DX64 -mcmodel=kernel -mtls-direct-seg-refs -mno-red-zone -O0 -fno-stack-protector -c -o main.o main.c 10 | #ld -m elf_x86_64 -nodefaultlibs -T kernel64.ld -o kernel.elf entry64.o main.o -b binary initcode entryother 11 | 12 | 13 | clean: 14 | rm -f initcode.o initcode.out initcode entryother.o entryother bootblockother.o entry64.o main.o kernel.elf *.d 15 | 16 | 17 | run: 18 | qemu-system-x86_64 -kernel kernel.elf -vnc :1 -no-reboot -d int 19 | -------------------------------------------------------------------------------- /boot/x86_64/entry64.S: -------------------------------------------------------------------------------- 1 | /* entry64.S 2 | * 3 | * Copyright (c) 2013 Brian Swetland 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #define mboot_magic 0x1badb002 27 | #define mboot_flags 0x00010000 28 | 29 | .code32 30 | .global mboot_header 31 | .global mboot_entry 32 | 33 | mboot_header: 34 | .long mboot_magic 35 | .long mboot_flags 36 | .long (-mboot_magic -mboot_flags) # checksum 37 | .long mboot_load_addr # header_addr 38 | .long mboot_load_addr 39 | .long mboot_load_end 40 | .long mboot_bss_end 41 | .long mboot_entry_addr 42 | 43 | mboot_entry: 44 | 45 | # zero 4 pages for our bootstrap page tables 46 | xor %eax, %eax 47 | mov $0x1000, %edi 48 | mov $0x5000, %ecx 49 | rep stosb 50 | 51 | # P4ML[0] -> 0x2000 (PDPT-A) 52 | mov $(0x2000 | 3), %eax 53 | mov %eax, 0x1000 54 | 55 | # P4ML[511] -> 0x3000 (PDPT-B) 56 | mov $(0x3000 | 3), %eax 57 | mov %eax, 0x1FF8 58 | 59 | # PDPT-A[0] -> 0x4000 (PD) 60 | mov $(0x4000 | 3), %eax 61 | mov %eax, 0x2000 62 | 63 | # PDPT-B[510] -> 0x4000 (PD) 64 | mov $(0x4000 | 3), %eax 65 | mov %eax, 0x3FF0 66 | 67 | # PD[0..511] -> 0..1022MB 68 | mov $0x83, %eax 69 | mov $0x4000, %ebx 70 | mov $512, %ecx 71 | ptbl_loop: 72 | mov %eax, (%ebx) 73 | add $0x200000, %eax 74 | add $0x8, %ebx 75 | dec %ecx 76 | jnz ptbl_loop 77 | 78 | # Clear ebx for initial processor boot. 79 | # When secondary processors boot, they'll call through 80 | # entry32mp (from entryother), but with a nonzero ebx. 81 | # We'll reuse these bootstrap pagetables and GDT. 82 | xor %ebx, %ebx 83 | 84 | .global entry32mp 85 | entry32mp: 86 | # CR3 -> 0x1000 (P4ML) 87 | mov $0x1000, %eax 88 | mov %eax, %cr3 89 | 90 | lgdt (gdtr64 - mboot_header + mboot_load_addr) 91 | 92 | # Enable PAE - CR4.PAE=1 93 | mov %cr4, %eax 94 | bts $5, %eax 95 | mov %eax, %cr4 96 | 97 | # enable long mode - EFER.LME=1 98 | mov $0xc0000080, %ecx 99 | rdmsr 100 | bts $8, %eax 101 | wrmsr 102 | 103 | # enable paging 104 | mov %cr0, %eax 105 | bts $31, %eax 106 | mov %eax, %cr0 107 | 108 | # shift to 64bit segment 109 | ljmp $8,$(entry64low - mboot_header + mboot_load_addr) 110 | 111 | .align 16 112 | gdtr64: 113 | .word gdt64_end - gdt64_begin - 1; 114 | .quad gdt64_begin - mboot_header + mboot_load_addr 115 | 116 | .align 16 117 | gdt64_begin: 118 | .long 0x00000000 # 0: null desc 119 | .long 0x00000000 120 | .long 0x00000000 # 1: Code, R/X, Nonconforming 121 | .long 0x00209800 122 | .long 0x00000000 # 2: Data, R/W, Expand Down 123 | .long 0x00009000 124 | gdt64_end: 125 | 126 | .align 16 127 | .code64 128 | entry64low: 129 | movq $entry64high, %rax 130 | jmp *%rax 131 | 132 | .global _start 133 | _start: 134 | entry64high: 135 | 136 | # ensure data segment registers are sane 137 | xor %rax, %rax 138 | mov %ax, %ss 139 | mov %ax, %ds 140 | mov %ax, %es 141 | mov %ax, %fs 142 | mov %ax, %gs 143 | 144 | # check to see if we're booting a secondary core 145 | test %ebx, %ebx 146 | jnz entry64mp 147 | 148 | # setup initial stack 149 | mov $0xFFFFFFFF80010000, %rax 150 | mov %rax, %rsp 151 | 152 | # enter main() 153 | jmp main 154 | 155 | .global __deadloop 156 | __deadloop: 157 | # we should never return here... 158 | jmp . 159 | 160 | entry64mp: 161 | # obtain kstack from data block before entryother 162 | mov $0x7000, %rax 163 | mov -16(%rax), %rsp 164 | jmp mpenter 165 | 166 | .global wrmsr 167 | wrmsr: 168 | mov %rdi, %rcx # arg0 -> msrnum 169 | mov %rsi, %rax # val.low -> eax 170 | shr $32, %rsi 171 | mov %rsi, %rdx # val.high -> edx 172 | wrmsr 173 | retq 174 | 175 | -------------------------------------------------------------------------------- /boot/x86_64/entryother.S: -------------------------------------------------------------------------------- 1 | #include "asm.h" 2 | #include "memlayout.h" 3 | #include "mmu.h" 4 | 5 | # Each non-boot CPU ("AP") is started up in response to a STARTUP 6 | # IPI from the boot CPU. Section B.4.2 of the Multi-Processor 7 | # Specification says that the AP will start in real mode with CS:IP 8 | # set to XY00:0000, where XY is an 8-bit value sent with the 9 | # STARTUP. Thus this code must start at a 4096-byte boundary. 10 | # 11 | # Because this code sets DS to zero, it must sit 12 | # at an address in the low 2^16 bytes. 13 | # 14 | # Startothers (in main.c) sends the STARTUPs one at a time. 15 | # It copies this code (start) at 0x7000. It puts the address of 16 | # a newly allocated per-core stack in start-4,the address of the 17 | # place to jump to (mpenter) in start-8, and the physical address 18 | # of entrypgdir in start-12. 19 | # 20 | # This code is identical to bootasm.S except: 21 | # - it does not need to enable A20 22 | # - it uses the address at start-4, start-8, and start-12 23 | 24 | .code16 25 | .globl start 26 | start: 27 | cli 28 | 29 | xorw %ax,%ax 30 | movw %ax,%ds 31 | movw %ax,%es 32 | movw %ax,%ss 33 | 34 | lgdt gdtdesc 35 | movl %cr0, %eax 36 | orl $CR0_PE, %eax 37 | movl %eax, %cr0 38 | 39 | //PAGEBREAK! 40 | ljmpl $(SEG_KCODE<<3), $(start32) 41 | 42 | .code32 43 | start32: 44 | movw $(SEG_KDATA<<3), %ax 45 | movw %ax, %ds 46 | movw %ax, %es 47 | movw %ax, %ss 48 | movw $0, %ax 49 | movw %ax, %fs 50 | movw %ax, %gs 51 | 52 | #if X64 53 | # defer paging until we switch to 64bit mode 54 | # set ebx=1 so shared boot code knows we're booting a secondary core 55 | mov $1, %ebx 56 | #else 57 | # Turn on page size extension for 4Mbyte pages 58 | movl %cr4, %eax 59 | orl $(CR4_PSE), %eax 60 | movl %eax, %cr4 61 | # Use enterpgdir as our initial page table 62 | movl (start-12), %eax 63 | movl %eax, %cr3 64 | # Turn on paging. 65 | movl %cr0, %eax 66 | orl $(CR0_PE|CR0_PG|CR0_WP), %eax 67 | movl %eax, %cr0 68 | #endif 69 | 70 | # Switch to the stack allocated by startothers() 71 | movl (start-4), %esp 72 | # Call mpenter() 73 | call *(start-8) 74 | 75 | movw $0x8a00, %ax 76 | movw %ax, %dx 77 | outw %ax, %dx 78 | movw $0x8ae0, %ax 79 | outw %ax, %dx 80 | spin: 81 | jmp spin 82 | 83 | .p2align 2 84 | gdt: 85 | SEG_NULLASM 86 | SEG_ASM(STA_X|STA_R, 0, 0xffffffff) 87 | SEG_ASM(STA_W, 0, 0xffffffff) 88 | 89 | 90 | gdtdesc: 91 | .word (gdtdesc - gdt - 1) 92 | .long gdt 93 | 94 | -------------------------------------------------------------------------------- /boot/x86_64/include/asm.h: -------------------------------------------------------------------------------- 1 | // 2 | // assembler macros to create x86 segments 3 | // 4 | 5 | #define SEG_NULLASM \ 6 | .word 0, 0; \ 7 | .byte 0, 0, 0, 0 8 | 9 | // The 0xC0 means the limit is in 4096-byte units 10 | // and (for executable segments) 32-bit mode. 11 | #define SEG_ASM(type,base,lim) \ 12 | .word (((lim) >> 12) & 0xffff), ((base) & 0xffff); \ 13 | .byte (((base) >> 16) & 0xff), (0x90 | (type)), \ 14 | (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff) 15 | 16 | #define STA_X 0x8 // Executable segment 17 | #define STA_E 0x4 // Expand down (non-executable segments) 18 | #define STA_C 0x4 // Conforming code segment (executable only) 19 | #define STA_W 0x2 // Writeable (non-executable segments) 20 | #define STA_R 0x2 // Readable (executable segments) 21 | #define STA_A 0x1 // Accessed 22 | -------------------------------------------------------------------------------- /boot/x86_64/include/defs.h: -------------------------------------------------------------------------------- 1 | struct buf; 2 | struct context; 3 | struct file; 4 | struct inode; 5 | struct pipe; 6 | struct proc; 7 | struct spinlock; 8 | struct stat; 9 | struct superblock; 10 | 11 | // bio.c 12 | void binit(void); 13 | struct buf* bread(uint, uint); 14 | void brelse(struct buf*); 15 | void bwrite(struct buf*); 16 | 17 | // console.c 18 | void consoleinit(void); 19 | void cprintf(char*, ...); 20 | void consoleintr(int(*)(void)); 21 | void panic(char*) __attribute__((noreturn)); 22 | 23 | // exec.c 24 | int exec(char*, char**); 25 | 26 | // file.c 27 | struct file* filealloc(void); 28 | void fileclose(struct file*); 29 | struct file* filedup(struct file*); 30 | void fileinit(void); 31 | int fileread(struct file*, char*, int n); 32 | int filestat(struct file*, struct stat*); 33 | int filewrite(struct file*, char*, int n); 34 | 35 | // fs.c 36 | void readsb(int dev, struct superblock *sb); 37 | int dirlink(struct inode*, char*, uint); 38 | struct inode* dirlookup(struct inode*, char*, uint*); 39 | struct inode* ialloc(uint, short); 40 | struct inode* idup(struct inode*); 41 | void iinit(void); 42 | void ilock(struct inode*); 43 | void iput(struct inode*); 44 | void iunlock(struct inode*); 45 | void iunlockput(struct inode*); 46 | void iupdate(struct inode*); 47 | int namecmp(const char*, const char*); 48 | struct inode* namei(char*); 49 | struct inode* nameiparent(char*, char*); 50 | int readi(struct inode*, char*, uint, uint); 51 | void stati(struct inode*, struct stat*); 52 | int writei(struct inode*, char*, uint, uint); 53 | 54 | // ide.c 55 | void ideinit(void); 56 | void ideintr(void); 57 | void iderw(struct buf*); 58 | 59 | // ioapic.c 60 | void ioapicenable(int irq, int cpu); 61 | extern uchar ioapicid; 62 | void ioapicinit(void); 63 | 64 | // kalloc.c 65 | char* kalloc(void); 66 | void kfree(char*); 67 | void kinit1(void*, void*); 68 | void kinit2(void*, void*); 69 | 70 | // kbd.c 71 | void kbdintr(void); 72 | 73 | // lapic.c 74 | int cpunum(void); 75 | extern volatile uint* lapic; 76 | void lapiceoi(void); 77 | void lapicinit(void); 78 | void lapicstartap(uchar, uint); 79 | void microdelay(int); 80 | 81 | // log.c 82 | void initlog(void); 83 | void log_write(struct buf*); 84 | void begin_trans(); 85 | void commit_trans(); 86 | 87 | // mp.c 88 | extern int ismp; 89 | int mpbcpu(void); 90 | void mpinit(void); 91 | void mpstartthem(void); 92 | 93 | // apic.c 94 | int acpiinit(void); 95 | 96 | // picirq.c 97 | void picenable(int); 98 | void picinit(void); 99 | 100 | // pipe.c 101 | int pipealloc(struct file**, struct file**); 102 | void pipeclose(struct pipe*, int); 103 | int piperead(struct pipe*, char*, int); 104 | int pipewrite(struct pipe*, char*, int); 105 | 106 | //PAGEBREAK: 16 107 | // proc.c 108 | struct proc* copyproc(struct proc*); 109 | void exit(void); 110 | int fork(void); 111 | int growproc(int); 112 | int kill(int); 113 | void pinit(void); 114 | void procdump(void); 115 | void scheduler(void) __attribute__((noreturn)); 116 | void sched(void); 117 | void sleep(void*, struct spinlock*); 118 | void userinit(void); 119 | int wait(void); 120 | void wakeup(void*); 121 | void yield(void); 122 | 123 | // swtch.S 124 | void swtch(struct context**, struct context*); 125 | 126 | // spinlock.c 127 | void acquire(struct spinlock*); 128 | void getcallerpcs(void*, uintp*); 129 | void getstackpcs(uintp*, uintp*); 130 | int holding(struct spinlock*); 131 | void initlock(struct spinlock*, char*); 132 | void release(struct spinlock*); 133 | void pushcli(void); 134 | void popcli(void); 135 | 136 | // string.c 137 | int memcmp(const void*, const void*, uint); 138 | void* memmove(void*, const void*, uint); 139 | void* memset(void*, int, uint); 140 | char* safestrcpy(char*, const char*, int); 141 | int strlen(const char*); 142 | int strncmp(const char*, const char*, uint); 143 | char* strncpy(char*, const char*, int); 144 | 145 | // syscall.c 146 | int argint(int, int*); 147 | int argptr(int, char**, int); 148 | int argstr(int, char**); 149 | int arguintp(int, uintp*); 150 | int fetchuintp(uintp, uintp*); 151 | int fetchstr(uintp, char**); 152 | void syscall(void); 153 | 154 | // timer.c 155 | void timerinit(void); 156 | 157 | // trap.c 158 | void idtinit(void); 159 | extern uint ticks; 160 | void tvinit(void); 161 | extern struct spinlock tickslock; 162 | 163 | // uart.c 164 | void uartearlyinit(void); 165 | void uartinit(void); 166 | void uartintr(void); 167 | void uartputc(int); 168 | 169 | // vm.c 170 | void seginit(void); 171 | void kvmalloc(void); 172 | void vmenable(void); 173 | pde_t* setupkvm(void); 174 | char* uva2ka(pde_t*, char*); 175 | int allocuvm(pde_t*, uint, uint); 176 | int deallocuvm(pde_t*, uintp, uintp); 177 | void freevm(pde_t*); 178 | void inituvm(pde_t*, char*, uint); 179 | int loaduvm(pde_t*, char*, struct inode*, uint, uint); 180 | pde_t* copyuvm(pde_t*, uint); 181 | void switchuvm(struct proc*); 182 | void switchkvm(void); 183 | int copyout(pde_t*, uint, void*, uint); 184 | void clearpteu(pde_t *pgdir, char *uva); 185 | 186 | // number of elements in fixed-size array 187 | #define NELEM(x) (sizeof(x)/sizeof((x)[0])) 188 | -------------------------------------------------------------------------------- /boot/x86_64/include/memlayout.h: -------------------------------------------------------------------------------- 1 | // Memory layout 2 | 3 | #define EXTMEM 0x100000 // Start of extended memory 4 | #define PHYSTOP 0xE000000 // Top physical memory 5 | #define DEVSPACE 0xFE000000 // Other devices are at high addresses 6 | 7 | // Key addresses for address space layout (see kmap in vm.c for layout) 8 | #if X64 9 | #define KERNBASE 0xFFFFFFFF80000000 // First kernel virtual address 10 | #define DEVBASE 0xFFFFFFFF40000000 // First device virtual address 11 | #else 12 | #define KERNBASE 0x80000000 // First kernel virtual address 13 | #define DEVBASE 0xFE000000 // First device virtual address 14 | #endif 15 | #define KERNLINK (KERNBASE+EXTMEM) // Address where kernel is linked 16 | 17 | #ifndef __ASSEMBLER__ 18 | 19 | static inline uintp v2p(void *a) { return ((uintp) (a)) - ((uintp)KERNBASE); } 20 | static inline void *p2v(uintp a) { return (void *) ((a) + ((uintp)KERNBASE)); } 21 | 22 | #endif 23 | 24 | #define V2P(a) (((uintp) (a)) - KERNBASE) 25 | #define P2V(a) (((void *) (a)) + KERNBASE) 26 | #define IO2V(a) (((void *) (a)) + DEVBASE - DEVSPACE) 27 | 28 | #define V2P_WO(x) ((x) - KERNBASE) // same as V2P, but without casts 29 | #define P2V_WO(x) ((x) + KERNBASE) // same as V2P, but without casts 30 | -------------------------------------------------------------------------------- /boot/x86_64/include/mmu.h: -------------------------------------------------------------------------------- 1 | // This file contains definitions for the 2 | // x86 memory management unit (MMU). 3 | 4 | // Eflags register 5 | #define FL_CF 0x00000001 // Carry Flag 6 | #define FL_PF 0x00000004 // Parity Flag 7 | #define FL_AF 0x00000010 // Auxiliary carry Flag 8 | #define FL_ZF 0x00000040 // Zero Flag 9 | #define FL_SF 0x00000080 // Sign Flag 10 | #define FL_TF 0x00000100 // Trap Flag 11 | #define FL_IF 0x00000200 // Interrupt Enable 12 | #define FL_DF 0x00000400 // Direction Flag 13 | #define FL_OF 0x00000800 // Overflow Flag 14 | #define FL_IOPL_MASK 0x00003000 // I/O Privilege Level bitmask 15 | #define FL_IOPL_0 0x00000000 // IOPL == 0 16 | #define FL_IOPL_1 0x00001000 // IOPL == 1 17 | #define FL_IOPL_2 0x00002000 // IOPL == 2 18 | #define FL_IOPL_3 0x00003000 // IOPL == 3 19 | #define FL_NT 0x00004000 // Nested Task 20 | #define FL_RF 0x00010000 // Resume Flag 21 | #define FL_VM 0x00020000 // Virtual 8086 mode 22 | #define FL_AC 0x00040000 // Alignment Check 23 | #define FL_VIF 0x00080000 // Virtual Interrupt Flag 24 | #define FL_VIP 0x00100000 // Virtual Interrupt Pending 25 | #define FL_ID 0x00200000 // ID flag 26 | 27 | // Control Register flags 28 | #define CR0_PE 0x00000001 // Protection Enable 29 | #define CR0_MP 0x00000002 // Monitor coProcessor 30 | #define CR0_EM 0x00000004 // Emulation 31 | #define CR0_TS 0x00000008 // Task Switched 32 | #define CR0_ET 0x00000010 // Extension Type 33 | #define CR0_NE 0x00000020 // Numeric Errror 34 | #define CR0_WP 0x00010000 // Write Protect 35 | #define CR0_AM 0x00040000 // Alignment Mask 36 | #define CR0_NW 0x20000000 // Not Writethrough 37 | #define CR0_CD 0x40000000 // Cache Disable 38 | #define CR0_PG 0x80000000 // Paging 39 | 40 | #define CR4_PSE 0x00000010 // Page size extension 41 | 42 | #define SEG_KCODE 1 // kernel code 43 | #define SEG_KDATA 2 // kernel data+stack 44 | #define SEG_KCPU 3 // kernel per-cpu data 45 | #define SEG_UCODE 4 // user code 46 | #define SEG_UDATA 5 // user data+stack 47 | #define SEG_TSS 6 // this process's task state 48 | 49 | //PAGEBREAK! 50 | #ifndef __ASSEMBLER__ 51 | // Segment Descriptor 52 | struct segdesc { 53 | uint lim_15_0 : 16; // Low bits of segment limit 54 | uint base_15_0 : 16; // Low bits of segment base address 55 | uint base_23_16 : 8; // Middle bits of segment base address 56 | uint type : 4; // Segment type (see STS_ constants) 57 | uint s : 1; // 0 = system, 1 = application 58 | uint dpl : 2; // Descriptor Privilege Level 59 | uint p : 1; // Present 60 | uint lim_19_16 : 4; // High bits of segment limit 61 | uint avl : 1; // Unused (available for software use) 62 | uint rsv1 : 1; // Reserved 63 | uint db : 1; // 0 = 16-bit segment, 1 = 32-bit segment 64 | uint g : 1; // Granularity: limit scaled by 4K when set 65 | uint base_31_24 : 8; // High bits of segment base address 66 | }; 67 | 68 | // Normal segment 69 | #define SEG(type, base, lim, dpl) (struct segdesc) \ 70 | { ((lim) >> 12) & 0xffff, (uint)(base) & 0xffff, \ 71 | ((uintp)(base) >> 16) & 0xff, type, 1, dpl, 1, \ 72 | (uintp)(lim) >> 28, 0, 0, 1, 1, (uintp)(base) >> 24 } 73 | #define SEG16(type, base, lim, dpl) (struct segdesc) \ 74 | { (lim) & 0xffff, (uintp)(base) & 0xffff, \ 75 | ((uintp)(base) >> 16) & 0xff, type, 1, dpl, 1, \ 76 | (uintp)(lim) >> 16, 0, 0, 1, 0, (uintp)(base) >> 24 } 77 | #endif 78 | 79 | #define DPL_USER 0x3 // User DPL 80 | 81 | // Application segment type bits 82 | #define STA_X 0x8 // Executable segment 83 | #define STA_E 0x4 // Expand down (non-executable segments) 84 | #define STA_C 0x4 // Conforming code segment (executable only) 85 | #define STA_W 0x2 // Writeable (non-executable segments) 86 | #define STA_R 0x2 // Readable (executable segments) 87 | #define STA_A 0x1 // Accessed 88 | 89 | // System segment type bits 90 | #define STS_T16A 0x1 // Available 16-bit TSS 91 | #define STS_LDT 0x2 // Local Descriptor Table 92 | #define STS_T16B 0x3 // Busy 16-bit TSS 93 | #define STS_CG16 0x4 // 16-bit Call Gate 94 | #define STS_TG 0x5 // Task Gate / Coum Transmitions 95 | #define STS_IG16 0x6 // 16-bit Interrupt Gate 96 | #define STS_TG16 0x7 // 16-bit Trap Gate 97 | #define STS_T32A 0x9 // Available 32-bit TSS 98 | #define STS_T32B 0xB // Busy 32-bit TSS 99 | #define STS_CG32 0xC // 32-bit Call Gate 100 | #define STS_IG32 0xE // 32-bit Interrupt Gate 101 | #define STS_TG32 0xF // 32-bit Trap Gate 102 | 103 | // A virtual address 'la' has a three-part structure as follows: 104 | // 105 | // +--------10------+-------10-------+---------12----------+ 106 | // | Page Directory | Page Table | Offset within Page | 107 | // | Index | Index | | 108 | // +----------------+----------------+---------------------+ 109 | // \--- PDX(va) --/ \--- PTX(va) --/ 110 | 111 | // page directory index 112 | #define PDX(va) (((uintp)(va) >> PDXSHIFT) & PXMASK) 113 | 114 | // page table index 115 | #define PTX(va) (((uintp)(va) >> PTXSHIFT) & PXMASK) 116 | 117 | // construct virtual address from indexes and offset 118 | #define PGADDR(d, t, o) ((uintp)((d) << PDXSHIFT | (t) << PTXSHIFT | (o))) 119 | 120 | // Page directory and page table constants. 121 | #if X64 122 | #define NPDENTRIES 512 // # directory entries per page directory 123 | #define NPTENTRIES 512 // # PTEs per page table 124 | #define PGSIZE 4096 // bytes mapped by a page 125 | 126 | #define PGSHIFT 12 // log2(PGSIZE) 127 | #define PTXSHIFT 12 // offset of PTX in a linear address 128 | #define PDXSHIFT 21 // offset of PDX in a linear address 129 | 130 | #define PXMASK 0x1FF 131 | #else 132 | #define NPDENTRIES 1024 // # directory entries per page directory 133 | #define NPTENTRIES 1024 // # PTEs per page table 134 | #define PGSIZE 4096 // bytes mapped by a page 135 | 136 | #define PGSHIFT 12 // log2(PGSIZE) 137 | #define PTXSHIFT 12 // offset of PTX in a linear address 138 | #define PDXSHIFT 22 // offset of PDX in a linear address 139 | 140 | #define PXMASK 0x3FF 141 | #endif 142 | 143 | #define PGROUNDUP(sz) (((sz)+((uintp)PGSIZE-1)) & ~((uintp)(PGSIZE-1))) 144 | #define PGROUNDDOWN(a) (((a)) & ~((uintp)(PGSIZE-1))) 145 | 146 | // Page table/directory entry flags. 147 | #define PTE_P 0x001 // Present 148 | #define PTE_W 0x002 // Writeable 149 | #define PTE_U 0x004 // User 150 | #define PTE_PWT 0x008 // Write-Through 151 | #define PTE_PCD 0x010 // Cache-Disable 152 | #define PTE_A 0x020 // Accessed 153 | #define PTE_D 0x040 // Dirty 154 | #define PTE_PS 0x080 // Page Size 155 | #define PTE_MBZ 0x180 // Bits must be zero 156 | 157 | // Address in page table or page directory entry 158 | #define PTE_ADDR(pte) ((uintp)(pte) & ~0xFFF) 159 | #define PTE_FLAGS(pte) ((uintp)(pte) & 0xFFF) 160 | 161 | #ifndef __ASSEMBLER__ 162 | typedef uintp pte_t; 163 | 164 | // Task state segment format 165 | struct taskstate { 166 | uint link; // Old ts selector 167 | uint esp0; // Stack pointers and segment selectors 168 | ushort ss0; // after an increase in privilege level 169 | ushort padding1; 170 | uint *esp1; 171 | ushort ss1; 172 | ushort padding2; 173 | uint *esp2; 174 | ushort ss2; 175 | ushort padding3; 176 | void *cr3; // Page directory base 177 | uint *eip; // Saved state from last task switch 178 | uint eflags; 179 | uint eax; // More saved state (registers) 180 | uint ecx; 181 | uint edx; 182 | uint ebx; 183 | uint *esp; 184 | uint *ebp; 185 | uint esi; 186 | uint edi; 187 | ushort es; // Even more saved state (segment selectors) 188 | ushort padding4; 189 | ushort cs; 190 | ushort padding5; 191 | ushort ss; 192 | ushort padding6; 193 | ushort ds; 194 | ushort padding7; 195 | ushort fs; 196 | ushort padding8; 197 | ushort gs; 198 | ushort padding9; 199 | ushort ldt; 200 | ushort padding10; 201 | ushort t; // Trap on task switch 202 | ushort iomb; // I/O map base address 203 | }; 204 | 205 | // PAGEBREAK: 12 206 | // Gate descriptors for interrupts and traps 207 | struct gatedesc { 208 | uint off_15_0 : 16; // low 16 bits of offset in segment 209 | uint cs : 16; // code segment selector 210 | uint args : 5; // # args, 0 for interrupt/trap gates 211 | uint rsv1 : 3; // reserved(should be zero I guess) 212 | uint type : 4; // type(STS_{TG,IG32,TG32}) 213 | uint s : 1; // must be 0 (system) 214 | uint dpl : 2; // descriptor(meaning new) privilege level 215 | uint p : 1; // Present 216 | uint off_31_16 : 16; // high bits of offset in segment 217 | }; 218 | 219 | // Set up a normal interrupt/trap gate descriptor. 220 | // - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate. 221 | // interrupt gate clears FL_IF, trap gate leaves FL_IF alone 222 | // - sel: Code segment selector for interrupt/trap handler 223 | // - off: Offset in code segment for interrupt/trap handler 224 | // - dpl: Descriptor Privilege Level - 225 | // the privilege level required for software to invoke 226 | // this interrupt/trap gate explicitly using an int instruction. 227 | #define SETGATE(gate, istrap, sel, off, d) \ 228 | { \ 229 | (gate).off_15_0 = (uint)(off) & 0xffff; \ 230 | (gate).cs = (sel); \ 231 | (gate).args = 0; \ 232 | (gate).rsv1 = 0; \ 233 | (gate).type = (istrap) ? STS_TG32 : STS_IG32; \ 234 | (gate).s = 0; \ 235 | (gate).dpl = (d); \ 236 | (gate).p = 1; \ 237 | (gate).off_31_16 = (uint)(off) >> 16; \ 238 | } 239 | 240 | #endif 241 | -------------------------------------------------------------------------------- /boot/x86_64/include/param.h: -------------------------------------------------------------------------------- 1 | #define NPROC 64 // maximum number of processes 2 | #define KSTACKSIZE 4096 // size of per-process kernel stack 3 | #define NCPU 8 // maximum number of CPUs 4 | #define NOFILE 16 // open files per process 5 | #define NFILE 100 // open files per system 6 | #define NBUF 10 // size of disk block cache 7 | #define NINODE 50 // maximum number of active i-nodes 8 | #define NDEV 10 // maximum major device number 9 | #define ROOTDEV 1 // device number of file system root disk 10 | #define MAXARG 32 // max exec arguments 11 | #define LOGSIZE 10 // max data sectors in on-disk log 12 | 13 | -------------------------------------------------------------------------------- /boot/x86_64/include/proc.h: -------------------------------------------------------------------------------- 1 | // Segments in proc->gdt. 2 | #define NSEGS 7 3 | 4 | // Per-CPU state 5 | struct cpu { 6 | uchar id; // index into cpus[] below 7 | uchar apicid; // Local APIC ID 8 | struct context *scheduler; // swtch() here to enter scheduler 9 | struct taskstate ts; // Used by x86 to find stack for interrupt 10 | struct segdesc gdt[NSEGS]; // x86 global descriptor table 11 | volatile uint started; // Has the CPU started? 12 | int ncli; // Depth of pushcli nesting. 13 | int intena; // Were interrupts enabled before pushcli? 14 | 15 | // Cpu-local storage variables; see below 16 | #if X64 17 | void *local; 18 | #else 19 | struct cpu *cpu; 20 | struct proc *proc; // The currently-running process. 21 | #endif 22 | }; 23 | 24 | extern struct cpu cpus[NCPU]; 25 | extern int ncpu; 26 | 27 | // Per-CPU variables, holding pointers to the 28 | // current cpu and to the current process. 29 | // The asm suffix tells gcc to use "%gs:0" to refer to cpu 30 | // and "%gs:4" to refer to proc. seginit sets up the 31 | // %gs segment register so that %gs refers to the memory 32 | // holding those two variables in the local cpu's struct cpu. 33 | // This is similar to how thread-local variables are implemented 34 | // in thread libraries such as Linux pthreads. 35 | #if X64 36 | extern __thread struct cpu *cpu; 37 | extern __thread struct proc *proc; 38 | #else 39 | extern struct cpu *cpu asm("%gs:0"); // &cpus[cpunum()] 40 | extern struct proc *proc asm("%gs:4"); // cpus[cpunum()].proc 41 | #endif 42 | 43 | //PAGEBREAK: 17 44 | // Saved registers for kernel context switches. 45 | // Don't need to save all the segment registers (%cs, etc), 46 | // because they are constant across kernel contexts. 47 | // Don't need to save %eax, %ecx, %edx, because the 48 | // x86 convention is that the caller has saved them. 49 | // Contexts are stored at the bottom of the stack they 50 | // describe; the stack pointer is the address of the context. 51 | // The layout of the context matches the layout of the stack in swtch.S 52 | // at the "Switch stacks" comment. Switch doesn't save eip explicitly, 53 | // but it is on the stack and allocproc() manipulates it. 54 | #if X64 55 | struct context { 56 | uintp r15; 57 | uintp r14; 58 | uintp r13; 59 | uintp r12; 60 | uintp r11; 61 | uintp rbx; 62 | uintp ebp; //rbp 63 | uintp eip; //rip; 64 | }; 65 | #else 66 | struct context { 67 | uintp edi; 68 | uintp esi; 69 | uintp ebx; 70 | uintp ebp; 71 | uintp eip; 72 | }; 73 | #endif 74 | 75 | enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; 76 | 77 | // Per-process state 78 | struct proc { 79 | uintp sz; // Size of process memory (bytes) 80 | pde_t* pgdir; // Page table 81 | char *kstack; // Bottom of kernel stack for this process 82 | enum procstate state; // Process state 83 | volatile int pid; // Process ID 84 | struct proc *parent; // Parent process 85 | struct trapframe *tf; // Trap frame for current syscall 86 | struct context *context; // swtch() here to run process 87 | void *chan; // If non-zero, sleeping on chan 88 | int killed; // If non-zero, have been killed 89 | struct file *ofile[NOFILE]; // Open files 90 | struct inode *cwd; // Current directory 91 | char name[16]; // Process name (debugging) 92 | }; 93 | 94 | // Process memory is laid out contiguously, low addresses first: 95 | // text 96 | // original data and bss 97 | // fixed-size stack 98 | // expandable heap 99 | -------------------------------------------------------------------------------- /boot/x86_64/include/syscall.h: -------------------------------------------------------------------------------- 1 | // System call numbers 2 | #define SYS_fork 1 3 | #define SYS_exit 2 4 | #define SYS_wait 3 5 | #define SYS_pipe 4 6 | #define SYS_read 5 7 | #define SYS_kill 6 8 | #define SYS_exec 7 9 | #define SYS_fstat 8 10 | #define SYS_chdir 9 11 | #define SYS_dup 10 12 | #define SYS_getpid 11 13 | #define SYS_sbrk 12 14 | #define SYS_sleep 13 15 | #define SYS_uptime 14 16 | #define SYS_open 15 17 | #define SYS_write 16 18 | #define SYS_mknod 17 19 | #define SYS_unlink 18 20 | #define SYS_link 19 21 | #define SYS_mkdir 20 22 | #define SYS_close 21 23 | -------------------------------------------------------------------------------- /boot/x86_64/include/traps.h: -------------------------------------------------------------------------------- 1 | // x86 trap and interrupt constants. 2 | 3 | // Processor-defined: 4 | #define T_DIVIDE 0 // divide error 5 | #define T_DEBUG 1 // debug exception 6 | #define T_NMI 2 // non-maskable interrupt 7 | #define T_BRKPT 3 // breakpoint 8 | #define T_OFLOW 4 // overflow 9 | #define T_BOUND 5 // bounds check 10 | #define T_ILLOP 6 // illegal opcode 11 | #define T_DEVICE 7 // device not available 12 | #define T_DBLFLT 8 // double fault 13 | // #define T_COPROC 9 // reserved (not used since 486) 14 | #define T_TSS 10 // invalid task switch segment 15 | #define T_SEGNP 11 // segment not present 16 | #define T_STACK 12 // stack exception 17 | #define T_GPFLT 13 // general protection fault 18 | #define T_PGFLT 14 // page fault 19 | // #define T_RES 15 // reserved 20 | #define T_FPERR 16 // floating point error 21 | #define T_ALIGN 17 // aligment check 22 | #define T_MCHK 18 // machine check 23 | #define T_SIMDERR 19 // SIMD floating point error 24 | 25 | // These are arbitrarily chosen, but with care not to overlap 26 | // processor defined exceptions or interrupt vectors. 27 | #define T_SYSCALL 64 // system call 28 | #define T_DEFAULT 500 // catchall 29 | 30 | #define T_IRQ0 32 // IRQ 0 corresponds to int T_IRQ 31 | 32 | #define IRQ_TIMER 0 33 | #define IRQ_KBD 1 34 | #define IRQ_COM1 4 35 | #define IRQ_IDE 14 36 | #define IRQ_ERROR 19 37 | #define IRQ_SPURIOUS 31 38 | 39 | -------------------------------------------------------------------------------- /boot/x86_64/include/types.h: -------------------------------------------------------------------------------- 1 | typedef unsigned int uint; 2 | typedef unsigned short ushort; 3 | typedef unsigned char uchar; 4 | 5 | typedef unsigned int uint32; 6 | typedef unsigned long uint64; 7 | 8 | #if X64 9 | typedef unsigned long uintp; 10 | #else 11 | typedef unsigned int uintp; 12 | #endif 13 | 14 | typedef uintp pde_t; 15 | -------------------------------------------------------------------------------- /boot/x86_64/include/x86.h: -------------------------------------------------------------------------------- 1 | // Routines to let C code use special x86 instructions. 2 | 3 | static inline uchar 4 | inb(ushort port) 5 | { 6 | uchar data; 7 | 8 | asm volatile("in %1,%0" : "=a" (data) : "d" (port)); 9 | return data; 10 | } 11 | 12 | static inline void 13 | insl(int port, void *addr, int cnt) 14 | { 15 | asm volatile("cld; rep insl" : 16 | "=D" (addr), "=c" (cnt) : 17 | "d" (port), "0" (addr), "1" (cnt) : 18 | "memory", "cc"); 19 | } 20 | 21 | static inline void 22 | outb(ushort port, uchar data) 23 | { 24 | asm volatile("out %0,%1" : : "a" (data), "d" (port)); 25 | } 26 | 27 | static inline void 28 | outw(ushort port, ushort data) 29 | { 30 | asm volatile("out %0,%1" : : "a" (data), "d" (port)); 31 | } 32 | 33 | static inline void 34 | outsl(int port, const void *addr, int cnt) 35 | { 36 | asm volatile("cld; rep outsl" : 37 | "=S" (addr), "=c" (cnt) : 38 | "d" (port), "0" (addr), "1" (cnt) : 39 | "cc"); 40 | } 41 | 42 | static inline void 43 | stosb(void *addr, int data, int cnt) 44 | { 45 | asm volatile("cld; rep stosb" : 46 | "=D" (addr), "=c" (cnt) : 47 | "0" (addr), "1" (cnt), "a" (data) : 48 | "memory", "cc"); 49 | } 50 | 51 | static inline void 52 | stosl(void *addr, int data, int cnt) 53 | { 54 | asm volatile("cld; rep stosl" : 55 | "=D" (addr), "=c" (cnt) : 56 | "0" (addr), "1" (cnt), "a" (data) : 57 | "memory", "cc"); 58 | } 59 | 60 | struct segdesc; 61 | 62 | static inline void 63 | lgdt(struct segdesc *p, int size) 64 | { 65 | volatile ushort pd[5]; 66 | 67 | pd[0] = size-1; 68 | pd[1] = (uintp)p; 69 | pd[2] = (uintp)p >> 16; 70 | #if X64 71 | pd[3] = (uintp)p >> 32; 72 | pd[4] = (uintp)p >> 48; 73 | #endif 74 | asm volatile("lgdt (%0)" : : "r" (pd)); 75 | } 76 | 77 | struct gatedesc; 78 | 79 | static inline void 80 | lidt(struct gatedesc *p, int size) 81 | { 82 | volatile ushort pd[5]; 83 | 84 | pd[0] = size-1; 85 | pd[1] = (uintp)p; 86 | pd[2] = (uintp)p >> 16; 87 | #if X64 88 | pd[3] = (uintp)p >> 32; 89 | pd[4] = (uintp)p >> 48; 90 | #endif 91 | asm volatile("lidt (%0)" : : "r" (pd)); 92 | } 93 | 94 | static inline void 95 | ltr(ushort sel) 96 | { 97 | asm volatile("ltr %0" : : "r" (sel)); 98 | } 99 | 100 | static inline uintp 101 | readeflags(void) 102 | { 103 | uintp eflags; 104 | asm volatile("pushf; pop %0" : "=r" (eflags)); 105 | return eflags; 106 | } 107 | 108 | static inline void 109 | loadgs(ushort v) 110 | { 111 | asm volatile("movw %0, %%gs" : : "r" (v)); 112 | } 113 | 114 | static inline void 115 | cli(void) 116 | { 117 | asm volatile("cli"); 118 | } 119 | 120 | static inline void 121 | sti(void) 122 | { 123 | asm volatile("sti"); 124 | } 125 | 126 | static inline void 127 | hlt(void) 128 | { 129 | asm volatile("hlt"); 130 | } 131 | 132 | static inline uint 133 | xchg(volatile uint *addr, uintp newval) 134 | { 135 | uint result; 136 | 137 | // The + in "+m" denotes a read-modify-write operand. 138 | asm volatile("lock; xchgl %0, %1" : 139 | "+m" (*addr), "=a" (result) : 140 | "1" (newval) : 141 | "cc"); 142 | return result; 143 | } 144 | 145 | static inline uintp 146 | rcr2(void) 147 | { 148 | uintp val; 149 | asm volatile("mov %%cr2,%0" : "=r" (val)); 150 | return val; 151 | } 152 | 153 | static inline void 154 | lcr3(uintp val) 155 | { 156 | asm volatile("mov %0,%%cr3" : : "r" (val)); 157 | } 158 | 159 | //PAGEBREAK: 36 160 | // Layout of the trap frame built on the stack by the 161 | // hardware and by trapasm.S, and passed to trap(). 162 | #if X64 163 | // lie about some register names in 64bit mode to avoid 164 | // clunky ifdefs in proc.c and trap.c. 165 | struct trapframe { 166 | uint64 eax; // rax 167 | uint64 rbx; 168 | uint64 rcx; 169 | uint64 rdx; 170 | uint64 rbp; 171 | uint64 rsi; 172 | uint64 rdi; 173 | uint64 r8; 174 | uint64 r9; 175 | uint64 r10; 176 | uint64 r11; 177 | uint64 r12; 178 | uint64 r13; 179 | uint64 r14; 180 | uint64 r15; 181 | 182 | uint64 trapno; 183 | uint64 err; 184 | 185 | uint64 eip; // rip 186 | uint64 cs; 187 | uint64 eflags; // rflags 188 | uint64 esp; // rsp 189 | uint64 ds; // ss 190 | }; 191 | #else 192 | struct trapframe { 193 | // registers as pushed by pusha 194 | uint edi; 195 | uint esi; 196 | uint ebp; 197 | uint oesp; // useless & ignored 198 | uint ebx; 199 | uint edx; 200 | uint ecx; 201 | uint eax; 202 | 203 | // rest of trap frame 204 | ushort gs; 205 | ushort padding1; 206 | ushort fs; 207 | ushort padding2; 208 | ushort es; 209 | ushort padding3; 210 | ushort ds; 211 | ushort padding4; 212 | uint trapno; 213 | 214 | // below here defined by x86 hardware 215 | uint err; 216 | uint eip; 217 | ushort cs; 218 | ushort padding5; 219 | uint eflags; 220 | 221 | // below here only when crossing rings, such as from user to kernel 222 | uint esp; 223 | ushort ss; 224 | ushort padding6; 225 | }; 226 | #endif 227 | -------------------------------------------------------------------------------- /boot/x86_64/initcode64.S: -------------------------------------------------------------------------------- 1 | # Initial process execs /init. 2 | 3 | #include "syscall.h" 4 | #include "traps.h" 5 | 6 | 7 | # exec(init, argv) 8 | .globl start 9 | start: 10 | mov $init, %rdi 11 | mov $argv, %rsi 12 | mov $SYS_exec, %rax 13 | int $T_SYSCALL 14 | 15 | # for(;;) exit(); 16 | exit: 17 | mov $SYS_exit, %rax 18 | int $T_SYSCALL 19 | jmp exit 20 | 21 | # char init[] = "/init\0"; 22 | init: 23 | .string "/init\0" 24 | 25 | # char *argv[] = { init, 0 }; 26 | .p2align 2 27 | argv: 28 | .quad init 29 | .quad 0 30 | 31 | -------------------------------------------------------------------------------- /boot/x86_64/kernel64.ld: -------------------------------------------------------------------------------- 1 | /* Simple linker script for the JOS kernel. 2 | See the GNU ld 'info' manual ("info ld") to learn the syntax. */ 3 | 4 | /* OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") */ 5 | OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") 6 | OUTPUT_ARCH(i386:x86-64) 7 | ENTRY(_start) 8 | 9 | mboot_load_addr = 0x00100000; 10 | 11 | SECTIONS 12 | { 13 | /* Link the kernel at this address: "." means the current address */ 14 | /* Must be equal to KERNLINK */ 15 | . = 0xFFFFFFFF80100000; 16 | 17 | PROVIDE(begin = .); 18 | 19 | .text : AT(mboot_load_addr) { 20 | *(.text .rela.text .stub .text.* .gnu.linkonce.t.*) 21 | } 22 | 23 | PROVIDE(etext = .); /* Define the 'etext' symbol to this value */ 24 | 25 | .rodata : { 26 | *(.rodata .rodata.* .gnu.linkonce.r.*) 27 | } 28 | 29 | /* Adjust the address for the data segment to the next page */ 30 | . = ALIGN(0x1000); 31 | 32 | /* Conventionally, Unix linkers provide pseudo-symbols 33 | * etext, edata, and end, at the end of the text, data, and bss. 34 | * For the kernel mapping, we need the address at the beginning 35 | * of the data section, but that's not one of the conventional 36 | * symbols, because the convention started before there was a 37 | * read-only rodata section between text and data. */ 38 | PROVIDE(data = .); 39 | 40 | /* The data segment */ 41 | .data : { 42 | *(.data) 43 | } 44 | 45 | . = ALIGN(0x1000); 46 | 47 | PROVIDE(edata = .); 48 | 49 | .bss : { 50 | *(.bss) 51 | *(COMMON) 52 | } 53 | 54 | . = ALIGN(0x1000); 55 | 56 | PROVIDE(end = .); 57 | 58 | /DISCARD/ : { 59 | *(.eh_frame .rela.eh_frame .note.GNU-stack) 60 | } 61 | } 62 | 63 | mboot_load_end = mboot_load_addr + (edata - begin); 64 | mboot_bss_end = mboot_load_addr + (end - begin); 65 | mboot_entry_addr = mboot_load_addr + (mboot_entry - begin); 66 | -------------------------------------------------------------------------------- /boot/x86_64/main.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "defs.h" 3 | #include "param.h" 4 | #include "memlayout.h" 5 | #include "mmu.h" 6 | #include "proc.h" 7 | #include "x86.h" 8 | 9 | static void startothers(void); 10 | static void mpmain(void) __attribute__((noreturn)); 11 | extern pde_t *kpgdir; 12 | extern char end[]; // first address after kernel loaded from ELF file 13 | 14 | // Bootstrap processor starts running C code here. 15 | // Allocate a real stack and switch to it, first 16 | // doing some setup required for memory allocator to work. 17 | 18 | void nimMain(void *); 19 | int 20 | main(void) 21 | { 22 | int i; 23 | char *screen=(char*)0xb8000; 24 | char ch = 'A'; 25 | char cl[] = {0x1f, 0x0e, 0x4f}; 26 | int ci=0; 27 | while(1) { 28 | ch='A'; 29 | for (i=0;i<4000;i+=2){ 30 | screen[i]=ch; 31 | ch++; 32 | if(ch>'Z')ch='A'; 33 | screen[i+1]=cl[ci]; 34 | } 35 | ci++; 36 | if(ci==3)ci=0; 37 | nimMain(end); 38 | } 39 | } 40 | 41 | // Other CPUs jump here from entryother.S. 42 | void 43 | mpenter(void) 44 | { 45 | } 46 | 47 | // Common CPU setup code. 48 | static void 49 | mpmain(void) 50 | { 51 | } 52 | 53 | pde_t entrypgdir[]; // For entry.S 54 | void entry32mp(void); 55 | 56 | // Start the non-boot (AP) processors. 57 | static void 58 | startothers(void) 59 | { 60 | } 61 | 62 | #ifndef X64 63 | // Boot page table used in entry.S and entryother.S. 64 | // Page directories (and page tables), must start on a page boundary, 65 | // hence the "__aligned__" attribute. 66 | // Use PTE_PS in page directory entry to enable 4Mbyte pages. 67 | __attribute__((__aligned__(PGSIZE))) 68 | pde_t entrypgdir[NPDENTRIES] = { 69 | // Map VA's [0, 4MB) to PA's [0, 4MB) 70 | [0] = (0) | PTE_P | PTE_W | PTE_PS, 71 | // Map VA's [KERNBASE, KERNBASE+4MB) to PA's [0, 4MB) 72 | [KERNBASE>>PDXSHIFT] = (0) | PTE_P | PTE_W | PTE_PS, 73 | }; 74 | #endif 75 | 76 | //PAGEBREAK! 77 | // Blank page. 78 | 79 | -------------------------------------------------------------------------------- /console.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2015 Kashyap 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | import uart 24 | 25 | proc panic*(s: cstring) = 26 | # TODO need to call cli 27 | uartPutStr(s) 28 | while true: 29 | asm """ 30 | nop 31 | """ 32 | 33 | -------------------------------------------------------------------------------- /consts.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2015 Kashyap 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | 24 | const PGSIZE* = 4096 25 | -------------------------------------------------------------------------------- /kalloc.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2015 Kashyap 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | import spinlock 24 | import mmu 25 | import types 26 | import consts 27 | import memlayout 28 | import console 29 | import stdlib 30 | import uart 31 | import unsigned 32 | 33 | type KMem = object 34 | lock: Spinlock 35 | useLock: bool 36 | #TODO - this structure is incomplete 37 | 38 | 39 | var kmem = KMem () 40 | var physicalMemEnd: Address; 41 | 42 | proc kfree(v: Address) = 43 | if ((int64(v) mod int64(PGSIZE)) != 0) or (v < physicalMemEnd) or (v2p(v) >= PHYSTOP): 44 | panic("kfree") 45 | var x = memsetNIM(cast[ArbitraryPointer](v), 1, PGSIZE) 46 | 47 | ## TODO not complete 48 | acquire(addr kmem.lock) 49 | 50 | 51 | proc freeRange(startAddress: Address, endAddress: Address) = 52 | var sa = PGROUNDUP(startAddress) 53 | while true: 54 | kfree(sa) 55 | sa = sa + PGSIZE 56 | if sa > endAddress: 57 | break 58 | 59 | 60 | proc kinit1*(startAddress: Address, endAddress: Address) = 61 | physicalMemEnd = startAddress 62 | initlock(addr kmem.lock, "kmem") 63 | kmem.useLock = false 64 | freeRange(startAddress, endAddress) 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /main.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2015 Kashyap 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | import uart 24 | import kalloc 25 | import stdlib 26 | import types 27 | import memlayout 28 | 29 | 30 | 31 | proc nimMain(endAddress: Address) {.exportc.} = 32 | while true: 33 | earlyInit() 34 | kinit1(endAddress, P2V(4*1024*1024)) 35 | 36 | 37 | 38 | nimMain(0) 39 | -------------------------------------------------------------------------------- /memlayout.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2015 Kashyap 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | import types 24 | import unsigned 25 | 26 | const EXTMEM* = Address(0x0fffff) # Start of extended memory 27 | const PHYSTOP* = Address(0xE000000) # Top physical memory 28 | const DEVSPACE* = Address(0xFE000000) # Other devices are at high addresses 29 | 30 | # Key addresses for address space layout (see kmap in vm.c for layout) 31 | 32 | const KERNBASE* = Address(0xFFFFFFFF80000000) # First kernel virtual address 33 | const DEVBASE* = Address(0xFFFFFFFF40000000) # First device virtual address 34 | const KERNLINK* = Address(KERNBASE + EXTMEM) # Address where kernel is linked 35 | 36 | proc v2p*(a: Address): Address = 37 | a - KERNBASE 38 | 39 | proc p2v*(a: Address): Address = 40 | a + KERNBASE 41 | 42 | proc V2P*(a: Address): Address = 43 | a - KERNBASE 44 | 45 | proc P2V*(a: Address): Address = 46 | a + KERNBASE 47 | 48 | proc IO2V*(a: Address): Address = 49 | a + DEVBASE - DEVSPACE 50 | 51 | 52 | proc V2P_WO*(a: Address): Address = 53 | a - KERNBASE 54 | 55 | proc P2V_WO*(a: Address): Address = 56 | a + KERNBASE 57 | 58 | -------------------------------------------------------------------------------- /mmu.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2015 Kashyap 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | import types 24 | import consts 25 | import unsigned 26 | 27 | # // Segment Descriptor 28 | # struct SegDesc { 29 | # uint lim_15_0 : 16; // Low bits of segment limit 30 | # uint base_15_0 : 16; // Low bits of segment base address 31 | # uint base_23_16 : 8; // Middle bits of segment base address 32 | # uint type : 4; // Segment type (see STS_ constants) 33 | # uint s : 1; // 0 = system, 1 = application 34 | # uint dpl : 2; // Descriptor Privilege Level 35 | # uint p : 1; // Present 36 | # uint lim_19_16 : 4; // High bits of segment limit 37 | # uint avl : 1; // Unused (available for software use) 38 | # uint rsv1 : 1; // Reserved 39 | # uint db : 1; // 0 = 16-bit segment, 1 = 32-bit segment 40 | # uint g : 1; // Granularity: limit scaled by 4K when set 41 | # uint base_31_24 : 8; // High bits of segment base address 42 | # }; 43 | 44 | 45 | type 46 | SegDesc* = uint64 47 | 48 | type 49 | SegDescPointer* = ptr array [8, int8] 50 | 51 | proc segmentBase(descPointer: SegDescPointer): int32 = 52 | let base_31_24 = descPointer[7] 53 | let base_23_16 = descPointer[4] 54 | let base_15_08 = descPointer[2] 55 | let base_07_00 = descPointer[3] 56 | (base_31_24 shl 24) or (base_23_16 shl 16) or (base_15_08 shl 8) or base_07_00 57 | 58 | proc `segmentBase=`(descPointer: SegDescPointer, val: int32) = 59 | descPointer[7] = cast[int8](0xff and (val shr 24)) 60 | descPointer[4] = cast[int8](0xff and (val shr 16)) 61 | descPointer[2] = cast[int8](0xff and (val shr 8)) 62 | descPointer[3] = cast[int8](0xff and val) 63 | 64 | proc segmentLimit(descPointer: SegDescPointer): int32 = 65 | let limit_19_16 = cast[int8]((descPointer[6] shr 4) and 0xf) 66 | let limit_15_08 = cast[int8](descPointer[0]) 67 | let limit_07_00 = cast[int8](descPointer[1]) 68 | (limit_19_16 shl 12) or (limit_15_08 shl 8) or limit_07_00 69 | 70 | proc `segmentLimit=`(descPointer: SegDescPointer, val:int32) = 71 | descPointer[6] = cast[int8](0xf and (val shr 12)) 72 | descPointer[0] = cast[int8](0xff and (val shr 8)) 73 | descPointer[1] = cast[int8](0xff and val) 74 | 75 | 76 | 77 | proc PGROUNDUP*(a: Address): Address = 78 | Address(bool(a + PGSIZE - 1) and (not bool(PGSIZE - 1))) 79 | 80 | -------------------------------------------------------------------------------- /panicoverride.nim: -------------------------------------------------------------------------------- 1 | {.push stack_trace: off, profiler:off.} 2 | 3 | import uart 4 | 5 | proc rawoutput(s: cstring) = 6 | uartPutStr(s) 7 | while true: 8 | asm """ 9 | nop 10 | """ 11 | 12 | 13 | proc panic(s: cstring) = 14 | rawoutput(s) 15 | 16 | # Alternatively we also could implement these 2 here: 17 | # 18 | # template sysFatal(exceptn: typeDesc, message: string) 19 | # template sysFatal(exceptn: typeDesc, message, arg: string) 20 | 21 | {.pop.} 22 | -------------------------------------------------------------------------------- /procs.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2015 Kashyap 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | import mmu 24 | 25 | const NSEGS = 7 26 | 27 | type Context = object 28 | r15: int64 29 | r14: int64 30 | r13: int64 31 | r12: int64 32 | r11: int64 33 | rbx: int64 34 | ebp: int64 #rbp 35 | eip: int64 #rip 36 | 37 | type CPU* = object 38 | id: uint8 # index into cpus[] below 39 | apicid: uint8 # Local APIC ID 40 | scheduler: ptr Context # swtch() here to enter scheduler 41 | gdt: array[NSEGS, SegDesc] # x86 global descriptor table 42 | # TODO struct taskstate ts; # Used by x86 to find stack for interrupt 43 | started: bool # Has the CPU started? 44 | ncli: int # Depth of pushcli nesting. 45 | intena*: int # Were interrupts enabled before pushcli? 46 | # TODO local needs to be figured out 47 | -------------------------------------------------------------------------------- /spinlock.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2015 Kashyap 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | import x86asm 24 | import vm64 25 | 26 | type Spinlock* = object 27 | locked: int 28 | name: cstring 29 | #TODO - this structure is incomplete 30 | 31 | 32 | proc initlock*(lk: ptr Spinlock, name: cstring) = 33 | lk.locked = 0 34 | lk.name = name 35 | #TODO - this structure is incomplete 36 | 37 | proc pushcli*() = 38 | var eflags = readeflags() 39 | cli() 40 | 41 | #TODO - add the if check also 42 | cpu.intena = 0 43 | 44 | 45 | proc acquire*(lk: ptr Spinlock) = 46 | pushcli() 47 | var x = 0 48 | -------------------------------------------------------------------------------- /stdlib.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2015 Kashyap 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | import types 24 | 25 | proc strlen* (s: cstring) : int {.exportc.} = 26 | var count = 0 27 | while true: 28 | if int(s[count]) == 0: 29 | break 30 | count = count + 1 31 | return count 32 | 33 | 34 | proc memset* (p: ArbitraryPointer, b: int8, n: int) : ArbitraryPointer{.exportc.} = 35 | for i in 0 .. n-1: 36 | p[i] = b 37 | 38 | proc memsetNIM* (p: ArbitraryPointer, b: int8, n: int) : ArbitraryPointer{.exportc.} = 39 | for i in 0 .. n-1: 40 | p[i] = b 41 | 42 | 43 | var x = strlen("") 44 | var y = memset(cast[ArbitraryPointer](0), 0, 0) 45 | -------------------------------------------------------------------------------- /types.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2015 Kashyap 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | 24 | type Address* = uint64 25 | 26 | # TODO an arbitrary pointer type with 1G size ... till I find something better 27 | type ArbitraryPointer* = ptr array[1024*1024*1024, int8] 28 | 29 | 30 | # TODO - consider using region pointers 31 | type 32 | KernelSpace = object 33 | UserSpace = object 34 | 35 | -------------------------------------------------------------------------------- /uart.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2015 Kashyap 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | import x86asm 24 | 25 | const COM1 = 0x3f8 26 | 27 | var uart : bool = false 28 | 29 | 30 | proc uartPutC(byte: int8) = 31 | if not uart: 32 | return 33 | for i in 0 .. 128: 34 | if 0 == (int8(inb(COM1+5)) and 0x20): 35 | break 36 | outb(COM1, uint8(byte)) 37 | 38 | proc uartGetC() : int = 39 | if not uart: 40 | return -1 41 | 42 | if 0 == (int8(inb(COM1+5)) and 0x01): 43 | return -1 44 | 45 | return int(inb(COM1)) 46 | 47 | 48 | proc uartPutHexDigit(h: int8) = 49 | var hexString: cstring = "0123456789ABCDEF" 50 | uartPutC(int8(hexString[h])) 51 | 52 | proc uartPutInt8*(b: int8) = 53 | let n1 = (b and 0xf0) shr 4 54 | let n2 = b and 0xf 55 | uartPutHexDigit(int8(n1)) 56 | uartPutHexDigit(int8(n2)) 57 | 58 | proc uartPutInt16*(w: int16) = 59 | var ww = w 60 | var p = cast[ptr array[2, int8]]( addr ww ) 61 | for i in 0 .. 1: 62 | uartPutInt8(p[1-i]) 63 | 64 | proc uartPutInt32*(dw: int32) = 65 | var dwdw = dw 66 | var p = cast[ptr array[4, int8]]( addr dwdw ) 67 | for i in 0 .. 3: 68 | uartPutInt8(p[3-i]) 69 | 70 | proc uartPutInt64*(qw: int64) = 71 | var qwqw = qw 72 | var p = cast[ptr array[8, int8]]( addr qwqw ) 73 | for i in 0 .. 7: 74 | uartPutInt8(p[7-i]) 75 | 76 | 77 | proc uartPutStr*(text: cstring) = 78 | for i in 0 .. text.len - 1: 79 | uartPutC(int8(text[i])) 80 | 81 | proc earlyInit* () = 82 | outb(COM1+2 , 0) 83 | 84 | #9600 baud, 8 data bits, 1 stop bit, parity off. 85 | outb(COM1+3, 0x80) # Unlock divisor 86 | outb(COM1+0, 12) # 115200/9600 87 | outb(COM1+1, 0) 88 | outb(COM1+3, 0x03) # Lock divisor, 8 data bits. 89 | outb(COM1+4, 0) 90 | outb(COM1+1, 0x01) # Enable receive interrupts. 91 | 92 | 93 | var b = inb(COM1 + 5) 94 | if int(b) == 0xff: 95 | return 96 | 97 | uart = true 98 | 99 | uartPutStr("xv6...\n") 100 | 101 | var x = uartGetC() 102 | 103 | if x == 65: 104 | while true: 105 | uartPutStr("Capital A pressed\n") 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /vm64.nim: -------------------------------------------------------------------------------- 1 | import procs 2 | 3 | #var cpu* {.codegenDecl: "__thread dingo $# $#$#".} : ptr CPU 4 | #var cpu* {.codegenDecl: "$# $# asm(\"%fs:0\")".} : ptr CPU 5 | var cpu*{.threadvar.}: ptr CPU 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /x86asm.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2015 Kashyap 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | proc outb* (port: uint16, value: uint8) = 24 | asm """ 25 | outb %%al, %%dx 26 | : 27 | :"a"(`value`), "d"(`port`) 28 | """ 29 | 30 | proc inb* (port: uint16): uint8 = 31 | asm """ 32 | inb %%dx, %%al 33 | :"=a"(`result`) 34 | :"d"(`port`) 35 | """ 36 | 37 | 38 | proc readeflags*(): uint64 = 39 | asm """ 40 | pushf 41 | pop %0 42 | :"=r"(`result`) 43 | : 44 | """ 45 | proc cli*() = 46 | asm """ 47 | cli 48 | """ 49 | 50 | discard readeflags() 51 | --------------------------------------------------------------------------------