├── .gitignore ├── Makefile ├── README.md ├── bootloader ├── Makefile └── bootloader.S ├── doc ├── help ├── iret ├── links ├── memorymanagement ├── mutex-theory ├── net ├── osmem.vsd ├── routing └── screenshots │ ├── boot.png │ ├── hexeditor.png │ ├── shell.png │ ├── tetris.png │ └── webserver.png ├── kernel ├── Makefile ├── apic.S ├── arp.c ├── arpcache.c ├── ata.c ├── block_cache.c ├── block_cache.h ├── block_device.c ├── block_device.h ├── boot.S ├── cmos.S ├── config.h ├── console.c ├── console.h ├── flatfs.c ├── flatfs.h ├── guest.S ├── hardware.S ├── hashtable.c ├── heap.S ├── helpers.S ├── icmp.c ├── includes │ └── kernel │ │ ├── hashtable.h │ │ ├── intA0.h │ │ ├── sockets.h │ │ ├── systemhandle.h │ │ ├── tree.h │ │ └── types.h ├── intA0.S ├── interrupts.S ├── ip.c ├── ip.h ├── ip_routing.c ├── kernelmain.S ├── keyboard.c ├── keyboard.h ├── link.lds ├── macros.h ├── memorypool.c ├── memorypool.h ├── mmu.S ├── mmu_c.c ├── mutex.S ├── netcard.c ├── netcard.h ├── pci.c ├── pic.S ├── pit.h ├── printf.c ├── printf.h ├── rtl8139.c ├── scheduler.S ├── sockets.c ├── sockets.h ├── tasks.h ├── test.c ├── timer.S ├── tree.c ├── userboot.c ├── userprocess.c ├── userprocess.h ├── utils.h ├── vfat.c ├── vfat.h ├── vfs.c ├── vfs.h ├── video.c ├── video.h ├── video_s.S ├── virtblock.c ├── virtio.c ├── virtio.h ├── virtnet.c ├── vmx.S ├── vmx.h └── vmx_ept.c ├── memorymap.h ├── tests ├── Makefile ├── bcache.c └── hash.c └── userapps ├── Makefile ├── Makefile.skel ├── README ├── bulkfiles ├── bootscript └── index.html ├── createapp ├── date ├── Makefile └── main.c ├── hexdump ├── Makefile └── main.c ├── hexedit ├── Makefile └── main.c ├── link.ld ├── shell ├── Makefile └── main.c ├── systemlib ├── Makefile ├── console.c ├── console.h ├── files.c ├── files.h ├── libc.elf ├── link.ld ├── memory.c ├── memory.h ├── network.c ├── network.h ├── string.c ├── string.h ├── threads.c ├── threads.h ├── types.h ├── utils.c └── utils.h ├── telnet ├── Makefile └── main.c ├── testapp1 ├── Makefile └── main.c ├── tetris ├── Makefile ├── main.c └── shapes.h └── webserver ├── Makefile └── main.c /.gitignore: -------------------------------------------------------------------------------- 1 | todo 2 | *.o 3 | *.out 4 | t 5 | *.bak 6 | *.a 7 | *.img 8 | *.inc 9 | qemu.log 10 | userapps/appsbin/ 11 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: image 2 | DISKSIZE=10240 #5 meg divided by 512 3 | 4 | 5 | .PHONY: image 6 | 7 | image: 8 | cd kernel && make 9 | cd bootloader && make 10 | cd tests && make 11 | cd userapps && make 12 | mkdir -p image 13 | dd if=/dev/zero of=image/disk.img count=$(DISKSIZE) 14 | dd conv=notrunc if=bootloader/bootloader.o of=image/disk.img 15 | dd conv=notrunc if=kernel/kernel.o of=image/disk.img seek=3 16 | 17 | .PHONY: net 18 | net: 19 | sudo tunctl -t tap100 20 | sudo tunctl -t tap200 21 | sudo ifconfig tap100 0.0.0.0 promisc up 22 | sudo ifconfig tap200 0.0.0.0 promisc up 23 | run: net 24 | sudo qemu-system-x86_64 --enable-kvm -cpu host -smp 4 -option-rom sgabios.bin \ 25 | -m 8192 -rtc base=localtime \ 26 | -monitor stdio -curses \ 27 | -drive file=image/disk.img,if=ide \ 28 | -drive file=userapps/disk.img,if=virtio \ 29 | -net nic,model=virtio,macaddr=52:54:00:12:34:60 -net tap,ifname=tap100,script=no \ 30 | -d cpu_reset -D qemu.log 31 | # -net nic,model=rtl8139,macaddr=52:54:00:12:34:61 -net tap,vlan=1,ifname=tap1,script=no \ 32 | 33 | test: net 34 | sudo qemu-system-x86_64 --enable-kvm -cpu host -smp 4 -option-rom sgabios.bin \ 35 | -m 8192 -rtc base=localtime \ 36 | -monitor telnet:127.0.0.1:2048,server,nowait,ipv4 -curses \ 37 | -drive file=image/disk.img,if=ide \ 38 | -drive file=userapps/disk.img,if=virtio \ 39 | -net nic,model=virtio,macaddr=52:54:00:12:34:60 -net tap,ifname=tap100,script=no \ 40 | -d cpu_reset -D qemu.log 41 | # -net nic,model=rtl8139,macaddr=52:54:00:12:34:61 -net tap,vlan=1,ifname=tap1,script=no \ 42 | 43 | server: net 44 | sudo qemu-system-x86_64 --enable-kvm -cpu host -smp 4 -option-rom sgabios.bin \ 45 | -m 4096 -rtc base=localtime \ 46 | --daemonize \ 47 | -drive file=image/disk.img,if=ide \ 48 | -drive file=userapps/disk.img,if=virtio \ 49 | -drive file=hddtest1/test2.img,if=virtio \ 50 | -net nic,model=virtio,macaddr=52:54:00:12:34:60 -net tap,ifname=tap100,script=no \ 51 | -d cpu_reset -D qemu.log 52 | # -net nic,model=rtl8139,macaddr=52:54:00:12:34:61 -net tap,vlan=1,ifname=tap1,script=no \ 53 | 54 | 55 | #test: 56 | #qemu-system-x86_64 --enable-kvm -cpu host -smp 4 -monitor telnet:127.0.0.1:3014,server,nowait,ipv4 -option-rom sgabios.bin -hda image/disk.img -hdb userapps/disk.img -curses -net nic,model=rtl8139,macaddr=52:54:00:12:34:60 -net tap,ifname=tap100,script=no -net nic,model=rtl8139,macaddr=52:54:00:12:34:61 -net tap,ifname=tap200,script=no -m 4096 -d int,cpu_reset -D qemu.log -rtc base=localtime 57 | 58 | # qemu-system-x86_64 --enable-kvm -cpu host -option-rom sgabios.bin -hda image/disk.img -monitor telnet:127.0.0.1:2048,server,nowait,ipv4 -nographic -no-reboot -net nic,model=rtl8139,macaddr=52:54:00:12:34:60 -net tap4,vlan=0,ifname=tap2,script=no -net nic,model=rtl8139,macaddr=52:54:00:12:34:61 -net tap,vlan=1,ifname=tap3,script=no -D qemu.log -d int,in_asm 59 | 60 | clean: 61 | cd kernel && make clean 62 | cd userapps && make clean 63 | -rm -f sizekernel.inc 64 | -rm -f image/* 65 | 66 | disasm: 67 | #objdump -D -b binary -mi386 -M x86-64 kernel/kernel.o 68 | objdump -D -mi386 -M x86-64 kernel/kerneldump.o 69 | 70 | tunctl: 71 | tunctl -u pat -t tap2 72 | tunctl -u pat -t tap4 73 | chown root:sysadmin /dev/kvm 74 | chmod 660 /dev/kvm 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bare metal x86_64 OS 2 | 3 | ## Specifications 4 | disk is a raw image with no MBR or partition 5 | user applications are stored in a tar file. The tar file is used as a readonly disk 6 | using "flatfs" as the "tar" filesystem 7 | paging uses identity mapping of the 2first mb with 2mb pages 8 | and virtual memory addresses with bit 46 set are mirror addresses. 9 | meaning that gig #65536 maps to gig #0. 10 | 11 | supports ring3 user threads and ring0 kernel threads 12 | supports multiprocessors 13 | Supports AVX 14 | supports APIC, and not PIC 15 | supports PCID and does TLB shootdowns 16 | supports sending IPIs and registering custom handlers 17 | supports RTL8139 netcard on PCI bus 18 | supports virtio block device and virtio net device. 19 | networking works but not fully tested 20 | - can receive TCP connection and establish one 21 | - send/rcv 22 | - no failure testing 23 | basic hypervisor 24 | CPU virtualization with VMX 25 | no BIOS 26 | no virtual devices 27 | no emulation of A20M 28 | 29 | 30 | ## Screenshots 31 | ### Booting 32 | ![boot](doc/screenshots/boot.png) 33 | 34 | ### Hex editor 35 | ![hexeditor](doc/screenshots/hexeditor.png) 36 | 37 | ### Simple shell 38 | ![shell](doc/screenshots/shell.png) 39 | 40 | ### tetris 41 | ![tetris](doc/screenshots/tetris.png) 42 | 43 | ### web server 44 | ![webserver](doc/screenshots/webserver.png) 45 | -------------------------------------------------------------------------------- /bootloader/Makefile: -------------------------------------------------------------------------------- 1 | all: bootloader 2 | 3 | bootloader: bootloader.S 4 | gcc -c -m32 bootloader.S -o bootloader.o 5 | objcopy bootloader.o -O binary 6 | 7 | disasm: 8 | ndisasm bootloader.o 9 | 10 | 11 | -------------------------------------------------------------------------------- /bootloader/bootloader.S: -------------------------------------------------------------------------------- 1 | // the drive is raw, no MBR, no partitions, no filesystems. 2 | // The kernel resides on sector 3 3 | 4 | #include "../memorymap.h" 5 | 6 | .include "../sizekernel.inc" 7 | 8 | .CODE16 9 | .ORG 0 10 | 11 | .EQU HEAP, 0x0500 /* this is relative to 0x00000000*/ 12 | .EQU STACK_END,0x7C00 13 | .EQU STACKSEG, 0 14 | .EQU KERNEL_BASE_ADDR, KERNEL_BASE 15 | 16 | start: 17 | .BYTE 0xEA 18 | .WORD 5 19 | .WORD 0x07C0 /* this will jump and will set CS to 0x07C0*/ 20 | 21 | .org 5 22 | main: 23 | cli 24 | //Setup Stack 25 | pushw $STACKSEG 26 | popw %ss 27 | mov $STACK_END,%sp 28 | mov %sp,%bp 29 | 30 | // create Application Processors boot address 31 | // This is a jump to the "apmain" label. 32 | push %cs 33 | pop %ds 34 | pushw $0 35 | pop %es 36 | mov $SMP_TRAMPOLINE,%di 37 | mov $JUMPCODETOAP,%si 38 | mov $8,%cx 39 | rep movsb 40 | 41 | mov $0,%ax 42 | mov %ax,%gs 43 | 44 | call detect_memory 45 | 46 | // enable A20 line adressing 47 | call a20wait 48 | mov $0xAD,%al 49 | out %al,$0x64 50 | call a20wait 51 | mov $0xD0,%al 52 | out %al,$0x64 53 | call a20wait2 54 | in $0x60,%al 55 | push %eax 56 | call a20wait 57 | mov $0xD1,%al 58 | out %al,$0x64 59 | call a20wait 60 | pop %eax 61 | or $2,%al 62 | out %al,$0x60 63 | call a20wait 64 | mov $0xAE,%al 65 | out %al,$0x64 66 | call a20wait 67 | 68 | // enable unreal mode to have access to full 32bit addressing 69 | push %cs /* remember, cs is 07C0*/ 70 | pop %ds 71 | mov $GDTINFO,%eax 72 | lgdtl (%eax) 73 | mov %cr0,%eax 74 | or $1,%al 75 | mov %eax,%cr0 /* protected mode */ 76 | mov $0x08,%bx 77 | mov %bx,%fs 78 | mov %bx,%es 79 | and $0xFE,%al /* Back to real mode. es will still be a valid 32bit segment because cached value not cleared */ 80 | mov %eax,%cr0 81 | 82 | // load sectors 1 by one for kernel in temporary buffer and copy to real location 83 | movl $0x1FA,%eax /* get kernel size */ 84 | movl (%eax),%ecx 85 | shrl $9,%ecx /* divide by 512 and add 1 to get number of sectors we should read */ 86 | incl %ecx /* dx now contains number of sectors for kernel */ 87 | xorl %ebx,%ebx 88 | 89 | mov $KERNEL_BASE_ADDR,%edi 90 | readNextSector: 91 | push %edi 92 | movl $DAP,%esi 93 | movl %ebx,%eax 94 | addl $3,%eax /* offset sector by 3, to skip first 3 sectors */ 95 | movl %eax,8(%esi) /* eax is the sector number*/ 96 | mov $0x42,%ah 97 | mov $0x80,%dl 98 | int $0x13 99 | 100 | // copy that sector to kernel memory 101 | pop %edi 102 | mov $HEAP,%esi 103 | push %ecx 104 | mov $512,%ecx 105 | copykernel: 106 | mov %gs:(%esi),%al 107 | mov %al,%fs:(%edi) 108 | inc %edi 109 | inc %esi 110 | loop copykernel 111 | pop %ecx 112 | 113 | incl %ebx 114 | cmpl %ebx,%ecx /* current sector is equal to number of sectors to read? */ 115 | jne readNextSector 116 | 117 | //swtich back to protected mode so we can jump to meg 1 118 | mov %cr0,%eax 119 | or $1,%al 120 | mov %eax,%cr0 121 | 122 | // WARNING: WE ARE BACK TO PROTECTED MODE NOW. NO BIOS CALLS ARE ALLOWED ANYMORE 123 | // Jump far to update 'cs' and to reach new code: the kernel 124 | ljmpl $0x10,$KERNEL_BASE_ADDR 125 | 126 | a20wait: 127 | in $0x64,%al 128 | test $2,%al 129 | jnz a20wait 130 | ret 131 | a20wait2: 132 | in $0x64,%al 133 | test $1,%al 134 | jz a20wait2 135 | ret 136 | 137 | printchar: /* param: al=char */ 138 | pushl %ebx 139 | pushl %ecx 140 | mov $0x09,%ah 141 | mov $0x0004,%bx 142 | mov $10,%cx 143 | int $0x10 144 | popl %ecx 145 | popl %ebx 146 | ret 147 | 148 | detect_memory: 149 | push %es 150 | mov $(MEMMAP >> 4),%ax 151 | mov %ax,%es 152 | mov $0,%di 153 | mov $0,%bx 154 | 1: mov $24,%cx 155 | mov $0x534d4150,%edx 156 | mov $0xe820,%ax 157 | int $0x15 158 | add $24,%di 159 | cmp $0,%bx 160 | jne 1b 161 | pop %es 162 | ret 163 | 164 | 165 | // WARNING: do not use the stack in here 166 | apmain: 167 | cli 168 | // Go in protected mode 169 | mov %cs,%ax /* remember, cs is 07C0*/ 170 | mov %ax,%ds 171 | mov $GDTINFO,%eax 172 | lgdtl (%eax) 173 | mov %cr0,%eax 174 | or $1,%al 175 | mov %eax,%cr0 /* protected mode */ 176 | ljmpl $0x10,$KERNEL_BASE_ADDR 177 | 178 | 179 | // =============================== END CODE ====================================================== 180 | 181 | 182 | .align 4 183 | JUMPCODETOAP: 184 | .BYTE 0x90 185 | .BYTE 0x90 186 | .BYTE 0x90 187 | .BYTE 0xEA 188 | .WORD apmain 189 | .WORD 0x07C0 190 | .align 4 191 | DAP: 192 | .BYTE 0x10 193 | .BYTE 0x00 194 | .WORD 0x01 195 | .WORD HEAP /*heap base location offset*/ 196 | .WORD 0 /*segment*/ 197 | sector: .LONG 0x02 /* sector 3 */ 198 | .LONG 0x00 199 | 200 | .align 4 201 | GDTINFO: 202 | // GDT INFO 203 | .WORD 0x20 204 | .LONG . + 0x7C04 /*that will be the address of the begining of GDT table*/ 205 | 206 | // GDT 207 | .LONG 00 208 | .LONG 00 209 | 210 | // GDT entry 1. Data segment descriptor used during unreal mode 211 | .BYTE 0xFF 212 | .BYTE 0xFF 213 | .BYTE 0x00 214 | .BYTE 0x00 215 | .BYTE 0x00 216 | .BYTE 0b10010010 217 | .BYTE 0b11001111 218 | .BYTE 0x00 219 | 220 | // GDT entry 2. Code segment used during protected mode code execution 221 | .BYTE 0xFF 222 | .BYTE 0xFF 223 | .BYTE 0x00 224 | .BYTE 0x00 225 | .BYTE 0x00 226 | .BYTE 0b10011010 227 | .BYTE 0b11001111 228 | .BYTE 0x00 229 | 230 | // GDT entry 3. 64bit Code segment used for jumping to 64bit mode. 231 | // This is just used to turn on 64bit mode. Segmentation will not be used anymore after 64bit code runs. 232 | // We will jump into that segment and it will enable 64bit. But limit and permissions are ignored, 233 | // the CPU will only check for bit D and L in this case because when we will jump in this, we will 234 | // already be in long mode, but in compatibility sub-mode. This means that while in long mode, segments are ignored. 235 | // but not entiorely. Long mode will check for D and L bits when jumping in another segment and will change 236 | // submodes accordingly. So in long mode, segments have a different purpose: to change sub-modes 237 | .BYTE 0xFF 238 | .BYTE 0xFF 239 | .BYTE 0x00 240 | .BYTE 0x00 241 | .BYTE 0x00 242 | .BYTE 0b10011010 243 | .BYTE 0b10101111 // bit 6 (D) must be 0, and bit 5 (L, was reserved before) must be 1 244 | .BYTE 0x00 245 | 246 | 247 | .ORG 0x01FA /* Kernel size */ 248 | .LONG KERNEL_SIZE 249 | .ORG 0x01FE 250 | .BYTE 0x55 251 | .BYTE 0xAA 252 | 253 | .org 0x200 254 | 255 | -------------------------------------------------------------------------------- /doc/help: -------------------------------------------------------------------------------- 1 | http://www.osdever.net/tutorials.php?cat=8&sort=1 2 | gdb: 3 | start qemu: qemu-system-x86_64 -S -s image/disk.img 4 | gdb: target remote :1234 5 | breakpoint: br *0x00000000 6 | gdb step next instruction: si 7 | 8 | 9 | dump machine mem: 10 | in qemu monitor console: xp/60b 0x092A8000 11 | will show 60 bytes of physical memory at addr 12 | 13 | 14 | calling convention for C: 15 | The first six integer or pointer arguments are passed in registers RDI, RSI, RDX, RCX, R8, and R9, while XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 and XMM7 are used for floating point arguments 16 | 17 | 18 | qemu: get info on triple fault: 19 | -d int,cpu_reset -nogrpahic -no-reboot 20 | 21 | disasm: 22 | objdump -D -b binary -mi386 -M x86-64 image/disk.img 23 | -------------------------------------------------------------------------------- /doc/iret: -------------------------------------------------------------------------------- 1 | (error) 2 | rip 3 | cs 4 | eflags 5 | rsp 6 | ss 7 | IF return code segment selector RPL < CPL then #GP 8 | IF return code segment selector RPL > CPL 9 | IF stack segment selector is NULL then #GP 10 | IF stack segment selector RPL != RPL of the return code segment selector 11 | or the stack segment descriptor does not indicate a a writable data segment 12 | or the stack segment DPL != RPL of the return code segment selector then #GP 13 | FOR each of segment register (ES, FS, GS, and DS) 14 | IF (segment register points to data || non-conforming code segment) 15 | && CPL > segment descriptor DPL 16 | (* Segment register invalid *) 17 | SegmentSelector = 0; 18 | FI; 19 | ROF; 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /doc/links: -------------------------------------------------------------------------------- 1 | http://www.ijack.org.uk/code.html 2 | https://littleosbook.github.io/ 3 | -------------------------------------------------------------------------------- /doc/memorymanagement: -------------------------------------------------------------------------------- 1 | The memory releasing mechnasim is pretty naive. Instead of having a heap that grows and shrink 2 | like linux, we just immediately free pages as they become unused in the heap. This has the advantage 3 | of maximizing memory usage wince every page that is not used will be released imemdiately. But this 4 | will impact performances when a process makes a lot of request to allocate/free small object because 5 | the memory will be freed completely and re-allocated everytime. On linux, the pages would still 6 | be allocated since freeing memory only has the effect of shrinking the heap, and fragmented memory 7 | is not freed. 8 | 9 | when mem is needed 10 | find all present pages with "accessed" cleared and free them. 11 | these pages must be invalidated from TLB (and do TLB shootdown) 12 | NOTES: 13 | after #PF, the page will be present but "accessed" will be 0. We must not reap those. 14 | When reaping a page, another CPU might try to access the page. 15 | using cmpxchg, we must guarantee that "P" will be cleared only if "Accessed" is still 0 16 | 17 | 18 | 19 | The "linux" way of doing this would be to have the kernel give a heap to the process. The kernel 20 | does not track free memory within the heap. This is done by malloc() in user space. 21 | If malloc detect that the heap is too smal, it requests the kernel to grow it. 22 | When freeing memory, the kernel is informed if the top of the heap should change and 23 | the kernel will shrink it back 24 | 25 | -------------------------------------------------------------- 26 | OLD IDEAS 27 | -------------------------------------------------------------- 28 | Need a better memory management method 29 | 30 | right now malloc reserves virt mem and phys is mapped upon #pf only. there 31 | is no free block remaping after free. pages freed after process death 32 | need better system: 33 | - should reclaim unused pages such as: 34 | a low-priority task than scavenges unused pages. Kind of like a garbage collector 35 | The task would go through all processes and invoke: 36 | - scanvengeStack() 37 | - scavengeHeap(size,F) 38 | F is a function void F(start,end). 39 | It will loop through the heap and find all 40 | areas larger than "size" and invoke F(area_start,area_end) 41 | The F function will then be able to free pages. 42 | But while scavenging, the stack should not move, nor the heap!! 43 | ----- 44 | on free: 45 | tell the kernel that what range was freed and let him dealloc pages 46 | 47 | 48 | stack: *** Search for "stack page deallocation" 49 | will need to scavenge. 50 | when? 51 | thread resume? 52 | thread going to sleep? 53 | 54 | 55 | ----------------------------------------------------------------------------------------- 56 | other concept: 57 | process gets a pool of heap. It starts with, let's say, 16mb in the pool. The pages are not allocated but they are reserved 58 | These are the virtual pages of the process. Since they are not present, we can use the rest of the bits to indicate that 59 | they are reserved. malloc() would be implemented in userland (systemlib). It would manage the linked list. 60 | It wouldn't allocate the page to phys. #PF will do that. But #PF can know if the page is reserved or not. 61 | If it wasn't, then it wasn't part of the pool. If the pool needs to grow, then malloc requests that to the kernel 62 | The kernel will then mark more more of these pages. 63 | 64 | free() would downsize the pool. But not all the time, because of fragmentation. So the kernel could reap 65 | pages that are beyond the end of the pool 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /doc/mutex-theory: -------------------------------------------------------------------------------- 1 | mutex 2 | { 3 | CurrentTicket=0; 4 | NextTicket=0; 5 | 6 | lock() 7 | n = FetchAndIncrement(NextTicket) 8 | while (n != CurrentTicket) yield; 9 | 10 | unlock() 11 | //TODO: should not do this if we don't hold the mutex right now 12 | CurrentTicket++ 13 | } 14 | 15 | if process dies and never unlocks, the count wont be increased 16 | If mutex only used within same process, its no big deal 17 | for pf(), the mutex is in kernel. 18 | maybe we should pool the request and not let threads trigger locks in kernel 19 | -- OR -- 20 | Each ticker should be associated to a processID and checked for existance? 21 | - overhead 22 | - if process frozen, we still get the deadlock 23 | -------------------------------------------------------------------------------- /doc/osmem.vsd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdumais/OperatingSystem/5fd5343c7af53fbc1e5ba5cbcf3c1a71844c56c3/doc/osmem.vsd -------------------------------------------------------------------------------- /doc/routing: -------------------------------------------------------------------------------- 1 | 192.168.1.0 255.255.255.0 0.0.0.0 if0 2 | 192.168.2.0 255.255.255.0 0.0.0.0 if1 3 | 0.0.0.0 0.0.0.0 192.168.1.1 if0 4 | 5 | OK - if 1.3 pings 2.28 directly using br0, 2.28 should recognize and reply 6 | - if if1 sends to google, it will need to go out on if0 with GW's mac 7 | ARP request for GW must be sent using if0's IP addr. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /doc/screenshots/boot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdumais/OperatingSystem/5fd5343c7af53fbc1e5ba5cbcf3c1a71844c56c3/doc/screenshots/boot.png -------------------------------------------------------------------------------- /doc/screenshots/hexeditor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdumais/OperatingSystem/5fd5343c7af53fbc1e5ba5cbcf3c1a71844c56c3/doc/screenshots/hexeditor.png -------------------------------------------------------------------------------- /doc/screenshots/shell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdumais/OperatingSystem/5fd5343c7af53fbc1e5ba5cbcf3c1a71844c56c3/doc/screenshots/shell.png -------------------------------------------------------------------------------- /doc/screenshots/tetris.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdumais/OperatingSystem/5fd5343c7af53fbc1e5ba5cbcf3c1a71844c56c3/doc/screenshots/tetris.png -------------------------------------------------------------------------------- /doc/screenshots/webserver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdumais/OperatingSystem/5fd5343c7af53fbc1e5ba5cbcf3c1a71844c56c3/doc/screenshots/webserver.png -------------------------------------------------------------------------------- /kernel/Makefile: -------------------------------------------------------------------------------- 1 | OUT=../image/ 2 | OBJC=printf.o pci.o rtl8139.o netcard.o arp.o arpcache.o ip.o icmp.o ip_routing.o block_cache.o ata.o test.o userboot.o console.o keyboard.o userprocess.o vfs.o flatfs.o sockets.o memorypool.o hashtable.o tree.o vfat.o virtio.o virtnet.o block_device.o virtblock.o vmx_ept.o video.o mmu_c.o 3 | SOURCEC=$(OBJC:.o=.c) 4 | OBJASM=boot.o kernelmain.o interrupts.o scheduler.o helpers.o mutex.o mmu.o hardware.o apic.o intA0.o heap.o cmos.o vmx.o guest.o video_s.o timer.o 5 | SOURCEASM=$(OBJASM:.o=.S) 6 | CFLAGS=-fno-zero-initialized-in-bss -Wno-pointer-to-int-cast -ffreestanding -mcmodel=large -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow -Wimplicit-function-declaration -Werror=implicit-function-declaration -fno-pie 7 | PFLAGS=-DPCID 8 | 9 | .c.o: 10 | gcc -m64 $(CFLAGS) -c $< -o $@ 11 | .S.o: 12 | gcc -m64 -c $< $(PFLAGS) -o $@ 13 | 14 | all: kernel 15 | 16 | kernel: $(OBJASM) $(OBJC) 17 | @printf "\r\n========== Linking =============\r\n" 18 | ld -m elf_x86_64 -static --oformat=binary -T link.lds $(OBJASM) $(OBJC) -o kernel.o 19 | ld -m elf_x86_64 -static -T link.lds $(OBJASM) $(OBJC) -o kerneldump.o 20 | echo -n ".EQU KERNEL_SIZE, " > ../sizekernel.inc 21 | wc -c < kernel.o >> ../sizekernel.inc 22 | 23 | clean: 24 | -rm -f *.o 25 | 26 | -------------------------------------------------------------------------------- /kernel/arp.c: -------------------------------------------------------------------------------- 1 | #include "netcard.h" 2 | #include "printf.h" 3 | #include "utils.h" 4 | 5 | extern struct NetworkConfig* net_getConfig(unsigned char index); 6 | extern unsigned long net_getMACAddress(unsigned char index); 7 | extern unsigned long arpcache_get(unsigned int ip); 8 | extern void arpcache_put(unsigned int ip, unsigned long mac); 9 | extern void yield(); 10 | extern unsigned long net_send(unsigned char interface, unsigned long destinationMAC, unsigned short vlan, unsigned short ethertype, struct NetworkBuffer* netbuf); 11 | extern unsigned char net_getNumberOfInterfaces(); 12 | 13 | void arp_process(struct Layer2Payload* payload) 14 | { 15 | 16 | unsigned long ownMAC = net_getMACAddress(payload->interface); 17 | unsigned short hwType = *((unsigned short*)&payload->data[0]); 18 | unsigned short protocolType = *((unsigned short*)&payload->data[2]); 19 | unsigned short operation = *((unsigned short*)&payload->data[6]); 20 | unsigned int targetIP = *((unsigned int*)&payload->data[24]); 21 | 22 | struct NetworkConfig* conf = net_getConfig(payload->interface); 23 | if (payload->to == 0x0000FFFFFFFFFFFF) 24 | { 25 | if (hwType==0x0100 && protocolType==0x0008) 26 | { 27 | //C_BREAKPOINT_VAR(targetIP,conf->ip,operation,0) 28 | if (operation==0x0100 && targetIP == conf->ip) 29 | { 30 | unsigned char* buf = payload->data; 31 | unsigned char buf2[28]; 32 | (*(unsigned short*)&buf2[0]) = 0x0100; 33 | (*(unsigned short*)&buf2[2]) = 0x0008; 34 | (*(unsigned short*)&buf2[4]) = 0x0406; 35 | (*(unsigned short*)&buf2[6]) = 0x0200; 36 | (*(unsigned short*)&buf2[8]) = (unsigned short)(ownMAC&0xFFFF); 37 | (*(unsigned short*)&buf2[10]) = (unsigned short)((ownMAC>>16)&0xFFFF); 38 | (*(unsigned short*)&buf2[12]) = (unsigned short)((ownMAC>>32)&0xFFFF); 39 | (*(unsigned short*)&buf2[14]) = (unsigned short)((conf->ip)&0xFFFF); 40 | (*(unsigned short*)&buf2[16]) = (unsigned short)((conf->ip>>16)&0xFFFF); 41 | (*(unsigned short*)&buf2[18]) = *(unsigned short*)&buf[8]; 42 | (*(unsigned short*)&buf2[20]) = *(unsigned short*)&buf[10]; 43 | (*(unsigned short*)&buf2[22]) = *(unsigned short*)&buf[12]; 44 | (*(unsigned short*)&buf2[24]) = *(unsigned short*)&buf[14]; 45 | (*(unsigned short*)&buf2[26]) = *(unsigned short*)&buf[16]; 46 | 47 | struct NetworkBuffer netbuf={0}; 48 | netbuf.layer3Data = (unsigned char*)&buf2; 49 | netbuf.layer3Size = 28; 50 | net_send(payload->interface, payload->from, 0x0100, 0x0608, &netbuf); 51 | } 52 | } 53 | 54 | } 55 | 56 | if (operation == 0x0200) 57 | { 58 | unsigned long mac = (*((unsigned long*)&payload->data[8])&0x0000FFFFFFFFFFFF); 59 | unsigned int ip = (*((unsigned int*)&payload->data[14])); 60 | SWAP4(ip); 61 | SWAP6(mac); 62 | arpcache_put(ip,mac); 63 | } 64 | 65 | } 66 | 67 | void arp_query(unsigned int ip, unsigned long interface) 68 | { 69 | // Queries will only be done for nodes on the same network. 70 | //SWAP4(ip); 71 | unsigned char i; 72 | 73 | unsigned long ret; 74 | unsigned char buf[28]; 75 | struct NetworkConfig* conf = net_getConfig(interface); 76 | unsigned long ownMAC = net_getMACAddress(interface); 77 | 78 | (*(unsigned short*)&buf[0]) = 0x0100; 79 | (*(unsigned short*)&buf[2]) = 0x0008; 80 | (*(unsigned short*)&buf[4]) = 0x0406; 81 | (*(unsigned short*)&buf[6]) = 0x0100; 82 | (*(unsigned short*)&buf[8]) = (unsigned short)(ownMAC&0xFFFF); 83 | (*(unsigned short*)&buf[10]) = (unsigned short)((ownMAC>>16)&0xFFFF); 84 | (*(unsigned short*)&buf[12]) = (unsigned short)((ownMAC>>32)&0xFFFF); 85 | (*(unsigned short*)&buf[14]) = (unsigned short)((conf->ip)&0xFFFF); 86 | (*(unsigned short*)&buf[16]) = (unsigned short)((conf->ip>>16)&0xFFFF); 87 | (*(unsigned short*)&buf[18]) = 0x0000; 88 | (*(unsigned short*)&buf[20]) = 0x0000; 89 | (*(unsigned short*)&buf[22]) = 0x0000; 90 | (*(unsigned short*)&buf[24]) = (unsigned short)((ip)&0xFFFF); 91 | (*(unsigned short*)&buf[26]) = (unsigned short)((ip>>16)&0xFFFF); 92 | 93 | struct NetworkBuffer netbuf={0}; 94 | netbuf.layer3Data = (unsigned char*)&buf; 95 | netbuf.layer3Size = 28; 96 | // Warning, we are working with big-endian here 97 | ret = net_send(interface, 0xFFFFFFFFFFFF, 0x0100, 0x0608, &netbuf); 98 | } 99 | 100 | //WARNING: this parameter takes big-endian 101 | unsigned long arp_getMAC(unsigned int ip, unsigned long interface) 102 | { 103 | unsigned int temp = ip; 104 | SWAP4(temp); 105 | unsigned long mac = 0; 106 | mac = arpcache_get(temp); // ARP cache is little endian 107 | if (mac==0) 108 | { 109 | arp_query(ip, interface); 110 | unsigned char retry = 50; 111 | while (mac==0 && retry > 0) 112 | { 113 | yield(); 114 | mac = arpcache_get(temp); 115 | retry--; 116 | } 117 | } 118 | 119 | return mac; 120 | } 121 | 122 | void arp_learn(struct Layer2Payload* payload) 123 | { 124 | struct NetworkConfig* conf = net_getConfig(payload->interface); 125 | unsigned int sourceIP = *(unsigned int*)&payload->data[12]; 126 | unsigned int net1 = sourceIP & conf->subnetmask; 127 | unsigned int net2 = conf->ip & conf->subnetmask; 128 | if (net1==net2) 129 | { 130 | unsigned long mac = payload->from; 131 | SWAP6(mac); 132 | SWAP4(sourceIP); 133 | arpcache_put(sourceIP,mac); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /kernel/arpcache.c: -------------------------------------------------------------------------------- 1 | #include "printf.h" 2 | extern unsigned long getTicksSinceBoot(); 3 | //TODO: we should also use a second level of cache for recently used addresses. this would reduce the chances of 4 | // collisions if we happen to be using 5 addresses that collision together (the collision depth is 4 here) 5 | //WARNING: entries in cache must be little-endian 6 | 7 | // This is the number of bits in the IP address that we will use as HASH index. 8 | #define MAC_HASH_PRECISION 1024 9 | // if a collision occur, we will have 4 entries in that slots 10 | #define MAC_HASH_COLLISION 4 11 | 12 | //#define CACHE_TIMEOUT (60*5) 13 | #define CACHE_TIMEOUT 0x10000000000LL 14 | 15 | struct ArpCacheEntry 16 | { 17 | unsigned int ip; 18 | unsigned long timestamp; 19 | unsigned long mac; 20 | }; 21 | 22 | // hash table with 4096 entries and 4 slots per entry (for collisions) 23 | struct ArpCacheEntry arpCache[MAC_HASH_PRECISION][MAC_HASH_COLLISION]={0}; 24 | 25 | unsigned short iphash(unsigned int ip) 26 | { 27 | return (ip&(MAC_HASH_PRECISION-1)); 28 | } 29 | 30 | 31 | unsigned long arpcache_get(unsigned int ip) 32 | { 33 | unsigned short hash = iphash(ip); 34 | unsigned short i; 35 | unsigned long s = getTicksSinceBoot(); //TODO: should use accurante seconds 36 | unsigned long timeout = s - CACHE_TIMEOUT; 37 | if (s= timeout)) 41 | { 42 | return arpCache[hash][i].mac; 43 | } 44 | } 45 | return 0; 46 | } 47 | 48 | void arpcache_put(unsigned int ip, unsigned long mac) 49 | { 50 | unsigned short hash = iphash(ip); 51 | unsigned short i; 52 | unsigned long s = getTicksSinceBoot(); //TODO: should use accurante seconds 53 | unsigned long timeout = s - CACHE_TIMEOUT; 54 | if (s RESERVED_FOR_NEW_WRITE_CREATION -> PENDING_USER_WRITE -> PENDING_WRITE 8 | // Guaranteed to happen on same thread 9 | // FREE -> RESERVED_FOR_NEW_READ_CREATION -> PENDING_READ 10 | // Guaranteed to happen on same thread 11 | // PENDING_WRITE -> WRITING 12 | // Done by IRQ handler or any thread 13 | // PENDING_READ -> READING 14 | // Done by IRQ handler or any thread 15 | // READING -> IDLE 16 | // Done by IRQ handler 17 | // WRITING -> IDLE 18 | // Done by IRQ handler 19 | // IDLE-> PENDING_USER_WRITE -> PENDING_WRITE 20 | // This transition can be done by any thread. so protection is needed 21 | // IDLE -> TRASHING 22 | // - Any other transition is impossible. 23 | // - A block is considered UPTODATE if it is idle, pending_write or writing 24 | // - to read a block, it must be up to date. so the "readers" count 25 | // will prevent the block from getting TRASHING or PENDING_USER_WRITE while we read it 26 | // - to write to a block, it must be IDLE or FREE. The transition from 27 | // IDLE->PENDING_USER_WRITE could be attempted by 2 competing threads so this 28 | // transtion must be protected 29 | // - The following properties are observed: 30 | // - Several threads can read from an UPTODATE block 31 | // - only one thread can write in block and no other threads can read at the same time. 32 | // - no threads can write to block while other threads are reading 33 | 34 | #define BLOCK_CACHE_FREE 0 35 | #define BLOCK_CACHE_RESERVED_FOR_NEW_WRITE_CREATION 1 36 | #define BLOCK_CACHE_RESERVED_FOR_NEW_READ_CREATION 2 37 | #define BLOCK_CACHE_PENDING_READ 3 38 | #define BLOCK_CACHE_PENDING_WRITE 4 39 | #define BLOCK_CACHE_PENDING_USER_WRITE 5 40 | #define BLOCK_CACHE_PENDING_USER_READ 6 41 | #define BLOCK_CACHE_IDLE 7 42 | #define BLOCK_CACHE_WRITING 8 43 | #define BLOCK_CACHE_READING 9 44 | #define BLOCK_CACHE_TRASHED 10 45 | 46 | 47 | struct block_cache_entry 48 | { 49 | uint64_t idle_transition_critical_section; 50 | uint64_t bufferlock; 51 | unsigned long block; 52 | // The readers count is used so that the block stays up to 53 | // date while threads are reading it. While the count is greater 54 | // than zero, the block cannot be deleted nor get overwritten 55 | // by writer. 56 | volatile uint64_t readers; 57 | char *data; 58 | unsigned char device; 59 | volatile uint8_t state; 60 | unsigned long lastAccess; 61 | } __attribute((packed))__; 62 | 63 | 64 | void block_cache_init(char* cacheAddress); 65 | int block_cache_read(unsigned long blockNumber, int dev, char* buffer, unsigned int numberOfBlocks); 66 | int block_cache_write(unsigned long blockNumber, int dev, char* buffer, unsigned int numberOfBlocks); 67 | -------------------------------------------------------------------------------- /kernel/block_device.c: -------------------------------------------------------------------------------- 1 | #include "block_device.h" 2 | #include "printf.h" 3 | #include "macros.h" 4 | #include "utils.h" 5 | 6 | extern int init_ata(); 7 | extern int ata_read(unsigned int dev, unsigned long sector, char* buffer, unsigned long count); 8 | extern int ata_write(unsigned int dev, unsigned long sector, char* buffer, unsigned long count); 9 | extern bool ata_pci_device_matches(u16 vendor, u16 device, u16 subsystem); 10 | extern u64 ata_add_device(u32 addr, u32 iobase, u64* hw_index); 11 | extern u64 ata_get_size(u64 dev); 12 | 13 | extern int init_virtioblock(); 14 | extern int virtioblock_read(unsigned int dev, unsigned long sector, char* buffer, unsigned long count); 15 | extern int virtioblock_write(unsigned int dev, unsigned long sector, char* buffer, unsigned long count); 16 | extern bool virtblock_pci_device_matches(u16 vendor, u16 device, u16 subsystem); 17 | extern u64 virtioblock_add_device(u32 addr, u32 iobase, u64* hw_index); 18 | extern u64 virtblock_get_size(u64 dev); 19 | 20 | extern unsigned int pci_getDeviceByClass(unsigned char class, unsigned char index, unsigned long* vendor, unsigned long* device, unsigned short* sub); 21 | extern unsigned int pci_getBar(unsigned int dev,unsigned char bar); 22 | extern unsigned short pci_getIRQ(unsigned int dev); 23 | extern unsigned short pci_getIOAPICIRQ(unsigned int dev); 24 | 25 | static block_device devices[32]; 26 | static blockirqcallback irq_callback; 27 | static blockreadycallback ready_callback; 28 | 29 | typedef struct 30 | { 31 | int (*read)(unsigned int,unsigned long, char*, unsigned long); 32 | int (*write)(unsigned int,unsigned long, char*, unsigned long); 33 | int (*pci_device_matches)(unsigned short, unsigned short, unsigned short); 34 | int (*add_device)(u32,u32,u64*); 35 | u64 (*get_size)(u64); 36 | u8 type; 37 | } driver_info; 38 | 39 | driver_info drivers[] = { 40 | { 41 | .read = &ata_read, 42 | .write = &ata_write, 43 | .pci_device_matches = &ata_pci_device_matches, 44 | .type = BLOCK_DEVICE_TYPE_ATA, 45 | .get_size = &ata_get_size, 46 | .add_device = &ata_add_device 47 | }, 48 | { 49 | .read = &virtioblock_read, 50 | .write = &virtioblock_write, 51 | .pci_device_matches = &virtblock_pci_device_matches, 52 | .add_device = &virtioblock_add_device, 53 | .get_size = &virtblock_get_size, 54 | .type = BLOCK_DEVICE_TYPE_VIRTIO 55 | } 56 | }; 57 | 58 | #define DRIVER_COUNT (sizeof(drivers)/sizeof(driver_info)) 59 | 60 | void ata_irq(unsigned char dev, unsigned long block, unsigned long count) 61 | { 62 | unsigned int i; 63 | for (i = 0; i <32; i++) 64 | { 65 | if (devices[i].hw_device_number == dev && devices[i].type == BLOCK_DEVICE_TYPE_ATA) 66 | { 67 | irq_callback(i,block,count); 68 | return; 69 | } 70 | } 71 | } 72 | 73 | void ata_ready(unsigned char dev) 74 | { 75 | unsigned int i; 76 | for (i = 0; i <32; i++) 77 | { 78 | if (devices[i].hw_device_number == dev && devices[i].type == BLOCK_DEVICE_TYPE_ATA) 79 | { 80 | ready_callback(i); 81 | return; 82 | } 83 | } 84 | } 85 | 86 | void virtio_irq(unsigned char dev, unsigned long block, unsigned long count) 87 | { 88 | unsigned int i; 89 | for (i = 0; i <32; i++) 90 | { 91 | if (devices[i].hw_device_number == dev && devices[i].type == BLOCK_DEVICE_TYPE_VIRTIO) 92 | { 93 | irq_callback(i,block,count); 94 | return; 95 | } 96 | } 97 | } 98 | 99 | void virtio_ready(unsigned char dev) 100 | { 101 | unsigned int i; 102 | for (i = 0; i <32; i++) 103 | { 104 | if (devices[i].hw_device_number == dev && devices[i].type == BLOCK_DEVICE_TYPE_VIRTIO) 105 | { 106 | ready_callback(i); 107 | return; 108 | } 109 | } 110 | } 111 | 112 | void init_block(blockirqcallback icb, blockreadycallback rcb) 113 | { 114 | unsigned int i,n; 115 | unsigned int dev_num = 0; 116 | unsigned int dev_count; 117 | u64 device,vendor; 118 | u16 subsystem; 119 | 120 | irq_callback = icb; 121 | ready_callback = rcb; 122 | 123 | init_ata(&ata_irq,&ata_ready); 124 | init_virtioblock(&virtio_irq, &virtio_ready); 125 | 126 | for (n = 0; n < DRIVER_COUNT; n++) 127 | { 128 | driver_info* driver = &drivers[n]; 129 | for (i = 0; i < 32; i++) 130 | { 131 | vendor =0; 132 | device = 0; 133 | subsystem = 0; 134 | u32 addr = pci_getDeviceByClass(1,i,&vendor,&device,&subsystem); 135 | if (addr==0xFFFFFFFF) continue; 136 | if (driver->pci_device_matches(vendor,device,subsystem)) 137 | { 138 | u32 iobase = 0; 139 | int i2; 140 | for (i2=0;i2<6;i2++) 141 | { 142 | u32 m = pci_getBar(addr,i2); 143 | if (m==0) continue; 144 | if (m&1) 145 | { 146 | iobase = m & 0xFFFC; 147 | break; 148 | } 149 | } 150 | if (iobase == 0) C_BREAKPOINT(); 151 | 152 | u64 hw_index; 153 | u64 count = driver->add_device(addr, iobase, &hw_index); 154 | for (i2=0;i2read; 158 | devices[dev_num].write = driver->write; 159 | devices[dev_num].get_size = driver->get_size; 160 | devices[dev_num].type = driver->type; 161 | pf("Adding block device number %x, type [%x], hw index [%x], size [%x]\r\n", 162 | dev_num,driver->type, hw_index, (driver->get_size(hw_index)*512)); 163 | 164 | dev_num++; 165 | hw_index++; 166 | if (dev_num >= 32) C_BREAKPOINT(); 167 | } 168 | } 169 | } 170 | } 171 | } 172 | 173 | int block_read(unsigned int dev, unsigned long sector, char* buffer, unsigned long count) 174 | { 175 | block_device* d = &devices[dev]; 176 | return d->read(d->hw_device_number,sector,buffer,count); 177 | } 178 | 179 | int block_write(unsigned int dev, unsigned long sector, char* buffer, unsigned long count) 180 | { 181 | block_device* d = &devices[dev]; 182 | return d->write(d->hw_device_number,sector,buffer,count); 183 | } 184 | 185 | u64 block_get_size(unsigned int dev) 186 | { 187 | block_device* d = &devices[dev]; 188 | return d->get_size(d->hw_device_number); 189 | } 190 | -------------------------------------------------------------------------------- /kernel/block_device.h: -------------------------------------------------------------------------------- 1 | 2 | #define BLOCK_DEVICE_TYPE_ATA 1 3 | #define BLOCK_DEVICE_TYPE_VIRTIO 2 4 | 5 | typedef struct 6 | { 7 | int (*read)(unsigned int,unsigned long, char*, unsigned long); 8 | int (*write)(unsigned int,unsigned long, char*, unsigned long); 9 | unsigned long long (*get_size)(unsigned int); 10 | unsigned char (*isBusy)(unsigned char); 11 | 12 | unsigned int hw_device_number; 13 | unsigned char type; 14 | } block_device; 15 | 16 | typedef void (*blockirqcallback)(unsigned char, unsigned long, unsigned long); 17 | typedef void (*blockreadycallback)(unsigned char); 18 | 19 | void init_block(blockirqcallback irq_callback, blockreadycallback ready_callback); 20 | int block_read(unsigned int dev, unsigned long sector, char* buffer, unsigned long count); 21 | int block_write(unsigned int dev, unsigned long sector, char* buffer, unsigned long count); 22 | -------------------------------------------------------------------------------- /kernel/cmos.S: -------------------------------------------------------------------------------- 1 | .global getDateTime 2 | 3 | #define READ_CMOS_BCD(reg) mov $reg,%al; out %al,$0x70; in $0x71,%al; \ 4 | mov %al,%ah; \ 5 | shr $4,%al; \ 6 | and $0x0F0F,%ax; \ 7 | add $0x3030,%ax 8 | 9 | 10 | 11 | 12 | //////////////////////////////////////////////////////////////////////////////////// 13 | //////////////////////////////////////////////////////////////////////////////////// 14 | // Function: getDateTime(rdi=buffer_address) 15 | // 16 | //////////////////////////////////////////////////////////////////////////////////// 17 | //////////////////////////////////////////////////////////////////////////////////// 18 | getDateTime: 19 | push %rax 20 | push %rdi 21 | 22 | push %rdi 23 | mov $cmoslock,%rdi 24 | call spinLock 25 | pop %rdi 26 | 27 | // TODO: should adjust for time zone 28 | 29 | //TODO: should be carefull about CMOS updates 30 | READ_CMOS_BCD(7) 31 | mov %ax,(%rdi) 32 | movb $'/',2(%rdi) 33 | add $3,%rdi 34 | 35 | READ_CMOS_BCD(8) 36 | mov %ax,(%rdi) 37 | movb $'/',2(%rdi) 38 | add $3,%rdi 39 | 40 | //TODO: This is a Y2.1K bug! 41 | movw $0x3032,(%rdi) 42 | add $2,%rdi 43 | 44 | READ_CMOS_BCD(9) 45 | mov %ax,(%rdi) 46 | movb $' ',2(%rdi) 47 | add $3,%rdi 48 | 49 | READ_CMOS_BCD(4) 50 | mov %ax,(%rdi) 51 | movb $':',2(%rdi) 52 | add $3,%rdi 53 | 54 | READ_CMOS_BCD(2) 55 | mov %ax,(%rdi) 56 | movb $':',2(%rdi) 57 | add $3,%rdi 58 | 59 | READ_CMOS_BCD(0) 60 | mov %ax,(%rdi) 61 | movb $' ',2(%rdi) 62 | add $3,%rdi 63 | 64 | movb $0,(%rdi) 65 | 66 | mov $cmoslock,%rdi 67 | call spinUnlock 68 | 69 | pop %rdi 70 | pop %rax 71 | ret 72 | 73 | cmoslock: .quad 0 74 | -------------------------------------------------------------------------------- /kernel/config.h: -------------------------------------------------------------------------------- 1 | #define MAX_PCI_DEVICES_SUPPORTED 100 2 | #define PAGE_SIZE 4096 3 | 4 | -------------------------------------------------------------------------------- /kernel/console.h: -------------------------------------------------------------------------------- 1 | #include "includes/kernel/types.h" 2 | #include "includes/kernel/systemhandle.h" 3 | #include "video.h" 4 | 5 | //WARNING: struct should be bigger than 4k 6 | struct ConsoleData 7 | { 8 | system_handle handle; 9 | 10 | uint64_t streamPointer; 11 | uint64_t backBufferPointer; 12 | char streamBuffer[512]; 13 | uint16_t keyboardBuffer[64]; 14 | uint64_t kQueueIn; 15 | uint64_t kQueueOut; 16 | uint64_t owningProcess; 17 | uint64_t previousOwningProcess; 18 | uint64_t lock; 19 | Screen* screen; 20 | void (*flush_function)(); 21 | char ansiData[8]; 22 | uint8_t ansiIndex; 23 | uint16_t ansiSavedPosition; 24 | bool cursorOn; 25 | } __attribute((packed))__; 26 | 27 | void storeCharacter(uint16_t c); 28 | uint16_t pollChar(); 29 | 30 | void flushTextVideo(); 31 | void streamCharacters(char* str); 32 | Screen* getDirectVideo(); 33 | -------------------------------------------------------------------------------- /kernel/flatfs.c: -------------------------------------------------------------------------------- 1 | #include "flatfs.h" 2 | #include "block_cache.h" 3 | #include "printf.h" 4 | #include "utils.h" 5 | 6 | /* 7 | This file system driver implements a flat fs following the "tar" file format. 8 | 9 | */ 10 | 11 | extern void memcpy64(char* source, char* destination, uint64_t size); 12 | extern uint64_t block_get_size(uint32_t device); 13 | 14 | typedef struct 15 | { 16 | char name[100]; 17 | char mode[8]; 18 | char owner[8]; 19 | char group[8]; 20 | char size[12]; 21 | char last_modification[12]; 22 | char checksum[8]; 23 | char link_indicator; 24 | char link_name[100]; 25 | char pad[255]; 26 | } tar_header; 27 | 28 | 29 | void flatfs_system_handle_destructor(system_handle* h); 30 | 31 | bool strcompare(char* src, char* dst) 32 | { 33 | if (*src == 0 || *dst == 0) return false; 34 | while(*src == *dst && *src != 0) 35 | { 36 | src++; 37 | dst++; 38 | } 39 | return (*src == 0 && *dst == 0); 40 | } 41 | 42 | // converts from ascii octal to bin number 43 | uint64_t ascii2number(char* c, uint8_t size) 44 | { 45 | uint8_t byte; 46 | uint64_t ret = 0; 47 | uint64_t factor = 1; 48 | size-=2; 49 | char *buf = c+size; 50 | while (size) 51 | { 52 | byte = (*buf)-0x30; 53 | ret += ((uint64_t)byte)*factor; 54 | buf--; 55 | factor <<= 3; 56 | size--; 57 | } 58 | return ret; 59 | } 60 | 61 | bool flatfs_fopen(system_handle* h, char* name, uint64_t access_type) 62 | { 63 | unsigned char n1,n2,device; 64 | uint64_t n,i; 65 | file_handle* f = (file_handle*)h; 66 | h->destructor = &flatfs_system_handle_destructor; 67 | 68 | n1 = name[0]; 69 | n2 = name[1]; 70 | device = ((n1-0x30)<<4) | (n2-0x30); 71 | name += 4; // skip the xx:/ part of path 72 | 73 | tar_header header; 74 | int sector = 0; 75 | 76 | f->position = 0; 77 | f->start = -1; 78 | f->size = 0; 79 | f->device = device; 80 | 81 | uint64_t disk_size = block_get_size(device); 82 | uint64_t fsize; 83 | 84 | while ((sector) < disk_size) 85 | { 86 | block_cache_read(sector,device,&header,1); 87 | char* fname = &header.name[2]; // skip the "./" in the tar filename 88 | fsize = ascii2number(header.size,12); 89 | if (strcompare(fname,name)) 90 | { 91 | f->start = sector+1; 92 | f->size = fsize; 93 | return true; 94 | } 95 | 96 | sector += (((fsize+511)&0x1FF)>>9)+1; 97 | } 98 | return false; 99 | } 100 | 101 | uint64_t flatfs_fread(system_handle* h, uint64_t count, char* destination) 102 | { 103 | char buf[512]; 104 | file_handle* f = (file_handle*)h; 105 | if ((f->position + count) > f->size) count = (f->size-f->position); 106 | 107 | uint64_t first_sector = f->start + (f->position>>9); 108 | uint64_t start_index= f->position&0x1ff; 109 | uint64_t bytes_read = 0; 110 | 111 | if (start_index > 0) 112 | { 113 | block_cache_read(first_sector,f->device,buf,1); 114 | memcpy64((char*)&buf[start_index],destination,512-start_index); 115 | bytes_read = (512-start_index); 116 | destination += bytes_read; 117 | f->position += bytes_read; 118 | first_sector++; 119 | } 120 | 121 | if ((count-bytes_read)>=512) 122 | { 123 | uint64_t n = (count-bytes_read)>>9; 124 | block_cache_read(first_sector,f->device,destination,n); 125 | first_sector+=n; 126 | bytes_read += n<<9; 127 | destination += bytes_read; 128 | f->position += bytes_read; 129 | } 130 | 131 | if (count!=bytes_read) 132 | { 133 | if (((count-bytes_read)<512)) 134 | { 135 | block_cache_read(first_sector,f->device,buf,1); 136 | memcpy64(buf,destination,count-bytes_read); 137 | bytes_read = count; 138 | } 139 | else 140 | { 141 | __asm("mov $0xDEADBEEF,%rax; int $3"); 142 | } 143 | } 144 | 145 | return bytes_read; 146 | } 147 | uint64_t flatfs_fwrite(system_handle* h, uint64_t count, char* destination) 148 | { 149 | } 150 | 151 | void flatfs_fclose(system_handle* h) 152 | { 153 | } 154 | 155 | void flatfs_fseek(system_handle* h, uint64_t count, bool absolute) 156 | { 157 | } 158 | 159 | uint64_t flatfs_fgetsize(system_handle* h) 160 | { 161 | file_handle* f = (file_handle*)h; 162 | return f->size; 163 | } 164 | void flatfs_system_handle_destructor(system_handle* h) 165 | { 166 | //TODO: should release any held locks 167 | //TODO: should cancel any pending block operations 168 | } 169 | -------------------------------------------------------------------------------- /kernel/flatfs.h: -------------------------------------------------------------------------------- 1 | #include "includes/kernel/types.h" 2 | #include "vfs.h" 3 | 4 | // This is a dumb flat FS implementation that I use while I dont 5 | // support any other FS 6 | 7 | bool flatfs_fopen(system_handle* h, char* name, uint64_t access_type); 8 | uint64_t flatfs_fread(system_handle* h, uint64_t count, char* destination); 9 | uint64_t flatfs_fwrite(system_handle* h, uint64_t count, char* destination); 10 | void flatfs_fclose(system_handle* h); 11 | void flatfs_fseek(system_handle* h, uint64_t count, bool absolute); 12 | uint64_t flatfs_fgetsize(system_handle* h); 13 | -------------------------------------------------------------------------------- /kernel/guest.S: -------------------------------------------------------------------------------- 1 | .global vm_bootstrap 2 | 3 | #define AP_START 0x1000 4 | #define APIC_BASE_MSR 0x1B 5 | #define TEST_INDEX 0x2000 6 | 7 | .CODE16 8 | vm_bootstrap: 9 | .BYTE 0xEA 10 | .WORD 10 11 | .WORD 0x0 12 | .BYTE 0xEA 13 | .WORD ap_entry_point-vm_bootstrap 14 | .WORD 0x0 15 | 1: 16 | mov $0,%ax 17 | mov %ax,%ss 18 | mov %ax,%ds 19 | mov $0xF10,%sp 20 | 21 | mov $0x2000,%si 22 | mov %di,%ds:(%si) 23 | push %di 24 | 25 | // copy jump instruction to 0x1000 26 | mov $AP_START,%di 27 | movb $0xEA,(%di) 28 | movw $(ap_entry_point-vm_bootstrap),1(%di) 29 | movw $0x0,3(%di) 30 | 31 | // now send IPI with rip=0x1000 32 | mov $1,%edx 33 | mov $AP_START,%edi 34 | vmcall 35 | 36 | pop %di 37 | mov $4,%ah 38 | 39 | spin_test: 40 | mov $0xB800,%bx 41 | mov %bx,%es 42 | mov $'A',%al 43 | 44 | mov %di,%dx 45 | 46 | 1: 47 | cmp %di,%dx 48 | jne 2f 49 | mov %ax,%es:(%di) 50 | inc %al 51 | cmp $'Z',%al 52 | jna 1b 53 | mov $'A',%al 54 | jmp 1b 55 | 56 | 2: hlt 57 | 58 | ap_entry_point: 59 | mov $0,%ax 60 | mov %ax,%ss 61 | mov %ax,%ds 62 | mov $0xF10,%sp 63 | 64 | mov $0x2000,%si 65 | 1: mov %ds:(%si),%ax 66 | mov %ax,%di 67 | add $2,%di 68 | lock cmpxchg %di,%ds:(%si) 69 | jnz 1b 70 | 71 | mov $2,%ah 72 | jmp spin_test 73 | -------------------------------------------------------------------------------- /kernel/hardware.S: -------------------------------------------------------------------------------- 1 | #include "macros.h" 2 | #include "../memorymap.h" 3 | 4 | .global initHardware 5 | 6 | .extern launchSoftIRQThread 7 | .extern net_process 8 | 9 | 10 | 11 | initHardware: 12 | push %rdi 13 | push %rsi 14 | 15 | mov $softirqthread,%rdi 16 | mov $(softirqthread_end-softirqthread),%rsi 17 | call launchSoftIRQThread 18 | 19 | call initIntA0 20 | 21 | pop %rsi 22 | pop %rdi 23 | ret 24 | 25 | 26 | 27 | ///////////////////////////////////////////////////////////////////////////////////////// 28 | // The softIRQ thread is a thread that sleeps all the time until 29 | // an IRQ handlers wakes it up. In order to avoid heavy processing inside 30 | // an IRQ handler, the IRQ handler will set one of the 64 possible softIRQ 31 | // flag and re-enable the softIRQ thread so that it gets executed upon the 32 | // next schedule. 33 | // 34 | // The 64bit bitfield located at $SOFTIRQLIST represents the enabled softIRQ 35 | // (ie: bit0 represents softIRQ0. When the softIRQ thread runs, it will 36 | // call the handlers for all softIRQ that are enabled and will disable the bit 37 | // 38 | // The softIRQ thread is a special thread (created by createSoftIRQThread) 39 | // because the scheduler know about it. The scheduler will schedule 40 | // that thread if the softIRQ flags is non-zero. This thread 41 | // would have priority since the scheduler wont even bother to look 42 | // for a task in the task list if softIRQ needs to run 43 | // 44 | // TODO: Currently, the thread has hardcoded handlers. softIRQ0 45 | // will invoke net_process. But it should be possible for 46 | // drivers to register their softIRQ. 47 | // TODO: softirq should get prioritized: would need a scheduler prioritization scheme. 48 | ///////////////////////////////////////////////////////////////////////////////////////// 49 | 50 | softirqthread: 51 | // we first copy the value to rax and atomically clear the softirq variable. if another 52 | // IRQ comes in after that, it doesn't matter since we will yield and the scheduler will 53 | // give us time again. 54 | clearIRQList: 55 | mov $0,%rbx 56 | mov $SOFTIRQLIST,%r15 57 | mov (%r15),%rax 58 | lock cmpxchg %rbx,(%r15) //TODO: we need the lock, but do we need to loop? 59 | jnz clearIRQList 60 | mov %rax,%r15 // now r15 contains the original value of the softIRQ flags 61 | cmp $0,%r15 62 | jne checkIRQs 63 | call yield 64 | jmp clearIRQList 65 | checkIRQs: 66 | bt $SOFTIRQ_NET,%r15 // SOFTIRQ_NET 67 | jnc no_softirq0 68 | call net_process 69 | no_softirq0: 70 | no_softirq63: 71 | jmp clearIRQList 72 | sit: .ASCIZ "soft irq\r\n" 73 | softirqthread_end: 74 | 75 | 76 | -------------------------------------------------------------------------------- /kernel/hashtable.c: -------------------------------------------------------------------------------- 1 | #include "includes/kernel/hashtable.h" 2 | 3 | extern void memcpy64(void* source, void* destination, uint64_t size); 4 | extern void memclear64(void* dst, uint64_t size); 5 | extern void rwlockWriteLock(uint64_t*); 6 | extern void rwlockWriteUnlock(uint64_t*); 7 | extern void rwlockReadLock(uint64_t*); 8 | extern void rwlockReadUnlock(uint64_t*); 9 | 10 | uint64_t andhash(hashtable* ht, uint64_t keysize, uint64_t* key) 11 | { 12 | uint64_t mask = ((1<keysize)-1); 13 | uint64_t k = 0; 14 | uint64_t i = 0; 15 | for (i = 0; ikeysize)-1); 29 | uint64_t high = k >> ht->keysize; 30 | uint64_t low = k&mask; 31 | while (high != 0) 32 | { 33 | low += high; 34 | high = low >> ht->keysize; 35 | low = low&mask; 36 | } 37 | return low; 38 | } 39 | 40 | uint64_t hashtable_getrequiredsize(unsigned char keysize) 41 | { 42 | uint64_t listsize = (1 << keysize)*sizeof(hashtable_bucket); 43 | uint64_t tablesize = listsize + sizeof(hashtable); 44 | 45 | return tablesize; 46 | } 47 | 48 | void hashtable_init(hashtable* ht,unsigned char keysize,unsigned char hash_function) 49 | { 50 | memclear64(ht, hashtable_getrequiredsize(keysize)); 51 | if (hash_function == HASH_CUMULATIVE) 52 | { 53 | ht->hash_function = &cumulativehash; 54 | } 55 | else if (hash_function == HASH_AND) 56 | { 57 | ht->hash_function = &andhash; 58 | } 59 | ht->keysize = keysize; 60 | } 61 | 62 | void hashtable_add(hashtable* ht,uint64_t keysize, uint64_t* key, hashtable_node* node) 63 | { 64 | if (ht->hash_function == 0) return; 65 | uint64_t h = ht->hash_function(ht,keysize,key); 66 | node->key = key; 67 | node->keysize = keysize; 68 | node->next = 0; 69 | 70 | hashtable_bucket* bucket = &ht->buckets[h]; 71 | rwlockWriteLock(&bucket->lock); 72 | hashtable_node* n = bucket->node; 73 | if (n==0) 74 | { 75 | bucket->node = node; 76 | } 77 | else 78 | { 79 | while (n->next != 0) n = n->next; 80 | n->next = node; 81 | } 82 | rwlockWriteUnlock(&bucket->lock); 83 | } 84 | 85 | static inline bool comparekey(uint64_t* src, uint64_t* dst, uint64_t size) 86 | { 87 | uint64_t i; 88 | for (i=0; i< size; i++) if (src[i]!=dst[i]) return false; 89 | return true; 90 | } 91 | 92 | void hashtable_remove(hashtable* ht,uint64_t keysize, uint64_t* key) 93 | { 94 | if (ht->hash_function == 0) return; 95 | uint64_t h = ht->hash_function(ht,keysize,key); 96 | 97 | hashtable_bucket* bucket = &ht->buckets[h]; 98 | rwlockWriteLock(&bucket->lock); 99 | hashtable_node* n = bucket->node; 100 | hashtable_node* previous = 0; 101 | while (n != 0) 102 | { 103 | if (comparekey(n->key,key,keysize)) 104 | { 105 | if (previous == 0) 106 | { 107 | bucket->node = n->next; 108 | } 109 | else 110 | { 111 | previous->next = n->next; 112 | } 113 | n->next = 0; 114 | rwlockWriteUnlock(&bucket->lock); 115 | return; 116 | } 117 | previous = n; 118 | n = n->next; 119 | } 120 | rwlockWriteUnlock(&bucket->lock); 121 | } 122 | 123 | void* hashtable_get(hashtable* ht,uint64_t keysize, uint64_t* key) 124 | { 125 | if (ht->hash_function == 0) return 0; 126 | 127 | void* ret = 0; 128 | 129 | uint64_t h = ht->hash_function(ht,keysize,key); 130 | hashtable_bucket* bucket = &ht->buckets[h]; 131 | rwlockReadLock(&bucket->lock); 132 | hashtable_node* n = bucket->node; 133 | while (n != 0) 134 | { 135 | if (comparekey(n->key,key,keysize)) 136 | { 137 | ret = n->data; 138 | break; 139 | } 140 | n = n->next; 141 | } 142 | rwlockReadUnlock(&bucket->lock); 143 | 144 | return ret; 145 | } 146 | 147 | // This function will go through all nodes, locking the current bucket 148 | // for write, and will invoke the functor on each node. If the functor returns 149 | // true, then the node will be removed from the list. This is usefull 150 | // when wanting to safely remove items based on some other critaria than the key. 151 | void hashtable_scan_and_clean(hashtable* ht, hashtable_clean_visitor visitor, void* meta) 152 | { 153 | uint64_t tablesize = 1<keysize; 154 | uint64_t i; 155 | for (i=0;ibuckets[i]; 158 | 159 | rwlockWriteLock(&bucket->lock); 160 | hashtable_node* n = bucket->node; 161 | hashtable_node* previous = 0; 162 | while (n != 0) 163 | { 164 | if (visitor(n->data,meta)) 165 | { 166 | if (previous == 0) 167 | { 168 | bucket->node = n->next; 169 | } 170 | else 171 | { 172 | previous->next = n->next; 173 | } 174 | n = n->next; 175 | } 176 | else 177 | { 178 | previous = n; 179 | n = n->next; 180 | } 181 | } 182 | rwlockWriteUnlock(&bucket->lock); 183 | } 184 | } 185 | 186 | bool hashtable_visit(hashtable* ht,uint64_t keysize, uint64_t* key,hashtable_visitor visitor, void* meta) 187 | { 188 | if (ht->hash_function == 0) return false; 189 | 190 | uint64_t h = ht->hash_function(ht,keysize,key); 191 | hashtable_bucket* bucket = &ht->buckets[h]; 192 | rwlockReadLock(&bucket->lock); 193 | hashtable_node* n = bucket->node; 194 | while (n != 0) 195 | { 196 | if (comparekey(n->key,key,keysize)) 197 | { 198 | visitor(n->data,meta); 199 | rwlockReadUnlock(&bucket->lock); 200 | return true; 201 | } 202 | n = n->next; 203 | } 204 | rwlockReadUnlock(&bucket->lock); 205 | return false; 206 | } 207 | 208 | -------------------------------------------------------------------------------- /kernel/helpers.S: -------------------------------------------------------------------------------- 1 | .global memcpy64 2 | .global memclear64 3 | .global checksum_1complement 4 | .global yield 5 | .global getCurrentThreadID 6 | .global strcpy 7 | .global atomic_increase_within_range 8 | .global tcp_checksum 9 | .global atomic_cmpxchg 10 | .global atomic_cmpxchg32 11 | .global atomic_set 12 | 13 | #include "../memorymap.h" 14 | #include "macros.h" 15 | #include "tasks.h" 16 | 17 | // threadID is physical address of stack 18 | // Note that the PAGETABLE entry is changed on every context switch 19 | getCurrentThreadID: 20 | mov %cr3,%rax 21 | CLEANCR3ADDRESS(%rax) 22 | ret 23 | 24 | // The problem with this function is that the task could switch anytime before the mov $1,(%rdi) 25 | // so yielding would have been done and we do it again 26 | yield: 27 | push %rdi 28 | pushf 29 | pop %rdi 30 | bt $9,%rdi 31 | jnc cant_yield 32 | mov $TIME_SLICE_COUNT,%rdi // This variable is mapped in thread space. So multi-thread safe 33 | movq $1,(%rdi) // next time we get scheduled, count will decrease to 0 and a switch will occur 34 | 1: hlt // if we do that while interrupts are cleared, we will never wake up 35 | // cmpq $1,(%rdi) //if another int triggered, hlt will return. Avoid that 36 | // je 1b we can only do this if interrupts in enabled 37 | pop %rdi 38 | ret 39 | cant_yield: 40 | // Interrupts are cleared!!! 41 | int $3 42 | 43 | 44 | // rdi = source, rsi = destination, rdx = size 45 | memcpy64: 46 | push %rcx 47 | xchg %rdi,%rsi 48 | mov %rdx,%rcx 49 | shr $3,%rcx 50 | rep movsq 51 | mov %rdx,%rcx 52 | and $0x07,%rcx 53 | rep movsb 54 | pop %rcx 55 | ret 56 | 57 | // rdi = buffer, rsi = size 58 | memclear64: 59 | push %rcx 60 | mov $0,%rax 61 | mov %rsi,%rcx 62 | shr $3,%rcx 63 | rep stosq 64 | mov %rsi,%rcx 65 | and $0x07,%rcx 66 | rep stosb 67 | pop %rcx 68 | ret 69 | 70 | 71 | // rdi= buffer, rsi=size. return: rax will contain the big-endian checksum 72 | checksum_1complement: 73 | push %rbx 74 | push %rcx 75 | mov %rsi,%rcx 76 | shr $1,%rcx // we work on 16bit words, so divide byte count by two. 77 | mov $0,%rax 78 | mov $0,%rbx 79 | 1: movw (%rdi),%bx 80 | xchg %bl,%bh 81 | add %rbx,%rax 82 | add $2,%rdi 83 | loop 1b 84 | 2: mov %rax,%rbx 85 | shr $16,%rbx 86 | jz sumdone 87 | and $0xFFFF,%rax 88 | add %rbx,%rax 89 | jmp 2b 90 | sumdone: 91 | not %rax 92 | xchg %ah,%al 93 | pop %rcx 94 | pop %rbx 95 | ret 96 | 97 | 98 | ///////////////////////////////////////////////////////////////////////////////////// 99 | ///////////////////////////////////////////////////////////////////////////////////// 100 | // tcp_checksum(rdi= buffer, rsi=bufsize, rdx=src, rcx=dst) 101 | // The buffer must contain the tcp header and tcp data 102 | // dst and src must be in bigendian 103 | // return: rax will contain the big-endian checksum 104 | ///////////////////////////////////////////////////////////////////////////////////// 105 | ///////////////////////////////////////////////////////////////////////////////////// 106 | tcp_checksum: 107 | push %rbx 108 | push %rcx 109 | push %r8 110 | push %r9 111 | 112 | mov %rcx,%r9 113 | mov %rsi,%r8 114 | 115 | mov %rsi,%rcx 116 | inc %rcx // round up to next 2bytes 117 | shr $1,%rcx // we work on 16bit words, so divide byte count by two. 118 | mov $0,%rax 119 | mov $0,%rbx 120 | 1: movw (%rdi),%bx 121 | xchg %bl,%bh 122 | add %rbx,%rax 123 | add $2,%rdi 124 | loop 1b 125 | 126 | // now add the pseudo header 127 | add %rdx,%rax 128 | add %r9,%rax 129 | // bswap %r8 130 | // shr $48,%r8 131 | add %r8,%rax 132 | add $0x06,%rax 133 | 134 | 2: mov %rax,%rbx 135 | shr $16,%rbx 136 | jz 3f 137 | and $0xFFFF,%rax 138 | add %rbx,%rax 139 | jmp 2b 140 | 3: not %rax 141 | xchg %ah,%al 142 | 143 | pop %r9 144 | pop %r8 145 | pop %rcx 146 | pop %rbx 147 | ret 148 | 149 | ///////////////////////////////////////////////////////////////////////////////////// 150 | ///////////////////////////////////////////////////////////////////////////////////// 151 | // strcpy(rdi=source, rsi=destination) 152 | ///////////////////////////////////////////////////////////////////////////////////// 153 | ///////////////////////////////////////////////////////////////////////////////////// 154 | strcpy: 155 | push %rsi 156 | push %rdi 157 | xchg %rsi,%rdi 158 | 159 | 1: movsb 160 | cmp $0,(%rsi) 161 | jne 1b 162 | 163 | pop %rdi 164 | pop %rsi 165 | ret 166 | 167 | ///////////////////////////////////////////////////////////////////////////////////// 168 | ///////////////////////////////////////////////////////////////////////////////////// 169 | // atomic_increase_within_range(rdi=var_addr,rsi=start,rdx=end) 170 | ///////////////////////////////////////////////////////////////////////////////////// 171 | ///////////////////////////////////////////////////////////////////////////////////// 172 | atomic_increase_within_range: 173 | push %rbx 174 | 1: mov (%rdi),%rax 175 | mov %rax,%rbx 176 | inc %rbx 177 | cmp %rdx,%rbx 178 | jb 2f 179 | mov %rsi,%rbx 180 | 2: lock cmpxchgq %rbx,(%rdi) 181 | jnz 1b 182 | mov %rbx,%rax 183 | pop %rbx 184 | ret 185 | 186 | ///////////////////////////////////////////////////////////////////////////////////// 187 | ///////////////////////////////////////////////////////////////////////////////////// 188 | // atomic_set(rdi=var_addr,rsi=bit) 189 | // Returns 1 if bit was already set, 0 if it was cleared 190 | ///////////////////////////////////////////////////////////////////////////////////// 191 | ///////////////////////////////////////////////////////////////////////////////////// 192 | atomic_set: 193 | xor %rax,%rax 194 | lock bts %rsi,(%rdi) 195 | setc %al 196 | ret 197 | 198 | ///////////////////////////////////////////////////////////////////////////////////// 199 | ///////////////////////////////////////////////////////////////////////////////////// 200 | // atomic_cmpxchg(rdi=var_addr,rsi=value,rdx=oldvalue) 201 | // returns 1 if success 202 | ///////////////////////////////////////////////////////////////////////////////////// 203 | ///////////////////////////////////////////////////////////////////////////////////// 204 | atomic_cmpxchg: 205 | mov %rdx,%rax 206 | xor %rdx,%rdx 207 | lock cmpxchgq %rsi,(%rdi) 208 | setz %dl 209 | mov %rdx,%rax 210 | ret 211 | 212 | ///////////////////////////////////////////////////////////////////////////////////// 213 | ///////////////////////////////////////////////////////////////////////////////////// 214 | // atomic_cmpxchg32(rdi=var_addr,rsi=value,rdx=oldvalue) 215 | // returns 1 if success 216 | ///////////////////////////////////////////////////////////////////////////////////// 217 | ///////////////////////////////////////////////////////////////////////////////////// 218 | atomic_cmpxchg32: 219 | mov %rdx,%rax 220 | xor %rdx,%rdx 221 | lock cmpxchg %esi,(%rdi) 222 | setz %dl 223 | mov %rdx,%rax 224 | ret 225 | -------------------------------------------------------------------------------- /kernel/icmp.c: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | #include "printf.h" 3 | #include "netcard.h" 4 | 5 | extern void memcpy64(char* src, char* dst, unsigned long size); 6 | extern unsigned short ip_send(unsigned long sourceInterface, unsigned int destIP, char* buf, unsigned short size, unsigned char protocol); 7 | extern unsigned short checksum_1complement(unsigned char* buf, unsigned short size); 8 | 9 | // this buffer is create on heap because it would be too big for stack. It will only be used by the 10 | // receive thread when replying to ping requests 11 | char buf[65536]; 12 | 13 | void icmp_process(char* buffer, unsigned short size, unsigned int from, unsigned long sourceInterface) 14 | { 15 | unsigned short typecode = *(unsigned short*)&buffer[0]; 16 | if (typecode == 0x0008) 17 | { 18 | unsigned short i; 19 | for (i=0;i<((size+1)&(~1));i++) buf[i]=0; 20 | memcpy64(buffer,(char*)&buf[0],size); 21 | *(unsigned short*)&buf[0] = 0; 22 | *(unsigned short*)&buf[2] = 0; 23 | unsigned short checksum = checksum_1complement((char*)&buf[0],((size+1)&(~1))); 24 | *(unsigned short*)&buf[2] = checksum; 25 | 26 | // WARNING: ip_send could make a ARP query and we would wait for the response. But 27 | // we are already in the receive thread here. This is somewhat safe anyway because 28 | // we have learned the MAC of the guy who made the ping request so we know ip_send() 29 | // will not make a ARP query. 30 | ip_send(sourceInterface, from, (char*)&buf[0], size, 0x01); 31 | } 32 | else if (typecode == 0x0000) 33 | { 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /kernel/includes/kernel/hashtable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | 4 | #define HASH_CUMULATIVE 0 5 | #define HASH_AND 1 6 | 7 | struct _hashtable_node 8 | { 9 | struct _hashtable_node* next; 10 | uint64_t* key; 11 | uint64_t keysize; 12 | void* data; 13 | }; 14 | 15 | // Since the hash list won't allocate memory for nodes, the node struct 16 | // must be contained in the object and it will reference itself. ie: 17 | // object->hashtable_node->data = object; 18 | 19 | typedef struct _hashtable_node hashtable_node; 20 | 21 | typedef struct 22 | { 23 | hashtable_node* node; 24 | uint64_t lock; 25 | } hashtable_bucket; 26 | 27 | 28 | struct _hashtable 29 | { 30 | uint64_t (*hash_function)(struct _hashtable*, uint64_t keysize, uint64_t* key); 31 | unsigned char keysize; 32 | hashtable_bucket buckets[]; 33 | } _hashtable; 34 | 35 | typedef struct _hashtable hashtable; 36 | 37 | typedef void (*hashtable_visitor)(void* data, void* meta); 38 | typedef bool (*hashtable_clean_visitor)(void* data, void* meta); 39 | 40 | // The hashtable code will not reserve memory for the hashtable. 41 | // You must determine the size of the hashtable with hashtable_getrequiredsize() 42 | // and then create a buffer of that size and pass it to hashtable_init to it 43 | // can initialize it. 44 | uint64_t hashtable_getrequiredsize(unsigned char hashsize); 45 | void hashtable_init(hashtable*,unsigned char hashsize,unsigned char hash_function); 46 | void hashtable_add(hashtable*,uint64_t keysize, uint64_t* key, hashtable_node* node); 47 | void hashtable_remove(hashtable*,uint64_t keysize, uint64_t* key); 48 | void* hashtable_get(hashtable*,uint64_t keysize, uint64_t* key); 49 | bool hashtable_visit(hashtable*,uint64_t keysize, uint64_t* key,hashtable_visitor visitor, void* meta); 50 | void hashtable_scan_and_clean(hashtable*, hashtable_clean_visitor visitor, void* meta); 51 | -------------------------------------------------------------------------------- /kernel/includes/kernel/intA0.h: -------------------------------------------------------------------------------- 1 | 2 | #define INTA0_GET_APIC_ID 0x00 3 | #define INTA0_VIRT2PHYS 0x01 4 | #define INTA0_LOADPROCESS 0x02 5 | #define INTA0_WAITPROCESS_DEATH 0x03 6 | #define INTA0_GET_DATETIME 0x04 7 | 8 | #define INTA0_KILL_CURRENT_TASK 0x10 9 | 10 | #define INTA0_PRINTF 0x20 11 | #define INTA0_CREATETEXTCONSOLE 0x21 12 | #define INTA0_POLL_IN 0x22 13 | #define INTA0_STEALTEXTCONSOLE 0x23 14 | #define INTA0_RESTORETEXTCONSOLE 0x24 15 | #define INTA0_GETDIRECTBUFFER 0x25 16 | 17 | #define INTA0_MALLOC 0x30 18 | #define INTA0_FREE 0x31 19 | 20 | #define INTA0_FOPEN 0x40 21 | #define INTA0_FREAD 0x41 22 | #define INTA0_FWRITE 0x42 23 | #define INTA0_FCLOSE 0x43 24 | #define INTA0_FSEEK 0x44 25 | #define INTA0_FGETSIZE 0x45 26 | 27 | #define INTA0_CREATE_SOCKET 0x50 28 | #define INTA0_CLOSE_SOCKET 0x51 29 | #define INTA0_CONNECT 0x52 30 | #define INTA0_RELEASE_SOCKET 0x53 31 | #define INTA0_RECV 0x54 32 | #define INTA0_SEND 0x55 33 | #define INTA0_LISTEN 0x56 34 | #define INTA0_ACCEPT 0x57 35 | -------------------------------------------------------------------------------- /kernel/includes/kernel/sockets.h: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "systemhandle.h" 3 | #include "hashtable.h" 4 | 5 | #define RING_BUFFER_SIZE (6*1024) 6 | #define MAX_BACKLOG 10 // should allow more 7 | 8 | #define SOCKET_MESSAGE_SYN 0 9 | #define SOCKET_MESSAGE_ACK 1 10 | #define SOCKET_MESSAGE_SYNACK 2 11 | #define SOCKET_MESSAGE_FIN 3 12 | #define SOCKET_MESSAGE_PAYLOAD 4 13 | 14 | #define SOCKET_STATE_NEW 0 15 | #define SOCKET_STATE_WAITSYNACK 1 16 | #define SOCKET_STATE_CONNECTED 2 17 | #define SOCKET_STATE_CLOSING 4 18 | #define SOCKET_STATE_LISTENING 5 19 | #define SOCKET_STATE_CONNECTING 6 20 | #define SOCKET_STATE_CLOSED 0x80 21 | #define SOCKET_STATE_RESET 0x81 22 | 23 | 24 | 25 | //TODO: a linked list for the sockets can be slow to search. 26 | typedef struct 27 | { 28 | // nextExpectedSeq will be used in the ack number field. 29 | // it represents the the next expected sequence number we expext 30 | // to receive and acknowledges the previous packet received 31 | uint32_t nextExpectedSeq; 32 | uint32_t seqNumber; 33 | uint8_t state; 34 | } tcp_state; 35 | 36 | typedef struct _socket_message socket_message; 37 | 38 | typedef struct 39 | { 40 | tcp_state tcp; 41 | uint32_t destinationIP; 42 | uint32_t sourceIP; 43 | uint16_t destinationPort; 44 | uint16_t sourcePort; 45 | 46 | } socket_info; 47 | 48 | typedef struct 49 | { 50 | uint32_t destinationIP; 51 | uint32_t sourceIP; 52 | uint16_t destinationPort; 53 | uint16_t sourcePort; 54 | uint32_t paddingTo64BitBoundary; 55 | } socket_description; 56 | 57 | struct _socket 58 | { 59 | system_handle handle; 60 | tcp_state tcp; 61 | socket_info backlog[MAX_BACKLOG]; 62 | 63 | socket_description desc; 64 | uint16_t backlogSize; 65 | uint32_t qin; 66 | uint32_t qout; 67 | uint16_t messageTypeWanted; 68 | uint64_t queueLock; 69 | uint64_t owner; 70 | hashtable_node hash_node; 71 | char receivedSegments[RING_BUFFER_SIZE]; 72 | }; 73 | 74 | typedef struct _socket socket; 75 | -------------------------------------------------------------------------------- /kernel/includes/kernel/systemhandle.h: -------------------------------------------------------------------------------- 1 | struct _system_handle 2 | { 3 | void (*destructor)(struct _system_handle*); 4 | }; 5 | 6 | typedef struct _system_handle system_handle; 7 | 8 | -------------------------------------------------------------------------------- /kernel/includes/kernel/tree.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | 4 | typedef struct _tree_node 5 | { 6 | void* data; 7 | struct _tree_node *left; 8 | struct _tree_node *right; 9 | } tree_node; 10 | 11 | typedef struct _tree 12 | { 13 | tree_node* root_node; 14 | // memory pool 15 | 16 | } tree; 17 | 18 | void tree_insert(tree* tree, void* data, uint64_t key); 19 | void tree_remove(tree* tree, uint64_t key); 20 | void* tree_get(tree* tree, uint64_t key); 21 | -------------------------------------------------------------------------------- /kernel/includes/kernel/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef unsigned long long uint64_t; 4 | typedef unsigned short uint16_t; 5 | typedef unsigned int uint32_t; 6 | typedef unsigned char uint8_t; 7 | typedef unsigned char bool; 8 | typedef unsigned long long u64; 9 | typedef unsigned short u16; 10 | typedef unsigned int u32; 11 | typedef unsigned char u8; 12 | 13 | #define true 1 14 | #define false 0 15 | -------------------------------------------------------------------------------- /kernel/intA0.S: -------------------------------------------------------------------------------- 1 | #include "../memorymap.h" 2 | #include "macros.h" 3 | #include "config.h" 4 | #include "includes/kernel/intA0.h" 5 | 6 | .global initIntA0 7 | 8 | initIntA0: 9 | push %rax 10 | push %rbx 11 | 12 | mov $intA0,%rbx 13 | mov $0xA0,%rax 14 | call registerTrapGate 15 | 16 | pop %rbx 17 | pop %rax 18 | ret 19 | 20 | 21 | intA0: 22 | push %r15 23 | push %r14 24 | push %r13 25 | push %r12 26 | push %r11 27 | push %r10 28 | push %r9 29 | push %r8 30 | push %rbp 31 | push %rdi 32 | push %rsi 33 | push %rdx 34 | push %rcx 35 | push %rbx 36 | 37 | cmp $INTA0_GET_APIC_ID,%rax 38 | je intA0_get_apic_id 39 | cmp $INTA0_KILL_CURRENT_TASK,%rax 40 | je intA0_kill_current_task 41 | cmp $INTA0_WAITPROCESS_DEATH,%rax 42 | je intA0_wait_process_death 43 | cmp $INTA0_PRINTF,%rax 44 | je intA0_printf 45 | cmp $INTA0_CREATETEXTCONSOLE,%rax 46 | je intA0_createTextConsole 47 | cmp $INTA0_STEALTEXTCONSOLE,%rax 48 | je intA0_stealTextConsole 49 | cmp $INTA0_RESTORETEXTCONSOLE,%rax 50 | je intA0_restoreTextConsole 51 | cmp $INTA0_POLL_IN,%rax 52 | je intA0_poll_in 53 | cmp $INTA0_MALLOC,%rax 54 | je intA0_malloc 55 | cmp $INTA0_FREE,%rax 56 | je intA0_free 57 | cmp $INTA0_VIRT2PHYS,%rax 58 | je intA0_virt2phys 59 | cmp $INTA0_LOADPROCESS,%rax 60 | je intA0_load_process 61 | cmp $INTA0_GET_DATETIME,%rax 62 | je intA0_get_datetime 63 | cmp $INTA0_FOPEN,%rax 64 | je intA0_fopen 65 | cmp $INTA0_FREAD,%rax 66 | je intA0_fread 67 | cmp $INTA0_FWRITE,%rax 68 | je intA0_fwrite 69 | cmp $INTA0_FCLOSE,%rax 70 | je intA0_fclose 71 | cmp $INTA0_FSEEK,%rax 72 | je intA0_fseek 73 | cmp $INTA0_FGETSIZE,%rax 74 | je intA0_fgetsize 75 | cmp $INTA0_CREATE_SOCKET,%rax 76 | je intA0_create_socket 77 | cmp $INTA0_CLOSE_SOCKET,%rax 78 | je intA0_close_socket 79 | cmp $INTA0_RELEASE_SOCKET,%rax 80 | je intA0_release_socket 81 | cmp $INTA0_CONNECT,%rax 82 | je intA0_connect 83 | cmp $INTA0_RECV,%rax 84 | je intA0_recv 85 | cmp $INTA0_SEND,%rax 86 | je intA0_send 87 | cmp $INTA0_LISTEN,%rax 88 | je intA0_listen 89 | cmp $INTA0_ACCEPT,%rax 90 | je intA0_accept 91 | cmp $INTA0_GETDIRECTBUFFER,%rax 92 | je intA0_get_direct_buffer 93 | jmp intA0_exit 94 | 95 | intA0_get_apic_id: 96 | GET_APIC_ID(%eax) 97 | jmp intA0_exit 98 | 99 | intA0_kill_current_task: 100 | mov %cr3,%rax 101 | mov %rax,%rdi 102 | call destroy_sockets 103 | call destroyFileHandles 104 | call removeConsole 105 | call killCurrentTask 106 | jmp intA0_exit 107 | 108 | intA0_get_direct_buffer: 109 | call getDirectVideo 110 | mov (%rax),%rax // backbuffer 111 | jmp intA0_exit 112 | 113 | intA0_printf: 114 | call safeWriteString 115 | jmp intA0_exit 116 | 117 | intA0_createTextConsole: 118 | call createTextConsole 119 | jmp intA0_exit 120 | 121 | intA0_stealTextConsole: 122 | call stealTextConsole 123 | jmp intA0_exit 124 | 125 | intA0_restoreTextConsole: 126 | call restoreTextConsole 127 | jmp intA0_exit 128 | 129 | intA0_poll_in: 130 | call pollChar 131 | jmp intA0_exit 132 | 133 | intA0_malloc: 134 | call malloc 135 | jmp intA0_exit 136 | 137 | intA0_free: 138 | call free 139 | jmp intA0_exit 140 | 141 | intA0_virt2phys: 142 | call currentProcessVirt2phys 143 | jmp intA0_exit 144 | 145 | intA0_load_process: 146 | call loadProcess 147 | jmp intA0_exit 148 | 149 | intA0_wait_process_death: 150 | call waitProcessDeath 151 | jmp intA0_exit 152 | 153 | intA0_get_datetime: 154 | call getDateTime 155 | jmp intA0_exit 156 | 157 | intA0_fopen: 158 | call fopen 159 | jmp intA0_exit 160 | intA0_fread: 161 | call fread 162 | jmp intA0_exit 163 | intA0_fwrite: 164 | call fwrite 165 | jmp intA0_exit 166 | intA0_fclose: 167 | call fclose 168 | jmp intA0_exit 169 | intA0_fseek: 170 | call fseek 171 | jmp intA0_exit 172 | intA0_fgetsize: 173 | call fgetsize 174 | jmp intA0_exit 175 | 176 | intA0_create_socket: 177 | call create_socket 178 | jmp intA0_exit 179 | intA0_close_socket: 180 | call close_socket 181 | jmp intA0_exit 182 | intA0_release_socket: 183 | call release_socket 184 | jmp intA0_exit 185 | intA0_connect: 186 | call connect 187 | jmp intA0_exit 188 | intA0_recv: 189 | call recv 190 | jmp intA0_exit 191 | intA0_send: 192 | call send 193 | jmp intA0_exit 194 | intA0_listen: 195 | call listen 196 | jmp intA0_exit 197 | intA0_accept: 198 | call accept 199 | jmp intA0_exit 200 | 201 | 202 | intA0_exit: 203 | pop %rbx 204 | pop %rcx 205 | pop %rdx 206 | pop %rsi 207 | pop %rdi 208 | pop %rbp 209 | pop %r8 210 | pop %r9 211 | pop %r10 212 | pop %r11 213 | pop %r12 214 | pop %r13 215 | pop %r14 216 | pop %r15 217 | iretq 218 | -------------------------------------------------------------------------------- /kernel/ip.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define IP_SEND_ERROR_NO_MAC -1 4 | #define IP_SEND_ERROR_HW -2 5 | 6 | int ip_send(unsigned long sourceInterface, unsigned int destIP, 7 | char* buffers, unsigned short size, unsigned char protocol); 8 | void ip_process(struct Layer2Payload* payload); 9 | 10 | -------------------------------------------------------------------------------- /kernel/ip_routing.c: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | #include "netcard.h" 3 | 4 | #define ROUTE_ENTRY_COUNT 128 5 | 6 | extern struct NetworkConfig* net_getConfig(unsigned char index); 7 | extern unsigned long arp_getMAC(unsigned int ip, unsigned char* interface); 8 | 9 | struct RouteEntry 10 | { 11 | unsigned int network; 12 | unsigned int netmask; 13 | unsigned int gateway; 14 | unsigned char metric; 15 | unsigned char interface; 16 | }; 17 | 18 | struct RouteEntry routingTable[ROUTE_ENTRY_COUNT]={0}; 19 | 20 | void ip_routing_addRoute(unsigned int network, unsigned int netmask, unsigned int gateway, unsigned char metric, unsigned long interface) 21 | { 22 | if (interface>255) return; 23 | 24 | unsigned long i; 25 | for (i=0;imetric == 0) 29 | { 30 | route->network = network; 31 | route->netmask = netmask; 32 | route->gateway = gateway; 33 | route->metric = metric; 34 | route->interface = (unsigned char)interface; 35 | return; 36 | } 37 | } 38 | } 39 | 40 | 41 | unsigned long ip_routing_route(unsigned int destinationIP, unsigned char* interface) 42 | { 43 | struct RouteEntry *chosenRoute = 0; 44 | unsigned long i; 45 | for (i=0;imetric>0) 49 | { 50 | if ((destinationIP&route->netmask) == route->network) 51 | { 52 | if (chosenRoute!=0) 53 | { 54 | if (chosenRoute->metric > route->metric) 55 | { 56 | chosenRoute = route; 57 | } 58 | } 59 | else 60 | { 61 | chosenRoute = route; 62 | } 63 | } 64 | } 65 | } 66 | 67 | if (chosenRoute==0) return 0; 68 | 69 | // A gateway would be set on a route only if the route is a default route. 70 | if (chosenRoute->gateway == 0) 71 | { 72 | // There is no gateway defined, so just flood on that interface. 73 | *interface = chosenRoute->interface; 74 | return arp_getMAC(destinationIP,chosenRoute->interface); 75 | } 76 | else 77 | { 78 | *interface = chosenRoute->interface; 79 | return arp_getMAC(chosenRoute->gateway,chosenRoute->interface); 80 | 81 | } 82 | return 0; 83 | 84 | } 85 | 86 | -------------------------------------------------------------------------------- /kernel/kernelmain.S: -------------------------------------------------------------------------------- 1 | #include "../memorymap.h" 2 | #include "macros.h" 3 | #include "includes/kernel/intA0.h" 4 | .global startKernelThread 5 | 6 | .extern loadUserApplications 7 | .extern writeString 8 | .extern writeNumber 9 | .extern setupIDT 10 | .extern initPIC 11 | .extern enableIRQ 12 | .extern initPIT 13 | .extern initScheduler 14 | .extern allocateStackPage 15 | .extern mapVirtualAddress 16 | .extern launchKernelThread 17 | .extern launchUserThread 18 | .extern mutexLock 19 | .extern mutexUnlock 20 | .extern gotoxy 21 | .extern initPCI 22 | .extern net_init 23 | .extern net_start 24 | .extern net_process 25 | .extern arp_getMAC 26 | .extern net_setIPConfig 27 | .extern net_setDefaultGateway 28 | .extern update_display 29 | .extern testThread 30 | .extern testThread2 31 | .extern divideByZeroHandler 32 | 33 | .align 16 34 | 35 | startKernelThread: 36 | mov $mainkernelthread,%rdi 37 | mov $(mainkernelthread_end-mainkernelthread),%rsi 38 | call launchKernelThread 39 | 40 | mov $testthread,%rdi 41 | mov $(testthread_end-testthread),%rsi 42 | call launchKernelThread 43 | 44 | mov $testthread,%rdi 45 | mov $(testthread_end-testthread),%rsi 46 | call launchKernelThread 47 | 48 | ret 49 | 50 | 51 | 52 | ////////////////////////////////////////////// 53 | ////////////////////////////////////////////// 54 | /////////// Main Kernel Thread /////////////// 55 | ////////////////////////////////////////////// 56 | ////////////////////////////////////////////// 57 | // this thread serves no purpose, it's just to test if 58 | // I can launch a thread from another thread 59 | mainkernelthread: 60 | call createTextConsole 61 | 62 | call initTestIPI 63 | 64 | // This thread will own the screen initially 65 | mov $0,%rdi 66 | call switchFrontLineProcessByIndex 67 | 68 | 69 | call initPCI 70 | call show_memory_map 71 | 72 | mov $BLOCK_CACHE,%rdi // blockNumber 242 73 | call block_cache_init 74 | 75 | call initKeyboard 76 | call net_init 77 | call net_start 78 | 79 | 80 | mov $0xC0A8011C,%rdi // 192.168.1.28 81 | mov $0xFFFFFF00,%rsi // 255.255.255.0 82 | mov $1,%rdx 83 | mov $0,%rcx // Card 0 84 | call net_setIPConfig 85 | mov $0xC0A8021C,%rdi // 192.168.2.28 86 | mov $0xFFFFFF00,%rsi // 255.255.255.0 87 | mov $1,%rdx 88 | mov $1,%rcx // Card 1 89 | call net_setIPConfig 90 | mov $0xC0A80101,%rdi 91 | mov $0,%rsi 92 | call net_setDefaultGateway 93 | 94 | 95 | mov $4,%rdi //4= virtio drive 96 | call loadUserApplications 97 | 98 | mov $0xA60,%rsi 99 | mov $6,%rdi 100 | call create_vm 101 | mov $shellname,%rdi 102 | mov $0,%rsi 103 | mov $INTA0_LOADPROCESS,%rax 104 | int $0xA0 105 | 106 | 1: 107 | call manageConsoles 108 | call manageDeadProcesses 109 | hlt 110 | jmp 1b 111 | 112 | shellname: .ASCIZ "04:/shell.elf" 113 | blockbuffer: 114 | .skip (10*512) 115 | 116 | mainkernelthread_end: 117 | 118 | 119 | testthread: 120 | sub $32,%rsp 121 | rdrand %rax 122 | movd %rax,%xmm1 123 | 1: 124 | movd %xmm1,%rbx 125 | cmp %rbx,%rax 126 | je 1b 127 | int $3 128 | jmp 1b 129 | 130 | testdata:.quad 0 131 | .quad 0 132 | testdata2:.quad 0 133 | .quad 0 134 | testthread_end: 135 | -------------------------------------------------------------------------------- /kernel/keyboard.c: -------------------------------------------------------------------------------- 1 | #include "keyboard.h" 2 | #include "utils.h" 3 | #include "../memorymap.h" 4 | #include "includes/kernel/types.h" 5 | #include "printf.h" 6 | // http://www.computer-engineering.org/ps2keyboard/scancodes1.html 7 | 8 | extern void getInterruptInfoForBus(unsigned long bus, unsigned int* buffer); 9 | extern void storeCharacter(uint16_t c); 10 | extern void registerIRQ(void* handler, unsigned long irq); 11 | 12 | unsigned char ctrlKey; 13 | unsigned char shiftKey; 14 | 15 | uint16_t scanCodes[] = { 16 | 0x0000,0x001B,'1' ,'2' ,'3' ,'4' ,'5' ,'6' ,'7' ,'8' ,'9' ,'0' ,'-' ,'=' ,0x0008,0x0009, 17 | 'q' ,'w' ,'e' ,'r' ,'t' ,'y' ,'u' ,'i' ,'o' ,'p' ,'[' ,']' ,0x000A,0x0000,'a' ,'s' , 18 | 'd' ,'f' ,'g' ,'h' ,'j' ,'k' ,'l' ,';' ,'\'' ,'`' ,0x0000,'\\' ,'z' ,'x' ,'c' ,'v' , 19 | 'b' ,'n' ,'m' ,',' ,'.' ,'/' ,0x0000,0x0000,0x0000,' ' ,0x0000,KEY_F1,KEY_F2,KEY_F3,KEY_F4,KEY_F5, 20 | KEY_F6,KEY_F7,KEY_F8,KEY_F9,KEY_F10,0x0000,0x0000,0x0000,KEY_UP,KEY_PGUP,0x0000,KEY_LEFT,0x0000,KEY_RIGHT,0x0000,0x0000, 21 | KEY_DOWN,KEY_PGDOWN,0x0000,0x0000,0x0000,0x0000,0x0000,KEY_F11,KEY_F12,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 22 | 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 23 | 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}; 24 | 25 | uint16_t shiftedScanCodes[] = { 26 | 0x0000,0x001B,'!' ,'@' ,'#' ,'$' ,'%' ,'^' ,'&' ,'*' ,'(' ,')' ,'_' ,'+' ,0x0008,0x0009, 27 | 'Q' ,'W' ,'E' ,'R' ,'T' ,'Y' ,'U' ,'I' ,'O' ,'P' ,'{' ,'}' ,0x000A,0x0000,'A' ,'S' , 28 | 'D' ,'F' ,'G' ,'H' ,'J' ,'K' ,'L' ,':' ,'"' ,'~' ,0x0000,'|' ,'Z' ,'X' ,'C' ,'V' , 29 | 'B' ,'N' ,'M' ,'<' ,'>' ,'?' ,0x0000,0x0000,0x0000,' ' ,0x0000,KEY_F1,KEY_F2,KEY_F3,KEY_F4,KEY_F5, 30 | KEY_F6,KEY_F7,KEY_F8,KEY_F9,KEY_F10,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 31 | 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,KEY_F11,KEY_F12,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 32 | 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 33 | 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}; 34 | 35 | 36 | void keyboardHandler() 37 | { 38 | unsigned char key; 39 | uint16_t c = 0; 40 | INPORTB(key,0x60); 41 | if (key==0xE0) 42 | { 43 | INPORTB(key,0x60); 44 | } 45 | 46 | 47 | if (key&0x80) // break code 48 | { 49 | key = key & 0x7F; 50 | 51 | if (key==0x1D) 52 | { 53 | ctrlKey = 0; 54 | } else if (key == 0x2A || key == 0x36) 55 | { 56 | shiftKey = 0; 57 | } 58 | } 59 | else // make code 60 | { 61 | if (key==0x1D) 62 | { 63 | ctrlKey = 1; 64 | } 65 | else if (key == 0x2A || key == 0x36) 66 | { 67 | shiftKey = 1; 68 | } 69 | else 70 | { 71 | if (shiftKey==0) c = scanCodes[key]; else c = shiftedScanCodes[key]; 72 | } 73 | 74 | 75 | if (c!=0) 76 | { 77 | storeCharacter(c); 78 | } 79 | } 80 | } 81 | 82 | void initKeyboard() 83 | { 84 | unsigned int i; 85 | unsigned int ioapicDevices[64]; 86 | 87 | ctrlKey = 0; 88 | shiftKey = 0; 89 | 90 | getInterruptInfoForBus(0x20415349, &ioapicDevices); // "ISA " 91 | for (i=0;i<64;i++) 92 | { 93 | if (ioapicDevices[i]==0) continue; 94 | 95 | unsigned char pin = ioapicDevices[i]&0xFF; 96 | unsigned short busirq = ioapicDevices[i]&0xFF00; 97 | if (busirq == 0x0100) 98 | { 99 | registerIRQ(&keyboardHandler,pin); 100 | return; 101 | } 102 | } 103 | 104 | pf("Could not find IOAPIC mapping of IRQ 1\r\n"); 105 | } 106 | -------------------------------------------------------------------------------- /kernel/keyboard.h: -------------------------------------------------------------------------------- 1 | #define KEY_F1 256 2 | #define KEY_F2 257 3 | #define KEY_F3 258 4 | #define KEY_F4 259 5 | #define KEY_F5 260 6 | #define KEY_F6 261 7 | #define KEY_F7 262 8 | #define KEY_F8 263 9 | #define KEY_F9 264 10 | #define KEY_F10 265 11 | #define KEY_F11 266 12 | #define KEY_F12 267 13 | 14 | #define KEY_CTRL_0 268 15 | #define KEY_CTRL_1 269 16 | #define KEY_CTRL_2 270 17 | #define KEY_CTRL_3 271 18 | #define KEY_CTRL_4 272 19 | #define KEY_CTRL_5 273 20 | #define KEY_CTRL_6 274 21 | #define KEY_CTRL_7 275 22 | #define KEY_CTRL_8 276 23 | #define KEY_CTRL_9 277 24 | 25 | #define KEY_PGUP 278 26 | #define KEY_PGDOWN 279 27 | #define KEY_UP 280 28 | #define KEY_DOWN 281 29 | #define KEY_LEFT 282 30 | #define KEY_RIGHT 283 31 | -------------------------------------------------------------------------------- /kernel/link.lds: -------------------------------------------------------------------------------- 1 | SECTIONS { 2 | . = 0x00100000; 3 | .text : { * (.text); } 4 | } 5 | 6 | -------------------------------------------------------------------------------- /kernel/macros.h: -------------------------------------------------------------------------------- 1 | 2 | // the reason for not using bit 47 for mirror mapping is because of cannonical adrreses 3 | // that requires that bit 64-48 be set to match bit 47. Using bit 46 will impose a limit 4 | // of 65536 gig of ram to the OS 5 | #define MIRROR_BIT 46 6 | #define GET_APIC_ID32(reg) mov APIC_BASE+0x20,reg; shr $24,reg 7 | #define GET_APIC_ID(reg) push %rdi; mov $(APIC_BASE+0x20),%rdi; btsq $MIRROR_BIT,%rdi; mov (%rdi),reg; shr $24,reg; pop %rdi 8 | #define STACK_ADDRESS_PAGE_TABLE_OFFSET (((((STACK0TOP_VIRTUAL_ADDRESS-1-THREAD_CODE_START))>>12)<<3)) 9 | #define STACK3_ADDRESS_PAGE_TABLE_OFFSET (((((STACK3TOP_VIRTUAL_ADDRESS-1-THREAD_CODE_START))>>12)<<3)) 10 | #define META_ADDRESS_PAGE_TABLE_OFFSET (((((META_VIRTUAL_ADDRESS-THREAD_CODE_START))>>12)<<3)) 11 | #define CODE_ADDRESS_PAGE_TABLE_OFFSET 0 12 | #define STALL() 1337: hlt; jmp 1337b; 13 | 14 | 15 | // Addresses starting at 0x4000000000 mirrors physical memory. So these addresses 16 | // are usefull when wanting to bypass physical mapping 17 | #define MIRROR(x) (((uint64_t)x)|(1LL<2048) 55 | { 56 | uint64_t page_count = (node_size+0xFFF) >> 12; 57 | new_nodes = (memory_pool_node*)kernelAllocPages(page_count); 58 | if (new_nodes == 0) return 0; 59 | memclear64((void*)new_nodes,page_count*4096); 60 | // This new node will start at begining of page and we will only have 1 node 61 | } 62 | else 63 | { 64 | uint64_t object_count = 4096/node_size; 65 | new_nodes = (memory_pool_node*)kernelAllocPages(1); 66 | if (new_nodes == 0) return 0; 67 | memclear64((void*)new_nodes,4096); 68 | memory_pool_node* n = new_nodes; 69 | 70 | // several nodes will exist in that page. Set the "next" pointer to 71 | // the folldwing node. Leave the last one to 0 72 | uint64_t addr = (uint64_t)new_nodes; 73 | for (i = 0; i < object_count-1;i++) 74 | { 75 | addr += node_size; 76 | n->next = (memory_pool_node*)addr; 77 | n = n->next; 78 | } 79 | } 80 | 81 | ////////////////////////////////////////////////////////////////////////// 82 | // Now, atomically append the new node(s) to the end of the pool 83 | ////////////////////////////////////////////////////////////////////////// 84 | spinLock(&(pools[pool].lock)); 85 | memory_pool_node* n = pools[pool].first; 86 | if (n==0) 87 | { 88 | pools[pool].first = new_nodes; 89 | } 90 | else 91 | { 92 | while (n->next != 0) n = n->next; 93 | n->next = new_nodes; 94 | } 95 | spinUnlock(&(pools[pool].lock)); 96 | 97 | return new_nodes; 98 | } 99 | 100 | void* reserve_object(uint64_t pool) 101 | { 102 | if (pool >= MAX_MEMORY_POOLS) return 0; 103 | if (pools[pool].node_size == 0) return 0; 104 | 105 | // The pool is guaranteed to contain at least 1 node. 106 | // might not be free though. There is no need to lock 107 | // the function since we only set the "used" flag in the node 108 | // so we can do it with BTS. If we need to expand the pool 109 | // and add more nodes in the linked list, then the 110 | // expand function will lock. 111 | while (1) 112 | { 113 | memory_pool_node* node = pools[pool].first; 114 | while (node != 0) 115 | { 116 | // We just need to be protected against other threads trying to reserve 117 | // the same slot at the same time. 118 | if (!atomic_set(&node->flags,0)) 119 | { 120 | uint64_t addr = ((uint64_t)node)+sizeof(memory_pool_node); 121 | return (void*)addr; 122 | } 123 | node = node->next; 124 | } 125 | //If none was found, expand the pool and search again. 126 | //But if pool expansion failed, then return 0 127 | //TODO: should prevent two threads from expanding the pool 128 | // if they get here at the time. The expand function does 129 | // lock to prevent corrupting the linked list but 130 | // that won't prevent two threads from expanding the pool, 131 | // possibly creating an unnecessary expansion. 132 | if (memory_pool_expand(pool) == 0) return 0; 133 | } 134 | 135 | return 0; 136 | } 137 | 138 | void release_object(uint64_t pool, void* obj) 139 | { 140 | uint64_t addr = ((uint64_t)obj)-sizeof(memory_pool_node); 141 | //pf("mempool release %x %x\r\n",pool,addr); 142 | memory_pool_node* node = (memory_pool_node*)addr; 143 | node->flags &= 0b11111110; 144 | } 145 | 146 | // 147 | // Obviously, no other thread should use objects from the pool when 148 | // the pool is being destroyed. The destroy function does not lock 149 | // so other threads must make sure they dont use the pool or any 150 | // objects in it. 151 | // 152 | void destroy_memory_pool(uint64_t pool) 153 | { 154 | if (pool >= MAX_MEMORY_POOLS) return; 155 | 156 | //TODO: release all pages for all nodes 157 | // There could be several nodes on ones page 158 | // or node that spans across several pages 159 | 160 | //No need to lock here 161 | pools[pool].node_size = 0; 162 | } 163 | 164 | void memory_pool_free_pages(uint64_t pool) 165 | { 166 | //TODO: lock 167 | // This function would compete with other access to the list 168 | // such as when we reserve a block or release a block. 169 | // also when we destroy the pool. 170 | // Also: make sure pool was not destroyed by the time we got in here 171 | memory_pool_node* node = pools[pool].first; 172 | while (node != 0) 173 | { 174 | if ((node->flags&1)==0) 175 | { 176 | //TODO: release pages for that node. 177 | // There could be several nodes on ones page 178 | // or node that spans across several pages 179 | } 180 | node = node->next; 181 | } 182 | } 183 | 184 | 185 | // TODO: this function should be called when mem goes low 186 | void memory_pool_reclaim() 187 | { 188 | uint64_t i; 189 | for (i=0;i< MAX_MEMORY_POOLS;i++) 190 | { 191 | if (pools[i].node_size == 0) continue; 192 | memory_pool_free_pages(i); 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /kernel/memorypool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "includes/kernel/types.h" 3 | #define MAX_MEMORY_POOLS 50 4 | 5 | struct _memory_pool_node 6 | { 7 | struct _memory_pool_node *next; 8 | char flags; 9 | char reserved[7]; // this is to pack struct to 16bytes 10 | } __attribute__((__packed__)); 11 | 12 | typedef struct _memory_pool_node memory_pool_node; 13 | 14 | typedef struct 15 | { 16 | memory_pool_node* first; 17 | uint64_t node_size; 18 | uint64_t lock; 19 | } __attribute__((__packed__)) memory_pool; 20 | 21 | void memory_pool_reclaim(); 22 | void init_memory_pools(); 23 | uint64_t create_memory_pool(uint64_t objSize); 24 | void* reserve_object(uint64_t pool); 25 | void release_object(uint64_t pool, void* obj); 26 | void destroy_memory_pool(uint64_t pool); 27 | -------------------------------------------------------------------------------- /kernel/mutex.S: -------------------------------------------------------------------------------- 1 | #include "../memorymap.h" 2 | .global mutexLock 3 | .global mutexUnlock 4 | .global spinLock 5 | .global spinUnlock 6 | .global spinLock_softirq 7 | .global spinUnlock_softirq 8 | .global disableCurrentThread 9 | .global enableThread 10 | .global rwlockWriteLock 11 | .global rwlockWriteUnlock 12 | .global rwlockReadLock 13 | .global rwlockReadUnlock 14 | .extern writeNumber 15 | .extern yield 16 | 17 | // mutex with ticketing system. 18 | // rdi= address to mutex 19 | // mutex is a 64bit value representing: 20 | // 63:32: next ticket 21 | // 31:0 : current ticket 22 | mutexLock: 23 | push %rax 24 | mov $1,%rax 25 | lock xadd %eax,(%rdi) 26 | 1: cmp %eax,4(%rdi) 27 | je 2f 28 | call yield 29 | jmp 1b 30 | 2: pop %rax 31 | ret 32 | 33 | mutexUnlock: // rdi = mutext address 34 | lock incq 4(%rdi) 35 | ret 36 | 37 | 38 | // spinlock with ticketing systemnfo . 39 | // rdi= address to mutex 40 | // spinlock is a 64bit value representing: 41 | // 63:32: next ticket 42 | // 31:0 : current ticket 43 | spinLock: 44 | push %rax 45 | mov $1,%rax 46 | lock xadd %eax,(%rdi) 47 | // eax has been loaded with the value that was in (%rdi), now wait until 48 | // the second part becomes equal to that 49 | 1: cmp %eax,4(%rdi) 50 | jne 1b 51 | pop %rax 52 | ret 53 | 54 | spinUnlock: // rdi = spinlock address 55 | lock incq 4(%rdi) 56 | ret 57 | 58 | 59 | // spinlock with ticketing system. 60 | // rdi= address to mutex 61 | // spinlock is a 128bit value representing: 62 | // 127:64: flags status 63 | // 63:32 : next ticket 64 | // 31:0 : current ticket 65 | // WARNING: This will disable interrupts. So this should not be used between 66 | // threads since they wont be preempted and won't give a chance 67 | // to concurrents to release the lock. but then again, it the 68 | // interrupts are cleared, then this thread will be guaranteed to 69 | // be able to release the lock without being preempted 70 | spinLock_softirq: 71 | push %rax 72 | pushfq 73 | pop %rax 74 | mov %rax,8(%rdi) 75 | cli 76 | mov $1,%rax 77 | lock xadd %eax,(%rdi) 78 | 1: cmp %eax,4(%rdi) 79 | jne 1b 80 | pop %rax 81 | ret 82 | 83 | spinUnlock_softirq: // rdi = spinlock address 84 | lock incq 4(%rdi) 85 | bt $9,8(%rdi) 86 | jnc 1f 87 | sti 88 | 1: ret 89 | 90 | 91 | 92 | //////////////////////////////////////////////////////////////////////////////////// 93 | //////////////////////////////////////////////////////////////////////////////////// 94 | // rwlockWriteLock(%rdi=lock) 95 | // lock format: 96 | // 63:32: readCount 97 | // 31:00: writeLock 98 | // It would be possible to waste time when this function waits for readers to be 0 99 | // another reader count constantly inc/dec 100 | //////////////////////////////////////////////////////////////////////////////////// 101 | //////////////////////////////////////////////////////////////////////////////////// 102 | rwlockWriteLock: 103 | // lock the write lock or wait if it is already. 104 | 1: lock btsq $0,(%rdi) 105 | jc 1b 106 | 107 | // Wait for readers to finish 108 | 1: cmpl $0,4(%rdi) 109 | jnz 1b 110 | ret 111 | 112 | //////////////////////////////////////////////////////////////////////////////////// 113 | //////////////////////////////////////////////////////////////////////////////////// 114 | // rwlockWriteUnlock(%rdi=lock) 115 | //////////////////////////////////////////////////////////////////////////////////// 116 | //////////////////////////////////////////////////////////////////////////////////// 117 | rwlockWriteUnlock: 118 | btrq $0,(%rdi) 119 | ret 120 | 121 | //////////////////////////////////////////////////////////////////////////////////// 122 | //////////////////////////////////////////////////////////////////////////////////// 123 | // rwlockReadLock(%rdi=lock) 124 | //////////////////////////////////////////////////////////////////////////////////// 125 | //////////////////////////////////////////////////////////////////////////////////// 126 | rwlockReadLock: 127 | 1: lock incl 4(%rdi) 128 | 129 | bt $0,(%rdi) 130 | jnc 3f 131 | 132 | lock decl 4(%rdi) 133 | 134 | bt $0,(%rdi) 135 | jnc 1b 136 | call yield 137 | jmp 1b 138 | 139 | 3: ret 140 | 141 | //////////////////////////////////////////////////////////////////////////////////// 142 | //////////////////////////////////////////////////////////////////////////////////// 143 | // rwlockReadUnlock(%rdi=lock) 144 | //////////////////////////////////////////////////////////////////////////////////// 145 | //////////////////////////////////////////////////////////////////////////////////// 146 | rwlockReadUnlock: 147 | lock decl 4(%rdi) 148 | ret 149 | 150 | -------------------------------------------------------------------------------- /kernel/netcard.h: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | #define MAC_DESTINATION_MULTICAST 0x8000 3 | #define MAC_DESTINATION_UNICAST 0x4000 4 | #define MAC_DESTINATION_BROADCAST 0x2000 5 | 6 | struct Layer2Payload 7 | { 8 | unsigned long from; 9 | unsigned long to; 10 | unsigned short vlan; 11 | unsigned short protocol; 12 | unsigned short size; 13 | unsigned char* data; 14 | unsigned char interface; 15 | }; 16 | 17 | struct NetworkConfig 18 | { 19 | unsigned int ip; 20 | unsigned int subnetmask; 21 | unsigned int gateway; 22 | unsigned short vlan; 23 | }; 24 | 25 | 26 | 27 | struct NetworkBuffer 28 | { 29 | unsigned char* payload; 30 | unsigned short payloadSize; 31 | unsigned char* layer3Data; 32 | unsigned short layer3Size; 33 | unsigned char* layer2Data; 34 | unsigned short layer2Size; 35 | }; 36 | 37 | 38 | struct NetworkCard 39 | { 40 | spinlock_softirq_lock send_mutex; 41 | struct NetworkConfig ownNetworkConfig; 42 | void* deviceInfo; 43 | 44 | void* (*init)(unsigned int); 45 | void (*start)(struct NetworkCard*); 46 | unsigned long (*getMACAddress)(struct NetworkCard*); 47 | unsigned long (*receive)(unsigned char** buffer, struct NetworkCard*); 48 | void (*recvProcessed)(struct NetworkCard*); 49 | unsigned long (*send)(struct NetworkBuffer *, struct NetworkCard*); 50 | }; 51 | 52 | unsigned char net_getInterfaceIndex(unsigned int ip); 53 | struct NetworkConfig* net_getConfig(unsigned char index); 54 | -------------------------------------------------------------------------------- /kernel/pci.c: -------------------------------------------------------------------------------- 1 | #include "../memorymap.h" 2 | #include "config.h" 3 | #include "printf.h" 4 | 5 | extern unsigned long ioAPICGetRedirect(unsigned long index); 6 | extern void getInterruptInfoForBus(unsigned long bus, unsigned int* buffer); 7 | #define CONFIG_ADDRESS 0xCF8 8 | #define CONFIG_DATA 0xCFC 9 | #define OUTPORTW(val,port) asm volatile( "outw %0, %1" : : "a"(val), "Nd"((unsigned short)port) ); 10 | #define OUTPORTL(val,port) asm volatile( "outl %0, %1" : : "a"(val), "Nd"((unsigned short)port) ); 11 | #define INPORTL(ret,port) asm volatile( "inl %1, %0" : "=a"(ret) : "Nd"((unsigned short)port) ); 12 | 13 | 14 | // http://www.freewebz.com/mrd/os/pci/pci.html 15 | // http://books.google.ca/books?id=tVfeqL5F1DwC&pg=PA78&lpg=PA78&dq=CONFIG_ADDRESS+pci&source=bl&ots=d0GeHkoa9Y&sig=FHnsqd0rb1dA2Pktt7MWhl0Pm64&hl=en&sa=X&ei=ao2WUun-BNPmsASWn4CwCw&ved=0CDYQ6AEwAg#v=onepage&q=CONFIG_ADDRESS%20pci&f=false 16 | // http://www.acm.uiuc.edu/sigops/roll_your_own/7.c.html 17 | // http://www.acm.uiuc.edu/sigops/roll_your_own/7.c.0.html 18 | 19 | struct PCIDevice 20 | { 21 | unsigned int bars[6]; 22 | unsigned short bus; 23 | unsigned short devnum; 24 | unsigned short vendorID; 25 | unsigned short deviceID; 26 | unsigned char irq; 27 | unsigned char pciIntPin; 28 | unsigned char classCode; 29 | unsigned char type; 30 | unsigned char function; 31 | unsigned char ioapicPin; 32 | unsigned char ioapicID; 33 | unsigned short subsystemID; 34 | }__attribute((packed))__; 35 | 36 | 37 | unsigned int ioapicDevices[128]; 38 | struct PCIDevice pciDevices[MAX_PCI_DEVICES_SUPPORTED]={0}; 39 | unsigned long pciDeviceIndex = 0; 40 | 41 | void pci_setIOAPICInterruptIndex(struct PCIDevice *dev) 42 | { 43 | unsigned int i; 44 | 45 | for (i=0;i<128&&ioapicDevices[i]!=0;i++) 46 | { 47 | unsigned char ioapicpin = (ioapicDevices[i])&0xFF; 48 | unsigned char devnum = (ioapicDevices[i]>>10)&0b11111; 49 | unsigned char pin = (ioapicDevices[i]>>8)&0b11; 50 | unsigned char bus = (ioapicDevices[i]>>16)&0xFF; 51 | 52 | if (bus==dev->bus && devnum==dev->devnum && pin==(dev->pciIntPin-1)) 53 | { 54 | dev->ioapicPin = ioapicpin; 55 | dev->ioapicID = 0; // TODO: should not hardcode that 56 | return; 57 | } 58 | } 59 | } 60 | 61 | // access device by Bus,Device,Function (BDF) 62 | unsigned int getPCIData(unsigned long bus, unsigned long device, unsigned long function, unsigned long reg) 63 | { 64 | unsigned int address = (1<<31)|(bus<<16)|(device<<11)|(function<<8)|((reg)&0b11111100); 65 | OUTPORTL(address,CONFIG_ADDRESS); 66 | unsigned int ret; 67 | INPORTL(ret,CONFIG_DATA); 68 | return ret; 69 | } 70 | 71 | 72 | void pci_enableBusMastering(unsigned int address) 73 | { 74 | address = (1<<31)|address|(4); 75 | OUTPORTL(address,CONFIG_ADDRESS); 76 | unsigned int ret; 77 | INPORTL(ret,CONFIG_DATA); 78 | OUTPORTL(ret|0b0000000100,CONFIG_DATA); // bus mastering 79 | } 80 | 81 | unsigned long validateDevice(unsigned long bus, unsigned long device, unsigned char function) 82 | { 83 | // get the vendorID (reg=0) for the bus/device/function. Function will always be zero here since 84 | // we won't support multi-function devices 85 | unsigned int data = getPCIData(bus,device,function,0); 86 | unsigned short vendorID = data & 0xFFFF; 87 | unsigned short devID = (data>>16); 88 | data = getPCIData(bus,device,function,0x2C); 89 | unsigned short subID = data>>16; 90 | if (vendorID != 0xFFFF) 91 | { 92 | data = getPCIData(bus,device,function,0x0C); 93 | pciDevices[pciDeviceIndex].type = (data>>16)&0xFF; 94 | data = getPCIData(bus,device,function,0x3C); 95 | pciDevices[pciDeviceIndex].bus = bus; 96 | pciDevices[pciDeviceIndex].devnum = device; 97 | pciDevices[pciDeviceIndex].vendorID = vendorID; 98 | pciDevices[pciDeviceIndex].function = function; 99 | pciDevices[pciDeviceIndex].deviceID = devID; 100 | pciDevices[pciDeviceIndex].irq = (data&0xFF); 101 | pciDevices[pciDeviceIndex].pciIntPin = ((data>>8)&0xFF); 102 | pciDevices[pciDeviceIndex].bars[0] = getPCIData(bus,device,function,0x10); 103 | pciDevices[pciDeviceIndex].bars[1] = getPCIData(bus,device,function,0x14); 104 | pciDevices[pciDeviceIndex].bars[2] = getPCIData(bus,device,function,0x18); 105 | pciDevices[pciDeviceIndex].bars[3] = getPCIData(bus,device,function,0x1C); 106 | pciDevices[pciDeviceIndex].bars[4] = getPCIData(bus,device,function,0x20); 107 | pciDevices[pciDeviceIndex].bars[5] = getPCIData(bus,device,function,0x24); 108 | pciDevices[pciDeviceIndex].subsystemID = subID, 109 | 110 | data = getPCIData(bus,device,function,0x08); 111 | pciDevices[pciDeviceIndex].classCode = (data>>24); 112 | 113 | pci_setIOAPICInterruptIndex((struct PCIDevice*)&pciDevices[pciDeviceIndex]); 114 | pciDeviceIndex++; 115 | return pciDeviceIndex-1; 116 | } 117 | 118 | return -1; 119 | } 120 | 121 | unsigned int getAddress(struct PCIDevice *dev) 122 | { 123 | return (1<<31)|(dev->bus<<16)|(dev->devnum<<11)|(dev->function<<8); 124 | } 125 | 126 | unsigned int pci_getBar(unsigned int dev,unsigned char bar) 127 | { 128 | unsigned long i; 129 | for (i=0;i> ((digits-i-1)*4))&0b1111; 17 | if (c<10) c+=48; else c+=55; 18 | *outbuf=c; 19 | outbuf++; 20 | } 21 | *outbuf = 0; 22 | return digits; 23 | } 24 | 25 | void safeWriteString(char* st) 26 | { 27 | streamCharacters(st); 28 | } 29 | 30 | // WARNING: there is noprotection here. If resulting string goes over 256, you're deadbeef 31 | void pf(char * fmt,...) 32 | { 33 | char st[256]; 34 | unsigned long stIndex = 0; 35 | 36 | va_list list; 37 | va_start(list,fmt); 38 | 39 | unsigned long i=0; 40 | while (*fmt!=0) 41 | { 42 | if (*fmt!='%') 43 | { 44 | st[stIndex++] = *fmt; 45 | } 46 | else 47 | { 48 | fmt++; 49 | if (*fmt=='s') 50 | { 51 | char *sta = va_arg(list,char *); 52 | while (*sta!=0) 53 | { 54 | st[stIndex++]=*sta; 55 | sta++; 56 | } 57 | } 58 | else if (*fmt=='x') 59 | { 60 | unsigned long v = va_arg(list,unsigned long); 61 | if (v&0xFFFFFFFF00000000) // 64bit 62 | { 63 | stIndex += itoh(v,(char*)&st[stIndex],16); 64 | } 65 | else if (v&0xFFFF0000) // 32bit 66 | { 67 | stIndex += itoh(v,(char*)&st[stIndex],8); 68 | } 69 | else if (v&0xFF00) //16bit 70 | { 71 | stIndex += itoh(v,(char*)&st[stIndex],4); 72 | } 73 | else // 8 bit 74 | { 75 | stIndex += itoh(v,(char*)&st[stIndex],2); 76 | } 77 | } 78 | else if (*fmt=='X') 79 | { 80 | unsigned long v = va_arg(list,unsigned long); 81 | stIndex += itoh(v,(char*)&st[stIndex],16); 82 | } 83 | } 84 | fmt++; 85 | } 86 | st[stIndex]=0; 87 | 88 | safeWriteString((char*)&st[0]); 89 | va_end(list); 90 | } 91 | 92 | void debug_writestring_dangerous(char *st) 93 | { 94 | streamCharacters(st); 95 | } 96 | 97 | void debug_writenumber_dangerous(unsigned long number) 98 | { 99 | char buf[19]; 100 | buf[0]='0'; 101 | buf[1]='x'; 102 | buf[18]=0; 103 | 104 | unsigned int i; 105 | for (i=0;i<16;i++) 106 | { 107 | unsigned char c = (number >> (i*4))&0b1111; 108 | if (c<10) c+=48; else c+=55; 109 | buf[17-i]=c; 110 | } 111 | 112 | streamCharacters((char*)&buf[0]); 113 | } 114 | 115 | -------------------------------------------------------------------------------- /kernel/printf.h: -------------------------------------------------------------------------------- 1 | #undef pf 2 | extern void pf(char * fmt,...); 3 | -------------------------------------------------------------------------------- /kernel/sockets.h: -------------------------------------------------------------------------------- 1 | #include "includes/kernel/sockets.h" 2 | 3 | typedef struct 4 | { 5 | uint16_t source; 6 | uint16_t destination; 7 | uint32_t sequence; 8 | uint32_t acknowledgement; 9 | uint16_t flags; 10 | uint16_t window; 11 | uint16_t checksum; 12 | uint16_t urgent; 13 | } tcp_header; 14 | 15 | socket* create_socket(); 16 | void close_socket(socket* s); 17 | void release_socket(socket* s); 18 | void destroy_sockets(uint64_t pid); 19 | void connect(socket *s, uint32_t ip, uint16_t port); 20 | void tcp_process(char* buffer, uint16_t size, uint32_t from, uint32_t to); 21 | -------------------------------------------------------------------------------- /kernel/tasks.h: -------------------------------------------------------------------------------- 1 | // We cant use bit 63 because it is used to return invalid task addresses (set to -1) 2 | #define TASK_ENABLE_BIT 62 3 | #define TASK_RUNNING_BIT 61 4 | #define TASK_DEAD_BIT 60 5 | #define CLEANCR3ADDRESS(x) \ 6 | shl $8,x; \ 7 | shr $(8+12),x; \ 8 | shl $12,x 9 | 10 | // We might want to only clear control flags in a register 11 | // before loading cr3. The lower 12bits represent the PCID 12 | // so We must not clear it. 13 | #define STRIPCONTROLFROMCR3(x) \ 14 | shl $8,x; \ 15 | shr $8,x 16 | -------------------------------------------------------------------------------- /kernel/test.c: -------------------------------------------------------------------------------- 1 | #include "../memorymap.h" 2 | #include "includes/kernel/types.h" 3 | #include "config.h" 4 | #include "printf.h" 5 | 6 | unsigned long mutex=0; 7 | uint64_t cpus[10]; 8 | 9 | extern void mutexLock(unsigned long mutex); 10 | extern void mutexUnlock(unsigned long mutex); 11 | extern uint64_t calculateMemoryUsage(); 12 | extern void registerIPIHandler(uint64_t vector, void* handler); 13 | extern void sendIPI(uint64_t vector, uint64_t data, uint64_t msgID); 14 | extern uint64_t getTicksSinceBoot(); 15 | 16 | void testThread2() 17 | { 18 | } 19 | 20 | void IPIHandler(uint64_t data, uint64_t msgID, uint64_t apicID) 21 | { 22 | cpus[apicID] += data; 23 | } 24 | 25 | void initTestIPI() 26 | { 27 | uint64_t i; 28 | for (i=0;i<10;i++) cpus[i]=0; 29 | registerIPIHandler(IPI_LAST_VECTOR-1,&IPIHandler); 30 | } 31 | 32 | void testIPI() 33 | { 34 | sendIPI(IPI_LAST_VECTOR-1,0x02,242); 35 | } 36 | 37 | void testThread(unsigned int param) 38 | { 39 | int i; 40 | char c = '0'; 41 | unsigned int* apic = (unsigned int*)(APIC_BASE+0x20); 42 | char* buf = (char*)(0xB8000+(160*(25-param))); 43 | buf[8*2] = 48+param; 44 | 45 | while(1) 46 | { 47 | mutexLock(mutex); // no real need for mutex. This is just for testing 48 | unsigned int cpuid = (*apic)>>24; 49 | 50 | c++; 51 | if (c>'9') c='0'; 52 | buf[150] = c; 53 | buf[152] = ' '; 54 | buf[154] = 48+cpuid; 55 | buf[156] = ' '; 56 | mutexUnlock(mutex); 57 | 58 | } 59 | } 60 | 61 | void showMem() 62 | { 63 | pf("Memory usage: %x\r\n",calculateMemoryUsage()); 64 | } 65 | 66 | void showIPITestResult() 67 | { 68 | pf("IPI: %x %x %x %x %x\r\n", cpus[0],cpus[1],cpus[2],cpus[3],cpus[4]); 69 | } 70 | 71 | void testGetTicksSinceBoot() 72 | { 73 | pf("%x\r\n",getTicksSinceBoot()); 74 | } 75 | -------------------------------------------------------------------------------- /kernel/timer.S: -------------------------------------------------------------------------------- 1 | .global apic_timer_handler 2 | 3 | apic_timer_handler: 4 | call video_handler 5 | jmp schedulerHandler // will do the iretq 6 | -------------------------------------------------------------------------------- /kernel/tree.c: -------------------------------------------------------------------------------- 1 | #include "includes/kernel/tree.h" 2 | 3 | void tree_insert(tree* tree, void* data, uint64_t key) 4 | { 5 | } 6 | 7 | void tree_remove(tree* tree, uint64_t key) 8 | { 9 | } 10 | 11 | void* tree_get(tree* tree, uint64_t key) 12 | { 13 | } 14 | -------------------------------------------------------------------------------- /kernel/userboot.c: -------------------------------------------------------------------------------- 1 | #include "includes/kernel/types.h" 2 | #include "block_cache.h" 3 | #include "userprocess.h" 4 | #include "vfs.h" 5 | #include "printf.h" 6 | #include "utils.h" 7 | 8 | // This MUST be a multiple of 4096 9 | //TODO: we should determine the count dynamically. This will be easy when using FAT32 10 | #define ELFBUFFER (4*4096) 11 | 12 | extern void* kernelAllocPages(uint64_t count); 13 | extern void kernelReleasePages(uint64_t addr, uint64_t count); 14 | extern void showMem(); 15 | extern void strcpy(char* src, char* dst); 16 | extern void* malloc(uint64_t size); 17 | extern void free(void*); 18 | 19 | uint64_t deviceContainingScript; 20 | uint64_t appParam = 0; 21 | 22 | struct __attribute__((__packed__)) ElfHeader 23 | { 24 | uint32_t magic; 25 | uint8_t bits; 26 | uint8_t endian; 27 | uint8_t version1; 28 | uint8_t abi; 29 | uint64_t reserved1; 30 | uint16_t relocatable; 31 | uint16_t instructionSet; 32 | uint32_t version2; 33 | uint64_t programPosition; 34 | uint64_t programHeaderPosition; 35 | uint64_t sectionHeaderPosition; 36 | uint32_t flags; 37 | uint16_t headerSize; 38 | uint16_t programHeaderEntrySize; 39 | uint16_t programHeaderEntryCount; 40 | uint16_t sectionHeaderEntrySize; 41 | uint16_t sectionHeaderEntryCount; 42 | uint16_t sectionHeaderNamesIndex; 43 | }; 44 | struct __attribute__((__packed__)) SectionHeader64 45 | { 46 | uint32_t nameIndex; 47 | uint32_t type; 48 | uint64_t flags; 49 | uint64_t virtualAddress; 50 | uint64_t offsetInFile; 51 | uint64_t size; 52 | uint32_t link; 53 | uint32_t info; 54 | uint64_t align; 55 | uint64_t entrySize; 56 | }; 57 | 58 | 59 | uint8_t isValidSection(struct SectionHeader64* sh) 60 | { 61 | // We only support progbits (data,rodata,text) and no bits (bss) 62 | if (sh->type != 1 && sh->type != 8) return 0; 63 | 64 | // only sections that needs allocation (alloc flag) 65 | if ((sh->flags & 0x02) == 0) return 0; 66 | 67 | // And, for now, we only allow sections aligned on a 4k boundary 68 | if ((sh->virtualAddress&0xFFF) > 0) 69 | { 70 | // But the text section will map on a non-4k-boundary. 71 | // That's the only exception 72 | if (sh->virtualAddress!=USER_PROCESS_CODE_START) 73 | { 74 | return 0; 75 | } 76 | } 77 | 78 | return 1; 79 | } 80 | 81 | 82 | 83 | 84 | uint64_t loadProcess(char* name, bool createNewConsole) 85 | { 86 | uint64_t i; 87 | uint64_t n; 88 | uint64_t size; 89 | char* elfBuffer; 90 | 91 | file_handle* f = fopen(name,ACCESS_TYPE_READ); 92 | if (f == 0) 93 | { 94 | pf("File not found [%s]\r\n",name); 95 | return 0; 96 | } 97 | 98 | size = fgetsize(f); 99 | if (size > ELFBUFFER) 100 | { 101 | pf("Can't load application. Too big\r\n"); 102 | fclose(f); 103 | return 0; 104 | } 105 | elfBuffer = (char*)malloc(size); 106 | 107 | fread(f,size,elfBuffer); 108 | struct ElfHeader *eh = (struct ElfHeader*)elfBuffer; 109 | 110 | struct UserProcessInfo upi; 111 | upi.entryPoint = (char*)eh->programPosition; 112 | upi.entryParameter = appParam; 113 | if (createNewConsole) 114 | { 115 | upi.consoleSteal = 0; 116 | } 117 | else 118 | { 119 | // the new process will takeover the current console 120 | __asm("mov %%cr3,%0" : "=r"(upi.consoleSteal)); 121 | } 122 | createUserProcess(&upi); 123 | char* sectionHeaders = elfBuffer[eh->sectionHeaderPosition]; 124 | for (n = 0; n < eh->sectionHeaderEntryCount; n++) 125 | { 126 | struct SectionHeader64* sh = (struct SectionHeader64*)&elfBuffer[eh->sectionHeaderPosition+(n*sizeof(struct SectionHeader64))]; 127 | if (isValidSection(sh) == 0) continue; 128 | 129 | bool readOnly = !(sh->flags&1); 130 | bool executable = (sh->flags&4); 131 | bool initZero = (sh->type==8); 132 | 133 | addUserProcessSection(&upi,&elfBuffer[sh->offsetInFile], sh->virtualAddress, sh->size, readOnly, executable, initZero); 134 | } 135 | 136 | createProcessHeap(&upi); 137 | launchUserProcess(&upi); 138 | appParam++; 139 | fclose(f); 140 | free((void*)elfBuffer); 141 | return upi.psi.pml4; 142 | } 143 | 144 | void loadUserApplications(uint64_t device) 145 | { 146 | unsigned int i,n; 147 | uint64_t param=0; 148 | char bootscript[512]; 149 | char fname[512]; 150 | 151 | if (device >9) 152 | { 153 | pf("Bad device name\r\n"); 154 | return; 155 | } 156 | fname[0]='0'; 157 | fname[1]=0x30+device; 158 | fname[2]=':'; 159 | fname[3]='/'; 160 | strcpy("bootscript",(char*)&fname[4]); 161 | file_handle* f = fopen(fname,ACCESS_TYPE_READ); 162 | if (f == 0) 163 | { 164 | pf("ERROR: bootscript file [%s] not found\r\n",fname); 165 | return; 166 | } 167 | 168 | int fsize = fread(f,512,bootscript); 169 | fclose(f); 170 | 171 | 172 | n = 0; 173 | for (i = 0; i< fsize; i++) 174 | { 175 | if (bootscript[i] == 0) break; 176 | if (bootscript[i] == 0x0A) 177 | { 178 | bootscript[i]=0; 179 | strcpy((char*)&bootscript[n],(char*)&fname[4]); 180 | fname[4+i-n]=0; 181 | pf("loading [%s] from bootscript\r\n",fname); 182 | loadProcess(fname,true); 183 | n = i+1; 184 | } 185 | } 186 | } 187 | 188 | 189 | -------------------------------------------------------------------------------- /kernel/userprocess.h: -------------------------------------------------------------------------------- 1 | #include "../memorymap.h" 2 | 3 | #define USER_PROCESS_STUB_SIZE 0x200 4 | #define USER_PROCESS_CODE_START (THREAD_CODE_START+USER_PROCESS_STUB_SIZE) 5 | 6 | struct ProcessStructureInfo 7 | { 8 | uint64_t* pml4; 9 | }; 10 | 11 | struct UserProcessInfo 12 | { 13 | char* entryPoint; 14 | char* metaPage; 15 | uint64_t entryParameter; 16 | uint64_t consoleSteal; 17 | struct ProcessStructureInfo psi; 18 | uint64_t lastProgramAddress; 19 | }; 20 | 21 | void createUserProcess(struct UserProcessInfo*); 22 | void addUserProcessSection(struct UserProcessInfo* upi, char* buffer, uint64_t virtualAddress, uint64_t size, bool readOnly, bool executable, bool initZero); 23 | void launchUserProcess(struct UserProcessInfo* upi); 24 | void createProcessHeap(struct UserProcessInfo* upi); 25 | -------------------------------------------------------------------------------- /kernel/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "includes/kernel/types.h" 3 | 4 | #ifndef UNIT_TEST 5 | 6 | #define C_BREAKPOINT() __asm("int $3"); 7 | #define C_BREAKPOINT_VAR(v1,v2,v3,v4) asm volatile ("int $3" : :"a"(v1),"b"(v2),"c"(v3),"d"(v4)); 8 | #define OUTPORTB(val,port) asm volatile( "outb %0, %1" : : "a"((unsigned char)(val)), "Nd"((unsigned short)(port)) ); 9 | #define OUTPORTW(val,port) asm volatile( "outw %0, %1" : : "a"((unsigned short)(val)), "Nd"((unsigned short)(port)) ); 10 | #define OUTPORTL(val,port) asm volatile( "outl %0, %1" : : "a"((unsigned int)(val)), "Nd"((unsigned short)(port)) ); 11 | #define INPORTB(ret,port) asm volatile( "inb %1, %0" : "=a"((unsigned char)(ret)) : "Nd"((unsigned short)(port)) ); 12 | #define INPORTW(ret,port) asm volatile( "inw %1, %0" : "=a"((unsigned short)(ret)) : "Nd"((unsigned short)(port)) ); 13 | #define INPORTL(ret,port) asm volatile( "inl %1, %0" : "=a"(ret) : "Nd"((unsigned short)(port)) ); 14 | #define CLI(oldstatus) asm volatile ("pushf; pop %0; shr $9,%0; and $1,%0; cli" : "=g"(oldstatus)); 15 | #define STI(oldstatus) { if (oldstatus!=0) asm volatile ("sti");} 16 | #define SWAP2(x) asm volatile("xchg %b0, %h0" : "=a" ((unsigned short)x) : "a" ((unsigned short)x)); 17 | #define SWAP4(x) asm volatile("bswap %0" : "=r" ((unsigned int)x) : "0" ((unsigned int)x)); 18 | #define SWAP6(x) asm volatile("bswap %0; shr $16,%0" : "=r" ((unsigned long)x) : "0" ((unsigned long)x)); 19 | 20 | #else 21 | 22 | #define OUTPORTB(val,port) asm volatile( "nop" :: ); 23 | #define OUTPORTW(val,port) asm volatile( "nop" :: ); 24 | #define OUTPORTL(val,port) asm volatile( "nop" :: ); 25 | #define INPORTB(ret,port) asm volatile( "nop" :: ); 26 | #define INPORTW(ret,port) asm volatile( "nop" :: ); 27 | #define INPORTL(ret,port) asm volatile( "nop" :: ); 28 | #define CLI(oldstatus) asm volatile( "nop" :: ); 29 | #define STI(oldstatus) asm volatile( "nop" :: ); 30 | #define SWAP2(x) asm volatile( "nop" :: ); 31 | #define SWAP4(x) asm volatile( "nop" :: ); 32 | #define SWAP6(x) asm volatile( "nop" :: ); 33 | 34 | #endif 35 | 36 | typedef struct 37 | { 38 | uint64_t part1; 39 | uint64_t part2; 40 | } spinlock_softirq_lock; 41 | -------------------------------------------------------------------------------- /kernel/vfat.c: -------------------------------------------------------------------------------- 1 | #include "vfat.h" 2 | #include "block_cache.h" 3 | 4 | //TODO: this driver is not implemented yet 5 | 6 | extern void memcpy64(char* source, char* destination, uint64_t size); 7 | 8 | void vfat_system_handle_destructor(system_handle* h); 9 | 10 | bool vfat_fopen(system_handle* h, char* name, uint64_t access_type) 11 | { 12 | return false; 13 | } 14 | 15 | uint64_t vfat_fread(system_handle* h, uint64_t count, char* destination) 16 | { 17 | return 0; 18 | } 19 | uint64_t vfat_fwrite(system_handle* h, uint64_t count, char* destination) 20 | { 21 | return 0; 22 | } 23 | 24 | void vfat_fclose(system_handle* h) 25 | { 26 | } 27 | 28 | void vfat_fseek(system_handle* h, uint64_t count, bool absolute) 29 | { 30 | } 31 | 32 | uint64_t vfat_fgetsize(system_handle* h) 33 | { 34 | file_handle* f = (file_handle*)h; 35 | return f->size; 36 | } 37 | void vfat_system_handle_destructor(system_handle* h) 38 | { 39 | //TODO: should release any held locks 40 | //TODO: should cancel any pending block operations 41 | } 42 | -------------------------------------------------------------------------------- /kernel/vfat.h: -------------------------------------------------------------------------------- 1 | #include "includes/kernel/types.h" 2 | #include "vfs.h" 3 | 4 | bool vfat_fopen(system_handle* h, char* name, uint64_t access_type); 5 | uint64_t vfat_fread(system_handle* h, uint64_t count, char* destination); 6 | uint64_t vfat_fwrite(system_handle* h, uint64_t count, char* destination); 7 | void vfat_fclose(system_handle* h); 8 | void vfat_fseek(system_handle* h, uint64_t count, bool absolute); 9 | uint64_t vfat_fgetsize(system_handle* h); 10 | -------------------------------------------------------------------------------- /kernel/vfs.c: -------------------------------------------------------------------------------- 1 | #include "vfs.h" 2 | #include "flatfs.h" 3 | #include "../memorymap.h" 4 | #include "memorypool.h" 5 | #include "printf.h" 6 | #include "utils.h" 7 | 8 | void add_file_handle_to_list(file_handle* f); 9 | void remove_file_handle_from_list(file_handle* f); 10 | uint64_t memoryPool; 11 | 12 | void init_vfs() 13 | { 14 | memoryPool = create_memory_pool(sizeof(file_handle)); 15 | } 16 | 17 | file_handle* fopen(char* name, uint64_t access_type) 18 | { 19 | //file_handle* f = (file_handle*)malloc(sizeof(file_handle)); 20 | file_handle* f = reserve_object(memoryPool); 21 | 22 | f->operations.fopen = &flatfs_fopen; 23 | f->operations.fread = &flatfs_fread; 24 | f->operations.fwrite = &flatfs_fwrite; 25 | f->operations.fseek = &flatfs_fseek; 26 | f->operations.fclose = &flatfs_fclose; 27 | f->operations.fgetsize = &flatfs_fgetsize; 28 | 29 | if (f->operations.fopen == 0) __asm("int $3"); 30 | if (!f->operations.fopen(f,name,access_type)) 31 | { 32 | // free(f); 33 | release_object(memoryPool,f); 34 | return 0; 35 | } 36 | 37 | // add in list 38 | add_file_handle_to_list(f); 39 | return f; 40 | } 41 | 42 | void add_file_handle_to_list(file_handle* f) 43 | { 44 | //TODO: this should lock so that it would be multi-thread safe 45 | file_handle* firstHandle = *((file_handle**)FILE_HANDLE_ADDRESS); 46 | 47 | f->next = 0; 48 | if (firstHandle == 0) 49 | { 50 | *((file_handle**)FILE_HANDLE_ADDRESS) = f; 51 | f->previous = 0; 52 | } 53 | else 54 | { 55 | while (firstHandle->next != 0) firstHandle = firstHandle->next; 56 | firstHandle->next = f; 57 | f->previous = firstHandle; 58 | } 59 | } 60 | 61 | void remove_file_handle_from_list(file_handle* f) 62 | { 63 | file_handle *previous = f->previous; 64 | file_handle *next = f->next; 65 | 66 | //TODO: this should lock so that it would be multi-thread safe 67 | if (previous == 0) 68 | { 69 | *((file_handle**)FILE_HANDLE_ADDRESS) = next; 70 | if (next != 0) next->previous = 0; 71 | } 72 | else 73 | { 74 | previous->next = next; 75 | if (next!=0) next->previous = previous; 76 | } 77 | 78 | } 79 | 80 | uint64_t fread(file_handle* f, uint64_t count, char* destination) 81 | { 82 | if (f->operations.fread == 0) __asm("int $3"); 83 | return f->operations.fread((system_handle*)f,count,destination); 84 | } 85 | 86 | uint64_t fwrite(file_handle* f, uint64_t count, char* destination) 87 | { 88 | return f->operations.fwrite((system_handle*)f,count,destination); 89 | } 90 | 91 | void fclose(file_handle* f) 92 | { 93 | if (f->operations.fclose == 0) __asm("int $3"); 94 | f->operations.fclose((system_handle*)f); 95 | remove_file_handle_from_list(f); 96 | //free(f); 97 | release_object(memoryPool,f); 98 | } 99 | 100 | void fseek(file_handle* f, uint64_t count, bool absolute) 101 | { 102 | f->operations.fseek((system_handle*)f,count,absolute); 103 | } 104 | 105 | uint64_t fgetsize(file_handle* f) 106 | { 107 | return f->operations.fgetsize(f); 108 | } 109 | 110 | // This function will be invoked by the kernel when killing a task 111 | // This function should not lock because we want to avoid deadlocks when 112 | // force-killing the task. No other threads should be messing with 113 | // the current process's file handles anyway since the process is dying. 114 | void destroyFileHandles() 115 | { 116 | file_handle* f = *((file_handle**)FILE_HANDLE_ADDRESS); 117 | while (f != 0) 118 | { 119 | pf("destroying improperly closed file handle\r\n"); 120 | system_handle* h = (system_handle*)f; 121 | f = f->next; 122 | h->destructor(h); 123 | } 124 | *((file_handle**)FILE_HANDLE_ADDRESS) = 0; 125 | } 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /kernel/vfs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "includes/kernel/types.h" 4 | #include "includes/kernel/systemhandle.h" 5 | 6 | #define ACCESS_TYPE_READ 1 7 | #define ACCESS_TYPE_WRITE 2 8 | 9 | // File path example: 01:/file.text 10 | 11 | 12 | // A system_handle is the base of all handles in the system. It provides a functor 13 | // for a destructor function. On process death, all system_handle's destructor 14 | // function will be invoked to make sure that resources are cleaned appropriately. 15 | // 16 | // A file_handle contains a system_handle. When a process dies, the system_handle's 17 | // destructor gets called. The kernel finds all opened file handles in a linked-list. 18 | // Each file_handle has a previous and next field because it is a linked-list. 19 | 20 | typedef struct 21 | { 22 | bool (*fopen)(system_handle* h, char* name, uint64_t access_type); 23 | uint64_t (*fread)(system_handle* h, uint64_t count, char* destination); 24 | uint64_t (*fwrite)(system_handle* h, uint64_t count, char* destination); 25 | void (*fclose)(system_handle* h); 26 | void (*fseek)(system_handle* h, uint64_t count, bool absolute); 27 | uint64_t (*fgetsize)(system_handle* h); 28 | } file_operations; 29 | 30 | struct _file_handle 31 | { 32 | system_handle handle; 33 | struct _file_handle* next; 34 | struct _file_handle* previous; 35 | file_operations operations; 36 | 37 | uint64_t start; //sector number 38 | uint64_t position; //relative byte offset in file 39 | uint64_t size; 40 | uint64_t device; 41 | }; 42 | 43 | typedef struct _file_handle file_handle; 44 | 45 | file_handle* fopen(char* name, uint64_t access_type); 46 | uint64_t fread(file_handle* f, uint64_t count, char* destination); 47 | uint64_t fwrite(file_handle* f, uint64_t count, char* destination); 48 | void fclose(file_handle* f); 49 | void fseek(file_handle* f, uint64_t count, bool absolute); 50 | uint64_t fgetsize(file_handle* f); 51 | -------------------------------------------------------------------------------- /kernel/video.c: -------------------------------------------------------------------------------- 1 | #include "memorypool.h" 2 | #include "video.h" 3 | #include "../memorymap.h" 4 | #include "utils.h" 5 | 6 | extern char* kernelAllocPages(uint64_t pageCount); 7 | extern void memcpy64(char* source, char* dest, uint64_t size); 8 | extern void memclear64(char* dest, uint64_t size); 9 | extern void mutexLock(uint64_t*); 10 | extern void mutexUnlock(uint64_t*); 11 | extern void rwlockWriteLock(uint64_t*); 12 | extern void rwlockWriteUnlock(uint64_t*); 13 | extern void rwlockReadLock(uint64_t*); 14 | extern void rwlockReadUnlock(uint64_t*); 15 | extern void mapPhysOnVirtualAddressSpace(uint64_t pageTableBase, uint64_t virtualAddress, uint64_t physicalAddress, uint64_t pageCount, uint64_t mask); 16 | 17 | #define MAX_SCREEN_COUNT 128 18 | 19 | volatile char* current_video_back_buffer; 20 | static uint64_t memorypool; 21 | 22 | 23 | void enable_cursor(bool enabled) 24 | { 25 | char tmp; 26 | OUTPORTB(0x0A,0x3D4); 27 | INPORTB(tmp,0x3D5) 28 | if (enabled) 29 | { 30 | tmp = (tmp & 0b11111); 31 | } 32 | else 33 | { 34 | tmp = (tmp | 0b100000); 35 | } 36 | OUTPORTB(0x3D4, 0x0A); 37 | OUTPORTB(tmp,0x3D5); 38 | } 39 | 40 | void video_update_cursor(Screen* scr, bool on, uint16_t position) 41 | { 42 | if (!scr->active) return; 43 | enable_cursor(on); 44 | if (on) 45 | { 46 | OUTPORTB(0x0F,0x3D4); 47 | OUTPORTB((unsigned char)position, 0x3D5); 48 | OUTPORTB(0x0E, 0x3D4); 49 | OUTPORTB((unsigned char )(position>>8), 0x3D5); 50 | } 51 | } 52 | 53 | void video_get_dimensions(Screen* src, uint32_t* width, uint32_t* height) 54 | { 55 | *width=80; 56 | *height=25; 57 | } 58 | 59 | void video_init() 60 | { 61 | uint64_t i; 62 | 63 | memorypool = create_memory_pool(sizeof(Screen)); 64 | enable_cursor(false); 65 | } 66 | 67 | Screen* video_create_screen() 68 | { 69 | uint64_t i; 70 | Screen* screen = (Screen*)reserve_object(memorypool); 71 | memclear64((void*)screen,sizeof(Screen)); 72 | 73 | screen->backBuffer = kernelAllocPages(1); 74 | screen->active = false; 75 | 76 | memclear64((void*)screen->backBuffer,4096); 77 | return screen; 78 | } 79 | 80 | char* video_get_buffer(Screen* scr) 81 | { 82 | return scr->backBuffer; 83 | } 84 | 85 | void video_change_active_screen(Screen* oldscr, Screen* newscr) 86 | { 87 | if (oldscr) 88 | { 89 | oldscr->active = false; 90 | } 91 | newscr->active = true; 92 | current_video_back_buffer = newscr->backBuffer; 93 | } 94 | -------------------------------------------------------------------------------- /kernel/video.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "includes/kernel/types.h" 4 | 5 | typedef struct 6 | { 7 | // char backBuffer[4096]; 8 | char* backBuffer; 9 | bool active; 10 | } Screen; 11 | 12 | void video_init(); 13 | Screen* video_create_screen(); 14 | char* video_get_buffer(Screen* scr); 15 | void video_update_cursor(Screen* scr, bool on, uint16_t position); 16 | void video_change_active_screen(Screen* oldscr, Screen* newscr); 17 | void video_get_dimensions(Screen* src, uint32_t* width, uint32_t* height); 18 | -------------------------------------------------------------------------------- /kernel/video_s.S: -------------------------------------------------------------------------------- 1 | #include "../memorymap.h" 2 | #include "macros.h" 3 | .global video_handler 4 | .global video_refresh_enable 5 | 6 | 7 | video_handler: 8 | push %rax 9 | 10 | // only do this on CPU0, we dont want to call it on all cores 11 | GET_APIC_ID(%rax) 12 | cmp $0,%al 13 | jne ignore_video_handler 14 | 15 | cmpq $0,video_refresh_enable 16 | jz ignore_video_handler 17 | 18 | 19 | push %rcx 20 | 21 | mov refresh_counter,%rcx 22 | cmp $0,%rcx 23 | jne 1f 24 | 25 | push %rsi 26 | push %rdi 27 | movq $SCREEN_REFRESH_RATE_COUNTER,refresh_counter 28 | 29 | //TODO: should lock this buffer because another CPU may have 30 | // changed it and unmapped it while we are executin movsb 31 | mov current_video_back_buffer,%rsi 32 | 33 | // TODO: should check dirty flag. But looking through the page tables 34 | // then clearing the flag and invalidating the TLB (because of 35 | // dirty flag clear) is a lot of operations... is it worth it? 36 | 37 | mov $0xB8000,%rdi 38 | mov $(4096/8),%rcx 39 | rep movsq 40 | 41 | 2: pop %rdi 42 | pop %rsi 43 | 1: pop %rcx 44 | decb refresh_counter 45 | ignore_video_handler: 46 | pop %rax 47 | ret 48 | 49 | refresh_counter: .quad SCREEN_REFRESH_RATE_COUNTER 50 | video_refresh_enable: .quad 1 51 | -------------------------------------------------------------------------------- /kernel/virtio.c: -------------------------------------------------------------------------------- 1 | #include "virtio.h" 2 | #include "macros.h" 3 | #include "../memorymap.h" 4 | #include "printf.h" 5 | #include "utils.h" 6 | 7 | extern char* kernelAllocPages(unsigned int pageCount); 8 | extern void memclear64(char* destination, uint64_t size); 9 | extern void memcpy64(char* source, char* dest, unsigned long size); 10 | extern void spinLock(u64* lock); 11 | extern void spinUnlock(u64* lock); 12 | 13 | bool virtio_queue_setup(struct virtio_device_info* dev, unsigned char index) 14 | { 15 | unsigned short c; 16 | unsigned short queueSize; 17 | unsigned int i; 18 | 19 | virt_queue* vq = &dev->queues[index]; 20 | memclear64(vq,sizeof(virt_queue)); 21 | 22 | // get queue size 23 | OUTPORTW(index,dev->iobase+0x0E); 24 | INPORTW(queueSize,dev->iobase+0x0C); 25 | vq->queue_size = queueSize; 26 | if (queueSize == 0) return false; 27 | 28 | // create virtqueue memory 29 | u32 sizeofBuffers = (sizeof(queue_buffer) * queueSize); 30 | u32 sizeofQueueAvailable = (2*sizeof(u16)) + (queueSize*sizeof(u16)); 31 | u32 sizeofQueueUsed = (2*sizeof(u16))+(queueSize*sizeof(virtio_used_item)); 32 | u32 queuePageCount = PAGE_COUNT(sizeofBuffers + sizeofQueueAvailable) + PAGE_COUNT(sizeofQueueUsed); 33 | char* buf = kernelAllocPages(queuePageCount); 34 | memclear64(buf,queuePageCount<<12); 35 | u32 bufPage = ((u64)UNMIRROR(buf))>>12; 36 | 37 | vq->baseAddress = (u64)buf; 38 | vq->available = (virtio_available*)&buf[sizeofBuffers]; 39 | vq->used = (virtio_used*)&buf[((sizeofBuffers + sizeofQueueAvailable+0xFFF)&~0xFFF)]; 40 | vq->next_buffer = 0; 41 | vq->lock = 0; 42 | 43 | OUTPORTL(bufPage,dev->iobase+0x08); 44 | 45 | vq->available->flags = 0; 46 | return true; 47 | } 48 | 49 | bool virtio_init(struct virtio_device_info* dev, void (*negotiate)(u32* features)) 50 | { 51 | unsigned char c,v; 52 | unsigned int i; 53 | 54 | //Virtual I/O Device (VIRTIO) Version 1.0, Spec 4, section 3.1.1: Device Initialization 55 | c = VIRTIO_ACKNOWLEDGE; 56 | OUTPORTB(c,dev->iobase+0x12); 57 | c |= VIRTIO_DRIVER; 58 | OUTPORTB(c,dev->iobase+0x12); 59 | 60 | INPORTL(i,dev->iobase+0x00); // read features offered by device 61 | negotiate(&i); 62 | OUTPORTL(i,dev->iobase+0x04); 63 | 64 | c |= VIRTIO_FEATURES_OK; 65 | OUTPORTB(c,dev->iobase+0x12); 66 | INPORTB(v,dev->iobase+0x12); 67 | if (v&VIRTIO_FEATURES_OK == 0) 68 | { 69 | //TODO: should set to driver_failed 70 | pf("Feature set not accepted\r\n"); 71 | return; 72 | } 73 | 74 | // Setup virt queues 75 | for (i = 0; i < 16; i++) virtio_queue_setup(dev,i); 76 | 77 | c |= VIRTIO_DRIVER_OK; 78 | OUTPORTB(c,dev->iobase+0x12); 79 | } 80 | 81 | void virtio_enable_interrupts(virt_queue* vq) 82 | { 83 | vq->used->flags = 0; 84 | } 85 | 86 | void virtio_disable_interrupts(virt_queue* vq) 87 | { 88 | vq->used->flags = 1; 89 | } 90 | 91 | /*void virtio_clean_used_buffers(struct virtio_device_info* dev, u16 queue_index) 92 | { 93 | virt_queue* vq = &dev->queues[queue_index]; 94 | 95 | if (vq->last_used_index == vq->used->index) return; 96 | 97 | //We have nothing to clean really... 98 | u16 index = vq->last_used_index; 99 | u16 normalized_index; 100 | u16 buffer_index; 101 | while (index != vq->used->index) 102 | { 103 | normalized_index = index % vq->queue_size; 104 | buffer_index = vq->used->rings[normalized_index].index; 105 | index++; 106 | } 107 | vq->last_used_index = index; 108 | }*/ 109 | void virtio_send_buffer(struct virtio_device_info* dev, u16 queue_index, buffer_info b[], u64 count) 110 | { 111 | u64 i; 112 | 113 | virt_queue* vq = &dev->queues[queue_index]; 114 | spinLock(&vq->lock); 115 | 116 | u16 index = vq->available->index % vq->queue_size; 117 | u16 buffer_index = vq->next_buffer; 118 | u16 next_buffer_index; 119 | 120 | unsigned char *buf = (u8*)(&vq->buffer[vq->chunk_size*buffer_index]); 121 | unsigned char *buf2 = buf; 122 | 123 | vq->available->rings[index] = buffer_index; 124 | for (i = 0; i < count; i++) 125 | { 126 | next_buffer_index = (buffer_index+1) % vq->queue_size; 127 | 128 | buffer_info* bi = &b[i]; 129 | vq->buffers[buffer_index].flags = bi->flags; 130 | if (i != (count-1)) vq->buffers[buffer_index].flags |= VIRTIO_DESC_FLAG_NEXT; 131 | 132 | vq->buffers[buffer_index].next = next_buffer_index; 133 | vq->buffers[buffer_index].length = bi->size; 134 | if (bi->copy) 135 | { 136 | vq->buffers[buffer_index].address = UNMIRROR(buf2); 137 | if (bi->buffer != 0) memcpy64(bi->buffer,buf2,bi->size); 138 | buf2+=bi->size; 139 | } 140 | else 141 | { 142 | // calling function wants to keep same buffer 143 | vq->buffers[buffer_index].address = bi->buffer; 144 | } 145 | buffer_index = next_buffer_index; 146 | } 147 | vq->next_buffer = buffer_index; 148 | 149 | vq->available->index++; 150 | OUTPORTW(queue_index, dev->iobase+0x10); 151 | 152 | // now, we will clear previously used buffers, it any. We do this here instead of in the interrupt 153 | // context. It adds latency to the calling thread instead of adding latency to any random thread 154 | // where the interrupt would be called from. 155 | // virtio_clean_used_buffers(dev, queue_index); 156 | spinUnlock(&vq->lock); 157 | } 158 | -------------------------------------------------------------------------------- /kernel/virtio.h: -------------------------------------------------------------------------------- 1 | // Documentation: 2 | // http://ozlabs.org/~rusty/virtio-spec/virtio-0.9.5.pdf, appendix C 3 | // http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html 4 | #include "includes/kernel/types.h" 5 | 6 | //Virtual I/O Device (VIRTIO) Version 1.0, Spec 4, section 5.1.3: Feature bits 7 | #define VIRTIO_CSUM 0 8 | #define VIRTIO_GUEST_CSUM 1 9 | #define VIRTIO_CTRL_GUEST_OFFLOADS 2 10 | #define VIRTIO_MAC 5 11 | #define VIRTIO_GUEST_TSO4 7 12 | #define VIRTIO_GUEST_TSO6 8 13 | #define VIRTIO_GUEST_ECN 9 14 | #define VIRTIO_GUEST_UFO 10 15 | #define VIRTIO_HOST_TSO4 11 16 | #define VIRTIO_HOST_TSO6 12 17 | #define VIRTIO_HOST_ECN 13 18 | #define VIRTIO_HOST_UFO 14 19 | #define VIRTIO_MRG_RXBUF 15 20 | #define VIRTIO_STATUS 16 21 | #define VIRTIO_CTRL_VQ 17 22 | #define VIRTIO_CTRL_RX 18 23 | #define VIRTIO_CTRL_VLAN 19 24 | #define VIRTIO_CTRL_RX_EXTRA 20 25 | #define VIRTIO_GUEST_ANNOUNCE 21 26 | #define VIRTIO_MQ 22 27 | #define VIRTIO_CTRL_MAC_ADDR 23 28 | #define VIRTIO_EVENT_IDX 29 29 | 30 | #define VIRTIO_ACKNOWLEDGE 1 31 | #define VIRTIO_DRIVER 2 32 | #define VIRTIO_FAILED 128 33 | #define VIRTIO_FEATURES_OK 8 34 | #define VIRTIO_DRIVER_OK 4 35 | #define VIRTIO_DEVICE_NEEDS_RESET 64 36 | 37 | #define VIRTIO_DESC_FLAG_NEXT 1 38 | #define VIRTIO_DESC_FLAG_WRITE_ONLY 2 39 | #define VIRTIO_DESC_FLAG_INDIRECT 4 40 | 41 | #define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 42 | #define VIRTIO_NET_HDR_GSO_NONE 0 43 | #define VIRTIO_NET_HDR_GSO_TCPV4 1 44 | #define VIRTIO_NET_HDR_GSO_UDP 3 45 | #define VIRTIO_NET_HDR_GSO_TCPV6 4 46 | #define VIRTIO_NET_HDR_GSO_ECN 0x80 47 | 48 | #define PAGE_COUNT(x) ((x+0xFFF)>>12) 49 | #define DISABLE_FEATURE(v,feature) v &= ~(1<> 39; 66 | uint64_t pdpt_index = vm_start_address >> 30; 67 | uint64_t pd_index = vm_start_address >> 21; 68 | uint64_t pt_index = vm_start_address >> 12; 69 | 70 | uint64_t* pdpt = MIRROR(pml4[pml4_index] & (~0xFFF)); 71 | uint64_t* pd = MIRROR(pdpt[pdpt_index] & (~0xFFF)); 72 | uint64_t* pt = MIRROR(pd[pd_index] & (~0xFFF)); 73 | 74 | return (uint64_t*)&pt[pt_index]; 75 | 76 | } 77 | 78 | 79 | void ept_map_pages(uint64_t vm_start_address, uint64_t map_address, uint64_t page_count, vminfo* vm) 80 | { 81 | uint64_t i; 82 | 83 | spinLock(&(vm->memory_lock)); 84 | 85 | //TODO: should check it not already mapped 86 | for (i=0;ipml4, vm_start_address); 89 | 90 | *pte = map_address | 0b010001000111; 91 | 92 | vm_start_address += 4096; 93 | map_address += 4096; 94 | } 95 | 96 | spinUnlock(&(vm->memory_lock)); 97 | } 98 | 99 | void ept_map_video_buffer(vminfo* vm) 100 | { 101 | Screen* s = getDirectVideo(); 102 | //__asm__("int $3": : "a"(s->backBuffer)); 103 | 104 | ept_map_pages(0xB8000, UNMIRROR(s->backBuffer), 1, vm); 105 | } 106 | 107 | void ept_init_static_pages(vminfo* vm) 108 | { 109 | 110 | // uint64_t apic_base = get_apic_address(); 111 | // ept_map_pages(VAPIC_GUEST_ADDRESS,apic_base, 1, vm); 112 | } 113 | 114 | uint64_t* ept_allocate_pages(uint64_t vm_start_address, uint64_t page_count, vminfo* vm) 115 | { 116 | uint64_t i; 117 | 118 | 119 | uint64_t* addr = kernelAllocPages(page_count); 120 | uint64_t realaddr = UNMIRROR(addr); 121 | 122 | 123 | ept_map_pages(vm_start_address, realaddr, page_count, vm); 124 | 125 | return addr; 126 | } 127 | 128 | -------------------------------------------------------------------------------- /memorymap.h: -------------------------------------------------------------------------------- 1 | 2 | #define TSS 0x00000500 3 | #define SOFTIRQLIST 0x00000600 4 | #define GDT 0x00000608 5 | #define SOCKETSLIST 0x00000708 6 | #define MEMMAP 0x00000710 7 | #define MEMMAPEND 0x00000BFF 8 | #define IOAPICHANDLERS 0x00000C00 9 | #define RESERVED2 0x00001C00 10 | #define RESERVED2END 0x00001FFF 11 | #define SMP_TRAMPOLINE 0x00002000 // needs to be aligned on a 4k page 12 | #define IPI_MESSAGES 0x00002100 13 | #define VMINFOS 0x00002300 14 | #define VMINFOSEND 0x00006000 15 | 16 | #define IDTSPACE 0x00006000 17 | #define RESERVED1 0x00007000 18 | #define RESERVED1END 0x00007FFF 19 | #define PML4TABLE 0x00008000 // needs to be 4k aligned. we only use 1 entry 20 | #define PDPTTABLE 0x00009000 // only 1 table is needed (512 gig) 21 | #define RESERVED5 0x0000A000 22 | #define RESERVED5END 0x0000DFFF 23 | #define TMP_PAGE_TABLES 0x0000E000 24 | #define PRDT1 0x00010000 25 | #define PRDT2 0x00010010 26 | #define TASKLIST_BASE 0x00020000 27 | #define TASKLISTEND 0x0005FFFF 28 | #define BLOCK_CACHE 0x00060000 29 | #define BLOCK_CACHE_END 0x0006FFFF 30 | #define AP_STACKS 0x00070000 // 64 256bytes stacks for max 64 CPUs 31 | #define AP_STACKS_END 0x00077FFF 32 | #define KERNEL_BASE 0x00100000 33 | #define KERNEL_END 0x00200000 34 | 35 | // Anything above this space is not mapped in user process. 36 | // Anything below, is mapped in user process 37 | #define PDTABLE KERNEL_END // need to be 4k aligned. enough space for 512 tables 38 | #define PAGETABLES (PDTABLE+0x00200000) 39 | 40 | 41 | //////////////////////////////////////////////////// 42 | //////////////////////////////////////////////////// 43 | // Process virtual memoty 44 | //////////////////////////////////////////////////// 45 | //////////////////////////////////////////////////// 46 | #define THREAD_CODE_START 0x02000000 47 | #ifdef __ASSEMBLER__ 48 | #define TOP_VIRTUAL 0xFFFFFFFF00000000 49 | #else 50 | #define TOP_VIRTUAL 0xFFFFFFFF00000000LL 51 | #endif 52 | #define META_VIRTUAL_ADDRESS ((TOP_VIRTUAL)-0x2000000) 53 | #define STACK0TOP_VIRTUAL_ADDRESS (META_VIRTUAL_ADDRESS) //this can't be more than 4pages since ring3 stack top is 16k below it 54 | #define STACK3TOP_VIRTUAL_ADDRESS (STACK0TOP_VIRTUAL_ADDRESS-0x4000) 55 | #define STACK3_DEPTH (20*1024*1024) 56 | #define STACK3BOTTOM_VIRTUAL_ADDRESS (STACK3TOP_VIRTUAL_ADDRESS-STACK3_DEPTH) 57 | #define PAGE_GUARD (STACK3BOTTOM_VIRTUAL_ADDRESS-0x1000) 58 | #define HEAP_TOP PAGE_GUARD 59 | 60 | // we save the following information after the stack 61 | #define AVX_SAVE_AREA (META_VIRTUAL_ADDRESS) //right at the begining. up to 0xFE0047F7 62 | #define AVX_SAVE_AREA_END (AVX_SAVE_AREA+0x7F8) 63 | #define TIME_SLICE_COUNT AVX_SAVE_AREA_END 64 | #define CONSOLE_POINTER (TIME_SLICE_COUNT+8) 65 | // file handles are stored as linked list at this address 66 | #define FILE_HANDLE_ADDRESS (CONSOLE_POINTER+8) 67 | #define PROCESS_HEAP_ADDRESS (FILE_HANDLE_ADDRESS+8) 68 | #define PROCESS_VMCS (PROCESS_HEAP_ADDRESS+8) 69 | #define VIDEO_POINTER (PROCESS_VMCS+8) 70 | 71 | // MMIO. 72 | #define APIC_BASE 0xFEE00000 73 | 74 | #define IDENTITY_MAPPING 0x4000000000 75 | 76 | 77 | // Segment selectors 78 | #define TSSSELECTOR (0x20) 79 | #define RING3CSSELECTOR (0x10) 80 | 81 | //SOFTIRQ 82 | #define SOFTIRQ_NET 0x01 83 | 84 | //APIC 85 | #define AP_STACK_SIZE 0x200 86 | #define IPI_FIRST_VECTOR 0x60 87 | #define IPI_TLB_SHOOTDOWN_VECTOR 0x60 88 | #define IPI_LAST_VECTOR 0x7F 89 | #define APIC_TIMER_VECTOR 0xF0 90 | #define APIC_SPURIOUS_VECTOR 0x4F // low nibble MUST be 0b1111 91 | #define APIC_ERROR_VECTOR 0xFF 92 | #define DESIRED_APIC_PERIOD_NS 10000000 // the APIC timer handler will be called every 10ms 93 | 94 | // Scheduler 95 | #define TASK_TIME_MS 40 // a task will 40 ms 96 | #define TASK_QUANTUM_COUNTER (TASK_TIME_MS/(DESIRED_APIC_PERIOD_NS/1000000)) 97 | #define SCREEN_REFRESH_RATE 30 98 | #define SCREEN_REFRESH_RATE_COUNTER ((1000000000/SCREEN_REFRESH_RATE)/DESIRED_APIC_PERIOD_NS) 99 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | all: hash 2 | 3 | hash: hash.c ../kernel/hashtable.c 4 | gcc -DUNIT_TEST hash.c ../kernel/hashtable.c -I ../kernel -I ../kernel/includes/kernel -g 5 | 6 | bcache: bcache.c ../kernel/block_cache.c 7 | gcc -DUNIT_TEST bcache.c ../kernel/block_cache.c -I ../kernel -g 8 | -------------------------------------------------------------------------------- /tests/bcache.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef void (*atairqcallback)(unsigned char, unsigned long, unsigned long); 5 | 6 | extern int block_cache_write(unsigned long blockNumber, int dev, char* buffer, unsigned int numberOfBlocks); 7 | extern void clearCacheEntries(unsigned int count); 8 | extern void block_cache_init(char* buf); 9 | extern int block_cache_read(unsigned long blockNumber, int dev, char* buffer, unsigned int numberOfBlocks); 10 | 11 | 12 | unsigned char isbusy; 13 | atairqcallback irqhandler; 14 | 15 | int main(int argc, char* argv) 16 | { 17 | char* buf = malloc(512*128); 18 | char* buf2 = malloc(512*512); 19 | 20 | isbusy=0; 21 | 22 | block_cache_init(buf); 23 | 24 | block_cache_write(0, 0, buf2, 130); 25 | // irqhandler(0,0,1); 26 | // isbusy = 0; 27 | // block_cache_read(0, 0, buf2, 1); 28 | 29 | } 30 | 31 | 32 | // stubs 33 | void yield() 34 | { 35 | } 36 | 37 | void init_ata(atairqcallback* handler) 38 | { 39 | irqhandler = handler; 40 | } 41 | 42 | int ata_read(unsigned int dev, unsigned long sector, char* buffer, unsigned long count) 43 | { 44 | isbusy = 1; 45 | irqhandler(dev,sector,count); 46 | isbusy = 0; 47 | } 48 | 49 | int ata_write(unsigned int dev, unsigned long sector, char* buffer, unsigned long count) 50 | { 51 | isbusy = 1; 52 | } 53 | 54 | unsigned char ata_isBusy(unsigned char dev) 55 | { 56 | return isbusy; 57 | } 58 | 59 | void memcpy64(char* source, char* dest, unsigned long size) 60 | { 61 | } 62 | 63 | unsigned long getTicksSinceBoot() 64 | { 65 | time_t t; 66 | time(&t); 67 | return t; 68 | } 69 | 70 | void pf(char * format,...) 71 | { 72 | printf("%s",format); 73 | } 74 | 75 | -------------------------------------------------------------------------------- /tests/hash.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "hashtable.h" 3 | #include 4 | 5 | #define KEY_SIZE 10 6 | 7 | typedef struct 8 | { 9 | hashtable_node node; 10 | int val; 11 | char* key; 12 | } test; 13 | 14 | 15 | void memclear64(void* dst, uint64_t size) 16 | { 17 | uint64_t i; 18 | for (i=0;ihash_function(ht,t->node.keysize, t->node.key); 40 | } 41 | 42 | void addItem(hashtable* ht, int val,char* key) 43 | { 44 | test* t = (test*)malloc(sizeof(test)); 45 | t->key = (char*)malloc(8); 46 | memcpy(t->key,key,8); 47 | t->val = val; 48 | t->node.data = t; 49 | 50 | hashtable_add(ht,1,t->key, &t->node); 51 | printf("hash for item: %x (%x %x)\r\n",gethash(ht,t),t->node.key, t->key); 52 | } 53 | 54 | bool clean_visitor(void* data, void* meta) 55 | { 56 | test* t = (test*)data; 57 | uint64_t id = *((uint64_t*)meta); 58 | if (t->val >= id) 59 | { 60 | return true; 61 | } 62 | return false; 63 | } 64 | 65 | 66 | int main(int argc, char** argv) 67 | { 68 | uint64_t size = hashtable_getrequiredsize(KEY_SIZE); 69 | printf("creating table of size %xh\r\n",size); 70 | hashtable* ht = (hashtable*)malloc(size); 71 | hashtable_init(ht,KEY_SIZE,HASH_AND); 72 | 73 | 74 | addItem(ht,1,"00000001"); 75 | addItem(ht,2,"00000002"); 76 | addItem(ht,3,"00000003"); 77 | addItem(ht,4,"00000004"); 78 | addItem(ht,5,"10000001"); 79 | 80 | if (ht->buckets[ht->hash_function(ht,1,"00000001")].node == 0) printf("ERROR %i\r\n",__LINE__); 81 | if (((test*)hashtable_get(ht,1,"00000001"))->val != 1) printf("ERROR %i\r\n",__LINE__); 82 | if (((test*)hashtable_get(ht,1,"00000002"))->val != 2) printf("ERROR %i\r\n",__LINE__); 83 | if (((test*)hashtable_get(ht,1,"00000003"))->val != 3) printf("ERROR %i\r\n",__LINE__); 84 | if (((test*)hashtable_get(ht,1,"00000004"))->val != 4) printf("ERROR %i\r\n",__LINE__); 85 | if (((test*)hashtable_get(ht,1,"10000001"))->val != 5) printf("ERROR %i\r\n",__LINE__); 86 | if (((test*)hashtable_get(ht,1,"20000000")) != 0) printf("ERROR %i\r\n",__LINE__); 87 | 88 | hashtable_remove(ht,1,"00000002"); 89 | if (ht->buckets[ht->hash_function(ht,1,"00000001")].node == 0) printf("ERROR %i\r\n",__LINE__); 90 | if (((test*)hashtable_get(ht,1,"00000001"))->val != 1) printf("ERROR %i\r\n",__LINE__); 91 | if (((test*)hashtable_get(ht,1,"00000002")) != 0) printf("ERROR %i\r\n",__LINE__); 92 | if (((test*)hashtable_get(ht,1,"00000003"))->val != 3) printf("ERROR %i\r\n",__LINE__); 93 | if (((test*)hashtable_get(ht,1,"00000004"))->val != 4) printf("ERROR %i\r\n",__LINE__); 94 | if (((test*)hashtable_get(ht,1,"10000001"))->val != 5) printf("ERROR %i\r\n",__LINE__); 95 | 96 | hashtable_remove(ht,1,"00000001"); 97 | if (ht->buckets[ht->hash_function(ht,1,"00000001")].node == 0) printf("ERROR %i\r\n",__LINE__); 98 | if (((test*)hashtable_get(ht,1,"00000001")) != 0) printf("ERROR %i\r\n",__LINE__); 99 | if (((test*)hashtable_get(ht,1,"00000002")) != 0) printf("ERROR %i\r\n",__LINE__); 100 | if (((test*)hashtable_get(ht,1,"00000003"))->val != 3) printf("ERROR %i\r\n",__LINE__); 101 | if (((test*)hashtable_get(ht,1,"00000004"))->val != 4) printf("ERROR %i\r\n",__LINE__); 102 | if (((test*)hashtable_get(ht,1,"10000001"))->val != 5) printf("ERROR %i\r\n",__LINE__); 103 | 104 | hashtable_remove(ht,1,"00000004"); 105 | if (ht->buckets[ht->hash_function(ht,1,"00000001")].node == 0) printf("ERROR %i\r\n",__LINE__); 106 | if (((test*)hashtable_get(ht,1,"00000001")) != 0) printf("ERROR %i\r\n",__LINE__); 107 | if (((test*)hashtable_get(ht,1,"00000002")) != 0) printf("ERROR %i\r\n",__LINE__); 108 | if (((test*)hashtable_get(ht,1,"00000003"))->val != 3) printf("ERROR %i\r\n",__LINE__); 109 | if (((test*)hashtable_get(ht,1,"00000004")) != 0) printf("ERROR %i\r\n",__LINE__); 110 | if (((test*)hashtable_get(ht,1,"10000001"))->val != 5) printf("ERROR %i\r\n",__LINE__); 111 | 112 | hashtable_remove(ht,1,"00000003"); 113 | if (ht->buckets[ht->hash_function(ht,1,"00000001")].node != 0) printf("ERROR %i\r\n",__LINE__); 114 | 115 | addItem(ht,3,"00000003"); 116 | addItem(ht,4,"00000004"); 117 | uint64_t tval = 3; 118 | hashtable_scan_and_clean(ht, &clean_visitor, &tval); 119 | if (((test*)hashtable_get(ht,1,"00000001")) != 0) printf("ERROR %i\r\n",__LINE__); 120 | if (((test*)hashtable_get(ht,1,"00000002")) != 0) printf("ERROR %i\r\n",__LINE__); 121 | if (((test*)hashtable_get(ht,1,"00000003")) != 0) printf("ERROR %i\r\n",__LINE__); 122 | if (((test*)hashtable_get(ht,1,"00000004")) != 0) printf("ERROR %i\r\n",__LINE__); 123 | 124 | addItem(ht,1,"00000001"); 125 | addItem(ht,2,"00000002"); 126 | addItem(ht,3,"00000003"); 127 | addItem(ht,4,"00000004"); 128 | hashtable_scan_and_clean(ht, &clean_visitor, &tval); 129 | if (((test*)hashtable_get(ht,1,"00000001")) == 0) printf("ERROR %i\r\n",__LINE__); 130 | if (((test*)hashtable_get(ht,1,"00000002")) == 0) printf("ERROR %i\r\n",__LINE__); 131 | if (((test*)hashtable_get(ht,1,"00000003")) != 0) printf("ERROR %i\r\n",__LINE__); 132 | if (((test*)hashtable_get(ht,1,"00000004")) != 0) printf("ERROR %i\r\n",__LINE__); 133 | 134 | } 135 | -------------------------------------------------------------------------------- /userapps/Makefile: -------------------------------------------------------------------------------- 1 | all: apps 2 | APPS=$(filter-out systemlib,$(sort $(patsubst ./%/,%,$(dir $(wildcard ./*/Makefile))))) 3 | BINS=$(addprefix appsbin/,$(APPS)) 4 | BINS:=$(addsuffix .bin,$(BINS)) 5 | 6 | .PHONY: systemlib 7 | systemlib: 8 | cd systemlib && make 9 | 10 | appsbin/%.bin:% 11 | cd $< && make 12 | 13 | apps: systemlib $(BINS) 14 | tar -cf disk.img -C appsbin/ . 15 | tar -rf disk.img -C bulkfiles/ . 16 | 17 | clean: 18 | cd systemlib && make clean 19 | -rm -Rf appsbin 20 | -rm -f disk.img 21 | -------------------------------------------------------------------------------- /userapps/Makefile.skel: -------------------------------------------------------------------------------- 1 | TARGET=**TARGET** 2 | SOURCES=main.c 3 | BINDIR=../appsbin/ 4 | OBJECTS=$(SOURCES:%.c=%.o) 5 | SYSTEMLIB=../systemlib 6 | CFLAGS=-I $(SYSTEMLIB)/ -fno-exceptions -I../../kernel/includes 7 | 8 | all: $(TARGET).bin 9 | 10 | $(OBJECTS): %.o : %.c 11 | mkdir -p $(BINDIR) 12 | gcc -ffreestanding $(CFLAGS) -c $< -o $@ 13 | 14 | 15 | $(TARGET).bin: $(OBJECTS) 16 | mkdir -p $(BINDIR) 17 | ld -T ../link.ld $(OBJECTS) $(SYSTEMLIB)/systemlib.a -o $(BINDIR)$(TARGET).elf 18 | 19 | -------------------------------------------------------------------------------- /userapps/README: -------------------------------------------------------------------------------- 1 | to create a new app: 2 | ./createApp 3 | 4 | to have laucnhed automatically add it in "bootscript" 5 | -------------------------------------------------------------------------------- /userapps/bulkfiles/bootscript: -------------------------------------------------------------------------------- 1 | shell.elf 2 | shell.elf 3 | hexedit.elf 4 | webserver.elf 5 | -------------------------------------------------------------------------------- /userapps/bulkfiles/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Oh yeah! This web page is served by my awesome web server 4 | running on my awesome OS. All home-brewed bro! This machine is NOT running windows nor linux. 5 | It is not using a POSIX kernel either. This is 100% code from scratch from the moment 6 | the BIOS handled controlled to the boot code. 7 |
8 | Do you have any idea how many operations that involved? 9 | A webserver application needed to open up a socket in listening mode and 10 | read files from disk and serve it to you. That involved: 11 |
    12 |
  • Writing a bootloader to oot my kernel 13 |
  • Booting the system in long mode (64bit, because by default we boot in 16bit mode) 14 |
  • A virtual memory subsystem was implemented to support paging with 4k pages 15 |
  • A stack and heap mechanism was developed. 16 |
  • A scheduler was implemented and then a process launching system. 17 |
  • A network card driver (virtio) 18 |
  • An interrupt management and IRQ (usign APIC) was needed 19 |
  • Then a network stack was created (This includes ARP, IP routing, sockets, TCP, UDP etc..) 20 |
  • A virtio disk driver 21 |
  • A block cache to cache any blocks read from disk (or written to). 22 |
  • A system call mechanism to allow RING3 applications to requests OS calls. 23 |
24 | So you might not be impressed by this crappy web page, but it involved a shitload 25 | of assembly and C code. There is no STL or libc in here. 26 | 27 | 28 | -------------------------------------------------------------------------------- /userapps/createapp: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mkdir $1 4 | cp Makefile.skel $1/Makefile 5 | sed -i "s/\*\*TARGET\*\*/$1/g" $1/Makefile 6 | -------------------------------------------------------------------------------- /userapps/date/Makefile: -------------------------------------------------------------------------------- 1 | TARGET=date 2 | SOURCES=main.c 3 | BINDIR=../appsbin/ 4 | OBJECTS=$(SOURCES:%.c=%.o) 5 | SYSTEMLIB=../systemlib 6 | CFLAGS=-I $(SYSTEMLIB)/ -fno-exceptions -I../../kernel/includes 7 | 8 | all: $(TARGET).bin 9 | 10 | $(OBJECTS): %.o : %.c 11 | mkdir -p $(BINDIR) 12 | gcc -ffreestanding $(CFLAGS) -c $< -o $@ 13 | 14 | 15 | $(TARGET).bin: $(OBJECTS) 16 | mkdir -p $(BINDIR) 17 | ld -T ../link.ld $(OBJECTS) $(SYSTEMLIB)/systemlib.a -o $(BINDIR)$(TARGET).elf 18 | 19 | -------------------------------------------------------------------------------- /userapps/date/main.c: -------------------------------------------------------------------------------- 1 | #include "threads.h" 2 | #include "console.h" 3 | #include "memory.h" 4 | #include "string.h" 5 | 6 | int main(uint64_t param) 7 | { 8 | char str[32]; 9 | str[0] = 0; 10 | 11 | getDateTime(str); 12 | 13 | printf("%s\r\n",str); 14 | } 15 | -------------------------------------------------------------------------------- /userapps/hexdump/Makefile: -------------------------------------------------------------------------------- 1 | TARGET=hexdump 2 | SOURCES=main.c 3 | BINDIR=../appsbin/ 4 | OBJECTS=$(SOURCES:%.c=%.o) 5 | SYSTEMLIB=../systemlib 6 | CFLAGS=-I $(SYSTEMLIB)/ -fno-exceptions -I../../kernel/includes 7 | 8 | all: $(TARGET).bin 9 | 10 | $(OBJECTS): %.o : %.c 11 | mkdir -p $(BINDIR) 12 | gcc -ffreestanding $(CFLAGS) -c $< -o $@ 13 | 14 | 15 | $(TARGET).bin: $(OBJECTS) 16 | mkdir -p $(BINDIR) 17 | ld -T ../link.ld $(OBJECTS) $(SYSTEMLIB)/systemlib.a -o $(BINDIR)$(TARGET).elf 18 | 19 | -------------------------------------------------------------------------------- /userapps/hexdump/main.c: -------------------------------------------------------------------------------- 1 | #include "threads.h" 2 | #include "console.h" 3 | #include "memory.h" 4 | #include "string.h" 5 | #include "files.h" 6 | 7 | int main(uint64_t param) 8 | { 9 | uint64_t i; 10 | 11 | //TODO: get filename from params 12 | file_handle* f = fopen("01:/bootscript",0); 13 | if (f == 0) 14 | { 15 | printf("hexdump: File not found\r\n"); 16 | return; 17 | } 18 | 19 | uint64_t size = fgetsize(f); 20 | char* buf = (char*)malloc(size); 21 | fread(f,size,buf); 22 | fclose(f); 23 | 24 | size = 64; 25 | for (i=0;i-1) 17 | { 18 | cmd[t1] = 0; 19 | params = (char*)&command[t1+1]; 20 | } 21 | 22 | t1 = strfind(params,' '); 23 | if (t1>-1) params[t1]=0; 24 | 25 | if (strcompare(cmd,"exit")) 26 | { 27 | quit = 1; 28 | return; 29 | } 30 | else if (strcompare(cmd,"load")) 31 | { 32 | char fname[255]; 33 | strcpy("04:/",fname); 34 | strcpy(params,(char*)&fname[4]); 35 | printf("Loading [%s]\r\n",fname); 36 | uint64_t pid = loadProcess(fname); 37 | if (pid == 0) 38 | { 39 | printf("ERROR: Application not found\r\n"); 40 | } 41 | else 42 | { 43 | waitForProcessDeath(pid); 44 | } 45 | 46 | return; 47 | } 48 | 49 | printf("ERROR: Command not found\r\n"); 50 | } 51 | 52 | 53 | int main(uint64_t param) 54 | { 55 | uint64_t cmdIndex = 0; 56 | char ch; 57 | 58 | //TODO: this is just a test 59 | uint64_t* test,test2; 60 | 61 | printf("shell> \003"); 62 | while (quit == 0) 63 | { 64 | //TODO: this is just a test 65 | ch = poll_in(); 66 | 67 | if ((ch>='0' && ch<='9')||(ch>='a' && ch<='z')||(ch>='A' && ch<='Z')||(ch==' ')||(ch=='.')) 68 | { 69 | if (cmdIndex <255) 70 | { 71 | command[cmdIndex] = ch; 72 | cmdIndex++; 73 | printf("%c\003",ch); 74 | } 75 | } 76 | else if (ch==0x08) 77 | { 78 | if (cmdIndex > 0) 79 | { 80 | printf("%c %c\003",ch,ch); 81 | cmdIndex--; 82 | } 83 | } 84 | else if (ch==0x0A) 85 | { 86 | printf("\r\n"); 87 | if (cmdIndex != 0) 88 | { 89 | command[cmdIndex]=0; 90 | processCommand(); 91 | cmdIndex = 0; 92 | } 93 | printf("shell> \003"); 94 | } 95 | } 96 | 97 | printf("\r \r\nShell terminated\r\n"); 98 | } 99 | -------------------------------------------------------------------------------- /userapps/systemlib/Makefile: -------------------------------------------------------------------------------- 1 | TARGET=libc 2 | SOURCES=$(wildcard *c) 3 | OBJECTS=$(SOURCES:%.c=%.o) 4 | 5 | all: $(TARGET).a 6 | 7 | $(OBJECTS): %.o : %.c 8 | gcc -ffreestanding -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow -fno-exceptions -c $< -o $@ -I../../kernel/includes 9 | 10 | 11 | $(TARGET).a: $(OBJECTS) 12 | ar rcs systemlib.a $(OBJECTS) 13 | 14 | clean: 15 | -rm -f *.o 16 | -rm -f *.a 17 | -------------------------------------------------------------------------------- /userapps/systemlib/console.c: -------------------------------------------------------------------------------- 1 | #include "console.h" 2 | #include "kernel/intA0.h" 3 | 4 | #define MAX_PRINTF_STR 1024 5 | #define va_start(v,l) __builtin_va_start(v,l) 6 | #define va_arg(v,l) __builtin_va_arg(v,l) 7 | #define va_end(v) __builtin_va_end(v) 8 | #define va_copy(d,s) __builtin_va_copy(d,s) 9 | typedef __builtin_va_list va_list; 10 | 11 | unsigned long itoh(unsigned long v, char* outbuf,unsigned long digits) 12 | { 13 | unsigned int i; 14 | for (i=0;i> ((digits-i-1)*4))&0b1111; 17 | if (c<10) c+=48; else c+=55; 18 | *outbuf=c; 19 | outbuf++; 20 | } 21 | *outbuf = 0; 22 | return digits; 23 | } 24 | 25 | unsigned long itoa(unsigned int v, char* outbuf) 26 | { 27 | unsigned int digits=0; 28 | unsigned int i; 29 | unsigned int div = 1000000000; 30 | unsigned char sequenceStarted = 0; 31 | while (div) 32 | { 33 | i = v/div; 34 | v = v%div; 35 | div = div/10; 36 | if (sequenceStarted | i!=0) 37 | { 38 | *outbuf=(char)(i+48); 39 | outbuf++; 40 | sequenceStarted = 1; 41 | digits++; 42 | } 43 | } 44 | *outbuf = 0; 45 | return digits; 46 | } 47 | 48 | void format(char* st, char* fmt, va_list list, unsigned int max) 49 | { 50 | int stIndex = 0; 51 | while (*fmt!=0) 52 | { 53 | if (*fmt!='%') 54 | { 55 | st[stIndex++] = *fmt; 56 | } 57 | else 58 | { 59 | fmt++; 60 | if (*fmt=='s') 61 | { 62 | char *sta = va_arg(list,char *); 63 | while (*sta!=0) 64 | { 65 | st[stIndex++]=*sta; 66 | sta++; 67 | } 68 | } 69 | else if (*fmt=='c') 70 | { 71 | char c = (char)va_arg(list,unsigned int); 72 | st[stIndex++]=c; 73 | } 74 | else if (*fmt=='i') 75 | { 76 | int long v = (unsigned int)va_arg(list,unsigned int); 77 | stIndex += itoa(v,(char*)&st[stIndex]); 78 | } 79 | else if (*fmt=='x') 80 | { 81 | unsigned long v = va_arg(list,unsigned long); 82 | if (v&0xFFFFFFFF00000000) // 64bit 83 | { 84 | stIndex += itoh(v,(char*)&st[stIndex],16); 85 | } 86 | else if (v&0xFFFF0000) // 32bit 87 | { 88 | stIndex += itoh(v,(char*)&st[stIndex],8); 89 | } 90 | else if (v&0xFF00) //16bit 91 | { 92 | stIndex += itoh(v,(char*)&st[stIndex],4); 93 | } 94 | else // 8 bit 95 | { 96 | stIndex += itoh(v,(char*)&st[stIndex],2); 97 | } 98 | } 99 | else if (*fmt=='X') // special case for 12 bytes display 100 | { 101 | unsigned long v = va_arg(list,unsigned long); 102 | stIndex += itoh(v,(char*)&st[stIndex],12); 103 | } 104 | } 105 | fmt++; 106 | if (stIndex>=(max-1)) break; 107 | } 108 | st[stIndex] = 0; 109 | } 110 | 111 | ///////////////////////////////////////////////////////////////////////////////////////// 112 | // WARNING: no protection. Resulting string must not go over 1024 bytes 113 | // This file must be compiled with no SSE support otherwise it compiles a whole bunch 114 | // of xmm transfers with will result in device not ready exception at every context 115 | // switch. 116 | ///////////////////////////////////////////////////////////////////////////////////////// 117 | void printf(char* fmt, ...) 118 | { 119 | va_list list; 120 | va_start(list,fmt); 121 | 122 | char st[MAX_PRINTF_STR]; 123 | format(st,fmt,list, MAX_PRINTF_STR); 124 | 125 | __asm("int $0xA0" : : "D"(st), "a"(INTA0_PRINTF)); 126 | va_end(list); 127 | } 128 | 129 | void sprintf(char* dst, unsigned int max, char* str,...) 130 | { 131 | va_list list; 132 | va_start(list,str); 133 | format(dst,str,list, max); 134 | va_end(list); 135 | } 136 | 137 | uint16_t poll_in() 138 | { 139 | uint16_t ret; 140 | __asm("int $0xA0" : "=a"(ret) : "a"(INTA0_POLL_IN)); 141 | return ret; 142 | } 143 | 144 | char* get_video_buffer() 145 | { 146 | char* ret; 147 | __asm("int $0xA0" : "=a"(ret) : "a"(INTA0_GETDIRECTBUFFER)); 148 | return ret; 149 | } 150 | -------------------------------------------------------------------------------- /userapps/systemlib/console.h: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | 3 | void printf(char* str,...); 4 | void sprintf(char* dst, unsigned int max, char* str,...); 5 | uint16_t poll_in(); 6 | char* get_video_buffer(); 7 | -------------------------------------------------------------------------------- /userapps/systemlib/files.c: -------------------------------------------------------------------------------- 1 | #include "files.h" 2 | 3 | file_handle* fopen(char* name, uint64_t access_type) 4 | { 5 | file_handle* ret; 6 | __asm("int $0xA0" : "=a"(ret) : "D"(name),"S"(access_type),"a"(INTA0_FOPEN)); 7 | return ret; 8 | } 9 | 10 | uint64_t fread(file_handle* f, uint64_t count, char* destination) 11 | { 12 | uint64_t ret; 13 | __asm("int $0xA0" : "=a"(ret) : "D"(f),"S"(count),"d"(destination),"a"(INTA0_FREAD)); 14 | return ret; 15 | } 16 | 17 | uint64_t fwrite(file_handle* f, uint64_t count, char* source) 18 | { 19 | uint64_t ret; 20 | __asm("int $0xA0" : "=a"(ret) : "D"(f),"S"(count),"d"(source),"a"(INTA0_FWRITE)); 21 | return ret; 22 | } 23 | 24 | void fclose(file_handle* f) 25 | { 26 | __asm("int $0xA0" : : "D"(f),"a"(INTA0_FCLOSE)); 27 | } 28 | 29 | void fseek(file_handle* f, uint64_t count, bool absolute) 30 | { 31 | __asm("int $0xA0" : : "D"(f),"S"(count),"d"(absolute),"a"(INTA0_FSEEK)); 32 | } 33 | 34 | uint64_t fgetsize(file_handle* f) 35 | { 36 | uint64_t ret; 37 | __asm("int $0xA0" : "=a"(ret) : "D"(f),"a"(INTA0_FGETSIZE)); 38 | return ret; 39 | } 40 | -------------------------------------------------------------------------------- /userapps/systemlib/files.h: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "kernel/intA0.h" 3 | 4 | typedef void file_handle; 5 | 6 | file_handle* fopen(char* name, uint64_t access_type); 7 | uint64_t fread(file_handle* f, uint64_t count, char* destination); 8 | uint64_t fwrite(file_handle* f, uint64_t count, char* destination); 9 | void fclose(file_handle* f); 10 | void fseek(file_handle* f, uint64_t count, bool absolute); 11 | uint64_t fgetsize(file_handle* f); 12 | -------------------------------------------------------------------------------- /userapps/systemlib/libc.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdumais/OperatingSystem/5fd5343c7af53fbc1e5ba5cbcf3c1a71844c56c3/userapps/systemlib/libc.elf -------------------------------------------------------------------------------- /userapps/systemlib/link.ld: -------------------------------------------------------------------------------- 1 | ENTRY(main) 2 | SECTIONS { 3 | . = (0x80000000); 4 | .text : { 5 | * (.text); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /userapps/systemlib/memory.c: -------------------------------------------------------------------------------- 1 | #include "memory.h" 2 | #include "kernel/intA0.h" 3 | 4 | 5 | void* malloc(uint64_t size) 6 | { 7 | uint64_t ret; 8 | __asm("int $0xA0" : "=a"(ret) : "D"(size), "a"(INTA0_MALLOC)); 9 | return (void*)ret; 10 | } 11 | 12 | void free(void* buffer) 13 | { 14 | __asm("int $0xA0" : : "D"(buffer), "a"(INTA0_FREE)); 15 | } 16 | -------------------------------------------------------------------------------- /userapps/systemlib/memory.h: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | 3 | void* malloc(uint64_t size); 4 | void free(void* buffer); 5 | 6 | -------------------------------------------------------------------------------- /userapps/systemlib/network.c: -------------------------------------------------------------------------------- 1 | #include "network.h" 2 | #include "kernel/intA0.h" 3 | 4 | socket* create_socket() 5 | { 6 | socket* ret; 7 | __asm("int $0xA0" : "=a"(ret) : "a"(INTA0_CREATE_SOCKET)); 8 | return ret; 9 | } 10 | 11 | void close_socket(socket* s) 12 | { 13 | __asm("int $0xA0" : : "D"(s), "a"(INTA0_CLOSE_SOCKET)); 14 | } 15 | 16 | void release_socket(socket* s) 17 | { 18 | __asm("int $0xA0" : : "D"(s), "a"(INTA0_RELEASE_SOCKET)); 19 | } 20 | 21 | void connect(socket *s, uint32_t destination, uint16_t port) 22 | { 23 | __asm("int $0xA0" : : "D"(s),"S"(destination),"d"(port), "a"(INTA0_CONNECT)); 24 | } 25 | 26 | char isconnected(socket* s) 27 | { 28 | if (s->tcp.state == SOCKET_STATE_RESET) return -1; 29 | if (s->tcp.state == SOCKET_STATE_CONNECTED) return 1; 30 | return 0; 31 | } 32 | 33 | char isclosed(socket* s) 34 | { 35 | if (s->tcp.state == SOCKET_STATE_RESET) return -1; 36 | if (s->tcp.state == SOCKET_STATE_CLOSED) return 1; 37 | return 0; 38 | } 39 | 40 | int recv(socket* s, char* buffer, uint16_t max) 41 | { 42 | int ret; 43 | __asm("int $0xA0" :"=a"(ret) : "D"(s),"S"(buffer),"d"(max), "a"(INTA0_RECV)); 44 | return ret; 45 | } 46 | 47 | int send(socket* s, char* buffer, uint16_t length) 48 | { 49 | int ret; 50 | __asm("int $0xA0" :"=a"(ret) : "D"(s),"S"(buffer),"d"(length), "a"(INTA0_SEND)); 51 | return ret; 52 | } 53 | 54 | void listen(socket*s, uint32_t source, uint16_t port, uint16_t backlog) 55 | { 56 | __asm("int $0xA0" : : "D"(s),"S"(source),"d"(port),"c"(backlog), "a"(INTA0_LISTEN)); 57 | } 58 | 59 | socket* accept(socket* s) 60 | { 61 | socket* ret; 62 | __asm("int $0xA0" :"=a"(ret) : "D"(s), "a"(INTA0_ACCEPT)); 63 | return ret; 64 | } 65 | 66 | uint32_t atoip(char* addr) 67 | { 68 | // TODO 69 | } 70 | 71 | void iptoa(uint32_t addr, char* buf) 72 | { 73 | // TODO 74 | } 75 | 76 | void resolveDNS(char* host) 77 | { 78 | // TODO 79 | } 80 | -------------------------------------------------------------------------------- /userapps/systemlib/network.h: -------------------------------------------------------------------------------- 1 | #include "kernel/types.h" 2 | #include "kernel/sockets.h" 3 | 4 | socket* create_socket(); 5 | void close_socket(socket* s); 6 | void connect(socket *s, uint32_t destination, uint16_t port); 7 | void listen(socket*s, uint32_t source, uint16_t port, uint16_t backlog); 8 | socket* accept(socket*s); 9 | int recv(socket* s, char* buffer, uint16_t max); 10 | int send(socket* s, char* buffer, uint16_t length); 11 | char isconnected(socket* s); 12 | char isclosed(socket* s); 13 | void resolveDNS(char* host); 14 | uint32_t atoip(char* addr); 15 | void iptoa(uint32_t addr, char* buf); 16 | 17 | -------------------------------------------------------------------------------- /userapps/systemlib/string.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | bool strcompare(char* src, char* dst) 4 | { 5 | while ((*src !=0) && (*dst !=0)) 6 | { 7 | if ((*src)!=(*dst)) return false; 8 | src++; 9 | dst++; 10 | } 11 | 12 | if ((*src==0) && (*dst==0)) return true; 13 | return false; 14 | } 15 | 16 | size_t strfind(char* src, char token) 17 | { 18 | size_t i =0; 19 | while (src[i]!=0 && src[i]!=token) i++; 20 | 21 | if (src[i]==0) return -1; 22 | return i; 23 | } 24 | 25 | void strcpy(char* src, char* dst) 26 | { 27 | while (*src!=0) 28 | { 29 | *dst = *src; 30 | dst++; 31 | src++; 32 | } 33 | *dst = 0; 34 | } 35 | 36 | size_t strlen(char* src) 37 | { 38 | size_t i=0; 39 | while (src[i] != 0) i++; 40 | return i; 41 | } 42 | -------------------------------------------------------------------------------- /userapps/systemlib/string.h: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | 3 | bool strcompare(char* src, char* dst); 4 | size_t strfind(char* src, char token); 5 | void strcpy(char* src, char* dst); 6 | size_t strlen(char* src); 7 | -------------------------------------------------------------------------------- /userapps/systemlib/threads.c: -------------------------------------------------------------------------------- 1 | #include "threads.h" 2 | #include "kernel/intA0.h" 3 | 4 | uint64_t getCurrentCPU() 5 | { 6 | uint64_t cpu; 7 | 8 | __asm("int $0xA0" : "=a"(cpu) : "a"(INTA0_GET_APIC_ID)); 9 | 10 | return cpu; 11 | } 12 | 13 | uint64_t virt2phys(uint64_t addr) 14 | { 15 | uint64_t ret; 16 | 17 | __asm("int $0xA0" : "=a"(ret) : "D"(addr),"a"(INTA0_VIRT2PHYS)); 18 | 19 | return ret; 20 | } 21 | 22 | uint64_t loadProcess(char* name) 23 | { 24 | uint64_t ret; 25 | 26 | __asm("int $0xA0" : "=a"(ret) : "D"(name),"S"(0),"a"(INTA0_LOADPROCESS)); 27 | 28 | return ret; 29 | } 30 | 31 | 32 | void waitForProcessDeath(uint64_t processID) 33 | { 34 | __asm("int $0xA0" : : "D"(processID),"a"(INTA0_WAITPROCESS_DEATH)); 35 | } 36 | 37 | void getDateTime(char* str) 38 | { 39 | uint64_t ret; 40 | 41 | __asm("int $0xA0" : : "D"(str),"a"(INTA0_GET_DATETIME)); 42 | } 43 | 44 | -------------------------------------------------------------------------------- /userapps/systemlib/threads.h: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | uint64_t getCurrentCPU(); 3 | uint64_t virt2phys(uint64_t addr); 4 | uint64_t loadProcess(char* name); 5 | void waitForProcessDeath(uint64_t processID); 6 | void getDateTime(char* str); 7 | -------------------------------------------------------------------------------- /userapps/systemlib/types.h: -------------------------------------------------------------------------------- 1 | typedef unsigned long long uint64_t; 2 | typedef unsigned short uint16_t; 3 | typedef unsigned int uint32_t; 4 | typedef signed long long size_t; 5 | typedef unsigned char bool; 6 | 7 | #define true 1 8 | #define false 0 9 | 10 | -------------------------------------------------------------------------------- /userapps/systemlib/utils.c: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | uint64_t hexStringToNumber(char* st) 4 | { 5 | uint64_t n = 0; 6 | while (*st!=0) 7 | { 8 | n = n << 4; 9 | char c = *st; 10 | if (c>='0' && c<='9') n|= (c-48); 11 | else if (c>='a' && c<='f') n|= (c-97+10); 12 | else if (c>='A' && c<='F') n|= (c-65+10); 13 | st++; 14 | } 15 | 16 | return n; 17 | } 18 | -------------------------------------------------------------------------------- /userapps/systemlib/utils.h: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | 3 | uint64_t hexStringToNumber(char*); 4 | -------------------------------------------------------------------------------- /userapps/telnet/Makefile: -------------------------------------------------------------------------------- 1 | TARGET=telnet 2 | SOURCES=main.c 3 | BINDIR=../appsbin/ 4 | OBJECTS=$(SOURCES:%.c=%.o) 5 | SYSTEMLIB=../systemlib 6 | CFLAGS=-I $(SYSTEMLIB)/ -fno-exceptions -I../../kernel/includes 7 | 8 | all: $(TARGET).bin 9 | 10 | $(OBJECTS): %.o : %.c 11 | mkdir -p $(BINDIR) 12 | gcc -ffreestanding $(CFLAGS) -c $< -o $@ 13 | 14 | 15 | $(TARGET).bin: $(OBJECTS) 16 | mkdir -p $(BINDIR) 17 | ld -T ../link.ld $(OBJECTS) $(SYSTEMLIB)/systemlib.a -o $(BINDIR)$(TARGET).elf 18 | 19 | -------------------------------------------------------------------------------- /userapps/telnet/main.c: -------------------------------------------------------------------------------- 1 | #include "threads.h" 2 | #include "console.h" 3 | #include "memory.h" 4 | #include "string.h" 5 | #include "network.h" 6 | 7 | int main(uint64_t param) 8 | { 9 | uint64_t i; 10 | 11 | socket* s = create_socket(); 12 | 13 | uint32_t ip = 0xFB01A8C0; 14 | connect(s,ip,23); 15 | 16 | char r=0; 17 | while (!r) r = isconnected(s); 18 | if (r==-1) 19 | { 20 | printf("Connection refused\r\n"); 21 | } 22 | else 23 | { 24 | printf("Connection established\r\n"); 25 | 26 | 27 | char* buf = (char*)malloc(0x10000); 28 | 29 | i = 0x20000000; 30 | while (i) i--; 31 | uint16_t received = recv(s,buf,0x10000-1); 32 | if (received > 0) 33 | { 34 | buf[received] = 0; 35 | printf("Got %x bytes: %s\r\n",received,buf); 36 | } 37 | send(s,"This is a test1",15); 38 | send(s,"This is a test2",15); 39 | i = 0x10000000; 40 | while (i) i--; 41 | 42 | close_socket(s); 43 | r=0; 44 | while (!r) r = isclosed(s); 45 | } 46 | 47 | printf("Closing sockets\r\n"); 48 | close_socket(s); 49 | while (!isclosed(s)); 50 | release_socket(s); 51 | printf("goodbye\r\n"); 52 | } 53 | -------------------------------------------------------------------------------- /userapps/testapp1/Makefile: -------------------------------------------------------------------------------- 1 | TARGET=testapp1 2 | SOURCES=main.c 3 | BINDIR=../appsbin/ 4 | OBJECTS=$(SOURCES:%.c=%.o) 5 | SYSTEMLIB=../systemlib 6 | CFLAGS=-I $(SYSTEMLIB)/ -fno-exceptions -I../../kernel/includes 7 | #CFLAGS=-I $(SYSTEMLIB)/ -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow -fno-exceptions 8 | 9 | all: $(TARGET).bin 10 | 11 | $(OBJECTS): %.o : %.c 12 | mkdir -p $(BINDIR) 13 | gcc -ffreestanding $(CFLAGS) -c $< -o $@ 14 | 15 | 16 | $(TARGET).bin: $(OBJECTS) 17 | mkdir -p $(BINDIR) 18 | ld -T ../link.ld $(OBJECTS) $(SYSTEMLIB)/systemlib.a -o $(BINDIR)$(TARGET).elf 19 | 20 | -------------------------------------------------------------------------------- /userapps/testapp1/main.c: -------------------------------------------------------------------------------- 1 | #include "threads.h" 2 | #include "console.h" 3 | #include "memory.h" 4 | 5 | uint64_t testRWVar=0x123456789; 6 | uint64_t testBSSVar; 7 | 8 | int meow(uint64_t tid) 9 | { 10 | // the terminating \003 is non-standard way to force flush 11 | printf("\033[?25l\033[s\033[16;6HRunning on CPU %x %x\033[u\033[?25h\003",tid, testBSSVar); 12 | } 13 | 14 | int main(uint64_t param) 15 | { 16 | uint64_t i,a; 17 | uint16_t ch; 18 | 19 | char* b0; 20 | char* b1; 21 | char* b2; 22 | char* b3; 23 | 24 | b1 = malloc(128); 25 | b2 = malloc(128); 26 | 27 | b3 = malloc(128); 28 | b0 = b1; 29 | if (b2!= (b1+128+16)) printf("Error 1\r\n"); 30 | if (b3!= (b2+128+16)) printf("Error 2\r\n"); 31 | free(b1); 32 | free(b3); 33 | b1 = malloc(256); 34 | if (b1!=(b2+128+16)) printf("Error 3: b1=%x b3=%x\r\n",b1, b3); 35 | free(b2); 36 | b2 = malloc(256); 37 | if (b2!=(b0)) printf("Error 4 %x\r\n",b2); 38 | 39 | 40 | char* buf1 = (char*)malloc(0x10000); 41 | char* buf2 = (char*)malloc(0x1); 42 | char* buf3 = (char*)malloc(0x10000); 43 | 44 | printf("User Thread %x %x %x %x\r\n",param, buf1, buf2, buf3); 45 | for (i=0;i<0x10000;i++) buf1[i] = (char)i; 46 | for (i=0;i<0x1;i++) buf2[i] = (char)i; 47 | for (i=0;i<0x10000;i++) buf3[i] = (char)i; 48 | 49 | while (1) 50 | { 51 | testBSSVar++; 52 | meow(getCurrentCPU()); 53 | ch = poll_in(); 54 | if (ch!=0) 55 | { 56 | if (ch == 0x1B) 57 | { 58 | printf("\033[2J\003"); 59 | } 60 | else if (ch=='A') 61 | { 62 | printf("\033[1A\003"); 63 | } 64 | else if (ch=='B') 65 | { 66 | printf("\033[1B\003"); 67 | } 68 | else if (ch=='C') 69 | { 70 | printf("\033[1C\003"); 71 | } 72 | else if (ch=='D') 73 | { 74 | printf("\033[1D\003"); 75 | } 76 | else if (ch=='Q') 77 | { 78 | return 0; 79 | } 80 | else 81 | { 82 | printf("keypress: %c [%x]\r\n",(char)ch,ch); 83 | } 84 | } 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /userapps/tetris/Makefile: -------------------------------------------------------------------------------- 1 | TARGET=tetris 2 | SOURCES=main.c 3 | BINDIR=../appsbin/ 4 | OBJECTS=$(SOURCES:%.c=%.o) 5 | SYSTEMLIB=../systemlib 6 | CFLAGS=-I $(SYSTEMLIB)/ -fno-exceptions -I../../kernel/includes 7 | 8 | all: $(TARGET).bin 9 | 10 | $(OBJECTS): %.o : %.c 11 | mkdir -p $(BINDIR) 12 | gcc -ffreestanding $(CFLAGS) -c $< -o $@ 13 | 14 | 15 | $(TARGET).bin: $(OBJECTS) 16 | mkdir -p $(BINDIR) 17 | ld -T ../link.ld $(OBJECTS) $(SYSTEMLIB)/systemlib.a -o $(BINDIR)$(TARGET).elf 18 | 19 | -------------------------------------------------------------------------------- /userapps/tetris/main.c: -------------------------------------------------------------------------------- 1 | #include "threads.h" 2 | #include "console.h" 3 | #include "memory.h" 4 | #include "string.h" 5 | #include "files.h" 6 | #include "threads.h" 7 | #include "shapes.h" 8 | 9 | 10 | 11 | #define KEY_PGUP 278 12 | #define KEY_PGDOWN 279 13 | #define KEY_UP 280 14 | #define KEY_DOWN 281 15 | #define KEY_LEFT 282 16 | #define KEY_RIGHT 283 17 | #define SQUARE '#' 18 | #define BORDER ':' 19 | 20 | typedef unsigned char uint8_t; 21 | 22 | typedef struct 23 | { 24 | uint64_t type; 25 | uint64_t orientation; 26 | unsigned char colour; 27 | int x; 28 | int y; 29 | } block; 30 | 31 | 32 | block* current_block; 33 | char * videoBuffer; 34 | char *board; 35 | 36 | uint64_t random() 37 | { 38 | uint64_t ret; 39 | __asm("rdrand %%rax" : "=a"(ret)); 40 | return ret; 41 | } 42 | 43 | 44 | void block_draw(block* b, char* buffer) 45 | { 46 | char *video = (buffer+68) + (b->y*160) + (b->x*2); 47 | char i; 48 | char i2; 49 | 50 | char* shape = (char*)&shapes[(b->type*4 + b->orientation)*16]; 51 | 52 | for (i = 0; i < 4; i++) for (i2 = 0; i2 < 4; i2++) 53 | { 54 | if (shape[i*4+i2] != ' ') 55 | { 56 | video[(i*160)+(i2*2)]=SQUARE; 57 | video[(i*160)+(i2*2)+1]=b->colour; 58 | } 59 | 60 | 61 | } 62 | 63 | } 64 | 65 | uint64_t detect_collision(block *b) 66 | { 67 | uint64_t i,i2; 68 | char *buf = (board+68) + (b->y*160) + (b->x*2); 69 | char* shape = (char*)&shapes[(b->type*4 + b->orientation)*16]; 70 | 71 | for (i = 0; i < 4; i++) for (i2 = 0; i2 < 4; i2++) 72 | { 73 | if (shape[i*4+i2] != ' ') 74 | { 75 | if (buf[(i*160)+(i2*2)] == '@') return 1; 76 | if (buf[(i*160)+(i2*2)] == SQUARE) return 2; 77 | } 78 | } 79 | return 0; 80 | } 81 | 82 | uint64_t detect_full_lines() 83 | { 84 | uint64_t i,i2,line,n; 85 | char *buf = (board+70); 86 | i = 20; 87 | 88 | while(1) 89 | { 90 | bool full = true; 91 | bool empty = true; 92 | 93 | for (i2 = 0; i2 < 10; i2++) 94 | { 95 | if (buf[(i*160)+(i2*2)]!=SQUARE) 96 | { 97 | full = false; 98 | } 99 | else 100 | { 101 | empty = false; 102 | } 103 | } 104 | 105 | if (full) 106 | { 107 | for (line = i; line > 1; line--) 108 | { 109 | for (n = 0; n < 10; n++) 110 | { 111 | buf[line*160+ (n*2)] = buf[(line-1)*160+ (n*2)]; 112 | buf[line*160+ (n*2)+1] = buf[(line-1)*160+ (n*2)+1]; 113 | } 114 | } 115 | for (n = 0; n < 10; n++) 116 | { 117 | buf[160+ (n*2)] = ' '; 118 | } 119 | } 120 | else 121 | { 122 | i--; 123 | if (i==0) break; 124 | } 125 | 126 | if (empty) break; 127 | 128 | } 129 | return 0; 130 | } 131 | 132 | block* block_create() 133 | { 134 | block *b = (block*)malloc(sizeof(block)); 135 | b->x=4; 136 | b->y=0; 137 | b->orientation=0; 138 | b->type=random() % 7; 139 | b->colour= random() & 0b111; 140 | 141 | return b; 142 | } 143 | 144 | void redraw() 145 | { 146 | uint64_t i; 147 | for (i = 0; i < 512; i++) ((uint64_t*)videoBuffer)[i] = ((uint64_t*)board)[i]; 148 | char *video = videoBuffer; 149 | block_draw(current_block, video); 150 | } 151 | 152 | void make_frame() 153 | { 154 | uint64_t i; 155 | uint8_t *buf = (uint8_t*)board+68; 156 | for (i = 0; i < 12; i++) buf[i*2] = (char)'@'; 157 | buf += 160; 158 | for (i = 0; i < 20; i++) 159 | { 160 | buf[0] = '@'; 161 | buf[22] = '@'; 162 | buf+=160; 163 | } 164 | 165 | for (i = 0; i < 12; i++) buf[i*2] = '@'; 166 | 167 | 168 | } 169 | 170 | 171 | 172 | 173 | int main(uint64_t param) 174 | { 175 | uint64_t i; 176 | uint16_t ch; 177 | char str[32]; 178 | str[0]=0; 179 | bool need_redraw = true; 180 | 181 | videoBuffer = get_video_buffer(); 182 | current_block = block_create(); 183 | board = (char*)malloc(4096); 184 | make_frame(); 185 | 186 | char lastSec = ' '; 187 | while(1) 188 | { 189 | getDateTime(str); 190 | if (str[18] != lastSec) 191 | { 192 | lastSec = str[18]; 193 | need_redraw = true; 194 | current_block->y++; 195 | uint64_t collision = detect_collision(current_block); 196 | if (collision != 0) 197 | { 198 | current_block->y--; 199 | block_draw(current_block, board); 200 | free(current_block); 201 | current_block = block_create(); 202 | } 203 | detect_full_lines(); 204 | } 205 | 206 | if (need_redraw) 207 | { 208 | redraw(); 209 | need_redraw = false; 210 | } 211 | 212 | ch = poll_in(); 213 | if (ch != 0) 214 | { 215 | if (ch == 'a') 216 | { 217 | current_block->x--; 218 | if (detect_collision(current_block)) 219 | { 220 | current_block->x++; 221 | } 222 | else 223 | { 224 | need_redraw = true; 225 | } 226 | } 227 | if (ch == 's') 228 | { 229 | current_block->x++; 230 | if (detect_collision(current_block)) 231 | { 232 | current_block->x--; 233 | } 234 | else 235 | { 236 | need_redraw = true; 237 | } 238 | } 239 | if (ch == 'x') 240 | { 241 | current_block->y++; 242 | if (detect_collision(current_block)) 243 | { 244 | current_block->y--; 245 | } 246 | else 247 | { 248 | need_redraw = true; 249 | } 250 | } 251 | if (ch == ' ') 252 | { 253 | uint64_t old = current_block->orientation; 254 | current_block->orientation = (current_block->orientation+1) & 0b11; 255 | if (detect_collision(current_block)) 256 | { 257 | current_block->orientation = old; 258 | } 259 | else 260 | { 261 | need_redraw = true; 262 | } 263 | } 264 | } 265 | } 266 | 267 | } 268 | -------------------------------------------------------------------------------- /userapps/tetris/shapes.h: -------------------------------------------------------------------------------- 1 | char shapes[7*4*16] = " " 2 | " AA " 3 | " AA " 4 | " " 5 | 6 | " " 7 | " AA " 8 | " AA " 9 | " " 10 | 11 | " " 12 | " AA " 13 | " AA " 14 | " " 15 | 16 | " " 17 | " AA " 18 | " AA " 19 | " " 20 | 21 | " " 22 | " A " 23 | " A " 24 | "AA " 25 | 26 | " " 27 | " " 28 | "A " 29 | "AAA " 30 | 31 | " " 32 | "AA " 33 | "A " 34 | "A " 35 | 36 | " " 37 | "AAA " 38 | " A " 39 | " " 40 | 41 | " A " 42 | " A " 43 | " A " 44 | " A " 45 | 46 | " " 47 | "AAAA" 48 | " " 49 | " " 50 | 51 | " A " 52 | " A " 53 | " A " 54 | " A " 55 | 56 | " " 57 | "AAAA" 58 | " " 59 | " " 60 | 61 | " A " 62 | " AA " 63 | " A " 64 | " " 65 | 66 | " " 67 | " A " 68 | "AAA " 69 | " " 70 | 71 | " A " 72 | " AA " 73 | " A " 74 | " " 75 | 76 | " " 77 | "AAA " 78 | " A " 79 | " " 80 | 81 | " " 82 | " A " 83 | " A " 84 | " AA " 85 | 86 | " " 87 | " " 88 | "AAA " 89 | "A " 90 | 91 | " " 92 | "AA " 93 | " A " 94 | " A " 95 | 96 | " A " 97 | "AAA " 98 | " " 99 | " " 100 | 101 | " " 102 | " A " 103 | " AA " 104 | " A " 105 | 106 | " " 107 | "AA " 108 | " AA " 109 | " " 110 | 111 | " " 112 | " A " 113 | " AA " 114 | " A " 115 | 116 | " " 117 | "AA " 118 | " AA " 119 | " " 120 | 121 | " " 122 | " A " 123 | " AA " 124 | " A " 125 | 126 | " " 127 | " AA " 128 | "AA " 129 | " " 130 | 131 | " " 132 | " A " 133 | " AA " 134 | " A " 135 | 136 | " " 137 | " AA " 138 | "AA " 139 | " "; 140 | -------------------------------------------------------------------------------- /userapps/webserver/Makefile: -------------------------------------------------------------------------------- 1 | TARGET=webserver 2 | SOURCES=main.c 3 | BINDIR=../appsbin/ 4 | OBJECTS=$(SOURCES:%.c=%.o) 5 | SYSTEMLIB=../systemlib 6 | CFLAGS=-I $(SYSTEMLIB)/ -fno-exceptions -I../../kernel/includes 7 | 8 | all: $(TARGET).bin 9 | 10 | $(OBJECTS): %.o : %.c 11 | mkdir -p $(BINDIR) 12 | gcc -ffreestanding $(CFLAGS) -c $< -o $@ 13 | 14 | 15 | $(TARGET).bin: $(OBJECTS) 16 | mkdir -p $(BINDIR) 17 | ld -T ../link.ld $(OBJECTS) $(SYSTEMLIB)/systemlib.a -o $(BINDIR)$(TARGET).elf 18 | 19 | -------------------------------------------------------------------------------- /userapps/webserver/main.c: -------------------------------------------------------------------------------- 1 | #include "threads.h" 2 | #include "console.h" 3 | #include "memory.h" 4 | #include "string.h" 5 | #include "network.h" 6 | #include "files.h" 7 | 8 | #define MAX_CLIENTS 10 9 | #define BUF_SIZE 2048 10 | 11 | socket* clients[MAX_CLIENTS]; 12 | char buf[BUF_SIZE]; 13 | 14 | void closeClient(socket* s) 15 | { 16 | printf("closing socket %x\r\n",s); 17 | close_socket(s); 18 | } 19 | 20 | void addClient(socket* s) 21 | { 22 | uint64_t i; 23 | 24 | for (i=0;i0) 103 | { 104 | send(clients[i],buf,n+pos); 105 | } 106 | pos = 0; 107 | if (n<1024) break; 108 | } 109 | sent = true; 110 | fclose(f); 111 | } 112 | } 113 | 114 | if (!sent) 115 | { 116 | sprintf(buf,200,"HTTP/1.1 404 NOT FOUND\r\n" \ 117 | "Content-Length: 0\r\n" \ 118 | "Content-Type: text/html\r\n" \ 119 | "\r\n"); 120 | send(clients[i],buf,strlen(buf)); 121 | } 122 | } 123 | closeClient(clients[i]); 124 | } 125 | 126 | } 127 | 128 | printf("Closing sockets\r\n"); 129 | close_socket(s); 130 | release_socket(s); 131 | printf("goodbye\r\n"); 132 | } 133 | --------------------------------------------------------------------------------