From 09901354eb4ed856f020c1316ea25ba2776b9b4f Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Wed, 19 Feb 2020 18:07:00 +0100 Subject: [PATCH 001/104] make run depend on build so it doesn't crash after make clean --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ae3c04fa..bef4a692 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ clean: $(MAKE) -C user/hello clean .PHONY: clean build: u-boot kernel -run: +run: build @$(MAKE) -C ./kernel run .PHONY: run From f2585bd9a8bda48984985180e2030aed75671824 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Wed, 19 Feb 2020 18:09:38 +0100 Subject: [PATCH 002/104] removed dead code 'SampleFile.c' --- kernel/sampleFile.c | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 kernel/sampleFile.c diff --git a/kernel/sampleFile.c b/kernel/sampleFile.c deleted file mode 100644 index ac8d11a1..00000000 --- a/kernel/sampleFile.c +++ /dev/null @@ -1,10 +0,0 @@ -#include - -uint32_t functionYO(uint32_t x, uint32_t y) -{ - int a = 100; - int b = 40000; - os_printf("%d\n", x + y); - return x + y; - -} From 91d38dc7f93c74e90796d38b51b0af39c033f840 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Wed, 19 Feb 2020 18:10:53 +0100 Subject: [PATCH 003/104] removed someones personal logfile it seems --- kernel/fs_aaa.txt | 122 ---------------------------------------------- 1 file changed, 122 deletions(-) delete mode 100644 kernel/fs_aaa.txt diff --git a/kernel/fs_aaa.txt b/kernel/fs_aaa.txt deleted file mode 100644 index 8d56e64e..00000000 --- a/kernel/fs_aaa.txt +++ /dev/null @@ -1,122 +0,0 @@ -make -C fs/cmdline -make[1]: Entering directory `/v/filer4b/v20q001/joeliven/Documents/2015sp/CS439_OS/Projects/Project_3/course_os_2/course_os/kernel/fs/cmdline' -gcc -g -c main.c -gcc -g -c fakelibs.c -gcc -g -c -I. ../fat16/file.c -o file.o -gcc -g -c -I. ../open_table.c -o open_table.o -gcc -g -c -I. ../../data_structures/bitvector.c -o bv.o -gcc -g main.o fakelibs.o file.o open_table.o bv.o -o buildfs -make[1]: Leaving directory `/v/filer4b/v20q001/joeliven/Documents/2015sp/CS439_OS/Projects/Project_3/course_os_2/course_os/kernel/fs/cmdline' -make -C ../user/hello -make[1]: Entering directory `/v/filer4b/v20q001/joeliven/Documents/2015sp/CS439_OS/Projects/Project_3/course_os_2/course_os/user/hello' -make[1]: `hello' is up to date. -make[1]: Leaving directory `/v/filer4b/v20q001/joeliven/Documents/2015sp/CS439_OS/Projects/Project_3/course_os_2/course_os/user/hello' -dd if=/dev/zero of=card.sd conv=notrunc bs=512 count=250000 -fs/cmdline/buildfs ../user/hello/ -SD Card initiallized successfully!!! -Finished initializing table... -Read: 'Hello, world!+' -Adding Makefile... -Adding hello.c... -Adding hello.o... -Adding hello... -0 -fd: 0 -qemu-system-arm -M versatilepb -sd card.sd -m 128M -nographic -kernel flash.bin -append "-load 0x410000 0x14000" - - -U-Boot 2014.10 (May 03 2015 - 17:00:52) - -DRAM: 128 MiB -WARNING: Caches not enabled -Using default environment - -In: serial -Out: serial -Err: serial -Net: SMC91111-0 -Warning: SMC91111-0 using MAC address from net device - -Warning: Your board does not use generic board. Please read -doc/README.generic-board and take action. Boards not -upgraded by the late 2014 may break or be removed. -Hit any key to stop autoboot: 2  1  0 -## Executing script at 0024f000 -## Booting kernel from Legacy Image at 00210000 ... - Image Name: - Image Type: ARM Linux Kernel Image (uncompressed) - Data Size: 67476 Bytes = 65.9 KiB - Load Address: 00010000 - Entry Point: 00010000 - Loading Kernel Image ... OK - -Starting kernel ... - -Enabling MMU... -5 -Initialized VM datastructures. -100 -first_level_pt=204000 -0x300402 -control reg: 0x2089107f -Got here -MMU enabled - -CourseOS! -Bootargs: 5 -test_vm_1 ... asdf -vm_l1pt_free_list=F0210000 -Got new vas at 0xF020000C -Stack addr: 0xFFF00000 -Created page table w/ 0xFFF00000's entry = 0x7F00402 -Hey, I'm printing! -F0200000 (FFFFBFA0) -F0204000 -F0204000 -Entry: 200402 -402 -(deref: entry at 0x200000: 0x0) -vm_l1pt_free_list=F0214000 -F020000C and F0200000 and F0200018 -ffffbf9c 24000000 -Testing shared memory... -301012 -map_shared_memory returned 0 -You should see a data abort... -DATA ABORT HANDLER -HANDLER: pc=12b60, lr=12b58, sp=ffffafc0, fp=ffffaffc -DSFR: 0x5 -603979776 -Freeing page at 24000000 -F0301000 F0302000 -PASSES -There are 31742 free frames. -There are 31742 free frames. -test_prq_1 ... PASSES -test_prq_2 ... PASSES -test_prq_3 ... PASSES -test_prq_4 ... PASSES -test_prq_5 ... PASSES -test_prq_6 ... PASSES - -SD card ready for transfer -SD Card initiallized successfully!!! -Finished initializing table... -test_fs_1 ... file descriptor is: 1 - -Opening file... -file descriptor is: 0 - -Writing string to file... - -Opening previous file... -0 - -Reading from file... -Read 39 bytes from file. -the buffer is: 'Hello, world I'm testing right now...! -' -PASSES -done parsing atag list -QEMU: Terminated - \ No newline at end of file From 534547856b7417afb158329d99dec436b5e7bcde Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Wed, 19 Feb 2020 18:27:00 +0100 Subject: [PATCH 004/104] added cmakelist to make development in clion possible --- CMakeLists.txt | 68 +++++++++++++++++++++++++++++++++++++++++++++++ kernel/argparse.c | 1 - 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..519a0d24 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,68 @@ +######################################################################## +## WARNING: This cmake file does *NOT* work to compile the course OS ## +## It is merely here to make clion detect all the source files ## +## so it can do code inspection. Use the supplied makefile to compile ## +######################################################################## + +cmake_minimum_required(VERSION 3.6) + +project(course_os) + +set(SOURCE_FILES + kernel/argparse.c + kernel/data_structures/array_list.c + kernel/data_structures/bin_tree.c + kernel/data_structures/bitvector.c + kernel/data_structures/hash_map.c + kernel/data_structures/linked_list.c + kernel/data_structures/priority_queue.c + kernel/data_structures/ring_buffer.c + kernel/data_structures/swap_pqueue.c + kernel/drivers/clock.c + kernel/drivers/mmci.c + kernel/drivers/timer.c + kernel/drivers/uart.c + kernel/drivers/uart_pi.c + kernel/elf.c + kernel/fs/cmdline/fakelibs.c + kernel/fs/cmdline/main.c + kernel/fs/fat16/test.c + kernel/fs/fat16/file.c + kernel/fs/open_table.c + kernel/hw_handlers.c + kernel/interrupt.c + kernel/klibc.c + kernel/loader.c + kernel/memory/allocator.c + kernel/memory/mem_alloc.c + kernel/mmap.c + kernel/pi_light.c + kernel/pm.c + kernel/priorityQueue.c + kernel/process.c + kernel/process/process_api.c + kernel/process/scheduler.c + kernel/signals.c + kernel/tests.c + kernel/tests/test_fs.c + kernel/tests/test_hash_map.c + kernel/tests/test_mem_alloc.c + kernel/tests/test_priority_queue.c + kernel/tests/test_vm.c + kernel/tests/testingsuite_example/arrayfill/arrayfill.c + kernel/tests/testingsuite_example/arrayfill/tap.c + kernel/tests/testingsuite_example/arrayfill/testarrayfill.c + kernel/threads/kthreads.c + kernel/vm/fastlz/6pack.c + kernel/vm/fastlz/6unpack.c + kernel/vm/fastlz/fastlz.c + kernel/vm/frame.c + kernel/vm/swap_framework.c + kernel/vm/swap_fs.c + kernel/vm/vm.c + kernel/start.c +) + +add_executable(course_os ${SOURCE_FILES}) + +include_directories(kernel/include) diff --git a/kernel/argparse.c b/kernel/argparse.c index 6b2d0c4c..a6f373d4 100644 --- a/kernel/argparse.c +++ b/kernel/argparse.c @@ -4,7 +4,6 @@ #include "klibc.h" #include "tests.h" #include "process.h" -#include "fs/file.h" static void argparse_parse(char *); From 97fa2cab43f4a7c0fa5d26dcc0b6e65c5f5c61b2 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Wed, 19 Feb 2020 20:04:16 +0100 Subject: [PATCH 005/104] all build files now generate in a build directory --- .gitignore | 1 + Makefile | 6 ++ kernel/Makefile | 99 ++++++++++++------ kernel/kernel.ld | 2 +- kernel/tests/a.out | Bin 8650 -> 0 bytes kernel/uboot_configuration/generate.sh | 0 .../uboot-commands.ubt | 0 7 files changed, 73 insertions(+), 35 deletions(-) delete mode 100755 kernel/tests/a.out create mode 100644 kernel/uboot_configuration/generate.sh rename kernel/{ => uboot_configuration}/uboot-commands.ubt (100%) diff --git a/.gitignore b/.gitignore index 8c2fa405..ab59ff6e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ /u-boot/u-boot-* /qemu/ !/qemu/build.sh +build/ .settings/ .cproject diff --git a/Makefile b/Makefile index bef4a692..842a032a 100644 --- a/Makefile +++ b/Makefile @@ -22,11 +22,17 @@ clean: $(MAKE) -C user/libc clean $(MAKE) -C user/hello clean .PHONY: clean + build: u-boot kernel +.PHONY: build + run: build @$(MAKE) -C ./kernel run .PHONY: run +test: build + @$(MAKE) -C ./kernel test + docs: doxygen doxyfile $(MAKE) -C latex pdf diff --git a/kernel/Makefile b/kernel/Makefile index 4bb6b9dd..7f544597 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -9,13 +9,35 @@ OBJCOPY:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-objcopy MKIMAGE:=$(CURDIR)/../u-boot/u-boot-$(UBOOT_VERSION)/tools/mkimage GDB:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gdb -PIOBJS = start.o pi_light.o startup.o drivers/uart_pi.o argparse.o klibc.o interrupt.o hw_handlers.o process.o elf.o loader.o memory/mem_alloc.o memory/allocator.o tests.o mmap.o vm/frame.o vm/vm.o drivers/timer.o data_structures/bitvector.o data_structures/array_list.o data_structures/priority_queue.o data_structures/linked_list.o data_structures/hash_map.o process/scheduler.o tests/test_mem_alloc.o tests/test_priority_queue.o tests/test_hash_map.o tests/test_vm.o fs/open_table.o fs/fat16/file.o tests/test_fs.o drivers/mmci.o +COMMONOBJS = build/start.o build/startup.o build/argparse.o \ + build/klibc.o build/interrupt.o build/process.o \ + build/hw_handlers.o build/elf.o build/loader.o \ + build/memory/mem_alloc.o build/memory/allocator.o \ + build/mmap.o build/vm/frame.o build/vm/vm.o \ + build/drivers/timer.o build/data_structures/bitvector.o \ + build/data_structures/array_list.o \ + build/data_structures/priority_queue.o \ + build/data_structures/linked_list.o \ + build/data_structures/hash_map.o build/process/scheduler.o \ + build/fs/open_table.o build/fs/fat16/file.o \ + build/drivers/mmci.o -OBJS=start.o drivers/uart.o startup.o argparse.o klibc.o interrupt.o hw_handlers.o process.o elf.o loader.o memory/mem_alloc.o memory/allocator.o tests.o mmap.o vm/frame.o vm/vm.o drivers/timer.o process/scheduler.o data_structures/bitvector.o data_structures/array_list.o data_structures/linked_list.o data_structures/priority_queue.o data_structures/hash_map.o tests/test_mem_alloc.o tests/test_priority_queue.o tests/test_hash_map.o tests/test_vm.o fs/open_table.o fs/fat16/file.o tests/test_fs.o drivers/mmci.o -all: flash.bin card.sd -make_Pi: kernelPi.img +TESTOBJS = build/tests.o build/tests/test_mem_alloc.o build/tests/test_hash_map.o \ + build/tests/test_priority_queue.o build/tests/test_vm.o \ + build/tests/test_fs.o + +PIOBJS = build/pi_light.o build/drivers/uart_pi.o +OBJS = build/drivers/uart.o + +OBJS += $(COMMONOBJS) $(TESTOBJS) +PIOBJS += $(COMMONOBJS) $(TESTOBJS) + + +all: build/flash.bin build/card.sd + +make_Pi: build/kernelPi.img CFLAGS += -pipe CFLAGS += -std=gnu99 @@ -30,25 +52,31 @@ PFLAGS += -mtune=arm1176jzf-s PFLAGS += -nostartfiles CFLAGS += -g -run: flash.bin card.sd - ${QEMU} -M versatilepb -cpu arm1176 -sd card.sd -m 128M -nographic -kernel flash.bin -append "-load 0x410000 0x14000" +run: build/flash.bin build/card.sd | builddir + ${QEMU} -M versatilepb -cpu arm1176 -sd card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" + +test: build/flash.bin build/card.sd | builddir + ${QEMU} -M versatilepb -cpu arm1176 -sd card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" + +run-debug: build/flash.bin build/card.sd | builddir + ${QEMU} -S -s -M versatilepb -cpu arm1176 -sd card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" -run-debug: flash.bin card.sd - ${QEMU} -S -s -M versatilepb -cpu arm1176 -sd card.sd -m 128M -nographic -kernel flash.bin -append "-load 0x410000 0x14000" +gdb: | builddir + ${GDB} -ex "target remote :1234" build/kernel.elf -gdb: - ${GDB} -ex "target remote :1234" kernel.elf +builddir: + mkdir -p build #boots the kernel at 0x210000 -flash.bin: kernel.img script.img - dd if=/dev/zero of=flash.bin bs=4k count=1536 - dd if=../u-boot/u-boot-$(UBOOT_VERSION)/u-boot.bin of=flash.bin conv=notrunc bs=4k - dd if=kernel.img of=flash.bin conv=notrunc bs=4k seek=512 - dd if=script.img of=flash.bin conv=notrunc bs=4k seek=575 +build/flash.bin: build/kernel.img build/script.img | builddir + dd if=/dev/zero of=$@ bs=4k count=1536 + dd if=../u-boot/u-boot-$(UBOOT_VERSION)/u-boot.bin of=build/flash.bin conv=notrunc bs=4k + dd if=build/kernel.img of=$@ conv=notrunc bs=4k seek=512 + dd if=build/script.img of=$@ conv=notrunc bs=4k seek=575 # 32678*4096 = 128MiB -card.sd: fs-cmdline userhello - dd if=/dev/zero of=card.sd conv=notrunc bs=4096 count=32768 +build/card.sd: fs-cmdline userhello | builddir + dd if=/dev/zero of=$@ conv=notrunc bs=4096 count=32768 fs/cmdline/buildfs ../user/hello/ userhello: @@ -57,34 +85,36 @@ userhello: fs-cmdline: make -C fs/cmdline -kernel.elf: $(OBJS) - $(LD) -T kernel.ld -nostartfiles -Wl,-Map,kernel.map $(OBJS) -o kernel.elf +build/kernel.elf: $(OBJS) | builddir + $(LD) -T kernel.ld -nostartfiles -Wl,-Map,kernel.map $(OBJS) -o $@ -kernel.bin: kernel.elf - $(OBJCOPY) -O binary kernel.elf kernel.bin +build/kernel.bin: build/kernel.elf | builddir + $(OBJCOPY) -O binary $< $@ -kernel.img: kernel.bin - $(MKIMAGE) -A arm -C none -O linux -T kernel -d kernel.bin -a 0x00010000 -e 0x00010000 kernel.img +build/kernel.img: build/kernel.bin | builddir + $(MKIMAGE) -A arm -C none -O linux -T kernel -d $< -a 0x00010000 -e 0x00010000 $@ # Begin Pi Make -kernelPi.elf: $(PIOBJS) - $(CC) -T kernelPi.ld -O2 $(PFLAGS) $(PIOBJS) -o kernelPi.elf +build/kernelPi.elf: $(PIOBJS) | builddir + $(CC) -T kernelPi.ld -O2 $(PFLAGS) $(PIOBJS) -o $@ -kernelPi.img: kernelPi.elf - $(OBJCOPY) kernelPi.elf -O binary kernelPi.img +build/kernelPi.img: build/kernelPi.elf | builddir + $(OBJCOPY) $< -O binary $@ # End Pi Make -script.img: uboot-commands.ubt - $(MKIMAGE) -A arm -C none -T script -d uboot-commands.ubt -a 0x10000 -e 0x10000 script.img +build/script.img: uboot_configuration/uboot-commands.ubt | builddir + $(MKIMAGE) -A arm -C none -T script -d $< -a 0x10000 -e 0x10000 $@ -course_os.img: kernel.img - cat ../u-boot/u-boot-$(UBOOT_VERSION)/u-boot.bin kernel.img > course_os.img +build/course_os.img: build/kernel.img | builddir + cat ../u-boot/u-boot-$(UBOOT_VERSION)/u-boot.bin $< > $@ -startup.o: startup.s - $(AS) -mcpu=arm1176jzf-s -g startup.s -o startup.o +build/startup.o: startup.s | builddir + @mkdir -p $(shell dirname $@) + $(AS) -mcpu=arm1176jzf-s -g $< -o $@ -%.o: %.c +build/%.o: %.c | builddir + @mkdir -p $(shell dirname $@) $(CC) $(CFLAGS) -Iinclude -c $< -o $@ clean: @@ -100,5 +130,6 @@ clean: rm -f memory/*.o rm -f data_structures/*.o rm -f mq/*.o + rm -rf build @echo "I'm persisting the SD card 'card.sd', you'll have to remove that yourself if you want to rebuild it." @echo "('rm sd.card')" diff --git a/kernel/kernel.ld b/kernel/kernel.ld index 3670ea97..cf74c7f2 100644 --- a/kernel/kernel.ld +++ b/kernel/kernel.ld @@ -2,7 +2,7 @@ ENTRY(_Reset) SECTIONS { . = 0x10000; - .startup . : { startup.o(.text) } + .startup . : { build/startup.o(.text) } .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss COMMON) } diff --git a/kernel/tests/a.out b/kernel/tests/a.out deleted file mode 100755 index 6d219ccbf7bf2627570725d7d8a454a2af78f72c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8650 zcmeHMZ){W76~DHVVE!e6(l$Uhtj!?G7W1E(GS(LohZiuAk}!1x`Y^FWOdT89&n$FI zV@p7|DKy*I#85TzVbdy&4``~kNR=Qc-53&@*rsinT4`Aak||V$c4g59c)xSsJ@NA+ z+1Q7D8prZG=lt$D_ndp*z4yI$@7F`&Mz_l)nB3wEg0%iJO+waHi05ZWRbfFfS!m*u zVy>tFQjWhSONd(%^HEhbbFZ@VfS2JPbX!2stx19TQx+_kbB4qzUXe5Fk0RHy$Tn{zH6dngh$3<5Z<9_bUB4prmr18ot`AE6 zo1{|;*Uv&<`hHXHH!tY9clGY8x0+jN1O2cgtxqahCkhBZ`^yu9;T>9$ajK95V zUV}j623>ltyc|Y_S-+4*z2$$O0+-dp>34rw{#S@D3b%ddPg%I2q~z0cU(4sRS1*R{lG%++Z|JUmQok_b(LJHO-isuw z2VSGr=l-DQF3P&{XYLmY1E(dZkW)Y&^lbJ@`@(M#eA@XR!66@k;f*Qh&yc(ga(C#i z3yy0-R}UV(G-OXo&t*r>(+JG(gq@xXjq1Jh-N)k+-EbIs`e(5U4)KzDejtVIU4 zM6|N{Tq|zb`JYnMlellF?bbPipmPKrwxCh{7+@L|Xled!M7@NL0_nMge>j|r`bYF* zwQZApB7AKA4r0Lb;hgEe70w;>kLtM{e%$?=!SK`9>T>s*a(DC#_dHFxKj!Q2A?D%t z&8L>WP2)41`$sr;ry=)2U18QcdiN0S`Hk#*dhZTD8k6u>hkK*`nlL0^xYzVA4EG-N zFTrgN4pq%NgzUseR$602Y;1gCME$A)!=rn&V9tJ%9y4kj-SA>u_F{aE7P7b1h_S|Q z-k{uQ7SWt_i}@Mh3j_i_(OlQk5^52Rbxq+G(b^Hu`1VCInOMe>+avKrhH`Pu^{mms zX>IShTPQ@q2TQ}sn#ItkOEL!gW6v1TEfWIH{ze_+}W%Utv z{qzcVA8NA7DZlTde2u+)zbuyiJ;2{U`BZy(W3l{)z)%01^0!d_GRo`h{s%38Kd`I# zpGA3&%Ab3s{78jSsdZ0!)qUJ^tjzsYcYnNsvxbkUB7b1{3&}l|?gPUoKcd&$yp;&sK2qaTxEKs+usn(3_QQDql zHn2Mz$A@J+DgvZ+L^2&B5IvAYeHJ&}TYIulPNOB4fT=~yB{4ocdWFhwAqjN@v? zx^QiWg0fUJVn#$D)?u`#Bb_m$BMM*EM4-(~r85XKMjG#F8jB-HE6~C2%pr7 zm$ITLrKPyq{Y|$faZ^=D?@xAe`Zu8P4#qmiKk3$_`AG$E{^b(2-dU9>*=Ag6ZnOV@ zTZ2aHfMlZ2VsdYW+U}f}Uj#;TpZ$3~(ba;$>xZi5f&O~|1vGcrpXcid<I z68wBA#l526quC)TdvN+PI4(X#@H%gI^599z>vt(WP4K#0iccRq|0%^Q1+Sx}coo(~ z%??S~gH@f^J$s=?%n-bumEtqU)~QnbF|0eg?2wc_*qz~Z#a`$UkK?>%Jo_ic_RCA{ zpAE-tI*7njofDigO0tTU(gA{R~=Xv5G>G+$lf z!G551$Tdzsgn+xnbaBfOce}JN=FjtHufl_Bo#FY|rRv#Lu0bl&MEUo?gz{hF$p2ds zpCN*iwPGcZPD}j3`}h;!lz+2hTwMS@UcX(M03QZUCpLaZKG%V|#u+CcPGDb-j&kAa z&^b=#0-uRI=~RMjuC7{24g)Cmrt)(R(D(2NJhr`_+REr~c6#_0xGS)x+{F%eo&7mi+0%Iv zQJuV^O$w(I3L@^$1;Bk0DZMu?*61Z_u$qAhJ^%q&ij=$Np+ zb<0*G+|<&F6Gg*lDA6|5+lrzoV^1QrJCZQu=c*COb_sln?n}hXSTwL|oY3Y58K!Y--KLPi8iirG7)5>?%P3|nV`h*naU<3hp_npv`rtMq z>2&0P5lcpe(eS0sb(@;%5zSU2k4uHIKD=dJUD(*t*w_+kHCpS|g+tU}c}m)r$r|#5 zy)7M!m@$I_3Hsu;&QIm}s;1cwP>q=UAh*28e5pErb(mQl%8hdz$vSOq5gkXph7rxA zjE+b$nurObX$$g-#*;=i6GN+uZIBxf)&a1iZrMGmCk*T&sD{adVM>3QFgENrw#N3v WGuSq%PgrL^>1 Date: Wed, 19 Feb 2020 20:49:09 +0100 Subject: [PATCH 006/104] tidied makefile --- kernel/Makefile | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/kernel/Makefile b/kernel/Makefile index 7f544597..06729aa4 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -39,18 +39,8 @@ all: build/flash.bin build/card.sd make_Pi: build/kernelPi.img -CFLAGS += -pipe -CFLAGS += -std=gnu99 -CFLAGS += -ffreestanding -CFLAGS += -nostdinc -CFLAGS += -Wall -CFLAGS += -Werror -PFLAGS += -mfpu=vfp -#PFLAGS += -mfloat-abi=hard -PFLAGS += -march=armv6zk -PFLAGS += -mtune=arm1176jzf-s -PFLAGS += -nostartfiles -CFLAGS += -g +CFLAGS += -pipe -std=gnu99 -ffreestanding -nostdinc -Wall -Werror -g +PFLAGS += -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -nostartfiles run: build/flash.bin build/card.sd | builddir ${QEMU} -M versatilepb -cpu arm1176 -sd card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" @@ -118,18 +108,6 @@ build/%.o: %.c | builddir $(CC) $(CFLAGS) -Iinclude -c $< -o $@ clean: - rm -f $(OBJS) - rm -f *.img - rm -f *.elf - rm -f *.bin - rm -f *.map - rm -f drivers/*.o - rm -f fs/cmdline/buildfs - rm -f vm/*.o - rm -f tests/*.o - rm -f memory/*.o - rm -f data_structures/*.o - rm -f mq/*.o rm -rf build @echo "I'm persisting the SD card 'card.sd', you'll have to remove that yourself if you want to rebuild it." @echo "('rm sd.card')" From dfe447db50fee1502499ffe82c88f3c6368397a3 Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Wed, 19 Feb 2020 20:53:47 +0100 Subject: [PATCH 007/104] simplified source files in cmakelist --- CMakeLists.txt | 57 +++----------------------------------------------- 1 file changed, 3 insertions(+), 54 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 519a0d24..087aaa9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,60 +8,9 @@ cmake_minimum_required(VERSION 3.6) project(course_os) -set(SOURCE_FILES - kernel/argparse.c - kernel/data_structures/array_list.c - kernel/data_structures/bin_tree.c - kernel/data_structures/bitvector.c - kernel/data_structures/hash_map.c - kernel/data_structures/linked_list.c - kernel/data_structures/priority_queue.c - kernel/data_structures/ring_buffer.c - kernel/data_structures/swap_pqueue.c - kernel/drivers/clock.c - kernel/drivers/mmci.c - kernel/drivers/timer.c - kernel/drivers/uart.c - kernel/drivers/uart_pi.c - kernel/elf.c - kernel/fs/cmdline/fakelibs.c - kernel/fs/cmdline/main.c - kernel/fs/fat16/test.c - kernel/fs/fat16/file.c - kernel/fs/open_table.c - kernel/hw_handlers.c - kernel/interrupt.c - kernel/klibc.c - kernel/loader.c - kernel/memory/allocator.c - kernel/memory/mem_alloc.c - kernel/mmap.c - kernel/pi_light.c - kernel/pm.c - kernel/priorityQueue.c - kernel/process.c - kernel/process/process_api.c - kernel/process/scheduler.c - kernel/signals.c - kernel/tests.c - kernel/tests/test_fs.c - kernel/tests/test_hash_map.c - kernel/tests/test_mem_alloc.c - kernel/tests/test_priority_queue.c - kernel/tests/test_vm.c - kernel/tests/testingsuite_example/arrayfill/arrayfill.c - kernel/tests/testingsuite_example/arrayfill/tap.c - kernel/tests/testingsuite_example/arrayfill/testarrayfill.c - kernel/threads/kthreads.c - kernel/vm/fastlz/6pack.c - kernel/vm/fastlz/6unpack.c - kernel/vm/fastlz/fastlz.c - kernel/vm/frame.c - kernel/vm/swap_framework.c - kernel/vm/swap_fs.c - kernel/vm/vm.c - kernel/start.c -) +file(GLOB kernel_sources ./kernel/*.c ./kernel/**/*.c) + +set(SOURCE_FILES ${kernel_sources}) add_executable(course_os ${SOURCE_FILES}) From 4187be850088429155e504373cefbb73a677d513 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Thu, 20 Feb 2020 12:01:54 +0100 Subject: [PATCH 008/104] fixed segfault due to move to build dir --- kernel/Makefile | 12 ++++++------ kernel/fs/cmdline/Makefile | 4 ++-- kernel/fs/cmdline/fakelibs.c | 4 ++-- kernel/kernel.ld | 16 ++++++++-------- kernel/kernelPi.ld | 2 +- kernel/start.c | 2 +- .../uboot_configuration/uboot-commands-test.ubt | 2 ++ 7 files changed, 22 insertions(+), 20 deletions(-) create mode 100644 kernel/uboot_configuration/uboot-commands-test.ubt diff --git a/kernel/Makefile b/kernel/Makefile index 06729aa4..faf4d775 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,4 +1,3 @@ - include $(CURDIR)/../config.mk TOOLCHAIN_PATH:=$(CURDIR)/../$(TOOLCHAIN_DIR)/$(BARE_METAL_TARGET)/bin @@ -43,13 +42,14 @@ CFLAGS += -pipe -std=gnu99 -ffreestanding -nostdinc -Wall -Werror -g PFLAGS += -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -nostartfiles run: build/flash.bin build/card.sd | builddir - ${QEMU} -M versatilepb -cpu arm1176 -sd card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" + ${QEMU} -M versatilepb -cpu arm1176 -sd build/card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" test: build/flash.bin build/card.sd | builddir - ${QEMU} -M versatilepb -cpu arm1176 -sd card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" + @echo $(UBOOTBUILDFILE) + ${QEMU} -M versatilepb -cpu arm1176 -sd build/card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" run-debug: build/flash.bin build/card.sd | builddir - ${QEMU} -S -s -M versatilepb -cpu arm1176 -sd card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" + ${QEMU} -S -s -M versatilepb -cpu arm1176 -sd build/card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" gdb: | builddir ${GDB} -ex "target remote :1234" build/kernel.elf @@ -93,8 +93,8 @@ build/kernelPi.img: build/kernelPi.elf | builddir # End Pi Make -build/script.img: uboot_configuration/uboot-commands.ubt | builddir - $(MKIMAGE) -A arm -C none -T script -d $< -a 0x10000 -e 0x10000 $@ +build/script.img: $(UBOOTBUILDFILE) | builddir + $(MKIMAGE) -A arm -C none -T script -d uboot_configuration/uboot-commands.ubt -a 0x10000 -e 0x10000 $@ build/course_os.img: build/kernel.img | builddir cat ../u-boot/u-boot-$(UBOOT_VERSION)/u-boot.bin $< > $@ diff --git a/kernel/fs/cmdline/Makefile b/kernel/fs/cmdline/Makefile index ee1f4b8e..c705457d 100755 --- a/kernel/fs/cmdline/Makefile +++ b/kernel/fs/cmdline/Makefile @@ -31,8 +31,8 @@ open_table.o: ../open_table.c %.o: %.c $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ -card.sd: - dd if=/dev/zero of=card.sd conv=notrunc bs=512 count=250000 +build/card.sd: + dd if=/dev/zero of=$@ conv=notrunc bs=512 count=250000 clean: rm -f $(OBJS) diff --git a/kernel/fs/cmdline/fakelibs.c b/kernel/fs/cmdline/fakelibs.c index 5594d094..3b79ae18 100644 --- a/kernel/fs/cmdline/fakelibs.c +++ b/kernel/fs/cmdline/fakelibs.c @@ -53,7 +53,7 @@ int init_sd() int sd_transmit(void *data, uint32_t addr) { - FILE *f = fopen("card.sd", "r+"); + FILE *f = fopen("build/card.sd", "r+"); fseek(f, addr, SEEK_SET); fwrite(data, 1, 512, f); fclose(f); @@ -62,7 +62,7 @@ int sd_transmit(void *data, uint32_t addr) int sd_receive(void *data, uint32_t addr) { - FILE *f = fopen("card.sd", "r+"); + FILE *f = fopen("build/card.sd", "r+"); fseek(f, addr, SEEK_SET); fread(data, 1, 512, f); fclose(f); diff --git a/kernel/kernel.ld b/kernel/kernel.ld index cf74c7f2..56c14327 100644 --- a/kernel/kernel.ld +++ b/kernel/kernel.ld @@ -1,13 +1,13 @@ ENTRY(_Reset) SECTIONS { - . = 0x10000; - .startup . : { build/startup.o(.text) } - .text : { *(.text) } - .data : { *(.data) } - .bss : { *(.bss COMMON) } - . = ALIGN(8); - . = . + 0x1000; - stack_top = .; + . = 0x10000; + .startup . : { build/startup.o(.text) } + .text : { *(.text) } + .data : { *(.data) } + .bss : { *(.bss COMMON) } + . = ALIGN(8); + . = . + 0x1000; + stack_top = .; } diff --git a/kernel/kernelPi.ld b/kernel/kernelPi.ld index 4b9b4529..b8f58421 100644 --- a/kernel/kernelPi.ld +++ b/kernel/kernelPi.ld @@ -2,7 +2,7 @@ ENTRY(_Reset) SECTIONS { . = 0x8000; - .startup . : { startup.o(.text) } + .startup . : { build/startup.o(.text) } .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss COMMON) } diff --git a/kernel/start.c b/kernel/start.c index 39e960a9..66919e37 100644 --- a/kernel/start.c +++ b/kernel/start.c @@ -106,7 +106,7 @@ void start2(uint32_t *p_bootargs) initialize_timers(); //assert(1==2 && "Test assert please ignore"); - process_init(); + process_init(); sched_init(); diff --git a/kernel/uboot_configuration/uboot-commands-test.ubt b/kernel/uboot_configuration/uboot-commands-test.ubt new file mode 100644 index 00000000..49141e8a --- /dev/null +++ b/kernel/uboot_configuration/uboot-commands-test.ubt @@ -0,0 +1,2 @@ +setenv bootargs root=/dev/ram mem=128M -test +bootm 0x210000 From 868d6bb38d4c9cd579861384d076aca5192e54e3 Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Thu, 20 Feb 2020 12:10:20 +0100 Subject: [PATCH 009/104] Updated gdb to 9.1 (so that it works with py3) --- toolchain/build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toolchain/build.sh b/toolchain/build.sh index 098c8478..508235bd 100755 --- a/toolchain/build.sh +++ b/toolchain/build.sh @@ -9,7 +9,7 @@ URL=ftp://ftp.gnu.org/gnu GCC_VERSION=4.8.1 BINUTILS_VERSION=2.24 NEWLIB_VERSION=2.0.0 -GDB_VERSION=7.7 +GDB_VERSION=9.1 GDB_EXT_VERSION=${GDB_VERSION} if [ -e ${PREFIX} ]; then @@ -43,7 +43,7 @@ fi cd ${TARGET}/src -if [ ! -d ${TARGET}/src/gcc-${GCC_VERSION} ]; then +if [ ! -d ${TARGET}/src/gcc-${GCC_VERSION} ]; then tar xvf ../orig/gcc-${GCC_VERSION}.tar.gz || exit 1; fi From 486381d8f24ca668295ff5994f8a88c7aee08de2 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Thu, 20 Feb 2020 13:22:27 +0100 Subject: [PATCH 010/104] moved process related code to processs/ --- kernel/Makefile | 4 ++-- kernel/{ => process}/elf.c | 0 kernel/{ => process}/process.c | 0 kernel/{ => process}/signals.c | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename kernel/{ => process}/elf.c (100%) rename kernel/{ => process}/process.c (100%) rename kernel/{ => process}/signals.c (100%) diff --git a/kernel/Makefile b/kernel/Makefile index faf4d775..cd5cd219 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -9,8 +9,8 @@ MKIMAGE:=$(CURDIR)/../u-boot/u-boot-$(UBOOT_VERSION)/tools/mkimage GDB:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gdb COMMONOBJS = build/start.o build/startup.o build/argparse.o \ - build/klibc.o build/interrupt.o build/process.o \ - build/hw_handlers.o build/elf.o build/loader.o \ + build/klibc.o build/interrupt.o build/process/process.o \ + build/hw_handlers.o build/process/elf.o build/loader.o \ build/memory/mem_alloc.o build/memory/allocator.o \ build/mmap.o build/vm/frame.o build/vm/vm.o \ build/drivers/timer.o build/data_structures/bitvector.o \ diff --git a/kernel/elf.c b/kernel/process/elf.c similarity index 100% rename from kernel/elf.c rename to kernel/process/elf.c diff --git a/kernel/process.c b/kernel/process/process.c similarity index 100% rename from kernel/process.c rename to kernel/process/process.c diff --git a/kernel/signals.c b/kernel/process/signals.c similarity index 100% rename from kernel/signals.c rename to kernel/process/signals.c From 813f87a08582f2a20c86deca5edde7b6d390cf44 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Thu, 20 Feb 2020 14:42:17 +0100 Subject: [PATCH 011/104] cleaned up the root folder --- kernel/Makefile | 28 +++++++--------- kernel/config.mk | 0 kernel/{ => legacy}/os_longjmp.s | 0 kernel/{ => legacy}/os_setjmp.s | 0 kernel/{ => legacy}/pm.c | 0 kernel/{ => legacy}/priorityQueue.c | 0 kernel/{ => main}/argparse.c | 0 kernel/{ => main}/interrupt.c | 0 kernel/{ => main}/klibc.c | 0 kernel/{ => main}/start.c | 2 +- kernel/{ => main}/startup.s | 0 kernel/{ => memory}/mmap.c | 2 +- kernel/{ => memory}/stacks.s | 0 kernel/{ => process}/loader.c | 0 kernel/process/stacks.s | 52 +++++++++++++++++++++++++++++ 15 files changed, 66 insertions(+), 18 deletions(-) create mode 100644 kernel/config.mk rename kernel/{ => legacy}/os_longjmp.s (100%) rename kernel/{ => legacy}/os_setjmp.s (100%) rename kernel/{ => legacy}/pm.c (100%) rename kernel/{ => legacy}/priorityQueue.c (100%) rename kernel/{ => main}/argparse.c (100%) rename kernel/{ => main}/interrupt.c (100%) rename kernel/{ => main}/klibc.c (100%) rename kernel/{ => main}/start.c (98%) rename kernel/{ => main}/startup.s (100%) rename kernel/{ => memory}/mmap.c (99%) rename kernel/{ => memory}/stacks.s (100%) rename kernel/{ => process}/loader.c (100%) create mode 100644 kernel/process/stacks.s diff --git a/kernel/Makefile b/kernel/Makefile index cd5cd219..7c40f4ce 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -8,17 +8,17 @@ OBJCOPY:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-objcopy MKIMAGE:=$(CURDIR)/../u-boot/u-boot-$(UBOOT_VERSION)/tools/mkimage GDB:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gdb -COMMONOBJS = build/start.o build/startup.o build/argparse.o \ - build/klibc.o build/interrupt.o build/process/process.o \ - build/hw_handlers.o build/process/elf.o build/loader.o \ - build/memory/mem_alloc.o build/memory/allocator.o \ - build/mmap.o build/vm/frame.o build/vm/vm.o \ - build/drivers/timer.o build/data_structures/bitvector.o \ - build/data_structures/array_list.o \ - build/data_structures/priority_queue.o \ - build/data_structures/linked_list.o \ - build/data_structures/hash_map.o build/process/scheduler.o \ - build/fs/open_table.o build/fs/fat16/file.o \ +COMMONOBJS = build/start.o build/startup.o build/main/argparse.o \ + build/main/klibc.o build/interrupt.o build/process/process.o \ + build/hw_handlers.o build/process/elf.o build/process/loader.o \ + build/memory/mem_alloc.o build/memory/allocator.o \ + build/memory/mmap.o build/vm/frame.o build/vm/vm.o \ + build/drivers/timer.o build/data_structures/bitvector.o \ + build/data_structures/array_list.o \ + build/data_structures/priority_queue.o \ + build/data_structures/linked_list.o \ + build/data_structures/hash_map.o build/process/scheduler.o \ + build/fs/open_table.o build/fs/fat16/file.o \ build/drivers/mmci.o @@ -44,10 +44,6 @@ PFLAGS += -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -nostartfiles run: build/flash.bin build/card.sd | builddir ${QEMU} -M versatilepb -cpu arm1176 -sd build/card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" -test: build/flash.bin build/card.sd | builddir - @echo $(UBOOTBUILDFILE) - ${QEMU} -M versatilepb -cpu arm1176 -sd build/card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" - run-debug: build/flash.bin build/card.sd | builddir ${QEMU} -S -s -M versatilepb -cpu arm1176 -sd build/card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" @@ -99,7 +95,7 @@ build/script.img: $(UBOOTBUILDFILE) | builddir build/course_os.img: build/kernel.img | builddir cat ../u-boot/u-boot-$(UBOOT_VERSION)/u-boot.bin $< > $@ -build/startup.o: startup.s | builddir +build/startup.o: main/startup.s | builddir @mkdir -p $(shell dirname $@) $(AS) -mcpu=arm1176jzf-s -g $< -o $@ diff --git a/kernel/config.mk b/kernel/config.mk new file mode 100644 index 00000000..e69de29b diff --git a/kernel/os_longjmp.s b/kernel/legacy/os_longjmp.s similarity index 100% rename from kernel/os_longjmp.s rename to kernel/legacy/os_longjmp.s diff --git a/kernel/os_setjmp.s b/kernel/legacy/os_setjmp.s similarity index 100% rename from kernel/os_setjmp.s rename to kernel/legacy/os_setjmp.s diff --git a/kernel/pm.c b/kernel/legacy/pm.c similarity index 100% rename from kernel/pm.c rename to kernel/legacy/pm.c diff --git a/kernel/priorityQueue.c b/kernel/legacy/priorityQueue.c similarity index 100% rename from kernel/priorityQueue.c rename to kernel/legacy/priorityQueue.c diff --git a/kernel/argparse.c b/kernel/main/argparse.c similarity index 100% rename from kernel/argparse.c rename to kernel/main/argparse.c diff --git a/kernel/interrupt.c b/kernel/main/interrupt.c similarity index 100% rename from kernel/interrupt.c rename to kernel/main/interrupt.c diff --git a/kernel/klibc.c b/kernel/main/klibc.c similarity index 100% rename from kernel/klibc.c rename to kernel/main/klibc.c diff --git a/kernel/start.c b/kernel/main/start.c similarity index 98% rename from kernel/start.c rename to kernel/main/start.c index 66919e37..890e4a4d 100644 --- a/kernel/start.c +++ b/kernel/main/start.c @@ -36,7 +36,7 @@ #include "scheduler.h" // Tests -#include "tests/test_klibc.h" +#include "../tests/test_klibc.h" #include "tests/test_hash_map.h" #include "tests/test_mem_alloc.h" #include "tests/test_vm.h" diff --git a/kernel/startup.s b/kernel/main/startup.s similarity index 100% rename from kernel/startup.s rename to kernel/main/startup.s diff --git a/kernel/mmap.c b/kernel/memory/mmap.c similarity index 99% rename from kernel/mmap.c rename to kernel/memory/mmap.c index ee8341ab..726166d0 100644 --- a/kernel/mmap.c +++ b/kernel/memory/mmap.c @@ -172,7 +172,7 @@ void mmap(void *p_bootargs) asm volatile("mov r0, %[args]" : : [args] "r" (p_bootargs)); asm volatile("cpsie if"); - asm volatile (".include \"stacks.s\""); + asm volatile (".include \"memory/stacks.s\""); //branch to proper kernel at start asm volatile("bl start2"); diff --git a/kernel/stacks.s b/kernel/memory/stacks.s similarity index 100% rename from kernel/stacks.s rename to kernel/memory/stacks.s diff --git a/kernel/loader.c b/kernel/process/loader.c similarity index 100% rename from kernel/loader.c rename to kernel/process/loader.c diff --git a/kernel/process/stacks.s b/kernel/process/stacks.s new file mode 100644 index 00000000..e0768994 --- /dev/null +++ b/kernel/process/stacks.s @@ -0,0 +1,52 @@ +.equ stack_size, 0x1000 +.equ stack_base, 0xfffff000 + +.equ Mode_USR, 0x10 +.equ Mode_FIQ, 0x11 +.equ Mode_IRQ, 0x12 +.equ Mode_SVC, 0x13 +.equ Mode_MON, 0x16 +.equ Mode_ABT, 0x17 +.equ Mode_UND, 0x1B +.equ Mode_SYS, 0x1F + + MOV R1, R0 // R0 has p_bootargs, which we need to hang onto + LDR R0, =stack_base + MSR CPSR_c, #Mode_FIQ + MOV sp, R0 + SUB R0, R0, #stack_size + + MSR CPSR_c, #Mode_IRQ + MOV sp, R0 + SUB R0, R0, #stack_size + + MSR CPSR_c, #Mode_SVC + MOV sp, R0 + SUB R0, R0, #stack_size + + MSR CPSR_c, #Mode_MON + MOV sp, R0 + SUB R0, R0, #stack_size + + MSR CPSR_c, #Mode_ABT + MOV sp, R0 + SUB R0, R0, #stack_size + + MSR CPSR_c, #Mode_UND + MOV sp, R0 + SUB R0, R0, #stack_size + + MSR CPSR_c, #Mode_SYS + MOV sp, R0 + + MSR CPSR_c, #Mode_SVC + ADD fp, sp, #0 + + EOR R0, R0 + ADD R0, pc, #0xf0000000 + MOV pc, R0 + + EOR R0, R0 + ADD R0, lr, #0xf0000000 + MOV lr, R0 + MOV R0, R1 From 8fd7dce4c54173aa3f55ba91d5b30b46add5baaf Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Thu, 20 Feb 2020 22:21:06 +0100 Subject: [PATCH 012/104] huge refactor of all source files. --- .gitignore | 5 + CMakeLists.txt | 9 +- config.mk | 1 - kernel/Makefile | 138 +++++++-------- kernel/Makefile.old | 109 ++++++++++++ kernel/config.mk | 0 kernel/include/.DS_Store | Bin 6148 -> 0 bytes kernel/include/drivers/clock.h | 7 - kernel/include/global_defs.h | 30 ---- kernel/{ => linker}/kernel.ld | 2 +- kernel/{ => linker}/kernelPi.ld | 2 +- kernel/{ => old}/drivers/clock.c | 2 +- kernel/{ => old}/fs/cmdline/Documents | 0 kernel/{ => old}/fs/cmdline/Makefile | 2 +- kernel/{ => old}/fs/cmdline/fakelibs.c | 2 +- .../include/data_structures/bitvector.h | 0 .../include/data_structures/linked_list.h | 0 .../fs/cmdline/include/drivers/mmci.h | 0 kernel/{ => old}/fs/cmdline/include/fs | 0 .../fs/cmdline/include/global_defs.h | 0 kernel/{ => old}/fs/cmdline/include/klibc.h | 0 kernel/{ => old}/fs/cmdline/main.c | 0 kernel/{ => old}/fs/fat16/file.c | 2 +- kernel/{ => old}/fs/fat16/test.c | 0 .../{ => old}/fs/fat16/test_superblock.data | 0 kernel/{ => old}/fs/fat16/test_superblock.txt | 0 kernel/{ => old}/fs/open_table.c | 2 +- kernel/old/include/drivers/clock.h | 7 + kernel/{ => old}/include/fs/file.h | 2 +- kernel/{ => old}/include/fs/open_table.h | 0 kernel/{ => old}/include/klibc.h | 4 +- kernel/{ => old}/include/misc_defs.h | 2 +- kernel/{ => old}/include/os_setjmp.h | 0 kernel/{ => old}/include/pi_light.h | 0 kernel/{ => old}/include/pm.h | 2 +- kernel/{ => old}/include/priorityQueue.h | 2 +- kernel/{ => old}/include/tests.h | 0 .../{ => old}/include/tests/test_hash_map.h | 0 .../{ => old}/include/tests/test_mem_alloc.h | 0 .../include/tests/test_priority_queue.h | 0 kernel/{ => old}/include/tests/test_vm.h | 0 kernel/{ => old}/legacy/os_longjmp.s | 0 kernel/{ => old}/legacy/os_setjmp.s | 0 kernel/{ => old}/legacy/pm.c | 6 +- kernel/{ => old}/legacy/priorityQueue.c | 0 kernel/{ => old}/tests/Makefile | 0 kernel/{ => old}/tests/test_fs.c | 0 kernel/{ => old}/tests/test_hash_map.c | 0 kernel/{ => old}/tests/test_klibc.h | 0 kernel/{ => old}/tests/test_mem_alloc.c | 0 kernel/{ => old}/tests/test_priority_queue.c | 0 kernel/{ => old}/tests/test_vm.c | 0 .../testingsuite_example/arrayfill/a.out | Bin .../arrayfill/arrayfill.c | 0 .../arrayfill/arrayfill.h | 0 .../testingsuite_example/arrayfill/tap.c | 2 +- .../testingsuite_example/arrayfill/tap.h | 2 +- .../arrayfill/testarrayfill.c | 2 +- kernel/pi_light.c | 2 +- kernel/process/process_api.c | 38 ---- kernel/process/stacks.s | 52 ------ kernel/{main => src/common}/argparse.c | 16 +- kernel/{ => src/common}/hw_handlers.c | 48 +++-- kernel/{ => src/common}/include/argparse.h | 0 kernel/{ => src/common}/include/hw_handlers.h | 2 +- kernel/{ => src/common}/include/interrupt.h | 2 +- kernel/{main => src/common}/interrupt.c | 5 +- kernel/{main => src/common}/start.c | 48 ++--- kernel/{main => src/common}/startup.s | 0 .../drivers/mmci/include}/mmci.h | 0 kernel/{drivers => src/drivers/mmci}/mmci.c | 6 +- .../drivers/time/include}/timer.h | 2 +- kernel/{drivers => src/drivers/time}/timer.c | 8 +- .../drivers/uart/include}/uart.h | 0 kernel/{drivers => src/drivers/uart}/uart.c | 7 +- .../{drivers => src/drivers/uart}/uart_pi.c | 7 +- .../{data_structures => src/ds}/array_list.c | 3 +- .../bin_tree.c => src/ds/bin_tree.c.old} | 2 +- .../{data_structures => src/ds}/bitvector.c | 4 +- kernel/{data_structures => src/ds}/hash_map.c | 4 +- .../ds/include}/array_list.h | 4 +- .../ds/include}/bin_tree.h | 0 .../ds/include}/bitvector.h | 2 +- .../ds/include}/hash_map.h | 0 .../ds/include}/linked_list.h | 0 .../ds/include}/priority_queue.h | 0 .../ds/include}/ring_buffer.h | 0 .../{data_structures => src/ds}/linked_list.c | 4 +- .../ds}/priority_queue.c | 4 +- .../ds/ring_buffer.c.old} | 2 +- .../{ => src/klibc}/include/bits/alltypes.h | 0 kernel/{ => src/klibc}/include/bits/stdint.h | 0 kernel/src/klibc/include/klibc.h | 167 ++++++++++++++++++ kernel/{ => src/klibc}/include/stdarg.h | 0 kernel/src/klibc/include/stdbool.h | 10 ++ kernel/{ => src/klibc}/include/stdint.h | 0 kernel/src/klibc/include/stdio.h | 6 + kernel/{main => src/klibc}/klibc.c | 41 ++--- kernel/{ => src/kthread}/include/kthread.h | 2 + .../kthreads.c => src/kthread/kthreads.c.old} | 5 +- kernel/{ => src}/memory/allocator.c | 5 +- kernel/{ => src/memory}/include/allocator.h | 3 +- kernel/{ => src/memory}/include/mem_alloc.h | 3 +- kernel/{ => src/memory}/include/memory.h | 0 kernel/{ => src/memory}/include/mmap.h | 0 kernel/{ => src}/memory/mem_alloc.c | 0 kernel/{ => src}/memory/mmap.c | 10 +- kernel/{ => src}/memory/stacks.s | 0 .../memory/vm/fastlz/6pack.c.old} | 2 +- .../memory/vm/fastlz/6unpack.c.old} | 4 +- kernel/{ => src/memory}/vm/fastlz/LICENSE | 0 kernel/{ => src/memory}/vm/fastlz/README.TXT | 0 .../memory/vm/fastlz/fastlz.c.old} | 6 +- .../memory/vm/fastlz/fastlz.h.old} | 0 kernel/{ => src/memory}/vm/frame.c | 0 kernel/{vm => src/memory/vm/include}/frame.h | 0 .../memory/vm}/include/swap_framework.h | 10 +- kernel/{ => src/memory/vm}/include/swap_fs.h | 4 +- .../{ => src/memory/vm}/include/swap_pqueue.h | 2 +- kernel/{ => src/memory/vm}/include/vm.h | 15 +- kernel/{ => src/memory}/vm/memory-layout.svg | 0 .../memory/vm/swap_framework.c.old} | 14 +- .../swap_fs.c => src/memory/vm/swap_fs.c.old} | 0 .../memory/vm/swap_pqueue.c.old} | 2 +- kernel/{ => src/memory}/vm/vm.c | 8 +- kernel/{ => src}/process/elf.c | 2 +- kernel/{ => src/process}/include/elf.h | 2 +- kernel/{ => src/process}/include/loader.h | 5 +- kernel/{ => src/process}/include/process.h | 4 +- kernel/{ => src/process}/include/scheduler.h | 11 +- .../process/include/signals.h.old} | 2 +- kernel/{ => src}/process/loader.c | 2 +- kernel/{ => src}/process/process.c | 91 +++++----- kernel/{ => src}/process/scheduler.c | 19 +- .../signals.c => src/process/signals.c.old} | 4 +- kernel/tests/testingsuite_example/.DS_Store | Bin 6148 -> 0 bytes kernel/uboot_configuration/generate.sh | 8 + .../uboot-commands-test.ubt | 2 - kernel/uboot_configuration/uboot-commands.ubt | 4 +- user/include/elf.h | 2 +- user/include/inttypes.h | 2 +- user/include/malloc_syscalls.h | 2 +- user/libc/exit/exit.c | 2 +- user/libc/file_system/fs_syscalls.c | 2 +- user/libc/internal/atomic.h | 2 +- user/libc/internal/libm.h | 2 +- user/libc/malloc/malloc_syscalls.c | 4 +- user/libc/math/frexp.c | 2 +- user/libc/stdio/printf.c | 2 +- user/libc/stdio/vfprintf.c | 2 +- user/libc/string/memchr.c | 2 +- user/libc/string/memcpy.c | 2 +- user/libc/string/memset.c | 2 +- 153 files changed, 658 insertions(+), 463 deletions(-) create mode 100644 kernel/Makefile.old delete mode 100644 kernel/config.mk delete mode 100644 kernel/include/.DS_Store delete mode 100644 kernel/include/drivers/clock.h delete mode 100644 kernel/include/global_defs.h rename kernel/{ => linker}/kernel.ld (78%) rename kernel/{ => linker}/kernelPi.ld (76%) rename kernel/{ => old}/drivers/clock.c (91%) rename kernel/{ => old}/fs/cmdline/Documents (100%) rename kernel/{ => old}/fs/cmdline/Makefile (92%) rename kernel/{ => old}/fs/cmdline/fakelibs.c (95%) rename kernel/{ => old}/fs/cmdline/include/data_structures/bitvector.h (100%) rename kernel/{ => old}/fs/cmdline/include/data_structures/linked_list.h (100%) rename kernel/{ => old}/fs/cmdline/include/drivers/mmci.h (100%) rename kernel/{ => old}/fs/cmdline/include/fs (100%) rename kernel/{ => old}/fs/cmdline/include/global_defs.h (100%) rename kernel/{ => old}/fs/cmdline/include/klibc.h (100%) rename kernel/{ => old}/fs/cmdline/main.c (100%) rename kernel/{ => old}/fs/fat16/file.c (99%) rename kernel/{ => old}/fs/fat16/test.c (100%) rename kernel/{ => old}/fs/fat16/test_superblock.data (100%) rename kernel/{ => old}/fs/fat16/test_superblock.txt (100%) rename kernel/{ => old}/fs/open_table.c (98%) create mode 100644 kernel/old/include/drivers/clock.h rename kernel/{ => old}/include/fs/file.h (99%) rename kernel/{ => old}/include/fs/open_table.h (100%) rename kernel/{ => old}/include/klibc.h (98%) rename kernel/{ => old}/include/misc_defs.h (95%) rename kernel/{ => old}/include/os_setjmp.h (100%) rename kernel/{ => old}/include/pi_light.h (100%) rename kernel/{ => old}/include/pm.h (90%) rename kernel/{ => old}/include/priorityQueue.h (90%) rename kernel/{ => old}/include/tests.h (100%) rename kernel/{ => old}/include/tests/test_hash_map.h (100%) rename kernel/{ => old}/include/tests/test_mem_alloc.h (100%) rename kernel/{ => old}/include/tests/test_priority_queue.h (100%) rename kernel/{ => old}/include/tests/test_vm.h (100%) rename kernel/{ => old}/legacy/os_longjmp.s (100%) rename kernel/{ => old}/legacy/os_setjmp.s (100%) rename kernel/{ => old}/legacy/pm.c (93%) rename kernel/{ => old}/legacy/priorityQueue.c (100%) rename kernel/{ => old}/tests/Makefile (100%) rename kernel/{ => old}/tests/test_fs.c (100%) rename kernel/{ => old}/tests/test_hash_map.c (100%) rename kernel/{ => old}/tests/test_klibc.h (100%) rename kernel/{ => old}/tests/test_mem_alloc.c (100%) rename kernel/{ => old}/tests/test_priority_queue.c (100%) rename kernel/{ => old}/tests/test_vm.c (100%) rename kernel/{ => old}/tests/testingsuite_example/arrayfill/a.out (100%) rename kernel/{ => old}/tests/testingsuite_example/arrayfill/arrayfill.c (100%) rename kernel/{ => old}/tests/testingsuite_example/arrayfill/arrayfill.h (100%) rename kernel/{ => old}/tests/testingsuite_example/arrayfill/tap.c (99%) rename kernel/{ => old}/tests/testingsuite_example/arrayfill/tap.h (98%) rename kernel/{ => old}/tests/testingsuite_example/arrayfill/testarrayfill.c (94%) delete mode 100644 kernel/process/process_api.c delete mode 100644 kernel/process/stacks.s rename kernel/{main => src/common}/argparse.c (93%) rename kernel/{ => src/common}/hw_handlers.c (90%) rename kernel/{ => src/common}/include/argparse.h (100%) rename kernel/{ => src/common}/include/hw_handlers.h (99%) rename kernel/{ => src/common}/include/interrupt.h (99%) rename kernel/{main => src/common}/interrupt.c (98%) rename kernel/{main => src/common}/start.c (80%) rename kernel/{main => src/common}/startup.s (100%) rename kernel/{include/drivers => src/drivers/mmci/include}/mmci.h (100%) rename kernel/{drivers => src/drivers/mmci}/mmci.c (98%) rename kernel/{include/drivers => src/drivers/time/include}/timer.h (96%) rename kernel/{drivers => src/drivers/time}/timer.c (98%) rename kernel/{include/drivers => src/drivers/uart/include}/uart.h (100%) rename kernel/{drivers => src/drivers/uart}/uart.c (93%) rename kernel/{drivers => src/drivers/uart}/uart_pi.c (97%) rename kernel/{data_structures => src/ds}/array_list.c (98%) rename kernel/{data_structures/bin_tree.c => src/ds/bin_tree.c.old} (99%) rename kernel/{data_structures => src/ds}/bitvector.c (98%) rename kernel/{data_structures => src/ds}/hash_map.c (98%) rename kernel/{include/data_structures => src/ds/include}/array_list.h (92%) rename kernel/{include/data_structures => src/ds/include}/bin_tree.h (100%) rename kernel/{include/data_structures => src/ds/include}/bitvector.h (98%) rename kernel/{include/data_structures => src/ds/include}/hash_map.h (100%) rename kernel/{include/data_structures => src/ds/include}/linked_list.h (100%) rename kernel/{include/data_structures => src/ds/include}/priority_queue.h (100%) rename kernel/{include/data_structures => src/ds/include}/ring_buffer.h (100%) rename kernel/{data_structures => src/ds}/linked_list.c (97%) rename kernel/{data_structures => src/ds}/priority_queue.c (98%) rename kernel/{data_structures/ring_buffer.c => src/ds/ring_buffer.c.old} (98%) rename kernel/{ => src/klibc}/include/bits/alltypes.h (100%) rename kernel/{ => src/klibc}/include/bits/stdint.h (100%) create mode 100644 kernel/src/klibc/include/klibc.h rename kernel/{ => src/klibc}/include/stdarg.h (100%) create mode 100644 kernel/src/klibc/include/stdbool.h rename kernel/{ => src/klibc}/include/stdint.h (100%) create mode 100644 kernel/src/klibc/include/stdio.h rename kernel/{main => src/klibc}/klibc.c (93%) rename kernel/{ => src/kthread}/include/kthread.h (94%) rename kernel/{threads/kthreads.c => src/kthread/kthreads.c.old} (86%) rename kernel/{ => src}/memory/allocator.c (99%) rename kernel/{ => src/memory}/include/allocator.h (95%) rename kernel/{ => src/memory}/include/mem_alloc.h (96%) rename kernel/{ => src/memory}/include/memory.h (100%) rename kernel/{ => src/memory}/include/mmap.h (100%) rename kernel/{ => src}/memory/mem_alloc.c (100%) rename kernel/{ => src}/memory/mmap.c (97%) rename kernel/{ => src}/memory/stacks.s (100%) rename kernel/{vm/fastlz/6pack.c => src/memory/vm/fastlz/6pack.c.old} (99%) rename kernel/{vm/fastlz/6unpack.c => src/memory/vm/fastlz/6unpack.c.old} (99%) rename kernel/{ => src/memory}/vm/fastlz/LICENSE (100%) rename kernel/{ => src/memory}/vm/fastlz/README.TXT (100%) rename kernel/{vm/fastlz/fastlz.c => src/memory/vm/fastlz/fastlz.c.old} (99%) rename kernel/{vm/fastlz/fastlz.h => src/memory/vm/fastlz/fastlz.h.old} (100%) rename kernel/{ => src/memory}/vm/frame.c (100%) rename kernel/{vm => src/memory/vm/include}/frame.h (100%) rename kernel/{ => src/memory/vm}/include/swap_framework.h (93%) rename kernel/{ => src/memory/vm}/include/swap_fs.h (87%) rename kernel/{ => src/memory/vm}/include/swap_pqueue.h (98%) rename kernel/{ => src/memory/vm}/include/vm.h (90%) rename kernel/{ => src/memory}/vm/memory-layout.svg (100%) rename kernel/{vm/swap_framework.c => src/memory/vm/swap_framework.c.old} (97%) rename kernel/{vm/swap_fs.c => src/memory/vm/swap_fs.c.old} (100%) rename kernel/{data_structures/swap_pqueue.c => src/memory/vm/swap_pqueue.c.old} (99%) rename kernel/{ => src/memory}/vm/vm.c (93%) rename kernel/{ => src}/process/elf.c (98%) rename kernel/{ => src/process}/include/elf.h (99%) rename kernel/{ => src/process}/include/loader.h (83%) rename kernel/{ => src/process}/include/process.h (99%) rename kernel/{ => src/process}/include/scheduler.h (90%) rename kernel/{include/signals.h => src/process/include/signals.h.old} (89%) rename kernel/{ => src}/process/loader.c (97%) rename kernel/{ => src}/process/process.c (81%) rename kernel/{ => src}/process/scheduler.c (98%) rename kernel/{process/signals.c => src/process/signals.c.old} (84%) delete mode 100644 kernel/tests/testingsuite_example/.DS_Store mode change 100644 => 100755 kernel/uboot_configuration/generate.sh delete mode 100644 kernel/uboot_configuration/uboot-commands-test.ubt diff --git a/.gitignore b/.gitignore index ab59ff6e..5f1972e3 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,9 @@ build/ Session.vim .netrwhist +.floo +.flooignore + +uboot-commands.ubt + NOTES diff --git a/CMakeLists.txt b/CMakeLists.txt index 087aaa9d..e2f4c505 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,10 +8,15 @@ cmake_minimum_required(VERSION 3.6) project(course_os) -file(GLOB kernel_sources ./kernel/*.c ./kernel/**/*.c) +file(GLOB_RECURSE kernel_sources ./kernel/src/*.c ./kernel/src/**/*.c) +file(GLOB_RECURSE kernel_include LIST_DIRECTORIES true ./kernel/src/**/include) set(SOURCE_FILES ${kernel_sources}) add_executable(course_os ${SOURCE_FILES}) -include_directories(kernel/include) +message(${kernel_include}) + +include_directories( + ${kernel_include} +) diff --git a/config.mk b/config.mk index d1924e66..1cb1f7d0 100644 --- a/config.mk +++ b/config.mk @@ -5,7 +5,6 @@ BARE_METAL_TARGET:=$(BARE_METAL_TUPLE) QEMU=qemu-system-arm -#UBOOT_VERSION=2010.03 UBOOT_VERSION=2014.10 #CFLAGS = -mcpu=arm1136j-s diff --git a/kernel/Makefile b/kernel/Makefile index 7c40f4ce..10761fb7 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,5 +1,23 @@ include $(CURDIR)/../config.mk +# ===================== Configuration ===================== + +# Flags to give to the c compiler +CFLAGS += -pipe -std=gnu99 -ffreestanding -nostdinc -Wall -Werror -g +PI_CFLAGS = -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -nostartfiles + +# variables to define in the preprocessor. +MEMORY = 128M +DEFINITIONS = +test: DEFINITIONS += TEST +KERNEL_PARAMS = root=/dev/ram mem=$(MEMORY) +SOURCEDIR = src +BUILDDIR = build +# every directory named `include` will have it's contents autoincluded +INCLUDEDIR = include + +# =================== End Configuration =================== + TOOLCHAIN_PATH:=$(CURDIR)/../$(TOOLCHAIN_DIR)/$(BARE_METAL_TARGET)/bin CC:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gcc AS:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-as @@ -8,102 +26,80 @@ OBJCOPY:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-objcopy MKIMAGE:=$(CURDIR)/../u-boot/u-boot-$(UBOOT_VERSION)/tools/mkimage GDB:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gdb -COMMONOBJS = build/start.o build/startup.o build/main/argparse.o \ - build/main/klibc.o build/interrupt.o build/process/process.o \ - build/hw_handlers.o build/process/elf.o build/process/loader.o \ - build/memory/mem_alloc.o build/memory/allocator.o \ - build/memory/mmap.o build/vm/frame.o build/vm/vm.o \ - build/drivers/timer.o build/data_structures/bitvector.o \ - build/data_structures/array_list.o \ - build/data_structures/priority_queue.o \ - build/data_structures/linked_list.o \ - build/data_structures/hash_map.o build/process/scheduler.o \ - build/fs/open_table.o build/fs/fat16/file.o \ - build/drivers/mmci.o - - - -TESTOBJS = build/tests.o build/tests/test_mem_alloc.o build/tests/test_hash_map.o \ - build/tests/test_priority_queue.o build/tests/test_vm.o \ - build/tests/test_fs.o - -PIOBJS = build/pi_light.o build/drivers/uart_pi.o -OBJS = build/drivers/uart.o - -OBJS += $(COMMONOBJS) $(TESTOBJS) -PIOBJS += $(COMMONOBJS) $(TESTOBJS) - +DIRS = $(shell find $(SOURCEDIR)/ -type d -print) +C_SOURCE_FILES := $(foreach dir,$(DIRS),$(wildcard $(dir)/*.c)) +C_OBJECT_FILES := $(patsubst $(SOURCEDIR)/%.c, \ + $(BUILDDIR)/%.o, $(C_SOURCE_FILES)) -all: build/flash.bin build/card.sd +S_SOURCE_FILES := $(foreach dir,$(DIRS),$(wildcard $(dir)/*.s)) +S_OBJECT_FILES := $(patsubst $(SOURCEDIR)/%.s, \ + $(BUILDDIR)/%.o, $(S_SOURCE_FILES)) -make_Pi: build/kernelPi.img +OBJECT_FILES := $(S_OBJECT_FILES) $(C_OBJECT_FILES) -CFLAGS += -pipe -std=gnu99 -ffreestanding -nostdinc -Wall -Werror -g -PFLAGS += -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -nostartfiles - -run: build/flash.bin build/card.sd | builddir - ${QEMU} -M versatilepb -cpu arm1176 -sd build/card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" +INCLUDEDIRS := $(sort $(foreach dir, $(foreach dir1, $(DIRS), $(shell dirname $(dir1))), $(wildcard $(dir)/$(INCLUDEDIR)))) +CFLAGS += $(foreach dir, $(INCLUDEDIRS), -I./$(dir)) +CFLAGS += $(foreach def, $(DEFINITIONS), -D$(def)) -run-debug: build/flash.bin build/card.sd | builddir - ${QEMU} -S -s -M versatilepb -cpu arm1176 -sd build/card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" +test: build | builddir + ${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" -gdb: | builddir - ${GDB} -ex "target remote :1234" build/kernel.elf +run: build | builddir + ${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" -builddir: - mkdir -p build +build: $(BUILDDIR)/card.sd $(BUILDDIR)/flash.bin | builddir +build_pi: $(BUILDDIR)/kernelPi.img | builddir -#boots the kernel at 0x210000 -build/flash.bin: build/kernel.img build/script.img | builddir +$(BUILDDIR)/flash.bin: $(BUILDDIR)/kernel.img $(BUILDDIR)/bootloader.img dd if=/dev/zero of=$@ bs=4k count=1536 - dd if=../u-boot/u-boot-$(UBOOT_VERSION)/u-boot.bin of=build/flash.bin conv=notrunc bs=4k - dd if=build/kernel.img of=$@ conv=notrunc bs=4k seek=512 - dd if=build/script.img of=$@ conv=notrunc bs=4k seek=575 + dd if=../u-boot/u-boot-$(UBOOT_VERSION)/u-boot.bin of=$@ conv=notrunc bs=4k + # kernel + dd if=$(BUILDDIR)/kernel.img of=$@ conv=notrunc bs=4k seek=512 + # bootloader + dd if=$(BUILDDIR)/bootloader.img of=$@ conv=notrunc bs=4k seek=575 -# 32678*4096 = 128MiB -build/card.sd: fs-cmdline userhello | builddir +$(BUILDDIR)/card.sd: | builddir dd if=/dev/zero of=$@ conv=notrunc bs=4096 count=32768 - fs/cmdline/buildfs ../user/hello/ -userhello: - make -C ../user/hello +$(BUILDDIR)/kernel.elf: $(OBJECT_FILES) | builddir + $(LD) -T linker/kernel.ld -nostartfiles -Wl,-Map,kernel.map $(OBJECT_FILES) -o $@ -fs-cmdline: - make -C fs/cmdline - -build/kernel.elf: $(OBJS) | builddir - $(LD) -T kernel.ld -nostartfiles -Wl,-Map,kernel.map $(OBJS) -o $@ - -build/kernel.bin: build/kernel.elf | builddir +$(BUILDDIR)/kernel.bin: $(BUILDDIR)/kernel.elf | builddir $(OBJCOPY) -O binary $< $@ -build/kernel.img: build/kernel.bin | builddir +$(BUILDDIR)/kernel.img: $(BUILDDIR)/kernel.bin | builddir $(MKIMAGE) -A arm -C none -O linux -T kernel -d $< -a 0x00010000 -e 0x00010000 $@ +# Begin bootloader Make +uboot_configuration/uboot-commands.ubt: $(and $(KERNEL_PARAMS),dummy) + uboot_configuration/generate.sh $(KERNEL_PARAMS) + +$(BUILDDIR)/bootloader.img: uboot_configuration/uboot-commands.ubt | builddir + $(MKIMAGE) -A arm -C none -T script -d $< -a 0x10000 -e 0x10000 $@ +# End bootloader make + # Begin Pi Make -build/kernelPi.elf: $(PIOBJS) | builddir - $(CC) -T kernelPi.ld -O2 $(PFLAGS) $(PIOBJS) -o $@ +$(BUILDDIR)/kernelPi.elf: $(C_OBJECT_FILES) | builddir + $(CC) -T kernelPi.ld -O2 $(PI_CFLAGS) $(C_OBJECT_FILES) -o $@ -build/kernelPi.img: build/kernelPi.elf | builddir +$(BUILDDIR)/kernelPi.img: $(BUILDDIR)/kernelPi.elf | builddir $(OBJCOPY) $< -O binary $@ - # End Pi Make -build/script.img: $(UBOOTBUILDFILE) | builddir - $(MKIMAGE) -A arm -C none -T script -d uboot_configuration/uboot-commands.ubt -a 0x10000 -e 0x10000 $@ - -build/course_os.img: build/kernel.img | builddir - cat ../u-boot/u-boot-$(UBOOT_VERSION)/u-boot.bin $< > $@ +builddir: + mkdir -p $(BUILDDIR) -build/startup.o: main/startup.s | builddir +$(BUILDDIR)/%.o: $(SOURCEDIR)/%.s | builddir @mkdir -p $(shell dirname $@) $(AS) -mcpu=arm1176jzf-s -g $< -o $@ -build/%.o: %.c | builddir +$(BUILDDIR)/%.o: $(SOURCEDIR)/%.c | builddir + @echo $(CFLAGS) @mkdir -p $(shell dirname $@) - $(CC) $(CFLAGS) -Iinclude -c $< -o $@ + $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -rf build - @echo "I'm persisting the SD card 'card.sd', you'll have to remove that yourself if you want to rebuild it." - @echo "('rm sd.card')" + rm -rf $(BUILDDIR) + +# use to force rebuild of certain recipes +dummy:; \ No newline at end of file diff --git a/kernel/Makefile.old b/kernel/Makefile.old new file mode 100644 index 00000000..b93fa430 --- /dev/null +++ b/kernel/Makefile.old @@ -0,0 +1,109 @@ +include $(CURDIR)/../config.mk + +TOOLCHAIN_PATH:=$(CURDIR)/../$(TOOLCHAIN_DIR)/$(BARE_METAL_TARGET)/bin +CC:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gcc +AS:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-as +LD:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gcc +OBJCOPY:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-objcopy +MKIMAGE:=$(CURDIR)/../u-boot/u-boot-$(UBOOT_VERSION)/tools/mkimage +GDB:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gdb + +COMMONOBJS = build/start.o build/startup.o build/main/argparse.o \ + build/main/klibc.o build/interrupt.o build/process/process.o \ + build/hw_handlers.o build/process/elf.o build/process/loader.o \ + build/memory/mem_alloc.o build/memory/allocator.o \ + build/memory/mmap.o build/vm/frame.o build/vm/vm.o \ + build/drivers/timer.o build/data_structures/bitvector.o \ + build/data_structures/array_list.o \ + build/data_structures/priority_queue.o \ + build/data_structures/linked_list.o \ + build/data_structures/hash_map.o build/process/scheduler.o \ + build/fs/open_table.o build/fs/fat16/file.o \ + build/drivers/mmci.o + + + +TESTOBJS = build/tests.o build/tests/test_mem_alloc.o build/tests/test_hash_map.o \ + build/tests/test_priority_queue.o build/tests/test_vm.o \ + build/tests/test_fs.o + +PIOBJS = build/pi_light.o build/drivers/uart_pi.o +OBJS = build/drivers/uart.o + +OBJS += $(COMMONOBJS) $(TESTOBJS) +PIOBJS += $(COMMONOBJS) $(TESTOBJS) + + +all: build/flash.bin build/card.sd + +make_Pi: build/kernelPi.img + +CFLAGS += -pipe -std=gnu99 -ffreestanding -nostdinc -Wall -Werror -g +PFLAGS += -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -nostartfiles + +run: build/flash.bin build/card.sd | builddir + ${QEMU} -M versatilepb -cpu arm1176 -sd build/card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" + +run-debug: build/flash.bin build/card.sd | builddir + ${QEMU} -S -s -M versatilepb -cpu arm1176 -sd build/card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" + +gdb: | builddir + ${GDB} -ex "target remote :1234" build/kernel.elf + +builddir: + mkdir -p build + +#boots the kernel at 0x210000 +build/flash.bin: build/kernel.img build/script.img | builddir + dd if=/dev/zero of=$@ bs=4k count=1536 + dd if=../u-boot/u-boot-$(UBOOT_VERSION)/u-boot.bin of=build/flash.bin conv=notrunc bs=4k + dd if=build/kernel.img of=$@ conv=notrunc bs=4k seek=512 + dd if=build/script.img of=$@ conv=notrunc bs=4k seek=575 + +# 32678*4096 = 128MiB +build/card.sd: fs-cmdline userhello | builddir + dd if=/dev/zero of=$@ conv=notrunc bs=4096 count=32768 + fs/cmdline/buildfs ../user/hello/ + +userhello: + make -C ../user/hello + +fs-cmdline: + make -C fs/cmdline + +build/kernel.elf: $(OBJS) | builddir + $(LD) -T kernel.ld -nostartfiles -Wl,-Map,kernel.map $(OBJS) -o $@ + +build/kernel.bin: build/kernel.elf | builddir + $(OBJCOPY) -O binary $< $@ + +build/kernel.img: build/kernel.bin | builddir + $(MKIMAGE) -A arm -C none -O linux -T kernel -d $< -a 0x00010000 -e 0x00010000 $@ + +# Begin Pi Make +build/kernelPi.elf: $(PIOBJS) | builddir + $(CC) -T kernelPi.ld -O2 $(PFLAGS) $(PIOBJS) -o $@ + +build/kernelPi.img: build/kernelPi.elf | builddir + $(OBJCOPY) $< -O binary $@ + +# End Pi Make + +build/script.img: $(UBOOTBUILDFILE) | builddir + $(MKIMAGE) -A arm -C none -T script -d uboot_configuration/uboot-commands.ubt -a 0x10000 -e 0x10000 $@ + +build/course_os.img: build/kernel.img | builddir + cat ../u-boot/u-boot-$(UBOOT_VERSION)/u-boot.bin $< > $@ + +build/startup.o: src/common | builddir + @mkdir -p $(shell dirname $@) + $(AS) -mcpu=arm1176jzf-s -g $< -o $@ + +build/%.o: %.c | builddir + @mkdir -p $(shell dirname $@) + $(CC) $(CFLAGS) -Iinclude -c $< -o $@ + +clean: + rm -rf build + @echo "I'm persisting the SD card 'card.sd', you'll have to remove that yourself if you want to rebuild it." + @echo "('rm sd.card')" diff --git a/kernel/config.mk b/kernel/config.mk deleted file mode 100644 index e69de29b..00000000 diff --git a/kernel/include/.DS_Store b/kernel/include/.DS_Store deleted file mode 100644 index b0f47a7fdf65b9111ba622d51689cf807f206003..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKPfNov6i>G4S_WFdgWhuUvcrbX>B%znjMa#BJc4=h1xK+4X$?FWZZYtVESw`H9AQQYdO;wWrE%E?g_hjP%6{Wwfc zJncM+!nCahH4e+NExYL~4TrVLMp;yAo1?NA*6WqBSgWs(M$VOOEw8L@?FI7k`sViT z{^9XS)6L<_RI*@j49{SES^0(6i#swthsd~UoJ~j!5Cg=(G%;Y#IIA>Gi=wp<1H{0u zFo5TS07Y~SW*XJe0S*2>V!VKe0ye%S5QRb4V5SiwAY7LM>QZi=7+jZwUzj}CV5U)* zGp=Taam>uzyimBB9sEM2Gwy1nmKY!gJ~NQlT?g;~-Jjq8pNptR3=jiT#Q-ntcsmVP zlDS(a7KeAO06ham!Msf4dkGloDu!IVikCo@fM1{i=o-v4f(L|t1QZR_5Ceb8z#HTx BTAcs@ diff --git a/kernel/include/drivers/clock.h b/kernel/include/drivers/clock.h deleted file mode 100644 index 817bbc98..00000000 --- a/kernel/include/drivers/clock.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef CLOCK_H -#define CLOCK_H - -#include -#include "../../include/mmap.h" - -#endif diff --git a/kernel/include/global_defs.h b/kernel/include/global_defs.h deleted file mode 100644 index ad90d0a6..00000000 --- a/kernel/include/global_defs.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _GLOBAL_DEFS_H_ -#define _GLOBAL_DEFS_H_ - -#include - -#define TRUE 1 -#define FALSE 0 - -#ifndef NULL -#define NULL ((void*) 0) -#endif - -typedef char *String; -typedef short Boolean; - -#ifndef __HOST -typedef uint32_t size_t; -#endif - -#define UNUSED(x) (void)(x) - -#define NBBY 8 - -#define STATUS_OK 0 -#define STATUS_FAIL -1 - -#define TEST_OK 0 -#define TEST_FAIL -1 - -#endif //defined _GLOBAL_DEFS_H_ diff --git a/kernel/kernel.ld b/kernel/linker/kernel.ld similarity index 78% rename from kernel/kernel.ld rename to kernel/linker/kernel.ld index 56c14327..db096f68 100644 --- a/kernel/kernel.ld +++ b/kernel/linker/kernel.ld @@ -2,7 +2,7 @@ ENTRY(_Reset) SECTIONS { . = 0x10000; - .startup . : { build/startup.o(.text) } + .startup . : { build/common/startup.o(.text) } .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss COMMON) } diff --git a/kernel/kernelPi.ld b/kernel/linker/kernelPi.ld similarity index 76% rename from kernel/kernelPi.ld rename to kernel/linker/kernelPi.ld index b8f58421..0f8a6d3b 100644 --- a/kernel/kernelPi.ld +++ b/kernel/linker/kernelPi.ld @@ -2,7 +2,7 @@ ENTRY(_Reset) SECTIONS { . = 0x8000; - .startup . : { build/startup.o(.text) } + .startup . : { build//common/startup.o(.text) } .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss COMMON) } diff --git a/kernel/drivers/clock.c b/kernel/old/drivers/clock.c similarity index 91% rename from kernel/drivers/clock.c rename to kernel/old/drivers/clock.c index 59d0c96e..e72bce54 100644 --- a/kernel/drivers/clock.c +++ b/kernel/old/drivers/clock.c @@ -1,4 +1,4 @@ -#include +#include "../../src/klibc//include/stdint.h" #include "clock.h" diff --git a/kernel/fs/cmdline/Documents b/kernel/old/fs/cmdline/Documents similarity index 100% rename from kernel/fs/cmdline/Documents rename to kernel/old/fs/cmdline/Documents diff --git a/kernel/fs/cmdline/Makefile b/kernel/old/fs/cmdline/Makefile similarity index 92% rename from kernel/fs/cmdline/Makefile rename to kernel/old/fs/cmdline/Makefile index c705457d..6d23e8a2 100755 --- a/kernel/fs/cmdline/Makefile +++ b/kernel/old/fs/cmdline/Makefile @@ -22,7 +22,7 @@ $(PROG): $(OBJS) file.o: ../fat16/file.c $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ -bitvector.o: ../../data_structures/bitvector.c +bitvector.o: ../../../src/ds $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ open_table.o: ../open_table.c diff --git a/kernel/fs/cmdline/fakelibs.c b/kernel/old/fs/cmdline/fakelibs.c similarity index 95% rename from kernel/fs/cmdline/fakelibs.c rename to kernel/old/fs/cmdline/fakelibs.c index 3b79ae18..fd8b1570 100644 --- a/kernel/fs/cmdline/fakelibs.c +++ b/kernel/old/fs/cmdline/fakelibs.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include "../../../src/klibc//include/stdint.h" /* Memory management */ diff --git a/kernel/fs/cmdline/include/data_structures/bitvector.h b/kernel/old/fs/cmdline/include/data_structures/bitvector.h similarity index 100% rename from kernel/fs/cmdline/include/data_structures/bitvector.h rename to kernel/old/fs/cmdline/include/data_structures/bitvector.h diff --git a/kernel/fs/cmdline/include/data_structures/linked_list.h b/kernel/old/fs/cmdline/include/data_structures/linked_list.h similarity index 100% rename from kernel/fs/cmdline/include/data_structures/linked_list.h rename to kernel/old/fs/cmdline/include/data_structures/linked_list.h diff --git a/kernel/fs/cmdline/include/drivers/mmci.h b/kernel/old/fs/cmdline/include/drivers/mmci.h similarity index 100% rename from kernel/fs/cmdline/include/drivers/mmci.h rename to kernel/old/fs/cmdline/include/drivers/mmci.h diff --git a/kernel/fs/cmdline/include/fs b/kernel/old/fs/cmdline/include/fs similarity index 100% rename from kernel/fs/cmdline/include/fs rename to kernel/old/fs/cmdline/include/fs diff --git a/kernel/fs/cmdline/include/global_defs.h b/kernel/old/fs/cmdline/include/global_defs.h similarity index 100% rename from kernel/fs/cmdline/include/global_defs.h rename to kernel/old/fs/cmdline/include/global_defs.h diff --git a/kernel/fs/cmdline/include/klibc.h b/kernel/old/fs/cmdline/include/klibc.h similarity index 100% rename from kernel/fs/cmdline/include/klibc.h rename to kernel/old/fs/cmdline/include/klibc.h diff --git a/kernel/fs/cmdline/main.c b/kernel/old/fs/cmdline/main.c similarity index 100% rename from kernel/fs/cmdline/main.c rename to kernel/old/fs/cmdline/main.c diff --git a/kernel/fs/fat16/file.c b/kernel/old/fs/fat16/file.c similarity index 99% rename from kernel/fs/fat16/file.c rename to kernel/old/fs/fat16/file.c index 8bb6d31b..ba4dbfcf 100644 --- a/kernel/fs/fat16/file.c +++ b/kernel/old/fs/fat16/file.c @@ -41,7 +41,7 @@ * - permissions * */ -#include +#include "../../../src/klibc//include/stdint.h" #include "klibc.h" #include "data_structures/bitvector.h" #include "fs/open_table.h" diff --git a/kernel/fs/fat16/test.c b/kernel/old/fs/fat16/test.c similarity index 100% rename from kernel/fs/fat16/test.c rename to kernel/old/fs/fat16/test.c diff --git a/kernel/fs/fat16/test_superblock.data b/kernel/old/fs/fat16/test_superblock.data similarity index 100% rename from kernel/fs/fat16/test_superblock.data rename to kernel/old/fs/fat16/test_superblock.data diff --git a/kernel/fs/fat16/test_superblock.txt b/kernel/old/fs/fat16/test_superblock.txt similarity index 100% rename from kernel/fs/fat16/test_superblock.txt rename to kernel/old/fs/fat16/test_superblock.txt diff --git a/kernel/fs/open_table.c b/kernel/old/fs/open_table.c similarity index 98% rename from kernel/fs/open_table.c rename to kernel/old/fs/open_table.c index efa075ac..1ff25d8c 100644 --- a/kernel/fs/open_table.c +++ b/kernel/old/fs/open_table.c @@ -7,7 +7,7 @@ #include "fs/file.h" #include "fs/open_table.h" #include "data_structures/bitvector.h" -#include +#include "../../src/klibc//include/stdint.h" //called by file.c initialization function, initializes free list and table diff --git a/kernel/old/include/drivers/clock.h b/kernel/old/include/drivers/clock.h new file mode 100644 index 00000000..a8d73a21 --- /dev/null +++ b/kernel/old/include/drivers/clock.h @@ -0,0 +1,7 @@ +#ifndef CLOCK_H +#define CLOCK_H + +#include "../../../src/klibc//include/stdint.h" +#include "mmap.h" + +#endif diff --git a/kernel/include/fs/file.h b/kernel/old/include/fs/file.h similarity index 99% rename from kernel/include/fs/file.h rename to kernel/old/include/fs/file.h index 078f3ebc..7efc8557 100644 --- a/kernel/include/fs/file.h +++ b/kernel/old/include/fs/file.h @@ -4,7 +4,7 @@ #include "global_defs.h" #include "data_structures/bitvector.h" #include "data_structures/linked_list.h" -#include +#include "../../../../../src/klibc//include/stdint.h" #define BLOCKSIZE 512 #define MAX_NAME_LENGTH 32 diff --git a/kernel/include/fs/open_table.h b/kernel/old/include/fs/open_table.h similarity index 100% rename from kernel/include/fs/open_table.h rename to kernel/old/include/fs/open_table.h diff --git a/kernel/include/klibc.h b/kernel/old/include/klibc.h similarity index 98% rename from kernel/include/klibc.h rename to kernel/old/include/klibc.h index f46061e0..554a224f 100644 --- a/kernel/include/klibc.h +++ b/kernel/old/include/klibc.h @@ -26,8 +26,8 @@ #ifndef __KLIBC_H__ #define __KLIBC_H__ -#include -#include +#include "../../src/klibc//include/stdint.h" +#include "../../src/klibc//include/stdarg.h" #include "global_defs.h" #ifndef __NO_WFI diff --git a/kernel/include/misc_defs.h b/kernel/old/include/misc_defs.h similarity index 95% rename from kernel/include/misc_defs.h rename to kernel/old/include/misc_defs.h index 40f0779b..884361fd 100644 --- a/kernel/include/misc_defs.h +++ b/kernel/old/include/misc_defs.h @@ -1,4 +1,4 @@ -#include +#include "../../src/klibc//include/stdint.h" /* Contained within this file is the base addresses to many of the Rasberry Pi's peripherals, diff --git a/kernel/include/os_setjmp.h b/kernel/old/include/os_setjmp.h similarity index 100% rename from kernel/include/os_setjmp.h rename to kernel/old/include/os_setjmp.h diff --git a/kernel/include/pi_light.h b/kernel/old/include/pi_light.h similarity index 100% rename from kernel/include/pi_light.h rename to kernel/old/include/pi_light.h diff --git a/kernel/include/pm.h b/kernel/old/include/pm.h similarity index 90% rename from kernel/include/pm.h rename to kernel/old/include/pm.h index c30c7e29..98980e69 100644 --- a/kernel/include/pm.h +++ b/kernel/old/include/pm.h @@ -2,7 +2,7 @@ #define _PM_H #include "klibc.h" #include "global_defs.h" -#include "stdint.h" +#include "../../src/klibc//include/stdint.h" #include "mmap.h" typedef struct diff --git a/kernel/include/priorityQueue.h b/kernel/old/include/priorityQueue.h similarity index 90% rename from kernel/include/priorityQueue.h rename to kernel/old/include/priorityQueue.h index 4dd889c3..124c6ee6 100644 --- a/kernel/include/priorityQueue.h +++ b/kernel/old/include/priorityQueue.h @@ -1,4 +1,4 @@ -#include "process.h" +#include "../../src/process/include/process.h" #include "global_defs.h" #define NOT_SET -1 diff --git a/kernel/include/tests.h b/kernel/old/include/tests.h similarity index 100% rename from kernel/include/tests.h rename to kernel/old/include/tests.h diff --git a/kernel/include/tests/test_hash_map.h b/kernel/old/include/tests/test_hash_map.h similarity index 100% rename from kernel/include/tests/test_hash_map.h rename to kernel/old/include/tests/test_hash_map.h diff --git a/kernel/include/tests/test_mem_alloc.h b/kernel/old/include/tests/test_mem_alloc.h similarity index 100% rename from kernel/include/tests/test_mem_alloc.h rename to kernel/old/include/tests/test_mem_alloc.h diff --git a/kernel/include/tests/test_priority_queue.h b/kernel/old/include/tests/test_priority_queue.h similarity index 100% rename from kernel/include/tests/test_priority_queue.h rename to kernel/old/include/tests/test_priority_queue.h diff --git a/kernel/include/tests/test_vm.h b/kernel/old/include/tests/test_vm.h similarity index 100% rename from kernel/include/tests/test_vm.h rename to kernel/old/include/tests/test_vm.h diff --git a/kernel/legacy/os_longjmp.s b/kernel/old/legacy/os_longjmp.s similarity index 100% rename from kernel/legacy/os_longjmp.s rename to kernel/old/legacy/os_longjmp.s diff --git a/kernel/legacy/os_setjmp.s b/kernel/old/legacy/os_setjmp.s similarity index 100% rename from kernel/legacy/os_setjmp.s rename to kernel/old/legacy/os_setjmp.s diff --git a/kernel/legacy/pm.c b/kernel/old/legacy/pm.c similarity index 93% rename from kernel/legacy/pm.c rename to kernel/old/legacy/pm.c index 14c905bc..b93509ba 100644 --- a/kernel/legacy/pm.c +++ b/kernel/old/legacy/pm.c @@ -1,7 +1,7 @@ #include "pm.h" -#include "stdint.h" -#include "stdarg.h" -#include "interrupt.h" +#include "../../src/klibc//include/stdint.h" +#include "../../src/klibc//include/stdarg.h" +#include "../../src/common/include/interrupt.h" #include "klibc.h" #include "stack.h" diff --git a/kernel/legacy/priorityQueue.c b/kernel/old/legacy/priorityQueue.c similarity index 100% rename from kernel/legacy/priorityQueue.c rename to kernel/old/legacy/priorityQueue.c diff --git a/kernel/tests/Makefile b/kernel/old/tests/Makefile similarity index 100% rename from kernel/tests/Makefile rename to kernel/old/tests/Makefile diff --git a/kernel/tests/test_fs.c b/kernel/old/tests/test_fs.c similarity index 100% rename from kernel/tests/test_fs.c rename to kernel/old/tests/test_fs.c diff --git a/kernel/tests/test_hash_map.c b/kernel/old/tests/test_hash_map.c similarity index 100% rename from kernel/tests/test_hash_map.c rename to kernel/old/tests/test_hash_map.c diff --git a/kernel/tests/test_klibc.h b/kernel/old/tests/test_klibc.h similarity index 100% rename from kernel/tests/test_klibc.h rename to kernel/old/tests/test_klibc.h diff --git a/kernel/tests/test_mem_alloc.c b/kernel/old/tests/test_mem_alloc.c similarity index 100% rename from kernel/tests/test_mem_alloc.c rename to kernel/old/tests/test_mem_alloc.c diff --git a/kernel/tests/test_priority_queue.c b/kernel/old/tests/test_priority_queue.c similarity index 100% rename from kernel/tests/test_priority_queue.c rename to kernel/old/tests/test_priority_queue.c diff --git a/kernel/tests/test_vm.c b/kernel/old/tests/test_vm.c similarity index 100% rename from kernel/tests/test_vm.c rename to kernel/old/tests/test_vm.c diff --git a/kernel/tests/testingsuite_example/arrayfill/a.out b/kernel/old/tests/testingsuite_example/arrayfill/a.out similarity index 100% rename from kernel/tests/testingsuite_example/arrayfill/a.out rename to kernel/old/tests/testingsuite_example/arrayfill/a.out diff --git a/kernel/tests/testingsuite_example/arrayfill/arrayfill.c b/kernel/old/tests/testingsuite_example/arrayfill/arrayfill.c similarity index 100% rename from kernel/tests/testingsuite_example/arrayfill/arrayfill.c rename to kernel/old/tests/testingsuite_example/arrayfill/arrayfill.c diff --git a/kernel/tests/testingsuite_example/arrayfill/arrayfill.h b/kernel/old/tests/testingsuite_example/arrayfill/arrayfill.h similarity index 100% rename from kernel/tests/testingsuite_example/arrayfill/arrayfill.h rename to kernel/old/tests/testingsuite_example/arrayfill/arrayfill.h diff --git a/kernel/tests/testingsuite_example/arrayfill/tap.c b/kernel/old/tests/testingsuite_example/arrayfill/tap.c similarity index 99% rename from kernel/tests/testingsuite_example/arrayfill/tap.c rename to kernel/old/tests/testingsuite_example/arrayfill/tap.c index 37f509e8..a7303d4a 100755 --- a/kernel/tests/testingsuite_example/arrayfill/tap.c +++ b/kernel/old/tests/testingsuite_example/arrayfill/tap.c @@ -8,7 +8,7 @@ This file is licensed under the GPLv2 or any later version #include #include -#include +#include "../../../../src/klibc//include/stdarg.h" #include #include "tap.h" diff --git a/kernel/tests/testingsuite_example/arrayfill/tap.h b/kernel/old/tests/testingsuite_example/arrayfill/tap.h similarity index 98% rename from kernel/tests/testingsuite_example/arrayfill/tap.h rename to kernel/old/tests/testingsuite_example/arrayfill/tap.h index 302e6d85..90e4e6f9 100755 --- a/kernel/tests/testingsuite_example/arrayfill/tap.h +++ b/kernel/old/tests/testingsuite_example/arrayfill/tap.h @@ -21,7 +21,7 @@ extern "C" { #include #include -#include +#include "../../../../src/klibc//include/stdarg.h" int vok_at_loc (const char *file, int line, int test, const char *fmt, va_list args); diff --git a/kernel/tests/testingsuite_example/arrayfill/testarrayfill.c b/kernel/old/tests/testingsuite_example/arrayfill/testarrayfill.c similarity index 94% rename from kernel/tests/testingsuite_example/arrayfill/testarrayfill.c rename to kernel/old/tests/testingsuite_example/arrayfill/testarrayfill.c index 1426bf18..1c2a6fd8 100644 --- a/kernel/tests/testingsuite_example/arrayfill/testarrayfill.c +++ b/kernel/old/tests/testingsuite_example/arrayfill/testarrayfill.c @@ -10,7 +10,7 @@ // } // } -// int main() { +// int common() { // plan(1); // ok(first_element(), "checks the first element"); // done_testing(); diff --git a/kernel/pi_light.c b/kernel/pi_light.c index 1ffa6d9b..fb0b11e0 100644 --- a/kernel/pi_light.c +++ b/kernel/pi_light.c @@ -1,6 +1,6 @@ #include "mmap.h" -#include +#include "src/klibc//include/stdint.h" #include "pi_light.h" //#define GPIO_BASE 0x20200000 diff --git a/kernel/process/process_api.c b/kernel/process/process_api.c deleted file mode 100644 index e021bf31..00000000 --- a/kernel/process/process_api.c +++ /dev/null @@ -1,38 +0,0 @@ -#include "scheduler.h" -#include "klibc.h" - -// Process / Scheduler API - -uint32_t prcs_exec(uint32_t file_p, int niceness) { - sched_task * task = sched_create_task(file_p, niceness); - return sched_add_task(task); -} - -// kill the process and its subprocesses -// can only be called if the process tree contains -// the request pid -uint32_t prcs_kill(uint32_t pid) { - return sched_remove_task(pid); -} - -// sends a message to a process (ipc) -uint32_t prcs_send_message(uint32_t dest_pid, uint32_t event, char * data, int len) { - return sched_send_message(dest_pid, event, data, len); -} - -// receives messages from processes -uint32_t prcs_register_message_callback_handler(sched_callback_handler cb_handler) { - return sched_register_callback_handler(cb_handler); -} - -// receives messages from processes -uint32_t prcs_deregister_message_callback_handler() { - return sched_deregister_callback_handler(); -} - -// set the niceness of a process -uint32_t prcs_set_niceness(uint32_t pid) { - return sched_set_niceness(pid); -} - -uint32_t prcs_fork(); // under construction diff --git a/kernel/process/stacks.s b/kernel/process/stacks.s deleted file mode 100644 index e0768994..00000000 --- a/kernel/process/stacks.s +++ /dev/null @@ -1,52 +0,0 @@ -.equ stack_size, 0x1000 -.equ stack_base, 0xfffff000 - -.equ Mode_USR, 0x10 -.equ Mode_FIQ, 0x11 -.equ Mode_IRQ, 0x12 -.equ Mode_SVC, 0x13 -.equ Mode_MON, 0x16 -.equ Mode_ABT, 0x17 -.equ Mode_UND, 0x1B -.equ Mode_SYS, 0x1F - - MOV R1, R0 // R0 has p_bootargs, which we need to hang onto - LDR R0, =stack_base - MSR CPSR_c, #Mode_FIQ - MOV sp, R0 - SUB R0, R0, #stack_size - - MSR CPSR_c, #Mode_IRQ - MOV sp, R0 - SUB R0, R0, #stack_size - - MSR CPSR_c, #Mode_SVC - MOV sp, R0 - SUB R0, R0, #stack_size - - MSR CPSR_c, #Mode_MON - MOV sp, R0 - SUB R0, R0, #stack_size - - MSR CPSR_c, #Mode_ABT - MOV sp, R0 - SUB R0, R0, #stack_size - - MSR CPSR_c, #Mode_UND - MOV sp, R0 - SUB R0, R0, #stack_size - - MSR CPSR_c, #Mode_SYS - MOV sp, R0 - - MSR CPSR_c, #Mode_SVC - ADD fp, sp, #0 - - EOR R0, R0 - ADD R0, pc, #0xf0000000 - MOV pc, R0 - - EOR R0, R0 - ADD R0, lr, #0xf0000000 - MOV lr, R0 - MOV R0, R1 diff --git a/kernel/main/argparse.c b/kernel/src/common/argparse.c similarity index 93% rename from kernel/main/argparse.c rename to kernel/src/common/argparse.c index a6f373d4..6d31d969 100644 --- a/kernel/main/argparse.c +++ b/kernel/src/common/argparse.c @@ -1,9 +1,9 @@ #include -#include "global_defs.h" -#include "argparse.h" +#include +#include "include/argparse.h" #include "klibc.h" -#include "tests.h" -#include "process.h" +#include +//#include "tests.h" static void argparse_parse(char *); @@ -83,10 +83,10 @@ static void argparse_parse(char *cmdline) { os_printf("RUNNING TESTS\n"); os_printf("Running tests...\n"); - Test *tests[2]; - tests[0] = create_test("This passes", &test1); - tests[1] = create_test("This fails", &test2); - run_tests(tests, 2); +// Test *tests[2]; +// tests[0] = create_test("This passes", &test1); +// tests[1] = create_test("This fails", &test2); +// run_tests(tests, 2); } token = os_strtok(NULL, " "); diff --git a/kernel/hw_handlers.c b/kernel/src/common/hw_handlers.c similarity index 90% rename from kernel/hw_handlers.c rename to kernel/src/common/hw_handlers.c index 20afe775..11e45332 100644 --- a/kernel/hw_handlers.c +++ b/kernel/src/common/hw_handlers.c @@ -3,14 +3,15 @@ * Harware Handler Interface * */ -#include "hw_handlers.h" -#include "mmap.h" -#include "memory.h" -#include "interrupt.h" -#include "klibc.h" -#include "vm.h" -#include "fs/file.h" -#include "process.h" +#include +#include +#include +#include +#include +#include +#include +// TODO: fs is removed +//#include "fs/file.h" /* copy vector table from wherever QEMU loads the kernel to 0x00 */ void init_vector_table(void) @@ -121,44 +122,53 @@ long __attribute__((interrupt("SWI"))) software_interrupt_handler(void) break; case SYSCALL_CREATE: os_printf("Create system call called!\n"); + return -1; - return (long) kcreate((char*) r0, r1, 0); +// return (long) kcreate((char*) r0, r1, 0); case SYSCALL_DELETE: os_printf("Delete system call called!\n"); + return -1; - return (long) kdelete((char*) r0, 1); +// return (long) kdelete((char*) r0, 1); case SYSCALL_OPEN: os_printf("Open system call called!\n"); + return -1; - return (long) kopen((char*) r0, r1); +// return (long) kopen((char*) r0, r1); case SYSCALL_MKDIR: os_printf("Mkdir system call called!\n"); + return -1; - return (long) kcreate((char*) r0, 'w', 1); +// return (long) kcreate((char*) r0, 'w', 1); case SYSCALL_READ: os_printf("Read system call called!\n"); + return -1; - return (long) kread(r0, (void*) r1, r2); +// return (long) kread(r0, (void*) r1, r2); case SYSCALL_WRITE: os_printf("Write system call called!\n"); + return -1; - return (long) kwrite(r0, (void*) r1, r2); +// return (long) kwrite(r0, (void*) r1, r2); case SYSCALL_CLOSE: os_printf("Close system call called!\n"); + return -1; - return (long) kclose(r0); +// return (long) kclose(r0); case SYSCALL_SEEK: os_printf("Seek system call called!\n"); + return -1; - return (long) kseek(r0, r1); +// return (long) kseek(r0, r1); case SYSCALL_COPY: os_printf("Copy system call called!\n"); + return -1; - return (long) kcopy((char*) r0, (char*) r1, r2); +// return (long) kcopy((char*) r0, (char*) r1, r2); case SYSCALL_LS: os_printf("Ls system call called!\n"); - - return (long) kls((char*) r0); + return -1; +// return (long) kls((char*) r0); case SYSCALL_SET_PERM: os_printf("Set permission system call called!\n"); os_printf("Yet to be implemented\n"); diff --git a/kernel/include/argparse.h b/kernel/src/common/include/argparse.h similarity index 100% rename from kernel/include/argparse.h rename to kernel/src/common/include/argparse.h diff --git a/kernel/include/hw_handlers.h b/kernel/src/common/include/hw_handlers.h similarity index 99% rename from kernel/include/hw_handlers.h rename to kernel/src/common/include/hw_handlers.h index 432f71b9..7180b027 100644 --- a/kernel/include/hw_handlers.h +++ b/kernel/src/common/include/hw_handlers.h @@ -30,7 +30,7 @@ * of the prototypes below. * */ -#include +#include "stdint.h" #define BRANCH_INSTRUCTION 0xe59ff018 // ldr pc, pc+offset diff --git a/kernel/include/interrupt.h b/kernel/src/common/include/interrupt.h similarity index 99% rename from kernel/include/interrupt.h rename to kernel/src/common/include/interrupt.h index bd304a32..e883c606 100644 --- a/kernel/include/interrupt.h +++ b/kernel/src/common/include/interrupt.h @@ -14,7 +14,7 @@ */ #include -#include "mmap.h" +#include // general syscall function extern int syscall(int number); diff --git a/kernel/main/interrupt.c b/kernel/src/common/interrupt.c similarity index 98% rename from kernel/main/interrupt.c rename to kernel/src/common/interrupt.c index c33d1c2a..77de4ac6 100644 --- a/kernel/main/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -3,9 +3,8 @@ * Interrupts * */ -#include "interrupt.h" -#include "klibc.h" -#include "drivers/timer.h" +#include +#include // there are 32 kinds of interrupts on the VIC // this structure may need to be expanded if the secondary controller is incorporated diff --git a/kernel/main/start.c b/kernel/src/common/start.c similarity index 80% rename from kernel/main/start.c rename to kernel/src/common/start.c index 890e4a4d..3a9372fe 100644 --- a/kernel/main/start.c +++ b/kernel/src/common/start.c @@ -17,30 +17,29 @@ */ #include -#include "hw_handlers.h" -#include "global_defs.h" -#include "argparse.h" -#include "interrupt.h" -#include "mmap.h" -#include "process.h" -#include "memory.h" -#include "drivers/uart.h" -#include "drivers/mmci.h" -#include "klibc.h" -#include "vm.h" -#include "fs/open_table.h" //to initialize fs opentable -#include "mem_alloc.h" -#include "tests.h" -#include "drivers/timer.h" -#include "kthread.h" -#include "scheduler.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// The file system has currently been *disabled* due to bugs +//#include "fs/open_table.h" //to initialize fs opentable +//#include "tests.h" + // Tests -#include "../tests/test_klibc.h" -#include "tests/test_hash_map.h" -#include "tests/test_mem_alloc.h" -#include "tests/test_vm.h" -#include "tests/test_priority_queue.h" +//#include "../../tests/test_klibc.h" +//#include "tests/test_hash_map.h" +//#include "tests/test_mem_alloc.h" +//#include "tests/test_vm.h" +//#include "tests/test_priority_queue.h" #define UART0_IMSC (*((volatile uint32_t *)(UART0_ADDRESS + 0x038))) @@ -88,7 +87,8 @@ void start2(uint32_t *p_bootargs) //run_prq_tests(); //run_hmap_tests(); - kfs_init(0, 0, 0); + // The file system has currently been *disabled* due to bugs + // kfs_init(0, 0, 0); /* @@ -127,7 +127,7 @@ void start2(uint32_t *p_bootargs) //run_process_tests(); //print_PID(); // init_q(); - //main(); + //common(); SLEEP; diff --git a/kernel/main/startup.s b/kernel/src/common/startup.s similarity index 100% rename from kernel/main/startup.s rename to kernel/src/common/startup.s diff --git a/kernel/include/drivers/mmci.h b/kernel/src/drivers/mmci/include/mmci.h similarity index 100% rename from kernel/include/drivers/mmci.h rename to kernel/src/drivers/mmci/include/mmci.h diff --git a/kernel/drivers/mmci.c b/kernel/src/drivers/mmci/mmci.c similarity index 98% rename from kernel/drivers/mmci.c rename to kernel/src/drivers/mmci/mmci.c index af4591a0..e6b80775 100644 --- a/kernel/drivers/mmci.c +++ b/kernel/src/drivers/mmci/mmci.c @@ -13,12 +13,12 @@ * to use FIFO for input and output * * TODO: Need to implement DMA support at some time in the future - * (Not needed until multi-threading implemented) + * (Not needed until multi-kthread implemented) * * Completed On: 4/20/2015 Last Updated: 5/5/2015 */ -#include "klibc.h" -#include "drivers/mmci.h" +#include +#include // MMCI Definitions - Used to access SD card registers; DO NOT CHANGE! #define MMCI_BASE 0x10005000 diff --git a/kernel/include/drivers/timer.h b/kernel/src/drivers/time/include/timer.h similarity index 96% rename from kernel/include/drivers/timer.h rename to kernel/src/drivers/time/include/timer.h index 60fac356..2778faaf 100644 --- a/kernel/include/drivers/timer.h +++ b/kernel/src/drivers/time/include/timer.h @@ -1,7 +1,7 @@ #ifndef TIMER_H #define TIMER_H -#include +#include "../../../src/klibc//include/stdint.h" typedef struct { uint32_t timer_load_value; // read/write diff --git a/kernel/drivers/timer.c b/kernel/src/drivers/time/timer.c similarity index 98% rename from kernel/drivers/timer.c rename to kernel/src/drivers/time/timer.c index d9b1efcb..d9aa6aee 100644 --- a/kernel/drivers/timer.c +++ b/kernel/src/drivers/time/timer.c @@ -1,9 +1,9 @@ /* Device Driver for ARM Dual-Timer Module (SP804) Reference Manual can be found here : http://infocenter.arm.com/help/topic/com.arm.doc.ddi0271d/DDI0271.pdf*/ -//#include -#include "klibc.h" -#include "drivers/timer.h" -#include "interrupt.h" +#include +#include +#include +#include rasp_pi_timer *timer_pointers[4]; diff --git a/kernel/include/drivers/uart.h b/kernel/src/drivers/uart/include/uart.h similarity index 100% rename from kernel/include/drivers/uart.h rename to kernel/src/drivers/uart/include/uart.h diff --git a/kernel/drivers/uart.c b/kernel/src/drivers/uart/uart.c similarity index 93% rename from kernel/drivers/uart.c rename to kernel/src/drivers/uart/uart.c index 3ce28b3e..7bfad9ec 100644 --- a/kernel/drivers/uart.c +++ b/kernel/src/drivers/uart/uart.c @@ -1,6 +1,8 @@ +// Only compile this file when **not** compiling for a raspberry pi +#ifndef RASPBERRY_PI + #include -#include "drivers/uart.h" -#include "mmap.h" +#include void print_uart0(const char *s) { @@ -103,3 +105,4 @@ void md(uint32_t * start) /*return buffer;*/ /*}*/ +#endif // RASPBERRY_PI diff --git a/kernel/drivers/uart_pi.c b/kernel/src/drivers/uart/uart_pi.c similarity index 97% rename from kernel/drivers/uart_pi.c rename to kernel/src/drivers/uart/uart_pi.c index 11d9464d..27abe916 100644 --- a/kernel/drivers/uart_pi.c +++ b/kernel/src/drivers/uart/uart_pi.c @@ -1,4 +1,8 @@ -#include + +// Only compile this file when compiling for a raspberry pi +#ifdef RASPBERRY_PI + +#include "stdint.h" #include "drivers/uart.h" #include "mmap.h" @@ -149,3 +153,4 @@ void md(uint32_t * start){ /*return buffer;*/ /*}*/ +#endif // RASPBERRY_PI diff --git a/kernel/data_structures/array_list.c b/kernel/src/ds/array_list.c similarity index 98% rename from kernel/data_structures/array_list.c rename to kernel/src/ds/array_list.c index c09fd10e..1ccfb417 100644 --- a/kernel/data_structures/array_list.c +++ b/kernel/src/ds/array_list.c @@ -5,7 +5,8 @@ * Author: kittenRainbow */ -#include "data_structures/array_list.h" +#include +#include arrl_handle* arrl_create() { return arrl_create_fixed(DEFAULT_BUCKET_SIZE); diff --git a/kernel/data_structures/bin_tree.c b/kernel/src/ds/bin_tree.c.old similarity index 99% rename from kernel/data_structures/bin_tree.c rename to kernel/src/ds/bin_tree.c.old index cef924b4..3baa5095 100644 --- a/kernel/data_structures/bin_tree.c +++ b/kernel/src/ds/bin_tree.c.old @@ -11,7 +11,7 @@ * ********************************************************************/ //#include "klibc.h" -//#include "data_structures/bin_tree.h" +//#include "ds/bin_tree.h" #include #include diff --git a/kernel/data_structures/bitvector.c b/kernel/src/ds/bitvector.c similarity index 98% rename from kernel/data_structures/bitvector.c rename to kernel/src/ds/bitvector.c index 5e23f289..020cf3dd 100644 --- a/kernel/data_structures/bitvector.c +++ b/kernel/src/ds/bitvector.c @@ -1,6 +1,6 @@ #include -#include "klibc.h" -#include "data_structures/bitvector.h" +#include +#include uint32_t const WORD_SIZE = 32; diff --git a/kernel/data_structures/hash_map.c b/kernel/src/ds/hash_map.c similarity index 98% rename from kernel/data_structures/hash_map.c rename to kernel/src/ds/hash_map.c index b084ec04..dbd0a272 100644 --- a/kernel/data_structures/hash_map.c +++ b/kernel/src/ds/hash_map.c @@ -1,5 +1,5 @@ -#include "data_structures/hash_map.h" -#include "klibc.h" +#include +#include /* this should be prime */ #define TABLE_STARTSIZE 1021 diff --git a/kernel/include/data_structures/array_list.h b/kernel/src/ds/include/array_list.h similarity index 92% rename from kernel/include/data_structures/array_list.h rename to kernel/src/ds/include/array_list.h index dc655603..2492180b 100644 --- a/kernel/include/data_structures/array_list.h +++ b/kernel/src/ds/include/array_list.h @@ -8,8 +8,8 @@ #ifndef KERNEL_INCLUDE_ARRAY_LIST_H_ #define KERNEL_INCLUDE_ARRAY_LIST_H_ -#include "data_structures/linked_list.h" -#include "klibc.h" +#include +#include #define DEFAULT_BUCKET_SIZE 20 diff --git a/kernel/include/data_structures/bin_tree.h b/kernel/src/ds/include/bin_tree.h similarity index 100% rename from kernel/include/data_structures/bin_tree.h rename to kernel/src/ds/include/bin_tree.h diff --git a/kernel/include/data_structures/bitvector.h b/kernel/src/ds/include/bitvector.h similarity index 98% rename from kernel/include/data_structures/bitvector.h rename to kernel/src/ds/include/bitvector.h index 20f2d330..6f5314b6 100644 --- a/kernel/include/data_structures/bitvector.h +++ b/kernel/src/ds/include/bitvector.h @@ -1,7 +1,7 @@ #ifndef BITVECTOR_H_ #define BITVECTOR_H_ -#include +#include "stdint.h" typedef struct bit_vector { uint32_t length; diff --git a/kernel/include/data_structures/hash_map.h b/kernel/src/ds/include/hash_map.h similarity index 100% rename from kernel/include/data_structures/hash_map.h rename to kernel/src/ds/include/hash_map.h diff --git a/kernel/include/data_structures/linked_list.h b/kernel/src/ds/include/linked_list.h similarity index 100% rename from kernel/include/data_structures/linked_list.h rename to kernel/src/ds/include/linked_list.h diff --git a/kernel/include/data_structures/priority_queue.h b/kernel/src/ds/include/priority_queue.h similarity index 100% rename from kernel/include/data_structures/priority_queue.h rename to kernel/src/ds/include/priority_queue.h diff --git a/kernel/include/data_structures/ring_buffer.h b/kernel/src/ds/include/ring_buffer.h similarity index 100% rename from kernel/include/data_structures/ring_buffer.h rename to kernel/src/ds/include/ring_buffer.h diff --git a/kernel/data_structures/linked_list.c b/kernel/src/ds/linked_list.c similarity index 97% rename from kernel/data_structures/linked_list.c rename to kernel/src/ds/linked_list.c index 492fc921..909a322e 100644 --- a/kernel/data_structures/linked_list.c +++ b/kernel/src/ds/linked_list.c @@ -17,8 +17,8 @@ * ********************************************************************/ -#include "klibc.h" -#include "data_structures/linked_list.h" +#include +#include llist_node* llist_create_node(void *data) { llist_node *node = (llist_node*) kmalloc(sizeof(llist_node)); diff --git a/kernel/data_structures/priority_queue.c b/kernel/src/ds/priority_queue.c similarity index 98% rename from kernel/data_structures/priority_queue.c rename to kernel/src/ds/priority_queue.c index 6a2118b2..f82246aa 100644 --- a/kernel/data_structures/priority_queue.c +++ b/kernel/src/ds/priority_queue.c @@ -1,5 +1,5 @@ -#include "klibc.h" -#include "data_structures/priority_queue.h" +#include +#include #define AMORITIZED_CONSTANT 2 #define DEFAULT_COUNT 10 diff --git a/kernel/data_structures/ring_buffer.c b/kernel/src/ds/ring_buffer.c.old similarity index 98% rename from kernel/data_structures/ring_buffer.c rename to kernel/src/ds/ring_buffer.c.old index c49eac1d..6858004b 100644 --- a/kernel/data_structures/ring_buffer.c +++ b/kernel/src/ds/ring_buffer.c.old @@ -11,7 +11,7 @@ * ********************************************************************/ -#include "ring_buffer.h" +#include ring_buffer* create(int size) { diff --git a/kernel/include/bits/alltypes.h b/kernel/src/klibc/include/bits/alltypes.h similarity index 100% rename from kernel/include/bits/alltypes.h rename to kernel/src/klibc/include/bits/alltypes.h diff --git a/kernel/include/bits/stdint.h b/kernel/src/klibc/include/bits/stdint.h similarity index 100% rename from kernel/include/bits/stdint.h rename to kernel/src/klibc/include/bits/stdint.h diff --git a/kernel/src/klibc/include/klibc.h b/kernel/src/klibc/include/klibc.h new file mode 100644 index 00000000..33de2f0c --- /dev/null +++ b/kernel/src/klibc/include/klibc.h @@ -0,0 +1,167 @@ +/******************************************************************** + * libc.h + * + * (Any collaborators, please add your name) + * Author: Jared McArthur, Taylor Smith, Sheldon Sandbekkhaug, Kaelen Haag + * + * Last edited: 20 April 2014 + * + * Purpose: Provide basic libc funtionality for CourseOS + * This header provides function skeletons + * for libc.c + * + * Usage: Compile into kernel. Adaptations of normal libc functions + * can be used by prepending os_ suffix. + ********************************************************************/ + +/* LOG: + * 3/30 added os_printf function - Taylor Smith + * 4/1 working more on os_printf - Taylor Smith + * 4/20 Added os_memset, os_strchrnul, os_strcpy, os_strlen, os_strtok, + * os_strspn, and os_strcspn from MUSL - Sheldon + * 4/21 Added os_memcpy for loader - Kaelen + * --------------Spring 2015--------------- + * 4/15/15: Added implementation of assert() + */ +#ifndef __KLIBC_H__ +#define __KLIBC_H__ + +#include +#include +#include + +#ifndef __NO_WFI +#define SLEEP while (1) asm volatile("wfi") +#else +#define SLEEP for(;;) +#endif + +// TODO: previously in global_defs +#define NBBY 8 +#define STATUS_OK 0 +#define STATUS_FAIL -1 +// END TODO + +typedef unsigned int os_size_t; + +// useful macros +#define MAX(a, b) ((a) > (b) ? a : b) +#define MIN(a, b) ((a) < (b) ? a : b) + +// basic constants +#define M_E 2.71828182845904523536 +#define M_LOG2E 1.44269504088896340736 +#define M_LOG10E 0.434294481903251827651 +#define M_LN2 0.693147180559945309417 +#define M_LN10 2.30258509299404568402 +#define M_PI 3.14159265358979323846 +#define M_PI_2 1.57079632679489661923 +#define M_PI_4 0.785398163397448309616 +#define M_1_PI 0.318309886183790671538 +#define M_2_PI 0.636619772367581343076 +#define M_1_SQRTPI 0.564189583547756286948 +#define M_2_SQRTPI 1.12837916709551257390 +#define M_SQRT2 1.41421356237309504880 +#define M_SQRT_2 0.707106781186547524401 + +#define os_printf(...) printf(__VA_ARGS__) + +/* string.h type functionality for comparing strings or mem blocks */ +int os_memcmp(const void *left, const void *right, os_size_t num); +int os_strcmp(const char *left, const char *right); + + +//4-17-15: Working assert implementation - Prakash +#define assert(X){\ + if ( (X) || _assert_fail(__FILE__, __LINE__, #X));\ +} + +/** + * Note: os_printf is restricted to printing only 256 characters. + * Supported format string conversions: + * X: upper-case hexadecimal print. + * x: lower-case hexadecimal print. + * d: signed integer. + * u: unsigned integer. + * c: ASCII character. + * s: string. + * %: the percent sign itself. + * + * Supported options: + * 0: zero-pad the result (applies to X,x,d,u). For example: + * os_printf("'%05d %05d %05u'\n", 15, -15, -15); + * prints '00015 -0015 4294967281' + */ +int os_vsnprintf(char *buf, int buflen, const char *str_buf, va_list args); +int os_snprintf(char *buf, int buflen, const char *fmt_string, ...); +int os_printf(const char *str_buf, ...); + +void *os_memset(void *dest, char c, os_size_t n); +char *__strchrnul(const char *s, char c); +char *os_strcpy(char *dest, const char *src); +char *os_strncpy(char *dest, const char *src, os_size_t n); +os_size_t os_strlen(const char *s); +char *os_strtok(char *s, const char *sep); +os_size_t os_strspn(const char *s, const char *accept); +os_size_t os_strcspn(const char *s, const char *reject); + +void os_memcpy(uint32_t * source, uint32_t * dest, os_size_t size); +/* TODO: create print function for kernel debugging purposes */ + +void* kmalloc(uint32_t size); +void* kmalloc_aligned(uint32_t size, uint32_t alignment); +void kfree(void* ptr); +uint32_t km_size(); +uint32_t kmcheck(); + +/** + * umalloc allocates memory on the user heap + * + * @param size of the block of memory allocated + * @param uint32_t size + * @return returns a pointer to the allocated block of memory + */ +void* umalloc(uint32_t size); //does user level malloc work + +/** + * ualigned alloc allocates memory on the user heap + * according to a specified alignemnt + * + * @param size of the block of memory allocated, and alignment desired + * @param uint32_t size, uint32_alignment + * @return returns a pointer to the allocated block of memory + * that is a multiple of the specified allignement + */ +void* ualigned_alloc(uint32_t size, uint32_t alignment); //does user level aligned_alloc work + +/** + * free's an allocated block of memory on the heap + * + * @param pointer to a block of memeory on the heap + * @param void* ptr + * @return nothing returned + */ +void ufree(void*); //does user level free work + +int32_t abs(int32_t); +unsigned int rand(); + +// as the codebase grows, it is important to use these macros +// so that we can filter out unnecessary messages esp. during +// development +#define LOG_LEVEL 5 + +#define DEBUG(...) if(LOG_LEVEL >= 5) os_printf(__VA_ARGS__) +#define LOG(...) if(LOG_LEVEL >= 4) os_printf(__VA_ARGS__) +#define INFO(...) if(LOG_LEVEL >= 3) os_printf(__VA_ARGS__) +#define WARN(...) if(LOG_LEVEL >= 2) os_printf(__VA_ARGS__) +#define ERROR(...) if(LOG_LEVEL >= 1) os_printf(__VA_ARGS__) + +//4-17-15: Initial panic * assert_fail functions added +void panic(); +int _assert_fail(char *_file, unsigned int _line, char *_func); + //__attribute__ ((__noreturn__)); + +void splash(void); + +#endif diff --git a/kernel/include/stdarg.h b/kernel/src/klibc/include/stdarg.h similarity index 100% rename from kernel/include/stdarg.h rename to kernel/src/klibc/include/stdarg.h diff --git a/kernel/src/klibc/include/stdbool.h b/kernel/src/klibc/include/stdbool.h new file mode 100644 index 00000000..4c2d176b --- /dev/null +++ b/kernel/src/klibc/include/stdbool.h @@ -0,0 +1,10 @@ + +#ifndef STDBOOL_H +#define STDBOOL_H + +#define true 1 +#define false 0 + +typedef _Bool bool; + +#endif \ No newline at end of file diff --git a/kernel/include/stdint.h b/kernel/src/klibc/include/stdint.h similarity index 100% rename from kernel/include/stdint.h rename to kernel/src/klibc/include/stdint.h diff --git a/kernel/src/klibc/include/stdio.h b/kernel/src/klibc/include/stdio.h new file mode 100644 index 00000000..8f97d4ed --- /dev/null +++ b/kernel/src/klibc/include/stdio.h @@ -0,0 +1,6 @@ + +#ifndef NULL +#define NULL ((void*) 0) +#endif + +#define UNUSED(x) (void)(x) diff --git a/kernel/main/klibc.c b/kernel/src/klibc/klibc.c similarity index 93% rename from kernel/main/klibc.c rename to kernel/src/klibc/klibc.c index 889a1dae..6b45ff25 100644 --- a/kernel/main/klibc.c +++ b/kernel/src/klibc/klibc.c @@ -18,14 +18,14 @@ ********************************************************************/ #include #include +#include -#include "klibc.h" -#include "global_defs.h" -#include "mem_alloc.h" -#include "interrupt.h" +#include +#include +#include //FIXME: decouple -#include "drivers/uart.h" +#include #define LOWER_CASE 0 #define UPPER_CASE 1 @@ -49,7 +49,7 @@ void panic() { disable_interrupts() ; - //os_printf("Kernel panic!\n"); + os_printf("Kernel panic!\n"); os_printf("\n ) ( \n"); os_printf(" ( /( ( )\\ ) \n"); os_printf(" )\\()) ( ( ( )\\ (()/( ) ( \n"); @@ -63,16 +63,11 @@ void panic() void splash() { - os_printf( - "\n\t ██████╗ ██████╗ ██╗ ██╗██████╗ ███████╗███████╗ ██████╗ ███████╗\n"); - os_printf( - "\t██╔════╝██╔═══██╗██║ ██║██╔══██╗██╔════╝██╔════╝██╔═══██╗██╔════╝\n"); - os_printf( - "\t██║ ██║ ██║██║ ██║██████╔╝███████╗█████╗ ██║ ██║███████╗\n"); - os_printf( - "\t██║ ██║ ██║██║ ██║██╔══██╗╚════██║██╔══╝ ██║ ██║╚════██║\n"); - os_printf( - "\t╚██████╗╚██████╔╝╚██████╔╝██║ ██║███████║███████╗╚██████╔╝███████║\n\n"); + os_printf("\n\t ██████╗ ██████╗ ██╗ ██╗██████╗ ███████╗███████╗ ██████╗ ███████╗\n"); + os_printf("\t██╔════╝██╔═══██╗██║ ██║██╔══██╗██╔════╝██╔════╝██╔═══██╗██╔════╝\n"); + os_printf("\t██║ ██║ ██║██║ ██║██████╔╝███████╗█████╗ ██║ ██║███████╗\n"); + os_printf("\t██║ ██║ ██║██║ ██║██╔══██╗╚════██║██╔══╝ ██║ ██║╚════██║\n"); + os_printf("\t╚██████╗╚██████╔╝╚██████╔╝██║ ██║███████║███████╗╚██████╔╝███████║\n\n"); } /*4-17-15: - Prakash @@ -501,7 +496,7 @@ os_size_t os_strspn(const char *s, const char *accept) // Check each character in s while (c != 0) { - Boolean ok = FALSE; + bool ok = false; // Check against each character in accept int i; @@ -509,11 +504,11 @@ os_size_t os_strspn(const char *s, const char *accept) { if (c == accept[i]) { - ok = TRUE; + ok = true; } } - if (ok == TRUE) + if (ok == true) { // If c matched any character in accept, continue length++; @@ -607,7 +602,7 @@ double katof(const char *string) double fraction = 0.0; // after decimal int sign = 1; // positive or negative? int divisor = 1; // used to push fraction past decimal point - Boolean after_decimal = FALSE; // decimal point reached? + bool after_decimal = false; // decimal point reached? // Check if string includes sign (including a "+") if (*string == '-') @@ -640,7 +635,7 @@ double katof(const char *string) { if (after_decimal) return 0.0; // more than one '.' - after_decimal = TRUE; + after_decimal = true; } else { @@ -726,7 +721,7 @@ if (!string) long int integer = 0; long int result = 0; -Boolean result_found = FALSE; +bool result_found = false; int sign = 1; if (*string == '-') @@ -750,7 +745,7 @@ while (!result_found) else { result = sign * integer; - result_found = TRUE; + result_found = true; } } *endptr = (char*) string; diff --git a/kernel/include/kthread.h b/kernel/src/kthread/include/kthread.h similarity index 94% rename from kernel/include/kthread.h rename to kernel/src/kthread/include/kthread.h index a7efd61f..deee3d28 100644 --- a/kernel/include/kthread.h +++ b/kernel/src/kthread/include/kthread.h @@ -8,6 +8,8 @@ #ifndef KERNEL_INCLUDE_KTHREAD_H_ #define KERNEL_INCLUDE_KTHREAD_H_ +#include + typedef void (*kthread_callback_handler)(); typedef struct kthread_handle { diff --git a/kernel/threads/kthreads.c b/kernel/src/kthread/kthreads.c.old similarity index 86% rename from kernel/threads/kthreads.c rename to kernel/src/kthread/kthreads.c.old index 420148b8..c8ad2be3 100644 --- a/kernel/threads/kthreads.c +++ b/kernel/src/kthread/kthreads.c.old @@ -5,8 +5,9 @@ * Author: mwkurian */ -#include "kthread.h" -#include +#include +#include +#include kthread_handle* kthread_create(kthread_callback_handler cb_handler) { diff --git a/kernel/memory/allocator.c b/kernel/src/memory/allocator.c similarity index 99% rename from kernel/memory/allocator.c rename to kernel/src/memory/allocator.c index e665f193..94ed5cc8 100644 --- a/kernel/memory/allocator.c +++ b/kernel/src/memory/allocator.c @@ -1,6 +1,5 @@ -#include "global_defs.h" -#include "klibc.h" -#include "allocator.h" +#include +#include uint32_t* __alloc_extend_heap(alloc_handle*allocator, uint32_t amount); diff --git a/kernel/include/allocator.h b/kernel/src/memory/include/allocator.h similarity index 95% rename from kernel/include/allocator.h rename to kernel/src/memory/include/allocator.h index 27059e6d..b26efc3f 100644 --- a/kernel/include/allocator.h +++ b/kernel/src/memory/include/allocator.h @@ -7,8 +7,7 @@ #ifndef __ALLOCATOR_H__ #define __ALLOCATOR_H__ -#include -#include +#include "stdint.h" #define MEM_START 0x500000 diff --git a/kernel/include/mem_alloc.h b/kernel/src/memory/include/mem_alloc.h similarity index 96% rename from kernel/include/mem_alloc.h rename to kernel/src/memory/include/mem_alloc.h index 45358d11..98ecef6c 100644 --- a/kernel/include/mem_alloc.h +++ b/kernel/src/memory/include/mem_alloc.h @@ -7,9 +7,8 @@ Log #ifndef __MEM_ALLOC_H__ #define __MEM_ALLOC_H__ -#include "allocator.h" +#include #include -#include #define MEM_START 0x500000 #define PROC_START 0x90000000 diff --git a/kernel/include/memory.h b/kernel/src/memory/include/memory.h similarity index 100% rename from kernel/include/memory.h rename to kernel/src/memory/include/memory.h diff --git a/kernel/include/mmap.h b/kernel/src/memory/include/mmap.h similarity index 100% rename from kernel/include/mmap.h rename to kernel/src/memory/include/mmap.h diff --git a/kernel/memory/mem_alloc.c b/kernel/src/memory/mem_alloc.c similarity index 100% rename from kernel/memory/mem_alloc.c rename to kernel/src/memory/mem_alloc.c diff --git a/kernel/memory/mmap.c b/kernel/src/memory/mmap.c similarity index 97% rename from kernel/memory/mmap.c rename to kernel/src/memory/mmap.c index 726166d0..6e99de78 100644 --- a/kernel/memory/mmap.c +++ b/kernel/src/memory/mmap.c @@ -1,8 +1,6 @@ -#include "mmap.h" -#include "memory.h" -#include "klibc.h" -#include "drivers/uart.h" -#include "vm.h" +#include +#include +#include /* * APX AP Privileged Unprivileged @@ -172,7 +170,7 @@ void mmap(void *p_bootargs) asm volatile("mov r0, %[args]" : : [args] "r" (p_bootargs)); asm volatile("cpsie if"); - asm volatile (".include \"memory/stacks.s\""); + asm volatile (".include \"src/memory/stacks.s\""); //branch to proper kernel at start asm volatile("bl start2"); diff --git a/kernel/memory/stacks.s b/kernel/src/memory/stacks.s similarity index 100% rename from kernel/memory/stacks.s rename to kernel/src/memory/stacks.s diff --git a/kernel/vm/fastlz/6pack.c b/kernel/src/memory/vm/fastlz/6pack.c.old similarity index 99% rename from kernel/vm/fastlz/6pack.c rename to kernel/src/memory/vm/fastlz/6pack.c.old index 89a1128d..604b17d7 100644 --- a/kernel/vm/fastlz/6pack.c +++ b/kernel/src/memory/vm/fastlz/6pack.c.old @@ -31,7 +31,7 @@ #define SIXPACK_VERSION_REVISION 0 #define SIXPACK_VERSION_STRING "snapshot 20070615" -#include "fastlz.h" +#include "fastlz.h.old" #undef PATH_SEPARATOR diff --git a/kernel/vm/fastlz/6unpack.c b/kernel/src/memory/vm/fastlz/6unpack.c.old similarity index 99% rename from kernel/vm/fastlz/6unpack.c rename to kernel/src/memory/vm/fastlz/6unpack.c.old index b0215f9f..6527cbcc 100644 --- a/kernel/vm/fastlz/6unpack.c +++ b/kernel/src/memory/vm/fastlz/6unpack.c.old @@ -31,7 +31,7 @@ #define SIXPACK_VERSION_REVISION 0 #define SIXPACK_VERSION_STRING "0.1.0" -#include "fastlz.h" +#include "fastlz.h.old" #if defined(WIN32) || defined(__NT__) || defined(_WIN32) || defined(__WIN32__) #if defined(__BORLANDC__) || defined(_MSC_VER) @@ -206,7 +206,7 @@ int unpack_file(const char* input_file) compressed_bufsize = 0; decompressed_bufsize = 0; - /* main loop */ + /* common loop */ for(;;) { /* end of file? */ diff --git a/kernel/vm/fastlz/LICENSE b/kernel/src/memory/vm/fastlz/LICENSE similarity index 100% rename from kernel/vm/fastlz/LICENSE rename to kernel/src/memory/vm/fastlz/LICENSE diff --git a/kernel/vm/fastlz/README.TXT b/kernel/src/memory/vm/fastlz/README.TXT similarity index 100% rename from kernel/vm/fastlz/README.TXT rename to kernel/src/memory/vm/fastlz/README.TXT diff --git a/kernel/vm/fastlz/fastlz.c b/kernel/src/memory/vm/fastlz/fastlz.c.old similarity index 99% rename from kernel/vm/fastlz/fastlz.c rename to kernel/src/memory/vm/fastlz/fastlz.c.old index 3c9d6f6f..0e7a2ae4 100644 --- a/kernel/vm/fastlz/fastlz.c +++ b/kernel/src/memory/vm/fastlz/fastlz.c.old @@ -110,7 +110,7 @@ int fastlz_decompress(const void* input, int length, void* output, int maxout); #define FASTLZ_DECOMPRESSOR fastlz1_decompress static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); -#include "fastlz.c" +#include "fastlz.c.old" #undef FASTLZ_LEVEL #define FASTLZ_LEVEL 2 @@ -125,7 +125,7 @@ static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void #define FASTLZ_DECOMPRESSOR fastlz2_decompress static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); -#include "fastlz.c" +#include "fastlz.c.old" int fastlz_compress(const void* input, int length, void* output) { @@ -202,7 +202,7 @@ static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* *op++ = *ip++; *op++ = *ip++; - /* main loop */ + /* common loop */ while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) { const flzuint8* ref; diff --git a/kernel/vm/fastlz/fastlz.h b/kernel/src/memory/vm/fastlz/fastlz.h.old similarity index 100% rename from kernel/vm/fastlz/fastlz.h rename to kernel/src/memory/vm/fastlz/fastlz.h.old diff --git a/kernel/vm/frame.c b/kernel/src/memory/vm/frame.c similarity index 100% rename from kernel/vm/frame.c rename to kernel/src/memory/vm/frame.c diff --git a/kernel/vm/frame.h b/kernel/src/memory/vm/include/frame.h similarity index 100% rename from kernel/vm/frame.h rename to kernel/src/memory/vm/include/frame.h diff --git a/kernel/include/swap_framework.h b/kernel/src/memory/vm/include/swap_framework.h similarity index 93% rename from kernel/include/swap_framework.h rename to kernel/src/memory/vm/include/swap_framework.h index 9b44906c..28329810 100644 --- a/kernel/include/swap_framework.h +++ b/kernel/src/memory/vm/include/swap_framework.h @@ -1,8 +1,8 @@ #ifndef __VM_SWAP_FRAMEWORK_H #define __VM_SWAP_FRAMEWORK_H -#include "klibc.h" -#include +#include "../../../../old/include/klibc.h" +#include "stdint.h" // NOTE: SWAPPING CANNOT WORK UNTIL FILESYSTEMS CAN ALLOCATE MORE THAN 16 PAGES AT A TIME /* Contributors: Noel Negusse and Jesse Thaden @@ -54,7 +54,7 @@ void swap_init(); //void swap_init(os_size_t); To be implemented... [specifies global page size] -/* store_page will store a page to media - not main memory - storage, e.g. HDD +/* store_page will store a page to media - not common memory - storage, e.g. HDD * from the page*. ID parameter passed will change to appropriate index (i.e. return value) * void* page -> data to be paged * os_size_t pagesize: The size of a page in bytes, i.e. 4096 b @@ -70,7 +70,7 @@ uint32_t store_page_LZ(void*, uint32_t*); // All LZ functions not yet working... /* retrieve_page will retrieve the page identified the ID pointer and - * will store it back into main memory (specified by the void *page pointer) + * will store it back into common memory (specified by the void *page pointer) * * Returns: NULL on failure or simply passes back ID on success * NOTE: Page size was set by store_page @@ -83,7 +83,7 @@ uint32_t retrieve_page_LZ(void*, uint32_t*); os_size_t sum_stored(); -/* vm_swap_page will store a page from main memory (specified by void *page) +/* vm_swap_page will store a page from common memory (specified by void *page) * to a swap space either on disk or a compressed block in memory * * Returns: The ID pointer - bit vector index - of where the swap_space was stored and diff --git a/kernel/include/swap_fs.h b/kernel/src/memory/vm/include/swap_fs.h similarity index 87% rename from kernel/include/swap_fs.h rename to kernel/src/memory/vm/include/swap_fs.h index ddd64701..951304d3 100644 --- a/kernel/include/swap_fs.h +++ b/kernel/src/memory/vm/include/swap_fs.h @@ -23,7 +23,7 @@ char *generate_filename(uint8_t); int32_t swapfs_init(int, uint8_t); -/* swapfs_store will store a page to media - not main memory - storage, e.g. HDD +/* swapfs_store will store a page to media - not common memory - storage, e.g. HDD * from the page* * void* page -> data to be paged * os_size_t pagesize: The size of a page in bytes, i.e. 4096 b @@ -37,7 +37,7 @@ int64_t swapfs_store(void*, uint32_t*, uint8_t); /* swapfs_retrieve will retrieve the page identified by the ID pointer and - * will store it back into main memory (specified by the void *page pointer) + * will store it back into common memory (specified by the void *page pointer) * * Returns: -1 on failure and 1 on success */ diff --git a/kernel/include/swap_pqueue.h b/kernel/src/memory/vm/include/swap_pqueue.h similarity index 98% rename from kernel/include/swap_pqueue.h rename to kernel/src/memory/vm/include/swap_pqueue.h index b2d5b406..3945070e 100644 --- a/kernel/include/swap_pqueue.h +++ b/kernel/src/memory/vm/include/swap_pqueue.h @@ -1,7 +1,7 @@ #ifndef __VM_SWAP_PQUEUE_H #define __VM_SWAP_PQUEUE_H -#include +#include "stdint.h" #include "swap_framework.h" diff --git a/kernel/include/vm.h b/kernel/src/memory/vm/include/vm.h similarity index 90% rename from kernel/include/vm.h rename to kernel/src/memory/vm/include/vm.h index 92228d41..e9c8b63f 100644 --- a/kernel/include/vm.h +++ b/kernel/src/memory/vm/include/vm.h @@ -1,9 +1,10 @@ #ifndef __VM_H -#define __VM_H 1 +#define __VM_H -#include "memory.h" +#include #include -#include "klibc.h" +#include +#include //#define BLOCK_SIZE (1<<20) #define BLOCK_SIZE (1<<12) @@ -29,6 +30,14 @@ struct vas { #define KERNEL_VAS ((struct vas*)V_L1PTBASE) + +#define VM_L1_GET_ENTRY(table,vptr) table[((unsigned int)vptr)>>20] +#define VM_L1_SET_ENTRY(table,vptr,ent) (table[((unsigned int)vptr)>>20]=ent) +#define VM_ENTRY_GET_FRAME(x) ((x)&~((PAGE_TABLE_SIZE<<1) - 1)) +#define VM_ENTRY_GET_L2(x) ((x)&~0x1FF) +#define VM_L2_ENTRY(l2pt,vptr) ((uint32_t*)l2pt)[((unsigned int)vptr&0x000FF000)>>12] +#define VM_L2ENTRY_GET_FRAME(x) ((x)&0xFFFFF000) + /** * These permissions dictate who can access what pages. Note that you * cannot combine these arbitrarily. For example: diff --git a/kernel/vm/memory-layout.svg b/kernel/src/memory/vm/memory-layout.svg similarity index 100% rename from kernel/vm/memory-layout.svg rename to kernel/src/memory/vm/memory-layout.svg diff --git a/kernel/vm/swap_framework.c b/kernel/src/memory/vm/swap_framework.c.old similarity index 97% rename from kernel/vm/swap_framework.c rename to kernel/src/memory/vm/swap_framework.c.old index 7fd9db76..e4a3efd6 100644 --- a/kernel/vm/swap_framework.c +++ b/kernel/src/memory/vm/swap_framework.c.old @@ -1,11 +1,11 @@ -#include "vm.h" -#include "memory.h" -#include "klibc.h" +#include +#include +#include #include -#include "swap_framework.h" -#include "swap_pqueue.h" -#include "swap_fs.h" -#include "fastlz/fastlz.h" +#include +#include +#include +#include "fastlz/fastlz.h.old" // NOTE: SWAPPING CANNOT WORK UNTIL FILESYSTEMS CAN ALLOCATE MORE THAN 16 PAGES AT A TIME void swap_init() diff --git a/kernel/vm/swap_fs.c b/kernel/src/memory/vm/swap_fs.c.old similarity index 100% rename from kernel/vm/swap_fs.c rename to kernel/src/memory/vm/swap_fs.c.old diff --git a/kernel/data_structures/swap_pqueue.c b/kernel/src/memory/vm/swap_pqueue.c.old similarity index 99% rename from kernel/data_structures/swap_pqueue.c rename to kernel/src/memory/vm/swap_pqueue.c.old index 8bd85b94..d87f7f50 100644 --- a/kernel/data_structures/swap_pqueue.c +++ b/kernel/src/memory/vm/swap_pqueue.c.old @@ -1,4 +1,4 @@ -#include +#include "stdint.h" #include "swap_pqueue.h" #include "swap_framework.h" #include "klibc.h" diff --git a/kernel/vm/vm.c b/kernel/src/memory/vm/vm.c similarity index 93% rename from kernel/vm/vm.c rename to kernel/src/memory/vm/vm.c index 3be3b78c..20629d66 100644 --- a/kernel/vm/vm.c +++ b/kernel/src/memory/vm/vm.c @@ -1,7 +1,7 @@ #include "vm.h" #include "memory.h" #include "klibc.h" -#include "frame.h" +#include "include/frame.h" #define CHECK_VPTR if ((unsigned int)vptr & (BLOCK_SIZE-1)) return VM_ERR_BADV; #define CHECK_PPTR if ((unsigned int)pptr & (BLOCK_SIZE-1)) return VM_ERR_BADP; @@ -193,12 +193,6 @@ void *vm_allocate_pages(struct vas *vas, void *vptr, uint32_t nbytes, return p; } -#define VM_L1_GET_ENTRY(table,vptr) table[((unsigned int)vptr)>>20] -#define VM_L1_SET_ENTRY(table,vptr,ent) (table[((unsigned int)vptr)>>20]=ent) -#define VM_ENTRY_GET_FRAME(x) ((x)&~((PAGE_TABLE_SIZE<<1) - 1)) -#define VM_ENTRY_GET_L2(x) ((x)&~0x1FF) -#define VM_L2_ENTRY(l2pt,vptr) ((uint32_t*)l2pt)[((unsigned int)vptr&0x000FF000)>>12] -#define VM_L2ENTRY_GET_FRAME(x) ((x)&0xFFFFF000) int vm_free_page(struct vas *vas, void *vptr) { diff --git a/kernel/process/elf.c b/kernel/src/process/elf.c similarity index 98% rename from kernel/process/elf.c rename to kernel/src/process/elf.c index 8038efe6..51946281 100644 --- a/kernel/process/elf.c +++ b/kernel/src/process/elf.c @@ -1,7 +1,7 @@ /* Worked on by Jeremy Wenzel, Kaelen Haag, and Sam Allen */ #include "elf.h" #include "klibc.h" -#include // Probably going to be removed +#include "../../src/klibc//include/stdint.h" // Probably going to be removed unsigned char* filePointer; unsigned char* startPointer; diff --git a/kernel/include/elf.h b/kernel/src/process/include/elf.h similarity index 99% rename from kernel/include/elf.h rename to kernel/src/process/include/elf.h index 710047b2..aadd6e68 100644 --- a/kernel/include/elf.h +++ b/kernel/src/process/include/elf.h @@ -7,7 +7,7 @@ #define _ELF_H_ #include -#include "klibc.h" +#include typedef uint32_t Elf_Addr; // Program Address typedef uint16_t Elf_Half; // 16 bit diff --git a/kernel/include/loader.h b/kernel/src/process/include/loader.h similarity index 83% rename from kernel/include/loader.h rename to kernel/src/process/include/loader.h index 79e38fc5..e242155e 100644 --- a/kernel/include/loader.h +++ b/kernel/src/process/include/loader.h @@ -1,8 +1,7 @@ #ifndef __loader_h #define __loader_h -#include "global_defs.h" -#include "elf.h" -#include "process.h" +#include +#include #define USER_PROC_STACK_SIZE 0x100000 //1 MB #define KERNEL_PROC_STACK_SIZE 0x1000 //4K diff --git a/kernel/include/process.h b/kernel/src/process/include/process.h similarity index 99% rename from kernel/include/process.h rename to kernel/src/process/include/process.h index c663ccf7..1e063af4 100644 --- a/kernel/include/process.h +++ b/kernel/src/process/include/process.h @@ -1,8 +1,8 @@ #ifndef PROCESS_H #define PROCESS_H -#include "global_defs.h" +#include #include -#include "vm.h" +#include /* LOG: 3/15: Initial skeleton and comments by Josh Guan. diff --git a/kernel/include/scheduler.h b/kernel/src/process/include/scheduler.h similarity index 90% rename from kernel/include/scheduler.h rename to kernel/src/process/include/scheduler.h index c9723229..a2f1e5d7 100644 --- a/kernel/include/scheduler.h +++ b/kernel/src/process/include/scheduler.h @@ -5,11 +5,12 @@ * Author: mwkurian */ -#include "process.h" -#include "klibc.h" -#include "data_structures/priority_queue.h" -#include "data_structures/linked_list.h" -#include "data_structures/array_list.h" +#include +#include +#include +#include +#include +#include #ifndef KERNEL_INCLUDE_SCHEDULER_H_ #define KERNEL_INCLUDE_SCHEDULER_H_ diff --git a/kernel/include/signals.h b/kernel/src/process/include/signals.h.old similarity index 89% rename from kernel/include/signals.h rename to kernel/src/process/include/signals.h.old index 2e53203c..8fd45baf 100644 --- a/kernel/include/signals.h +++ b/kernel/src/process/include/signals.h.old @@ -1,6 +1,6 @@ //Contributors: Andrew Stepek, Michael Brennen, and Matthew Stromberg -#include +#include "stdint.h" #include "include/mmap.h" #include "include/process.h" diff --git a/kernel/process/loader.c b/kernel/src/process/loader.c similarity index 97% rename from kernel/process/loader.c rename to kernel/src/process/loader.c index 0f4ad1f7..22d30196 100644 --- a/kernel/process/loader.c +++ b/kernel/src/process/loader.c @@ -1,4 +1,4 @@ -#include +#include "../../src/klibc//include/stdint.h" #include "loader.h" #include "mem_alloc.h" #include "klibc.h" diff --git a/kernel/process/process.c b/kernel/src/process/process.c similarity index 81% rename from kernel/process/process.c rename to kernel/src/process/process.c index ff84825d..a7e7b989 100644 --- a/kernel/process/process.c +++ b/kernel/src/process/process.c @@ -1,13 +1,9 @@ -#include "global_defs.h" -#include "process.h" -#include "klibc.h" -#include "mem_alloc.h" -#include "loader.h" -#include "vm.h" -#include "elf.h" -#include "drivers/timer.h" -#include "fs/file.h" -#include "data_structures/bitvector.h" +#include +#include +#include +#include +//#include +#include static pcb** pcb_table; static bit_vector* pcb_map; @@ -75,7 +71,7 @@ pcb* __process_create() //initialize PCB pcb_p->stored_vas = vm_new_vas(); pcb_p->PID = pcb_index; - //4-13-15: function pointer should point to main() of file pointer. + //4-13-15: function pointer should point to common() of file pointer. // TODO: Eventually should be able to pass parameters. Put them on the stack (argv/argc) pcb_p->current_state = PROCESS_NEW; pcb_p->has_executed = 0; @@ -86,42 +82,43 @@ pcb* __process_create() } void __process_elf_init(pcb* pcb_p, const char* name) { - int fd = kopen(name, 'r'); - uint32_t start = PROC_LOCATION; - uint32_t len = 0; - - struct stats fstats; - get_stats(name, &fstats); - len = fstats.size; - os_printf("LOADING PROCESS <<%s>>, start address %X\n", - name, start, len); - - for (int i = 0; i < (len / BLOCK_SIZE) + 1; i++) - { - uint32_t *v = (uint32_t*) (start + (i * BLOCK_SIZE)); - int x = vm_allocate_page(pcb_p->stored_vas, (void*) v, VM_PERM_USER_RW); - assert(x == 0); - vm_map_shared_memory(KERNEL_VAS, (void*) v, - pcb_p->stored_vas,(void*) v, - VM_PERM_USER_RW); - } - - int* location = (int*) start; - int counter = 0; - while (counter < len) - { - kread(fd, location, 4); - location += 1; - counter += 4; - } - - Elf_Ehdr* success = (Elf_Ehdr*) load_file(pcb_p, (uint32_t*) start); - pcb_p->R15 = success->e_entry; - for (int i = 0; i < (len / BLOCK_SIZE) + 1; i++) - { - uint32_t *v = (uint32_t *) (start + (i * BLOCK_SIZE)); - vm_free_mapping(KERNEL_VAS, (void*) v); - } + // TODO: depends on fs. did it not before? how did that work? fix fs? etc +// int fd = kopen(name, 'r'); +// uint32_t start = PROC_LOCATION; +// uint32_t len = 0; +// +// struct stats fstats; +// get_stats(name, &fstats); +// len = fstats.size; +// os_printf("LOADING PROCESS <<%s>>, start address %X\n", +// name, start, len); +// +// for (int i = 0; i < (len / BLOCK_SIZE) + 1; i++) +// { +// uint32_t *v = (uint32_t*) (start + (i * BLOCK_SIZE)); +// int x = vm_allocate_page(pcb_p->stored_vas, (void*) v, VM_PERM_USER_RW); +// assert(x == 0); +// vm_map_shared_memory(KERNEL_VAS, (void*) v, +// pcb_p->stored_vas,(void*) v, +// VM_PERM_USER_RW); +// } +// +// int* location = (int*) start; +// int counter = 0; +// while (counter < len) +// { +// kread(fd, location, 4); +// location += 1; +// counter += 4; +// } +// +// Elf_Ehdr* success = (Elf_Ehdr*) load_file(pcb_p, (uint32_t*) start); +// pcb_p->R15 = success->e_entry; +// for (int i = 0; i < (len / BLOCK_SIZE) + 1; i++) +// { +// uint32_t *v = (uint32_t *) (start + (i * BLOCK_SIZE)); +// vm_free_mapping(KERNEL_VAS, (void*) v); +// } } /* diff --git a/kernel/process/scheduler.c b/kernel/src/process/scheduler.c similarity index 98% rename from kernel/process/scheduler.c rename to kernel/src/process/scheduler.c index b3cae6dc..5b25be05 100644 --- a/kernel/process/scheduler.c +++ b/kernel/src/process/scheduler.c @@ -1,13 +1,12 @@ -#include "global_defs.h" -#include "kthread.h" -#include "scheduler.h" -#include "vm.h" -#include "klibc.h" -#include "process.h" -#include "data_structures/linked_list.h" -#include "data_structures/hash_map.h" -#include "data_structures/array_list.h" -#include "drivers/timer.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #define MAX_TASKS 100 // in the future, cap will be removed #define MAX_ACTIVE_TASKS 4 // in the future, will dynamically change based on load diff --git a/kernel/process/signals.c b/kernel/src/process/signals.c.old similarity index 84% rename from kernel/process/signals.c rename to kernel/src/process/signals.c.old index a299f487..d2447631 100644 --- a/kernel/process/signals.c +++ b/kernel/src/process/signals.c.old @@ -9,8 +9,8 @@ SIGTERM */ -#include "signals.h" -#include "process.h" +#include +#include void signal_mask(char * type, int index, uint32_t PID) { diff --git a/kernel/tests/testingsuite_example/.DS_Store b/kernel/tests/testingsuite_example/.DS_Store deleted file mode 100644 index fb0c27234dee3e4ce91e84c76e4962d98b161887..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}N6?5Kd~WRl5}FOb<`jPXj_Ut!E$?kcD1nXf-+hBLjGM1?I9AH23rUB~34kJ(zv-nxRb6Qt6fF#`5D6lU8AB8k;>c zby{o0om%Rq?WE$ij@3x|foJThn>Ie|{WuN>w(A|ppi{T!w&N&uWfZhNg`OPB$d5af zxE=Y)Nlou}DE+iix96*^-~vLcZWJ8IM0zrmY1b-XtJ@2`-eys(u9W*l(JPlrMX|O~ z>i6v{%UW7q-`YEB_Ajq*Ztw0N9-p4|ZEz$2WmdzWe;HV05Cg;jF)(rrn5WO09=Vgz zfrtTO;I|Cm`yfCO9fO%h^>jd|N&vt-xRrp7wFJfpgO0&WBg}ws9SW#JxhXNY4hO$5 z>l}lbMjg($DL%OQGB*_pS6_$yg<8(Iqmg=IfEf77z?dG|nE!WwuK&LV(TErz21bej zp5LkMRNzP^w+@@pi00m&;WD{W*Wf*LO%kE2I`1` HKV{$@LCs$; diff --git a/kernel/uboot_configuration/generate.sh b/kernel/uboot_configuration/generate.sh old mode 100644 new mode 100755 index e69de29b..edf2f5ed --- a/kernel/uboot_configuration/generate.sh +++ b/kernel/uboot_configuration/generate.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +echo " +setenv bootargs $*@ +bootm 0x210000 +" > "$DIR/uboot-commands.ubt" \ No newline at end of file diff --git a/kernel/uboot_configuration/uboot-commands-test.ubt b/kernel/uboot_configuration/uboot-commands-test.ubt deleted file mode 100644 index 49141e8a..00000000 --- a/kernel/uboot_configuration/uboot-commands-test.ubt +++ /dev/null @@ -1,2 +0,0 @@ -setenv bootargs root=/dev/ram mem=128M -test -bootm 0x210000 diff --git a/kernel/uboot_configuration/uboot-commands.ubt b/kernel/uboot_configuration/uboot-commands.ubt index c6945626..15f90ee9 100644 --- a/kernel/uboot_configuration/uboot-commands.ubt +++ b/kernel/uboot_configuration/uboot-commands.ubt @@ -1,2 +1,4 @@ -setenv bootargs root=/dev/ram mem=128M -load /hello + +setenv bootargs root=/dev/ram mem=128M@ bootm 0x210000 + diff --git a/user/include/elf.h b/user/include/elf.h index 4d8c0c8e..5422cf35 100644 --- a/user/include/elf.h +++ b/user/include/elf.h @@ -5,7 +5,7 @@ extern "C" { #endif -#include +#include "../../kernel/src/klibc//include/stdint.h" typedef uint16_t Elf32_Half; typedef uint16_t Elf64_Half; diff --git a/user/include/inttypes.h b/user/include/inttypes.h index acd023c1..d7b882e1 100644 --- a/user/include/inttypes.h +++ b/user/include/inttypes.h @@ -7,7 +7,7 @@ extern "C" #endif #include -#include +#include "../../kernel/src/klibc//include/stdint.h" #define __NEED_wchar_t #include diff --git a/user/include/malloc_syscalls.h b/user/include/malloc_syscalls.h index ffcd2340..74a77883 100644 --- a/user/include/malloc_syscalls.h +++ b/user/include/malloc_syscalls.h @@ -1,4 +1,4 @@ -#include +#include "../../kernel/src/klibc//include/stdint.h" //#include "../arch/arm/syscall_arch.h" #include "stdint.h" diff --git a/user/libc/exit/exit.c b/user/libc/exit/exit.c index acb3462a..46584505 100644 --- a/user/libc/exit/exit.c +++ b/user/libc/exit/exit.c @@ -1,5 +1,5 @@ #include -#include +#include "../../../kernel/src/klibc//include/stdint.h" #include "libc.h" #include "atomic.h" #include "syscall.h" diff --git a/user/libc/file_system/fs_syscalls.c b/user/libc/file_system/fs_syscalls.c index 06a169ae..87ede8ff 100644 --- a/user/libc/file_system/fs_syscalls.c +++ b/user/libc/file_system/fs_syscalls.c @@ -1,4 +1,4 @@ -#include +#include "../../../kernel/src/klibc//include/stdint.h" #include "../../include/fs_syscalls.h" #include "../arch/arm/syscall_arch.h" diff --git a/user/libc/internal/atomic.h b/user/libc/internal/atomic.h index 734d2871..154e5609 100644 --- a/user/libc/internal/atomic.h +++ b/user/libc/internal/atomic.h @@ -1,7 +1,7 @@ #ifndef _INTERNAL_ATOMIC_H #define _INTERNAL_ATOMIC_H -#include +#include "../../../kernel/src/klibc//include/stdint.h" static inline int a_ctz_l(unsigned long x) { diff --git a/user/libc/internal/libm.h b/user/libc/internal/libm.h index ebcd7849..e98ea51e 100644 --- a/user/libc/internal/libm.h +++ b/user/libc/internal/libm.h @@ -13,7 +13,7 @@ #ifndef _LIBM_H #define _LIBM_H -#include +#include "../../../kernel/src/klibc//include/stdint.h" #include #include #include diff --git a/user/libc/malloc/malloc_syscalls.c b/user/libc/malloc/malloc_syscalls.c index 30f6d946..5e223f79 100644 --- a/user/libc/malloc/malloc_syscalls.c +++ b/user/libc/malloc/malloc_syscalls.c @@ -1,7 +1,7 @@ -#include +#include "../../../kernel/src/klibc//include/stdint.h" #include #include "../arch/arm/syscall_arch.h" -#include "stdint.h" +#include "../../../kernel/src/klibc//include/stdint.h" /** * malloc does a system call to allocate memory on the user heap diff --git a/user/libc/math/frexp.c b/user/libc/math/frexp.c index 27b6266e..4aaf877e 100644 --- a/user/libc/math/frexp.c +++ b/user/libc/math/frexp.c @@ -1,5 +1,5 @@ #include -#include +#include "../../../kernel/src/klibc//include/stdint.h" double frexp(double x, int *e) { diff --git a/user/libc/stdio/printf.c b/user/libc/stdio/printf.c index 55bf6c65..e9a627e8 100644 --- a/user/libc/stdio/printf.c +++ b/user/libc/stdio/printf.c @@ -1,5 +1,5 @@ #include -#include +#include "../../../kernel/src/klibc/include/stdarg.h" #include "../arch/arm/syscall_arch.h" int printf(const char *restrict fmt, ...) diff --git a/user/libc/stdio/vfprintf.c b/user/libc/stdio/vfprintf.c index ce0bf7b3..c6153fed 100644 --- a/user/libc/stdio/vfprintf.c +++ b/user/libc/stdio/vfprintf.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include "../../../kernel/src/klibc//include/stdarg.h" #include #include #include diff --git a/user/libc/string/memchr.c b/user/libc/string/memchr.c index 4daff7bb..617213a6 100644 --- a/user/libc/string/memchr.c +++ b/user/libc/string/memchr.c @@ -1,5 +1,5 @@ #include -#include +#include "../../../kernel/src/klibc//include/stdint.h" #include #define SS (sizeof(size_t)) diff --git a/user/libc/string/memcpy.c b/user/libc/string/memcpy.c index 06e88742..97efcae4 100644 --- a/user/libc/string/memcpy.c +++ b/user/libc/string/memcpy.c @@ -1,5 +1,5 @@ #include -#include +#include "../../../kernel/src/klibc//include/stdint.h" #include void *memcpy(void *restrict dest, const void *restrict src, size_t n) diff --git a/user/libc/string/memset.c b/user/libc/string/memset.c index f438b073..a7bff6c7 100644 --- a/user/libc/string/memset.c +++ b/user/libc/string/memset.c @@ -1,5 +1,5 @@ #include -#include +#include "../../../kernel/src/klibc//include/stdint.h" void *memset(void *dest, int c, size_t n) { From c1c182663c4c079b65b99d1bdb117c1ab6ffc8ea Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Fri, 21 Feb 2020 10:46:10 +0100 Subject: [PATCH 013/104] new test framework autodetecting tests and executing them in ci --- CMakeLists.txt | 1 + kernel/Makefile | 27 ++++- kernel/Makefile.old | 109 ------------------ kernel/src/common/hw_handlers.c | 2 + kernel/src/common/start.c | 14 ++- kernel/src/klibc/include/stdio.h | 7 ++ kernel/src/klibc/klibc.c | 14 +-- kernel/src/memory/vm/include/swap_framework.h | 6 +- kernel/src/memory/vm/include/swap_fs.h | 4 +- kernel/src/test/generate_tests.sh | 37 ++++++ kernel/src/test/include/test.h | 48 ++++++++ kernel/src/test/monitor_tests.sh | 18 +++ kernel/src/test/test.c | 15 +++ kernel/src/test/test_main.c | 17 +++ 14 files changed, 186 insertions(+), 133 deletions(-) delete mode 100644 kernel/Makefile.old create mode 100755 kernel/src/test/generate_tests.sh create mode 100644 kernel/src/test/include/test.h create mode 100755 kernel/src/test/monitor_tests.sh create mode 100644 kernel/src/test/test.c create mode 100644 kernel/src/test/test_main.c diff --git a/CMakeLists.txt b/CMakeLists.txt index e2f4c505..e45278a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,3 +20,4 @@ message(${kernel_include}) include_directories( ${kernel_include} ) + diff --git a/kernel/Makefile b/kernel/Makefile index 10761fb7..dc2bdede 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -9,7 +9,7 @@ PI_CFLAGS = -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -nostartfiles # variables to define in the preprocessor. MEMORY = 128M DEFINITIONS = -test: DEFINITIONS += TEST +test: DEFINITIONS += ENABLE_TESTS # if we execute the test: rule, enable tests before recompiling KERNEL_PARAMS = root=/dev/ram mem=$(MEMORY) SOURCEDIR = src BUILDDIR = build @@ -42,7 +42,11 @@ CFLAGS += $(foreach dir, $(INCLUDEDIRS), -I./$(dir)) CFLAGS += $(foreach def, $(DEFINITIONS), -D$(def)) test: build | builddir - ${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" + ${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" > test.log & echo $$! > server.PID; + # montior the output, save exit code, remove logfile, kill qemu, + # remove pid file used to kill qemu, exit with correct exit code + $(SOURCEDIR)/test/monitor_tests.sh;e=$$?; rm test.log; kill $$(cat server.PID); rm server.PID; exit $$e + run: build | builddir ${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" @@ -91,12 +95,23 @@ builddir: $(BUILDDIR)/%.o: $(SOURCEDIR)/%.s | builddir @mkdir -p $(shell dirname $@) - $(AS) -mcpu=arm1176jzf-s -g $< -o $@ + @echo Assembling $< + @$(AS) -mcpu=arm1176jzf-s -g $< -o $@ + +$(BUILDDIR)/test/test.o: $(SOURCEDIR)/test/test.c dummy | builddir + @$(SOURCEDIR)/test/generate_tests.sh + @mkdir -p $(shell dirname $@) + @echo Compiling $< + @$(CC) $(CFLAGS) -c $< -o $@ + -$(BUILDDIR)/%.o: $(SOURCEDIR)/%.c | builddir - @echo $(CFLAGS) +# depend on dummy to always recompile. There aren't that many files atm anyway and +# when the definitions change, we have to recompile. TODO: move definitions to some kind of file +# so make knows that when it changed it should recompile. +$(BUILDDIR)/%.o: $(SOURCEDIR)/%.c dummy | builddir @mkdir -p $(shell dirname $@) - $(CC) $(CFLAGS) -c $< -o $@ + @echo Compiling $< + @$(CC) $(CFLAGS) -c $< -o $@ clean: rm -rf $(BUILDDIR) diff --git a/kernel/Makefile.old b/kernel/Makefile.old deleted file mode 100644 index b93fa430..00000000 --- a/kernel/Makefile.old +++ /dev/null @@ -1,109 +0,0 @@ -include $(CURDIR)/../config.mk - -TOOLCHAIN_PATH:=$(CURDIR)/../$(TOOLCHAIN_DIR)/$(BARE_METAL_TARGET)/bin -CC:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gcc -AS:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-as -LD:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gcc -OBJCOPY:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-objcopy -MKIMAGE:=$(CURDIR)/../u-boot/u-boot-$(UBOOT_VERSION)/tools/mkimage -GDB:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gdb - -COMMONOBJS = build/start.o build/startup.o build/main/argparse.o \ - build/main/klibc.o build/interrupt.o build/process/process.o \ - build/hw_handlers.o build/process/elf.o build/process/loader.o \ - build/memory/mem_alloc.o build/memory/allocator.o \ - build/memory/mmap.o build/vm/frame.o build/vm/vm.o \ - build/drivers/timer.o build/data_structures/bitvector.o \ - build/data_structures/array_list.o \ - build/data_structures/priority_queue.o \ - build/data_structures/linked_list.o \ - build/data_structures/hash_map.o build/process/scheduler.o \ - build/fs/open_table.o build/fs/fat16/file.o \ - build/drivers/mmci.o - - - -TESTOBJS = build/tests.o build/tests/test_mem_alloc.o build/tests/test_hash_map.o \ - build/tests/test_priority_queue.o build/tests/test_vm.o \ - build/tests/test_fs.o - -PIOBJS = build/pi_light.o build/drivers/uart_pi.o -OBJS = build/drivers/uart.o - -OBJS += $(COMMONOBJS) $(TESTOBJS) -PIOBJS += $(COMMONOBJS) $(TESTOBJS) - - -all: build/flash.bin build/card.sd - -make_Pi: build/kernelPi.img - -CFLAGS += -pipe -std=gnu99 -ffreestanding -nostdinc -Wall -Werror -g -PFLAGS += -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -nostartfiles - -run: build/flash.bin build/card.sd | builddir - ${QEMU} -M versatilepb -cpu arm1176 -sd build/card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" - -run-debug: build/flash.bin build/card.sd | builddir - ${QEMU} -S -s -M versatilepb -cpu arm1176 -sd build/card.sd -m 128M -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" - -gdb: | builddir - ${GDB} -ex "target remote :1234" build/kernel.elf - -builddir: - mkdir -p build - -#boots the kernel at 0x210000 -build/flash.bin: build/kernel.img build/script.img | builddir - dd if=/dev/zero of=$@ bs=4k count=1536 - dd if=../u-boot/u-boot-$(UBOOT_VERSION)/u-boot.bin of=build/flash.bin conv=notrunc bs=4k - dd if=build/kernel.img of=$@ conv=notrunc bs=4k seek=512 - dd if=build/script.img of=$@ conv=notrunc bs=4k seek=575 - -# 32678*4096 = 128MiB -build/card.sd: fs-cmdline userhello | builddir - dd if=/dev/zero of=$@ conv=notrunc bs=4096 count=32768 - fs/cmdline/buildfs ../user/hello/ - -userhello: - make -C ../user/hello - -fs-cmdline: - make -C fs/cmdline - -build/kernel.elf: $(OBJS) | builddir - $(LD) -T kernel.ld -nostartfiles -Wl,-Map,kernel.map $(OBJS) -o $@ - -build/kernel.bin: build/kernel.elf | builddir - $(OBJCOPY) -O binary $< $@ - -build/kernel.img: build/kernel.bin | builddir - $(MKIMAGE) -A arm -C none -O linux -T kernel -d $< -a 0x00010000 -e 0x00010000 $@ - -# Begin Pi Make -build/kernelPi.elf: $(PIOBJS) | builddir - $(CC) -T kernelPi.ld -O2 $(PFLAGS) $(PIOBJS) -o $@ - -build/kernelPi.img: build/kernelPi.elf | builddir - $(OBJCOPY) $< -O binary $@ - -# End Pi Make - -build/script.img: $(UBOOTBUILDFILE) | builddir - $(MKIMAGE) -A arm -C none -T script -d uboot_configuration/uboot-commands.ubt -a 0x10000 -e 0x10000 $@ - -build/course_os.img: build/kernel.img | builddir - cat ../u-boot/u-boot-$(UBOOT_VERSION)/u-boot.bin $< > $@ - -build/startup.o: src/common | builddir - @mkdir -p $(shell dirname $@) - $(AS) -mcpu=arm1176jzf-s -g $< -o $@ - -build/%.o: %.c | builddir - @mkdir -p $(shell dirname $@) - $(CC) $(CFLAGS) -Iinclude -c $< -o $@ - -clean: - rm -rf build - @echo "I'm persisting the SD card 'card.sd', you'll have to remove that yourself if you want to rebuild it." - @echo "('rm sd.card')" diff --git a/kernel/src/common/hw_handlers.c b/kernel/src/common/hw_handlers.c index 11e45332..7530e14d 100644 --- a/kernel/src/common/hw_handlers.c +++ b/kernel/src/common/hw_handlers.c @@ -120,6 +120,8 @@ long __attribute__((interrupt("SWI"))) software_interrupt_handler(void) return 0L; break; + + // NOTE: All FS syscalls have been *DISABLED* until the filesystem works again. case SYSCALL_CREATE: os_printf("Create system call called!\n"); return -1; diff --git a/kernel/src/common/start.c b/kernel/src/common/start.c index 3a9372fe..061b15fc 100644 --- a/kernel/src/common/start.c +++ b/kernel/src/common/start.c @@ -28,6 +28,7 @@ #include #include #include +#include // The file system has currently been *disabled* due to bugs //#include "fs/open_table.h" //to initialize fs opentable @@ -43,15 +44,13 @@ #define UART0_IMSC (*((volatile uint32_t *)(UART0_ADDRESS + 0x038))) -void uart_handler(void *null) -{ +void uart_handler(void *null) { print_uart0("uart0!\n"); } // This start is what u-boot calls. It's just a wrapper around setting up the // virtual memory for the kernel. -void start(uint32_t *p_bootargs) -{ +void start(uint32_t *p_bootargs) { // Initialize the virtual memory print_uart0("Enabling MMU...\n"); vm_init(); @@ -63,8 +62,7 @@ void start(uint32_t *p_bootargs) // This start is what starts the kernel. Note that virtual memory is enabled // at this point (And running, also, in the kernel's VAS). -void start2(uint32_t *p_bootargs) -{ +void start2(uint32_t *p_bootargs) { // Setup all of the exception handlers... (hrm, interaction with VM?) init_vector_table(); @@ -114,7 +112,11 @@ void start2(uint32_t *p_bootargs) os_printf("Programming the timer interrupt\n"); start_timer_interrupts(0, 10); + #ifndef ENABLE_TESTS argparse_process(p_bootargs); + #else + test_main(); + #endif print_uart0("done parsing atag list\n"); diff --git a/kernel/src/klibc/include/stdio.h b/kernel/src/klibc/include/stdio.h index 8f97d4ed..f68ee9ea 100644 --- a/kernel/src/klibc/include/stdio.h +++ b/kernel/src/klibc/include/stdio.h @@ -1,6 +1,13 @@ +#ifndef STDIO_H +#define STDIO_H + #ifndef NULL #define NULL ((void*) 0) #endif #define UNUSED(x) (void)(x) + +#include + +#endif diff --git a/kernel/src/klibc/klibc.c b/kernel/src/klibc/klibc.c index 6b45ff25..08db888c 100644 --- a/kernel/src/klibc/klibc.c +++ b/kernel/src/klibc/klibc.c @@ -306,13 +306,13 @@ int os_snprintf(char *buf, int buflen, const char *fmt, ...) } int os_printf(const char *str_buf, ...){ -va_list args; -va_start(args, str_buf); -char buf[256]; -int n = os_vsnprintf(buf, 255, str_buf, args); -va_end(args); -print_uart0(buf); -return n; + va_list args; + va_start(args, str_buf); + char buf[256]; + int n = os_vsnprintf(buf, 255, str_buf, args); + va_end(args); + print_uart0(buf); + return n; } /* Set the first n bytes of dest to be the value c.*/ diff --git a/kernel/src/memory/vm/include/swap_framework.h b/kernel/src/memory/vm/include/swap_framework.h index 28329810..d8a6380b 100644 --- a/kernel/src/memory/vm/include/swap_framework.h +++ b/kernel/src/memory/vm/include/swap_framework.h @@ -54,7 +54,7 @@ void swap_init(); //void swap_init(os_size_t); To be implemented... [specifies global page size] -/* store_page will store a page to media - not common memory - storage, e.g. HDD +/* store_page will store a page to media - not main memory - storage, e.g. HDD * from the page*. ID parameter passed will change to appropriate index (i.e. return value) * void* page -> data to be paged * os_size_t pagesize: The size of a page in bytes, i.e. 4096 b @@ -70,7 +70,7 @@ uint32_t store_page_LZ(void*, uint32_t*); // All LZ functions not yet working... /* retrieve_page will retrieve the page identified the ID pointer and - * will store it back into common memory (specified by the void *page pointer) + * will store it back into main memory (specified by the void *page pointer) * * Returns: NULL on failure or simply passes back ID on success * NOTE: Page size was set by store_page @@ -83,7 +83,7 @@ uint32_t retrieve_page_LZ(void*, uint32_t*); os_size_t sum_stored(); -/* vm_swap_page will store a page from common memory (specified by void *page) +/* vm_swap_page will store a page from main memory (specified by void *page) * to a swap space either on disk or a compressed block in memory * * Returns: The ID pointer - bit vector index - of where the swap_space was stored and diff --git a/kernel/src/memory/vm/include/swap_fs.h b/kernel/src/memory/vm/include/swap_fs.h index 951304d3..ddd64701 100644 --- a/kernel/src/memory/vm/include/swap_fs.h +++ b/kernel/src/memory/vm/include/swap_fs.h @@ -23,7 +23,7 @@ char *generate_filename(uint8_t); int32_t swapfs_init(int, uint8_t); -/* swapfs_store will store a page to media - not common memory - storage, e.g. HDD +/* swapfs_store will store a page to media - not main memory - storage, e.g. HDD * from the page* * void* page -> data to be paged * os_size_t pagesize: The size of a page in bytes, i.e. 4096 b @@ -37,7 +37,7 @@ int64_t swapfs_store(void*, uint32_t*, uint8_t); /* swapfs_retrieve will retrieve the page identified by the ID pointer and - * will store it back into common memory (specified by the void *page pointer) + * will store it back into main memory (specified by the void *page pointer) * * Returns: -1 on failure and 1 on success */ diff --git a/kernel/src/test/generate_tests.sh b/kernel/src/test/generate_tests.sh new file mode 100755 index 00000000..9e4f095e --- /dev/null +++ b/kernel/src/test/generate_tests.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# this bash script will read all directories to find tests. +# it will make a list of tests and write this to test.c +# the makefile will run this file automatically while building, +# so all tests are automatically executed. + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +# clear the file +echo -n "" > "$DIR/test.c" + +echo " +// DO NOT EDIT +// this file is generated by generate_tests.sh + +#include + +" >> "$DIR/test.c" + +TESTFNS=$(grep -hr --include "*.c" -oP "(?<=TEST_CREATE\()(.*)(?=,)") + +for FNNAME in $TESTFNS +do + echo "int test_$FNNAME();" >> "$DIR/test.c" +done + +echo "void test_main(){" >> "$DIR/test.c" + +for FNNAME in $TESTFNS +do + echo " if (!test_$FNNAME()) {return;}" >> "$DIR/test.c" +done + + +echo " + os_printf(\"TESTS COMPLETE\n\"); +}" >> "$DIR/test.c" \ No newline at end of file diff --git a/kernel/src/test/include/test.h b/kernel/src/test/include/test.h new file mode 100644 index 00000000..2c57555c --- /dev/null +++ b/kernel/src/test/include/test.h @@ -0,0 +1,48 @@ + +#ifndef TEST_H +#define TEST_H + +#define TEST_PASS 1 +#define TEST_FAIL 0 + +#include + +// Only compile test definitions if enabled +#if ENABLE_TESTS + +#define TEST_CREATE(name, block) \ + int __internal_test_##name() block \ + int test_##name() { \ + os_printf("Testing %s\n", #name); \ + int res = __internal_test_##name(); \ + if (res == TEST_PASS) { \ + os_printf("PASSED\n"); \ + return 1; \ + } else { \ + os_printf("FAILED\n"); \ + return 0; \ + } \ + } + +#define PASS() return TEST_PASS +#define FAIL() return TEST_FAIL +#define ASSERT(expr) do { if(!expr) { return TEST_FAIL } } while(0) +#define ASSERT_EQ(l, r) do { if(l != r) { return TEST_FAIL } } while(0) + + +#else + +// If tests are disabled during compile time, all the macros expand to nothing + +#define TEST_CREATE(name, block) +#define PASS() 0 +#define FAIL() 0 +#define ASSERT(expr) 0 +#define ASSERT_EQ(l, r) d0 + +#endif + +void test_main(); + +#endif + diff --git a/kernel/src/test/monitor_tests.sh b/kernel/src/test/monitor_tests.sh new file mode 100755 index 00000000..e7c653da --- /dev/null +++ b/kernel/src/test/monitor_tests.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +tail -f -n +1 "$DIR/../../test.log" | while read line +do + if [[ $line == *"TESTS COMPLETE"* ]]; then + echo "COMPLETE" + exit 0 + + elif [[ $line == *"FAILED"* ]]; then + echo "FAILED" + exit 1 + else + echo "$line" + fi +done + diff --git a/kernel/src/test/test.c b/kernel/src/test/test.c new file mode 100644 index 00000000..94f983d2 --- /dev/null +++ b/kernel/src/test/test.c @@ -0,0 +1,15 @@ + +// DO NOT EDIT +// this file is generated by generate_tests.sh + +#include + + +int test_first(); +int test_second(); +void test_main(){ + if (!test_first()) {return;} + if (!test_second()) {return;} + + os_printf("TESTS COMPLETE\n"); +} diff --git a/kernel/src/test/test_main.c b/kernel/src/test/test_main.c new file mode 100644 index 00000000..21c1b759 --- /dev/null +++ b/kernel/src/test/test_main.c @@ -0,0 +1,17 @@ + +#include + + +TEST_CREATE(first, { + os_printf("test"); + + + PASS(); +}) + +TEST_CREATE(second, { + os_printf("test"); + + + PASS(); +}) From 2be2bea805e6b5d412f78f4f4c8c3e9c2b9af16f Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Sun, 23 Feb 2020 23:00:43 +0100 Subject: [PATCH 014/104] Added: * Quickstring * u8 array list * vp array list * Lots of FS code * Lots of tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes: * Updated some klibc * Changed the memory allocator Co-authored-by: Jonathan Dönszelmann --- .vscode/settings.json | 7 + CMakeLists.txt | 4 + kernel/Makefile | 4 +- kernel/src/common/argparse.c | 12 +- kernel/src/common/hw_handlers.c | 3 +- kernel/src/common/interrupt.c | 2 +- kernel/src/common/start.c | 108 +- kernel/src/drivers/mmci/mmci.c | 2 +- kernel/src/drivers/time/timer.c | 3 +- kernel/src/ds/array_list.c | 6 +- kernel/src/ds/array_list.c.old | 119 +++ kernel/src/ds/bitvector.c | 2 +- kernel/src/ds/hash_map.c | 11 +- kernel/src/ds/include/qstr.h | 35 + kernel/src/ds/include/u8_array_list.h | 43 + kernel/src/ds/include/vp_array_list.h | 35 + kernel/src/ds/linked_list.c | 11 +- kernel/src/ds/priority_queue.c | 10 +- kernel/src/ds/qstr.c | 74 ++ kernel/src/ds/test/qstr_test.c | 63 ++ kernel/src/ds/test/u8_array_list_test.c | 123 +++ kernel/src/ds/test/vp_array_list_test.c | 74 ++ kernel/src/ds/u8_array_list.c | 100 ++ kernel/src/ds/vp_array_list.c | 92 ++ kernel/src/fs/file.c | 56 + kernel/src/fs/include/file.h | 31 + kernel/src/fs/include/fs.h | 13 + kernel/src/fs/include/inode.h | 42 + kernel/src/fs/include/path.h | 99 ++ kernel/src/fs/include/vfs.h | 64 ++ kernel/src/fs/inode.c | 34 + kernel/src/fs/path.c | 215 ++++ kernel/src/fs/test/test.c | 23 + kernel/src/fs/test/test_path.c | 261 +++++ kernel/src/fs/tmpfs/include/tmpfs.h | 30 + kernel/src/fs/tmpfs/test/test.c | 118 +++ kernel/src/fs/tmpfs/tmpfs.c | 209 ++++ kernel/src/fs/vfs.c | 92 ++ kernel/src/klibc/alloc.c | 136 +++ kernel/src/klibc/include/klibc.h | 96 +- kernel/src/klibc/include/math.h | 10 + kernel/src/klibc/include/stdint.h | 4 + kernel/src/klibc/include/stdio.h | 23 + kernel/src/klibc/include/stdlib.h | 42 + kernel/src/klibc/include/string.h | 19 + kernel/src/klibc/klibc.c | 971 ++++-------------- kernel/src/klibc/mem.c | 30 + kernel/src/klibc/printf.c | 178 ++++ kernel/src/klibc/string.c | 79 ++ .../kthread/{kthreads.c.old => kthreads.c} | 6 +- kernel/src/memory/allocator.c | 478 ++++----- kernel/src/memory/allocator.c.old | 333 ++++++ kernel/src/memory/include/allocator.h | 89 +- kernel/src/memory/include/allocator.h.old | 32 + kernel/src/memory/include/mem_alloc.h | 24 +- kernel/src/memory/llist.c | 88 ++ kernel/src/memory/mem_alloc.c | 106 +- kernel/src/memory/mmap.c | 17 +- kernel/src/memory/test/test_allocator.c | 30 + kernel/src/memory/vm/include/vm.h | 2 +- kernel/src/memory/vm/vm.c | 49 +- kernel/src/process/elf.c | 26 +- kernel/src/process/include/process.h | 3 +- kernel/src/process/loader.c | 12 +- kernel/src/process/process.c | 16 +- kernel/src/process/scheduler.c | 9 +- kernel/src/test/generate_tests.sh | 4 +- kernel/src/test/include/test.h | 72 +- kernel/src/test/monitor_tests.sh | 9 +- kernel/src/test/test.c | 94 +- kernel/src/test/test_main.c | 17 - 71 files changed, 3933 insertions(+), 1401 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 kernel/src/ds/array_list.c.old create mode 100644 kernel/src/ds/include/qstr.h create mode 100644 kernel/src/ds/include/u8_array_list.h create mode 100644 kernel/src/ds/include/vp_array_list.h create mode 100644 kernel/src/ds/qstr.c create mode 100644 kernel/src/ds/test/qstr_test.c create mode 100644 kernel/src/ds/test/u8_array_list_test.c create mode 100644 kernel/src/ds/test/vp_array_list_test.c create mode 100644 kernel/src/ds/u8_array_list.c create mode 100644 kernel/src/ds/vp_array_list.c create mode 100644 kernel/src/fs/file.c create mode 100644 kernel/src/fs/include/file.h create mode 100644 kernel/src/fs/include/fs.h create mode 100644 kernel/src/fs/include/inode.h create mode 100644 kernel/src/fs/include/path.h create mode 100644 kernel/src/fs/include/vfs.h create mode 100644 kernel/src/fs/inode.c create mode 100644 kernel/src/fs/path.c create mode 100644 kernel/src/fs/test/test.c create mode 100644 kernel/src/fs/test/test_path.c create mode 100644 kernel/src/fs/tmpfs/include/tmpfs.h create mode 100644 kernel/src/fs/tmpfs/test/test.c create mode 100644 kernel/src/fs/tmpfs/tmpfs.c create mode 100644 kernel/src/fs/vfs.c create mode 100644 kernel/src/klibc/alloc.c create mode 100644 kernel/src/klibc/include/math.h create mode 100644 kernel/src/klibc/include/stdlib.h create mode 100644 kernel/src/klibc/include/string.h create mode 100644 kernel/src/klibc/mem.c create mode 100644 kernel/src/klibc/printf.c create mode 100644 kernel/src/klibc/string.c rename kernel/src/kthread/{kthreads.c.old => kthreads.c} (75%) create mode 100644 kernel/src/memory/allocator.c.old create mode 100644 kernel/src/memory/include/allocator.h.old create mode 100644 kernel/src/memory/llist.c create mode 100644 kernel/src/memory/test/test_allocator.c delete mode 100644 kernel/src/test/test_main.c diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..ba02a079 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "files.associations": { + "string.h": "c", + "stdint.h": "c", + "stdio.h": "c" + } +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index e45278a5..8d98ccf2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,10 @@ file(GLOB_RECURSE kernel_include LIST_DIRECTORIES true ./kernel/src/**/include) set(SOURCE_FILES ${kernel_sources}) +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") + +add_compile_definitions(ENABLE_TESTS MEM_DEBUG) + add_executable(course_os ${SOURCE_FILES}) message(${kernel_include}) diff --git a/kernel/Makefile b/kernel/Makefile index dc2bdede..c0b0f80a 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -3,12 +3,12 @@ include $(CURDIR)/../config.mk # ===================== Configuration ===================== # Flags to give to the c compiler -CFLAGS += -pipe -std=gnu99 -ffreestanding -nostdinc -Wall -Werror -g +CFLAGS += -pipe -std=gnu99 -ffreestanding -nostdinc -Wall -Werror -g -O2 PI_CFLAGS = -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -nostartfiles # variables to define in the preprocessor. MEMORY = 128M -DEFINITIONS = +DEFINITIONS = MEM_DEBUG test: DEFINITIONS += ENABLE_TESTS # if we execute the test: rule, enable tests before recompiling KERNEL_PARAMS = root=/dev/ram mem=$(MEMORY) SOURCEDIR = src diff --git a/kernel/src/common/argparse.c b/kernel/src/common/argparse.c index 6d31d969..0c88324d 100644 --- a/kernel/src/common/argparse.c +++ b/kernel/src/common/argparse.c @@ -1,9 +1,9 @@ #include #include -#include "include/argparse.h" -#include "klibc.h" +#include +#include +#include #include -//#include "tests.h" static void argparse_parse(char *); @@ -70,7 +70,7 @@ static void argparse_parse(char *cmdline) { os_printf("token: %s\n", token); - if (os_strcmp("-load", token) == 0) + if (strcmp("-load", token) == 0) { char* name = os_strtok(NULL, " "); @@ -79,7 +79,7 @@ static void argparse_parse(char *cmdline) process_execute(proc); } - else if (os_strcmp("-test", token) == 0) + else if (strcmp("-test", token) == 0) { os_printf("RUNNING TESTS\n"); os_printf("Running tests...\n"); @@ -101,7 +101,7 @@ static void argparse_parse(char *cmdline) */ int string_to_unsigned_int(char *input, int base) { - int i = os_strlen(input) - 1; // Index in the string + int i = strlen(input) - 1; // Index in the string if (hex_value_of_character(input[i]) == -1) { diff --git a/kernel/src/common/hw_handlers.c b/kernel/src/common/hw_handlers.c index 7530e14d..23ff8844 100644 --- a/kernel/src/common/hw_handlers.c +++ b/kernel/src/common/hw_handlers.c @@ -7,7 +7,8 @@ #include #include #include -#include +#include +#include #include #include // TODO: fs is removed diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index 77de4ac6..74ba2ec0 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -4,7 +4,7 @@ * */ #include -#include +#include // there are 32 kinds of interrupts on the VIC // this structure may need to be expanded if the secondary controller is incorporated diff --git a/kernel/src/common/start.c b/kernel/src/common/start.c index 061b15fc..493d9fcc 100644 --- a/kernel/src/common/start.c +++ b/kernel/src/common/start.c @@ -45,17 +45,17 @@ #define UART0_IMSC (*((volatile uint32_t *)(UART0_ADDRESS + 0x038))) void uart_handler(void *null) { - print_uart0("uart0!\n"); + print_uart0("uart0!\n"); } // This start is what u-boot calls. It's just a wrapper around setting up the // virtual memory for the kernel. void start(uint32_t *p_bootargs) { - // Initialize the virtual memory - print_uart0("Enabling MMU...\n"); - vm_init(); - os_printf("Initialized VM datastructures.\n"); - mmap(p_bootargs); + // Initialize the virtual memory + print_uart0("Enabling MMU...\n"); + vm_init(); + os_printf("Initialized VM datastructures.\n"); + mmap(p_bootargs); } @@ -63,74 +63,74 @@ void start(uint32_t *p_bootargs) { // This start is what starts the kernel. Note that virtual memory is enabled // at this point (And running, also, in the kernel's VAS). void start2(uint32_t *p_bootargs) { - // Setup all of the exception handlers... (hrm, interaction with VM?) - init_vector_table(); + // Setup all of the exception handlers... (hrm, interaction with VM?) + init_vector_table(); - // Setup kmalloc... - init_heap(); + // Setup kmalloc... + init_heap(); - //print_uart0("\nCourseOS!\n"); + //print_uart0("\nCourseOS!\n"); - splash(); + splash(); - // Test stuff... - /*int *p = (int*)0xFFFFFFF0; - p[0] = 1; - os_printf("0x%x == 1?\n", p[0]);*/ + // Test stuff... + /*int *p = (int*)0xFFFFFFF0; + p[0] = 1; + os_printf("0x%x == 1?\n", p[0]);*/ - //run_vm_tests(); - //INFO("There are %d free frames.\n", vm_count_free_frames()); - //run_mem_alloc_tests(); - //INFO("There are %d free frames.\n", vm_count_free_frames()); - //run_prq_tests(); - //run_hmap_tests(); + //run_vm_tests(); + //INFO("There are %d free frames.\n", vm_count_free_frames()); + //run_mem_alloc_tests(); + //INFO("There are %d free frames.\n", vm_count_free_frames()); + //run_prq_tests(); + //run_hmap_tests(); - // The file system has currently been *disabled* due to bugs + // The file system has currently been *disabled* due to bugs // kfs_init(0, 0, 0); - /* - 4-15-15: #Prakash: What happens if we let the program load here? - Let's make argparse_process() do its thing + /* + 4-15-15: #Prakash: What happens if we let the program load here? + Let's make argparse_process() do its thing - Note: As of 4-15-15 this fails horribly with hello.o not being - recognized as an ELF file and DATA ABORT HANDLER being syscalled - */ + Note: As of 4-15-15 this fails horribly with hello.o not being + recognized as an ELF file and DATA ABORT HANDLER being syscalled + */ - // enable interrupt handling - enable_interrupts(); + // enable interrupt handling + enable_interrupts(); - // initialize the timers - initialize_timers(); + // initialize the timers + initialize_timers(); - //assert(1==2 && "Test assert please ignore"); + //assert(1==2 && "Test assert please ignore"); process_init(); - sched_init(); + sched_init(); - // FIXME: temporary - os_printf("Programming the timer interrupt\n"); - start_timer_interrupts(0, 10); + // FIXME: temporary + os_printf("Programming the timer interrupt\n"); + start_timer_interrupts(0, 10); - #ifndef ENABLE_TESTS - argparse_process(p_bootargs); - #else - test_main(); - #endif +#ifndef ENABLE_TESTS + argparse_process(p_bootargs); +#else + test_main(); +#endif - print_uart0("done parsing atag list\n"); + print_uart0("done parsing atag list\n"); - //init_kheap(31 * 0x100000); - //init_uheap(0x100000); + //init_kheap(31 * 0x100000); + //init_uheap(0x100000); - //initialize pcb table and PID - /* init_all_processes(); */ - //print_process_state(0); - //run_process_tests(); - //print_PID(); - // init_q(); - //common(); + //initialize pcb table and PID + /* init_all_processes(); */ + //print_process_state(0); + //run_process_tests(); + //print_PID(); + // init_q(); + //common(); - SLEEP; + SLEEP; } diff --git a/kernel/src/drivers/mmci/mmci.c b/kernel/src/drivers/mmci/mmci.c index e6b80775..c31e4096 100644 --- a/kernel/src/drivers/mmci/mmci.c +++ b/kernel/src/drivers/mmci/mmci.c @@ -118,7 +118,7 @@ int init_sd() /** * SD Capacity Method * - * Returns the maximum capacity of the SD card in bytes; for our + * Returns the maximum filled of the SD card in bytes; for our * current needs it computes the size statically * * TODO: Eventually this needs to be set up to calculate the size diff --git a/kernel/src/drivers/time/timer.c b/kernel/src/drivers/time/timer.c index d9aa6aee..3b94f986 100644 --- a/kernel/src/drivers/time/timer.c +++ b/kernel/src/drivers/time/timer.c @@ -1,7 +1,8 @@ /* Device Driver for ARM Dual-Timer Module (SP804) Reference Manual can be found here : http://infocenter.arm.com/help/topic/com.arm.doc.ddi0271d/DDI0271.pdf*/ #include -#include +#include +#include #include #include diff --git a/kernel/src/ds/array_list.c b/kernel/src/ds/array_list.c index 1ccfb417..00760c83 100644 --- a/kernel/src/ds/array_list.c +++ b/kernel/src/ds/array_list.c @@ -6,7 +6,9 @@ */ #include -#include +#include +#include +#include arrl_handle* arrl_create() { return arrl_create_fixed(DEFAULT_BUCKET_SIZE); @@ -68,7 +70,7 @@ void arrl_remove(arrl_handle* arrl, void* elem) { // Except the last bucket, shift each bucket up by one and copy first element of the next bucket to the last cell of the current bucket out: while (curr_bucket != tail) { - os_memcpy(*(((uint32_t**)curr_bucket->data) + bucket_index + 1), + memcpy(*(((uint32_t**)curr_bucket->data) + bucket_index + 1), *(((uint32_t**)curr_bucket->data) + bucket_index + 0), bucket_size - bucket_index - 1); bucket_index = 0; diff --git a/kernel/src/ds/array_list.c.old b/kernel/src/ds/array_list.c.old new file mode 100644 index 00000000..b60105e8 --- /dev/null +++ b/kernel/src/ds/array_list.c.old @@ -0,0 +1,119 @@ +/* + * array_list.c + * + * Created on: Apr 21, 2015 + * Author: kittenRainbow + */ + +#include +#include +#include + +arrl_handle* arrl_create() { + return arrl_create_fixed(DEFAULT_BUCKET_SIZE); +} + +arrl_handle* arrl_create_fixed(uint32_t bucket_size) { + arrl_handle* result = (arrl_handle *) kmalloc(sizeof(arrl_handle)); + void** bucket = kmalloc(bucket_size * sizeof(void*)); + llist_handle * l = llist_create(bucket); + result->linked_list = l; + result->size = 0; + result->capacity = bucket_size; + return result; +} + +void arrl_append(arrl_handle* arrl, void* elem) { + llist_node * curr_bucket; + uint32_t list_size; + uint32_t last_bucket_size; + + if (arrl->capacity == arrl->size) { + void* data = kmalloc(arrl->bucket_size * sizeof(void*)); + llist_enqueue(arrl->linked_list, data); + arrl->capacity += arrl->bucket_size; + } + + curr_bucket = arrl->linked_list->head; + list_size = arrl->size / arrl->bucket_size; + last_bucket_size = arrl->size % arrl->bucket_size; + + for(uint32_t i=0; i < list_size; ++i) { + curr_bucket= curr_bucket->next; + } + *(((int**)curr_bucket->data) + last_bucket_size) = (int*)elem; +} + +void arrl_remove(arrl_handle* arrl, void* elem) { + uint32_t bucket_size; + uint32_t list_size; + uint32_t bucket_index; + uint32_t list_index; + llist_node* curr_bucket; + llist_node* tail; + + bucket_size = arrl->bucket_size; + list_size = arrl->linked_list->count; + curr_bucket = arrl->linked_list->head; + tail = arrl->linked_list->tail; + + for (list_index = 0; list_index < list_size; ++list_index) { + for (bucket_index = 0; bucket_index < bucket_size; ++bucket_index) { + //if (elem == curr_bucket->data[bucket_index]) { + kfree(elem); + goto out; + //} + } + curr_bucket = curr_bucket->next; + } + + // Except the last bucket, shift each bucket up by one and copy first element of the next bucket to the last cell of the current bucket + out: while (curr_bucket != tail) { + os_memcpy(*(((uint32_t**)curr_bucket->data) + bucket_index + 1), + *(((uint32_t**)curr_bucket->data) + bucket_index + 0), + bucket_size - bucket_index - 1); + bucket_index = 0; + *(((int**)curr_bucket->data) + bucket_size - 1) = *((int**)curr_bucket->next->data); + curr_bucket = curr_bucket->next; + } + + --arrl->size; +} + +uint32_t arrl_contains(arrl_handle* arrl, void* elem) { + uint32_t bucket_size = arrl->bucket_size; + uint32_t list_size = arrl->linked_list->count; + llist_node* bucket = arrl->linked_list->head; + + for (uint32_t list_index = 0; list_index < list_size; ++list_index) { + for (uint32_t bucket_index = 0; bucket_index < bucket_size; + ++bucket_index) { + //if (elem == bucket->data[bucket_index]) { + return 1; + //} + } + bucket = bucket->next; + } + return 0; +} + +uint32_t arrl_index_of(arrl_handle* arrl, void* elem) { + int bucket_size = arrl->bucket_size; + int list_size = arrl->linked_list->count; + llist_node* bucket = arrl->linked_list->head; + + for (int list_index = 0; list_index < list_size; ++list_index) { + for (int bucket_index = 0; bucket_index < bucket_size; ++bucket_index) { +// if (elem == bucket->data[bucket_index]) { + return list_index * DEFAULT_BUCKET_SIZE + bucket_index; +// } + } + bucket = bucket->next; + } + return -1; +} + +uint32_t arrl_count(arrl_handle* arrl) { + return arrl->size; +} + diff --git a/kernel/src/ds/bitvector.c b/kernel/src/ds/bitvector.c index 020cf3dd..62a117ed 100644 --- a/kernel/src/ds/bitvector.c +++ b/kernel/src/ds/bitvector.c @@ -1,5 +1,5 @@ #include -#include +#include #include uint32_t const WORD_SIZE = 32; diff --git a/kernel/src/ds/hash_map.c b/kernel/src/ds/hash_map.c index dbd0a272..6e7f8f8a 100644 --- a/kernel/src/ds/hash_map.c +++ b/kernel/src/ds/hash_map.c @@ -1,5 +1,8 @@ #include -#include +#include +#include +#include +#include /* this should be prime */ #define TABLE_STARTSIZE 1021 @@ -20,12 +23,10 @@ static unsigned long __hmap_is_prime(unsigned long val) { a = (a * a) % val; exp >>= 1; } - if (p != 1) { return 0; } } - return 1; } @@ -49,7 +50,7 @@ static void __hmap_rehash(hmap_handle* hmap) { hmap->size = __hmap_find_prime_greater_than(size << 1); hmap->table = (hmap_entry*) kmalloc(sizeof(hmap_entry) * hmap->size); - os_memset(hmap->table, 0, sizeof(hmap_entry) * hmap->size); + memset(hmap->table, 0, sizeof(hmap_entry) * hmap->size); hmap->count = 0; while (--size >= 0) { @@ -76,7 +77,7 @@ hmap_handle* hmap_create_fixed(int startsize) { hmap->table = (hmap_entry*) kmalloc(sizeof(hmap_entry) * startsize); - os_memset(hmap->table, 0, startsize); + memset(hmap->table, 0, startsize); hmap->size = startsize; hmap->count = 0; diff --git a/kernel/src/ds/include/qstr.h b/kernel/src/ds/include/qstr.h new file mode 100644 index 00000000..d10b1c43 --- /dev/null +++ b/kernel/src/ds/include/qstr.h @@ -0,0 +1,35 @@ +#ifndef QSTR_H +#define QSTR_H + +#include +#include + +// A Qstr or quickstring, is a string which stores it's length, +// and on first compare calculates and stores its hash to speed up +// further comparisons. Apart from storing the length, the last byte of a Qstr's +// data is always a null. Therefore a pointer to a Qstr is *always* also a valid null +// terminated string. + + +typedef struct Qstr { + char * data; + size_t length; + uint32_t hash; +} Qstr; + +Qstr qstr_from_null_terminated_string(char * arr); +Qstr qstr_from_length_string(char * arr, size_t length); + +void qstr_free(Qstr * qstr); + +// Quick eq. Either compares hashes and lengths to quickly determine non equality. +// While doing full string compare, calculates the hash of left to store. If equal +// this automatically also is the hash of right and both are set. Otherwise just the +// hash of left is set. +bool qstr_eq(Qstr * left, Qstr * right); + +// Normal strincompare. Slightly slower than default compare. +// Also calculates hash of left to speed up further stringcompares. +bool qstr_eq_null_terminated(Qstr * left, char * right); + +#endif \ No newline at end of file diff --git a/kernel/src/ds/include/u8_array_list.h b/kernel/src/ds/include/u8_array_list.h new file mode 100644 index 00000000..cef4f64d --- /dev/null +++ b/kernel/src/ds/include/u8_array_list.h @@ -0,0 +1,43 @@ +// +// Created by victor on 2/21/20. +// + +#ifndef U8ARRAY_LIST_H +#define U8ARRAY_LIST_H + +#include + +typedef struct U8ArrayList { + uint32_t length; + uint32_t capacity; + uint8_t * array; +} U8ArrayList; + +U8ArrayList * u8a_create(uint32_t initial_cap); + +// Frees the list. +void u8a_free(U8ArrayList * arr); + +// Gets element of specified index; +uint8_t u8a_get(U8ArrayList * list, uint32_t index); + +// Sets element to specific data +void u8a_set(U8ArrayList * list, uint32_t index, uint8_t data); + +// Inserts data at the end of the list +uint32_t u8a_push(U8ArrayList * list, uint8_t data); + +// Returns the topmost element and removes it fromhe list. +uint8_t u8a_pop(U8ArrayList * list); + +// Truncates the list to specified size +void u8a_resize(U8ArrayList * list, uint32_t new_size); + +// appends a null terminated string of data to the end of the list. +// Does not copy the null terminator as this can be found using the array length. +uint32_t u8a_push_string(U8ArrayList * arr, char * data); + +// Creates a new u8a with the same contents as another one. +U8ArrayList * u8a_clone(U8ArrayList * arr); + +#endif //U8ARRAY_LIST_H diff --git a/kernel/src/ds/include/vp_array_list.h b/kernel/src/ds/include/vp_array_list.h new file mode 100644 index 00000000..3bcd46ee --- /dev/null +++ b/kernel/src/ds/include/vp_array_list.h @@ -0,0 +1,35 @@ +#ifndef VP_ARRAYLIST_H +#define VP_ARRAYLIST_H +#include + +typedef void (*FreeFunc)(void * data); + +typedef struct VPArrayList { + uint32_t length; + uint32_t capacity; + void ** array; +} VPArrayList; + +VPArrayList * vpa_create(uint32_t initial_cap); + +// Frees the list. +void vpa_free(VPArrayList * arr, FreeFunc freef); + +// Gets element of specified index; +void * vpa_get(VPArrayList * list, uint32_t index); + +// Sets element to specific data +void vpa_set(VPArrayList * list, uint32_t index, void * data); + +// Inserts data at the end of the list +uint32_t vpa_push(VPArrayList * list, void * data); + +// Returns the topmost element and removes it fromhe list. +void * vpa_pop(VPArrayList * list); + +// Truncates the list to specified size +void vpa_resize(VPArrayList * list, uint32_t new_size, FreeFunc freeFunc); + +void * vpa_remove(VPArrayList * list, size_t index); + +#endif \ No newline at end of file diff --git a/kernel/src/ds/linked_list.c b/kernel/src/ds/linked_list.c index 909a322e..72f7486a 100644 --- a/kernel/src/ds/linked_list.c +++ b/kernel/src/ds/linked_list.c @@ -17,7 +17,8 @@ * ********************************************************************/ -#include +#include +#include #include llist_node* llist_create_node(void *data) { @@ -65,11 +66,10 @@ void llist_free_node(llist_node *node) { } void llist_insert(llist_handle *l, void *data, int index) { - int i; llist_node *next = l->head; - llist_node *prev; + llist_node *prev = NULL; l->count++; - for (i = 0; i < index; i++) { + for (int i = 0; i < index; i++) { prev = next; next = next->next; } @@ -96,9 +96,8 @@ void llist_remove_at(llist_handle *l, int index) { llist_node* llist_get_node(llist_handle *l, int index) { - int i; llist_node *tmp = l->head; - for (i = 0; i < index; i++) { + for (int i = 0; i < index; i++) { tmp = tmp->next; } return tmp; diff --git a/kernel/src/ds/priority_queue.c b/kernel/src/ds/priority_queue.c index f82246aa..8ef84dfb 100644 --- a/kernel/src/ds/priority_queue.c +++ b/kernel/src/ds/priority_queue.c @@ -1,5 +1,7 @@ -#include +#include #include +#include +#include #define AMORITIZED_CONSTANT 2 #define DEFAULT_COUNT 10 @@ -82,8 +84,8 @@ void __prq_amoritize(prq_handle * queue) { int new_heap_size = queue->heap_size * AMORITIZED_CONSTANT; prq_node** new_heap = (prq_node**) kmalloc( sizeof(prq_node*) * new_heap_size); - os_memcpy((uint32_t *) queue->heap, (uint32_t *) new_heap, - (os_size_t) queue->heap_size * sizeof(prq_node*)); + memcpy((uint32_t *) queue->heap, (uint32_t *) new_heap, + (size_t) queue->heap_size * sizeof(prq_node*)); kfree(queue->heap); queue->heap = new_heap; queue->heap_size = new_heap_size; @@ -136,7 +138,7 @@ prq_node * prq_dequeue(prq_handle * queue) { } prq_handle * prq_create_fixed(int n) { - n = MAX(1, n); + n = max(1, n); prq_handle * queue = (prq_handle*) kmalloc(sizeof(prq_handle)); queue->count = 0; queue->heap_size = n + 1; diff --git a/kernel/src/ds/qstr.c b/kernel/src/ds/qstr.c new file mode 100644 index 00000000..c6defc22 --- /dev/null +++ b/kernel/src/ds/qstr.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include + +Qstr qstr_from_null_terminated_string(char * arr) { + size_t length = strlen(arr); + return qstr_from_length_string(arr, length); +} + +Qstr qstr_from_length_string(char * arr, size_t length) { + char * data = kmalloc(length + 1); + memcpy(data, arr, length); + data[length] = 0; // make null terminated. + + return (Qstr){ + .data = data, + .length = length, + .hash = 0, + }; +} + +void qstr_free(Qstr* qstr) { + kfree(qstr->data); +} + +static inline bool __eq(Qstr * left, Qstr * right, bool fake) { + // Hash function from http://www.cse.yorku.ca/~oz/hash.html (djb2) + char * rightstr; + if(!fake){ + if (left->hash != 0 && right->hash != 0 && left->hash != right->hash) { + return false; + } + if(left->length != right->length) { + return false; + } + rightstr = right->data; + } else { + rightstr = (char *) right; + } + + char * leftstr = left->data; + + uint32_t hash = 5381; + + bool equal = true; + char c; + while ((c = *(leftstr++)) != '\0') { + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + + if (c != (*rightstr++)) { + equal = false; + } + } + + if (hash == 0) { + hash = 42; // just has to be non-zero as to not be confused with empty hash. + } + + left->hash = hash; + if (equal && !fake) { + right->hash = hash; + } + + return equal; +} + +bool qstr_eq(Qstr * left, Qstr * right) { + return __eq(left, right, false); +} + +bool qstr_eq_null_terminated(Qstr * left, char * right) { + return __eq(left, (Qstr *) right, true); +} diff --git a/kernel/src/ds/test/qstr_test.c b/kernel/src/ds/test/qstr_test.c new file mode 100644 index 00000000..fd0f1e6e --- /dev/null +++ b/kernel/src/ds/test/qstr_test.c @@ -0,0 +1,63 @@ +#include +#include + +TEST_CREATE(test_compare_nonequal_length, { + Qstr a = qstr_from_null_terminated_string("test"); + Qstr b = qstr_from_null_terminated_string("toast"); + ASSERT(!qstr_eq(&a, &b)); + ASSERT_EQ(a.hash, 0); + ASSERT_EQ(b.hash, 0); + qstr_free(&a); + qstr_free(&b); +}) + +TEST_CREATE(test_compare_equal_length, { + Qstr a = qstr_from_null_terminated_string("tosti"); + Qstr b = qstr_from_null_terminated_string("toast"); + ASSERT(!qstr_eq(&a, &b)); + ASSERT_NEQ(a.hash, 0); + ASSERT_EQ(b.hash, 0); + qstr_free(&a); + qstr_free(&b); +}) + +TEST_CREATE(test_compare_equal_length_eq, { + Qstr a = qstr_from_null_terminated_string("toast"); + Qstr b = qstr_from_null_terminated_string("toast"); + ASSERT(qstr_eq(&a, &b)); + ASSERT_EQ(a.hash, b.hash); + qstr_free(&a); + qstr_free(&b); +}) + +TEST_CREATE(test_compare_equal_length_eq_null, { + Qstr a = qstr_from_null_terminated_string("toast"); + ASSERT(qstr_eq_null_terminated(&a, "toast")); + ASSERT_NEQ(a.hash, 0); + + qstr_free(&a); +}) + + +TEST_CREATE(test_compare_various, { + Qstr a = qstr_from_null_terminated_string("toast"); + Qstr b = qstr_from_null_terminated_string("tosti"); + Qstr c = qstr_from_null_terminated_string("toast"); + + ASSERT(!qstr_eq(&a, &b)); + ASSERT_NEQ(a.hash, 0); + ASSERT_EQ(b.hash, 0); + + ASSERT(!qstr_eq(&b, &a)); + ASSERT_NEQ(a.hash, 0); + ASSERT_NEQ(b.hash, 0); + ASSERT_NEQ(a.hash, b.hash); + + ASSERT(qstr_eq(&c, &a)); + ASSERT(qstr_eq(&a, &c)); + ASSERT_NEQ(c.hash, 0); + + qstr_free(&a); + qstr_free(&b); + qstr_free(&c); +}) diff --git a/kernel/src/ds/test/u8_array_list_test.c b/kernel/src/ds/test/u8_array_list_test.c new file mode 100644 index 00000000..068129c0 --- /dev/null +++ b/kernel/src/ds/test/u8_array_list_test.c @@ -0,0 +1,123 @@ +#include +#include + + +TEST_CREATE(u8a_push_get_pop_test, { + uint32_t length = 30; + + U8ArrayList * arr = u8a_create(1); + for (int i = 0; i < length; i++){ + u8a_push(arr, i % 0xff); + } + + ASSERT_EQ(arr->length, length); + ASSERT_GTEQ(arr->capacity, length); + + for (int i = 0; i < length; i++){ + uint8_t a = u8a_get(arr, i); + ASSERT_EQ(a, i % 0xff); + } + + ASSERT_EQ(arr->length, length); + ASSERT_GTEQ(arr->capacity, length); + + for (int i = length - 1; i >= 0; i--){ + ASSERT_EQ(u8a_pop(arr), i % 0xff); + } + + ASSERT_EQ(arr->length, 0); + ASSERT_LT(arr->capacity, length); + + u8a_free(arr); +}) + +TEST_CREATE(u8a_push_set_pop_test, { + U8ArrayList * arr = u8a_create(1); + for (int i = 0; i < 1000; i++){ + u8a_push(arr, i % 0xff); + } + + ASSERT_EQ(arr->length, 1000); + ASSERT_GTEQ(arr->capacity, 1000); + + for (int i = 0; i < 1000; i++){ + u8a_set(arr, i, 42); + } + + ASSERT_EQ(arr->length, 1000); + ASSERT_GTEQ(arr->capacity, 1000); + + for (int i = 999; i >= 0; i--){ + ASSERT_EQ(u8a_pop(arr), 42); + } + + ASSERT_EQ(arr->length, 0); + ASSERT_LT(arr->capacity, 1000); + + u8a_free(arr); +}) + +TEST_CREATE(u8a_resize_test, { + U8ArrayList * list = u8a_create(8); + ASSERT_EQ(list->length,0); + ASSERT_EQ(list->capacity, 8); + + u8a_resize(list, 4); + ASSERT_EQ(list->length,0); + ASSERT_EQ(list->capacity, 4); + + u8a_free(list); + +}) + +TEST_CREATE(u8a_push_string_test, { + U8ArrayList * list = u8a_create(1); + + size_t length = u8a_push_string(list, "TESTSTRING"); + + ASSERT_EQ(length, list->length); + ASSERT_EQ(length, 10); + + ASSERT_GTEQ(list->capacity, 10); + + ASSERT_EQ(u8a_get(list, 0), (uint8_t)'T'); + ASSERT_EQ(u8a_get(list, 1), (uint8_t)'E'); + ASSERT_EQ(u8a_get(list, 2), (uint8_t)'S'); + ASSERT_EQ(u8a_get(list, 3), (uint8_t)'T'); + ASSERT_EQ(u8a_get(list, 4), (uint8_t)'S'); + ASSERT_EQ(u8a_get(list, 5), (uint8_t)'T'); + ASSERT_EQ(u8a_get(list, 6), (uint8_t)'R'); + ASSERT_EQ(u8a_get(list, 7), (uint8_t)'I'); + ASSERT_EQ(u8a_get(list, 8), (uint8_t)'N'); + ASSERT_EQ(u8a_get(list, 9), (uint8_t)'G'); + + u8a_free(list); +}) + +TEST_CREATE(u8a_clone_test, { + U8ArrayList * list = u8a_create(1); + u8a_push_string(list, "TESTSTRING"); + + U8ArrayList * list2 = u8a_clone(list); + + + ASSERT_EQ(list2->length, list->length); + ASSERT_EQ(list2->length, 10); + + ASSERT_GTEQ(list2->capacity, 10); + + ASSERT_EQ(u8a_get(list2, 0), (uint8_t)'T'); + ASSERT_EQ(u8a_get(list2, 1), (uint8_t)'E'); + ASSERT_EQ(u8a_get(list2, 2), (uint8_t)'S'); + ASSERT_EQ(u8a_get(list2, 3), (uint8_t)'T'); + ASSERT_EQ(u8a_get(list2, 4), (uint8_t)'S'); + ASSERT_EQ(u8a_get(list2, 5), (uint8_t)'T'); + ASSERT_EQ(u8a_get(list2, 6), (uint8_t)'R'); + ASSERT_EQ(u8a_get(list2, 7), (uint8_t)'I'); + ASSERT_EQ(u8a_get(list2, 8), (uint8_t)'N'); + ASSERT_EQ(u8a_get(list2, 9), (uint8_t)'G'); + + u8a_free(list); + u8a_free(list2); + +}) \ No newline at end of file diff --git a/kernel/src/ds/test/vp_array_list_test.c b/kernel/src/ds/test/vp_array_list_test.c new file mode 100644 index 00000000..82208c1a --- /dev/null +++ b/kernel/src/ds/test/vp_array_list_test.c @@ -0,0 +1,74 @@ +#include +#include +#include + +void freefunc(void * data) { + if ((*(int *)data != 42)) { + panic(); + } +} + +int data[] = {1, 2, 3, 4, 5, 6, 7, 8}; + +TEST_CREATE(vpa_push_get_pop_test, { + uint32_t length = 30; + + VPArrayList * arr = vpa_create(1); + for (int i = 0; i < length; i++){ + vpa_push(arr, &data[i % 8]); + } + + ASSERT_EQ(arr->length, length); + ASSERT_GTEQ(arr->capacity, length); + + for (int i = 0; i < length; i++){ + int * a = vpa_get(arr, i); + + ASSERT_EQ(*a, data[i % 8]); + } + + ASSERT_EQ(arr->length, length); + ASSERT_GTEQ(arr->capacity, length); + + for (int i = length - 1; i >= 0; i--){ + ASSERT_EQ(*(int *)vpa_pop(arr), data[i % 8]); + } + + ASSERT_EQ(arr->length, 0); + ASSERT_LT(arr->capacity, length); + + vpa_free(arr, NULL); +}) + +TEST_CREATE(vpa_push_set_pop_test, { + VPArrayList * arr = vpa_create(1); + for (int i = 0; i < 1000; i++){ + vpa_push(arr, &data[i % 8]); + } + + ASSERT_EQ(arr->length, 1000); + ASSERT_GTEQ(arr->capacity, 1000); + + int intdata = 42; + + for (int i = 0; i < 1000; i++){ + vpa_set(arr, i, &intdata); + } + + ASSERT_EQ(arr->length, 1000); + ASSERT_GTEQ(arr->capacity, 1000); + + vpa_free(arr, freefunc); +}) + +TEST_CREATE(vpa_resize_test, { + VPArrayList * list = vpa_create(8); + ASSERT_EQ(list->length,0); + ASSERT_EQ(list->capacity, 8); + + vpa_resize(list, 4, NULL); + ASSERT_EQ(list->length,0); + ASSERT_EQ(list->capacity, 4); + + vpa_free(list, NULL); +}) \ No newline at end of file diff --git a/kernel/src/ds/u8_array_list.c b/kernel/src/ds/u8_array_list.c new file mode 100644 index 00000000..b24f9b60 --- /dev/null +++ b/kernel/src/ds/u8_array_list.c @@ -0,0 +1,100 @@ +// +// Created by victor on 2/21/20. +// +#include +#include +#include +#include +#include + +U8ArrayList * u8a_create(uint32_t initial_cap) { + U8ArrayList * list = kmalloc(sizeof(U8ArrayList)); + + *list = (U8ArrayList) { + .length = 0, + .capacity = initial_cap, + .array = kmalloc(initial_cap * sizeof(uint8_t)) + }; + + return list; +} + +void u8a_free(U8ArrayList * arr) { + if(arr->capacity > 0) { + kfree(arr->array); + } + kfree(arr); +} + +uint8_t u8a_get(U8ArrayList * list, uint32_t index) { + return list->array[index]; +} + +// Sets element to specific data +void u8a_set(U8ArrayList * list, uint32_t index, uint8_t data) { + list->array[index] = data; +} + +// Inserts data at the end of the list. Returns the new size. +uint32_t u8a_push(U8ArrayList * list, uint8_t data) { + + if(list->capacity == 0 || list->length >= list->capacity - 1) { + uint32_t new_size = max((list->capacity + (list->capacity >> 2)), list->capacity + 2); + + assert(new_size > list->capacity) + + list->capacity = new_size; + + list->array = krealloc(list->array, list->capacity * sizeof(uint8_t)); + } + list->array[list->length++] = data; + + return list->length; +} + +uint32_t u8a_push_string(U8ArrayList * arr, char * data) { + size_t length = strlen(data); + + u8a_resize(arr, arr->length + length); + + for (int i = 0; i < length; i++) { + arr->array[arr->length++] = data[i]; + } + + return arr->length; +} + +uint8_t u8a_pop(U8ArrayList * list) { + if(list->length == 0) { + return 0; + } + + uint8_t res = list->array[--list->length]; + + if(list->length < (list->capacity / 2)) { + list->capacity /= 2; + list->array = krealloc(list->array, list->capacity * sizeof(uint8_t)); + } + + return res; +} + +// Resizes the list to specified size +void u8a_resize(U8ArrayList * list, uint32_t new_size) { + list->array = krealloc(list->array, new_size); + + list->capacity = new_size; + if(list->length > list->capacity) { + list->length = list->capacity; + } +} + +U8ArrayList * u8a_clone(U8ArrayList * arr) { + U8ArrayList * newarr = u8a_create(arr->length); + + for (int i = 0; i < arr->length; i++) { + newarr->array[newarr->length++] = arr->array[i]; + } + + return newarr; +} \ No newline at end of file diff --git a/kernel/src/ds/vp_array_list.c b/kernel/src/ds/vp_array_list.c new file mode 100644 index 00000000..8422b523 --- /dev/null +++ b/kernel/src/ds/vp_array_list.c @@ -0,0 +1,92 @@ +// +// Created by victor on 2/21/20. +// +#include +#include +#include +#include + +struct VPArrayList * vpa_create(uint32_t initial_cap) { + VPArrayList * list = kmalloc(sizeof(VPArrayList)); + *list = (VPArrayList) { + .length = 0, + .capacity = initial_cap, + .array = kmalloc(initial_cap * sizeof(void *)) + }; + + return list; +} + +void vpa_free(VPArrayList * arr, FreeFunc freefunc) { + + if (freefunc != NULL) { + for (uint32_t i = 0; i < arr->length; i++){ + freefunc(arr->array[i]); + } + } + + kfree(arr->array); + kfree(arr); +} + +void * vpa_get(VPArrayList * list, uint32_t index) { + return list->array[index]; +} + +// Sets element to specific data +void vpa_set(VPArrayList * list, uint32_t index, void * data) { + list->array[index] = data; +} + +// Inserts data at the end of the list. Returns the new size. +uint32_t vpa_push(VPArrayList * list, void * data) { + + list->array[list->length++] = data; + + if(list->length >= list->capacity) { + uint32_t new_size = max((list->capacity + (list->capacity >> 2)), list->capacity + 2); + + assert(new_size > list->capacity) + + list->capacity = new_size; + + list->array = krealloc(list->array, list->capacity * sizeof(void *)); + + } + + return list->length; +} + +void * vpa_pop(VPArrayList * list) { + if(list->length == 0) { + return 0; + } + + void * res = list->array[--list->length]; + + if(list->length < (list->capacity / 2)) { + list->capacity /= 2; + list->array = krealloc(list->array, list->capacity * sizeof(void *)); + } + + return res; +} + +// Resizes the list to specified size +void vpa_resize(VPArrayList * list, uint32_t new_size, FreeFunc freeFunc) { + list->capacity = new_size; + + if(list->length > list->capacity) { + if(freeFunc != NULL){ + for(uint32_t i = list->length; i > list->capacity; i--) { + freeFunc(list->array[i]); + } + } + + list->length = list->capacity; + } + + list->array = krealloc(list->array, new_size); +} + +void * vpa_remove(VPArrayList * list, size_t index); \ No newline at end of file diff --git a/kernel/src/fs/file.c b/kernel/src/fs/file.c new file mode 100644 index 00000000..a7882382 --- /dev/null +++ b/kernel/src/fs/file.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include + + +void create_file(Path * p, VfsErr * err) { + +} + +void create_dir(Vfs * vfs, Path * p, VfsErr *err) { + if(path_exists(vfs, p)) { + if(err != NULL && *err == OK) { + *err = ERR_EXISTS; + } + return; + } + + Path * parent = u8a_clone(p); + path_parent(parent); + + VfsErr ourErr = OK; + DirEntry * parentDir = path_get_direntry(vfs, parent, &ourErr); + + // TODO: make a macro for error handling? + if(ourErr != OK || parentDir == NULL) { + if(err != NULL && *err == OK && ourErr != OK) { + *err = ourErr; + } else if (err != NULL){ + *err = ERR_NO_PARENT; + } + return; + } + + DirEntry * child = kmalloc(sizeof(DirEntry)); + UNUSED(child); +// memcpy(child->name, ) + +// parentDir->inode->fs_identifier->operations->create_dir(parentDir, , &ourErr); + + + + +} + +//void remove_dir(Path * p, bool recurse, VfsErr * err); +//void remove_file(Path * p, VfsErr * err); +// +//VPArrayList * list_dir(Path * p, VfsErr * err); +// +//File * open_file(Path * p, VfsErr * err); +//size_t read_file(File * f, uint8_t * buf, size_t length, VfsErr * err); +//size_t write_file(File * f, uint8_t * buf, size_t length, VfsErr * err); +//void seek_file(File * f, size_t pos, VfsErr * err); +//void close_file(File * f, VfsErr * err); \ No newline at end of file diff --git a/kernel/src/fs/include/file.h b/kernel/src/fs/include/file.h new file mode 100644 index 00000000..5fca965f --- /dev/null +++ b/kernel/src/fs/include/file.h @@ -0,0 +1,31 @@ + +#ifndef FILE_H +#define FILE_H + +#include +#include + +struct FsOperations; + +typedef struct File { + struct DirEntry * dentry; + size_t file_position; + const struct FsOperations * operations; +} File; + +void create_file(Path * p, enum VfsErr * err); +void create_dir(struct Vfs * vfs, Path * p, enum VfsErr *err); + +void remove_dir(Path * p, bool recurse,enum VfsErr * err); +void remove_file(Path * p,enum VfsErr * err); + +VPArrayList * list_dir(Path * p,enum VfsErr * err); + +File * open_file(Path * p,enum VfsErr * err); +size_t read_file(File * f, uint8_t * buf, size_t length,enum VfsErr * err); +size_t write_file(File * f, uint8_t * buf, size_t length,enum VfsErr * err); +void seek_file(File * f, size_t pos,enum VfsErr * err); +void close_file(File * f,enum VfsErr * err); + + +#endif diff --git a/kernel/src/fs/include/fs.h b/kernel/src/fs/include/fs.h new file mode 100644 index 00000000..6878ae38 --- /dev/null +++ b/kernel/src/fs/include/fs.h @@ -0,0 +1,13 @@ + +#ifndef FS_H +#define FS_H + +struct Vfs; +enum VfsErr; + +#include +#include +#include +#include + +#endif diff --git a/kernel/src/fs/include/inode.h b/kernel/src/fs/include/inode.h new file mode 100644 index 00000000..e8f11086 --- /dev/null +++ b/kernel/src/fs/include/inode.h @@ -0,0 +1,42 @@ + +#ifndef INODE_H +#define INODE_H + +#include +#include +#include +#include + + +typedef enum { + DIRECTORY, + FILE, +} InodeType; + +// This is the base Inode. Any filesystem can extend it for it's own needs. +// The first field in any extended Inode must be this Inode. This makes +// casting between extended inodes and base inodes seamless as long as you +// refer to inodes only by it's pointer. +typedef struct Inode{ + InodeType inode_type; + uint32_t id; + uint32_t refcount; + const struct FsIdentifier * fs_identifier; + struct DirEntry * direntry; + struct Inode * next; + bool should_delete; + struct Vfs * vfs; +} Inode; + +typedef struct DirEntry { + struct Inode * inode; + Qstr name; + struct DirEntry * parent; +} DirEntry; + +Inode create_inode_base(struct Vfs * vfs, InodeType type, const struct FsIdentifier * fs, DirEntry* dirEntry); + +DirEntry * create_direntry(Qstr name, DirEntry * parent); +void free_direntry(DirEntry * d); + +#endif \ No newline at end of file diff --git a/kernel/src/fs/include/path.h b/kernel/src/fs/include/path.h new file mode 100644 index 00000000..c3e8471a --- /dev/null +++ b/kernel/src/fs/include/path.h @@ -0,0 +1,99 @@ + +#ifndef PATH_H +#define PATH_H + +#include +#include +#include + +struct Vfs; +enum VfsErr; + +typedef U8ArrayList Path; + +const Path ROOT_PATH; + +// Parse the path and return the direntry which corresponds with the path. +struct DirEntry *path_get_direntry(struct Vfs *vfs, Path *path, enum VfsErr *err); + +// Duplicates a path. +Path * path_clone(Path * path); + +// Creates a new path from a string. +Path * path_from_string(char * str); + +// Appends a string to the end of a path. +// Inserts a slash ('/') between the path and the new element. +void path_append(Path * path, char * elem); + +// Returns the path without it's last element. +// If the path is absolute and there is only one element in the path, +// or the path is root ('/'), returns '/'. +// +// If the path is relative and there's only one element in the path, +// or the path is the current directory ('.'), returns '.' +// +// If the path is empty, returns root. +// +// Examples: +// '.' => '.' +// '' => '/' +// './test' => '.' +// '.test' => '.' +// 'test' => '.' +// '/test' => '/' +// '/a/b/c' => '/a/b' +// './a/b' => './a' +void path_parent(Path * path); + +// Frees a path completely +void path_free(Path * path); + +// Returns true if the path starts with '/' +bool path_is_absolute(Path * path); +// Inverse of `path_is_absolute` +bool path_is_relative(Path * path); +// Returns the final component of a path. +void path_filename(Path * path); +// The same as [path_filename] but copies the path. +Path * path_filename_cloned(Path * path); + +// Returns the part of the filename before the extension. +// examples: +// ".test" ==> .test +// "test.txt" ==> test +// "test" ==> test +// "" ==> NULL (no filename) +char * path_filestem(Path * path); + +// Returns the part of the filename after the stem. +// examples: +// ".test" ==> NULL +// "test.txt" ==> txt +// "test" ==> NULL +// "" ==> NULL (no filename) +char * path_extension(Path * path); + + +// Joins two paths together. +// After a join, the first path (`base`) is extended with the second path +// and the econd path is freed. +void path_join(Path base, Path * path); + +// Produces a string representation of the path. The string should be freed. +// The path that is converted into the string is freed by this function. +char * path_into_string(Path * path); + +// Test if the paths are exactly equal. +bool path_contents_equal(Path * a, Path * b); + +// Tests if the paths point to the same file. (slower) +bool path_parsed_equal(Path * a, Path * b); + +// Prints a path. +void path_print(Path * path); + +// Checks if a path has an associated DirEntry +bool path_exists(struct Vfs *vfs, Path *path); + +#endif \ No newline at end of file diff --git a/kernel/src/fs/include/vfs.h b/kernel/src/fs/include/vfs.h new file mode 100644 index 00000000..085b00b9 --- /dev/null +++ b/kernel/src/fs/include/vfs.h @@ -0,0 +1,64 @@ +#ifndef VFS_H +#define VFS_H + +#include +#include +#include + +struct InodeOperations; +struct inode; + +typedef struct FsOperations { + + /// Inode ops + // allocates a new Inode and returns this newly made Inode. + struct Inode * (*create_file) (struct DirEntry * parent, struct DirEntry * child, enum VfsErr * err); + struct Inode * (*create_dir) (struct DirEntry * parent, struct DirEntry * child, enum VfsErr * err); + void (*remove_dir) (struct DirEntry * entry, enum VfsErr * err); + VPArrayList * (*list_dir) (struct DirEntry * entry, enum VfsErr * err); + void (*move) (struct Inode * oldDir, struct DirEntry * oldDirEntry, struct Inode * newDir, struct DirEntry * newDirEntry, enum VfsErr * err); + void (*remove_file) (struct DirEntry * entry, enum VfsErr * err); + + void (*free_inode) (struct Inode * inode); + + + /// File ops + File * (*open)(struct Inode * inode, enum VfsErr * err); + size_t (*read)(File * fp, uint8_t * buf, size_t count, enum VfsErr * err); + size_t (*write)(File * fp, uint8_t * buf, size_t count, enum VfsErr * err); + void (*close)(File * fp, enum VfsErr * err); + +} FsOperations; + + +typedef struct FsIdentifier { + char * fsname; + const FsOperations * operations; +} FsIdentifier; + +typedef struct Vfs { + uint32_t filesystems_size; + uint32_t filesystems_filled; + const FsIdentifier ** filesystems; + + // Inodes start at the head and are added at the tail end. + // The linked list starts at head. + struct Inode * head; + struct Inode * tail; +} Vfs; + +typedef enum VfsErr{ + OK, + ERR_NOT_DIR, + ERR_EXISTS, + ERR_ALLOC_FAILED, + ERR_NO_PARENT, +} VfsErr; + +Vfs * vfs_create(); +VfsErr vfs_add_inode(Vfs * vfs, struct Inode * inode); +VfsErr vfs_register(Vfs * vfs, const FsIdentifier * fs_identifier); +void vfs_free(Vfs * vfs); +struct DirEntry * vfs_get_root(Vfs * vfs); + +#endif diff --git a/kernel/src/fs/inode.c b/kernel/src/fs/inode.c new file mode 100644 index 00000000..3003b262 --- /dev/null +++ b/kernel/src/fs/inode.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include +uint32_t cnt = 0; + +Inode create_inode_base(Vfs * vfs, InodeType type, const struct FsIdentifier * fs, DirEntry* dirEntry) { + return (Inode) { + .refcount = 0, + .id = ++cnt, + .inode_type = type, + .fs_identifier = fs, + .direntry = dirEntry, + .next = NULL, + .should_delete = false, + .vfs = vfs, + }; +} + + +DirEntry * create_direntry(Qstr name, DirEntry * parent) { + DirEntry * entry = kmalloc(sizeof(DirEntry)); + + entry->parent = parent; + entry->name = name; + + return entry; +} + +void free_direntry(DirEntry * entry) { + qstr_free(&entry->name); + kfree(entry); +} diff --git a/kernel/src/fs/path.c b/kernel/src/fs/path.c new file mode 100644 index 00000000..833304c8 --- /dev/null +++ b/kernel/src/fs/path.c @@ -0,0 +1,215 @@ + +#include +#include +#include +#include +#include + + +const Path root = { + .length = 1, + .capacity = 1, + .array = (uint8_t []){(uint8_t)'/'}, +}; + +struct DirEntry *path_get_direntry(struct Vfs *vfs, Path *path, enum VfsErr *err) { + /* + Algorithm: + ``` + // find in hashmap + + current: inode = if is_absolute(path) { + root_inode + } else { + process cwd + } + + for each part in path { + if part in inode.list_dir() { + current = inode.child(part) + } else { + return NULL + } + } + + // store in hashmap + + return curr + + ``` + */ + DirEntry * curr; + uint8_t * pathpointer; + uint8_t * endpointer = path->array + path->length; + + if (path_is_absolute(path)) { + curr = vfs_get_root(vfs); + + // + 1 because we skip the starting '/' + pathpointer = path->array + 1; + + } else { + os_printf("Inode lookup only supports absolute path right now."); + panic(); + curr = NULL; + pathpointer = path->array; + } + + + while(true) { + uint8_t * nextslash = pathpointer; + for (; *nextslash != '/' && nextslash < endpointer; nextslash++); + + // FIXME: `curr` may be NULL + VPArrayList * dirlist = curr->inode->fs_identifier->operations->list_dir(curr, err); + if (*err != OK) { + // Error! + return NULL; + } + + bool changed = false; + for (int i = 0; i < dirlist->length; i++) { + DirEntry * child = vpa_get(dirlist, i); + // Todo: quick cmp + if (strncmp(child->name.data, (char *)pathpointer, (nextslash-pathpointer)) == 0) { + curr = child; + changed = true; + break; + } + } + + if (!changed) { + // The path could not be found + return NULL; + } + + // Skip the slash + pathpointer = nextslash+1; + + if (nextslash == endpointer) { + return curr; + } + } +} + +Path * path_clone(Path * path) { + return u8a_clone(path); +} + +Path * path_from_string(char * str) { + U8ArrayList * arr = u8a_create(1); + u8a_push_string(arr, str); + + return arr; +} + +void path_append(Path * path, char * elem) { + u8a_push(path, '/'); + u8a_push_string(path, elem); +} + +void path_parent(Path * path) { + // for the case of path='.' + if (path->length == 1 && path->array[0] == '.') { + return; + } + + // for the case of path='' + if (path->length == 0) { + u8a_push(path, (uint8_t)'.'); + return; + } + + for (isize_t i = path->length; i >= 0; i--) { + if(path->array[i] == '/') { + if (i == 0) { + // If we got to the start, but there's a '/' there, make the path just this '/' + path->length = 1; + } else { + // if we go back and see a /, just make this the new length. + path->length = i; + } + return; + } + } + + path->length = 0; + u8a_push(path, '.'); +} + +void path_free(Path * path) { + u8a_free(path); +} + +bool path_contents_equal(Path * a, Path * b) { + if (a->length != b->length) { + return false; + } + + for (int i = 0; i < a->length; i++) { + if (a->array[i] != b->array[i]) { + return false; + } + } + + return true; +} + +void path_print(Path * path) { + os_printf("Path: (%i) \"", path->length); + for (int i = 0; i < path->length; i++){ + os_printf("%c", path->array[i]); + } + os_printf("\"\n"); +} + +bool path_is_absolute(Path * path) { + return path->array[0] == (uint8_t)'/'; +} + +bool path_is_relative(Path * path) { + return !path_is_absolute(path); +} + +bool path_exists(struct Vfs *vfs, Path *path) { + DirEntry * pd = path_get_direntry(vfs, path, NULL); + return pd != NULL; +} + +void strip_chars_from_end(Path * p) { + while(u8a_get(p, p->length - 1) == '.' || u8a_get(p, p->length - 1) == '/') { + u8a_pop(p); + } +} + +void path_filename(Path * p) { + // partially based on Rust's file_name + + // if path ends on ".." return None + if(p->length >= 2 && p->array[p->length - 1] == '.' && p->array[p->length - 2] == '.') { + u8a_resize(p, 0); + return; + } + + // strip characters from the back + while(u8a_get(p, p->length - 1) == '.' || u8a_get(p, p->length - 1) == '/') { + p->length--; + } + + // Find first '/' from the back + isize_t filename_start = p->length - 1; + while (u8a_get(p, filename_start) != '/' && filename_start > -1) { + --filename_start; + } + filename_start++; + + size_t filename_length = p->length - filename_start; + memmove(p->array, p->array + filename_start, filename_length); + u8a_resize(p, filename_length); +} + +Path * path_filename_cloned(Path * path) { + Path * p = u8a_clone(path); + path_filename(p); + return p; +} diff --git a/kernel/src/fs/test/test.c b/kernel/src/fs/test/test.c new file mode 100644 index 00000000..c8e5fc01 --- /dev/null +++ b/kernel/src/fs/test/test.c @@ -0,0 +1,23 @@ +#include +#include +#include + +TEST_CREATE(test_create_vfs, { + Vfs * test_vfs = vfs_create(); + ASSERT_NOT_NULL(test_vfs); + vfs_free(test_vfs); +}) + + + +TEST_CREATE(test_get_root, { + Vfs * test_vfs = vfs_create(); + tmpfs_init(test_vfs); + + Inode * root1 = (Inode *)create_tmpfs_root(test_vfs); + Inode * root2 = vfs_get_root(test_vfs)->inode; + + ASSERT_EQ(root1->id, root2->id); + + vfs_free(test_vfs); +}) diff --git a/kernel/src/fs/test/test_path.c b/kernel/src/fs/test/test_path.c new file mode 100644 index 00000000..d5b222c2 --- /dev/null +++ b/kernel/src/fs/test/test_path.c @@ -0,0 +1,261 @@ +#include +#include +#include +#include +#include + +TEST_CREATE(path_create_test, { + Path * p = path_from_string("test"); + + ASSERT_EQ(p->length, 4); + ASSERT_EQ(u8a_get(p, 0), 't'); + ASSERT_EQ(u8a_get(p, 1), 'e'); + ASSERT_EQ(u8a_get(p, 2), 's'); + ASSERT_EQ(u8a_get(p, 3), 't'); + + path_free(p); +}) + +TEST_CREATE(path_equal_test_1, { + Path * p1 = path_from_string("/a/b"); + Path * p2 = path_from_string("/a/b"); + Path * p3 = path_from_string("/a/b/c"); + + ASSERT(path_contents_equal(p1, p2)); + ASSERT(!path_contents_equal(p1, p3)); + + path_free(p1); + path_free(p2); + path_free(p3); +}) + +TEST_CREATE(path_parent_test_1, { + Path * p1 = path_from_string("/a/b/c"); + Path * p2 = path_from_string("/a/b"); + + path_parent(p1); + + ASSERT(path_contents_equal(p1, p2)); + + path_free(p1); + path_free(p2); +}) + +TEST_CREATE(path_parent_test_2, { + Path * p1 = path_from_string("./a/b"); + Path * p2 = path_from_string("./a"); + + path_parent(p1); + + ASSERT(path_contents_equal(p1, p2)); + + path_free(p1); + path_free(p2); +}) + +TEST_CREATE(path_parent_test_3, { + Path * p1 = path_from_string("."); + Path * p2 = path_from_string("."); + + path_parent(p1); + + ASSERT(path_contents_equal(p1, p2)); + + path_free(p1); + path_free(p2); +}) + +TEST_CREATE(path_parent_test_4, { + Path * p1 = path_from_string(""); + Path * p2 = path_from_string("."); + + path_parent(p1); + + ASSERT(path_contents_equal(p1, p2)); + + path_free(p1); + path_free(p2); +}) + +TEST_CREATE(path_parent_test_5, { + Path * p1 = path_from_string(""); + Path * p2 = path_from_string("."); + + path_parent(p1); + + ASSERT(path_contents_equal(p1, p2)); + + path_free(p1); + path_free(p2); +}) + +TEST_CREATE(path_parent_test_6, { + Path * p1 = path_from_string("./test"); + Path * p2 = path_from_string("."); + + path_parent(p1); + + ASSERT(path_contents_equal(p1, p2)); + + path_free(p1); + path_free(p2); +}) + +TEST_CREATE(path_parent_test_7, { + Path * p1 = path_from_string(".test"); + Path * p2 = path_from_string("."); + + path_parent(p1); + + ASSERT(path_contents_equal(p1, p2)); + + path_free(p1); + path_free(p2); +}) + +TEST_CREATE(path_parent_test_8, { + Path * p1 = path_from_string("test"); + Path * p2 = path_from_string("."); + + path_parent(p1); + + ASSERT(path_contents_equal(p1, p2)); + + path_free(p1); + path_free(p2); +}) + +TEST_CREATE(path_parent_test_9, { + Path * p1 = path_from_string("test"); + Path * p2 = path_from_string("."); + + path_parent(p1); + + ASSERT(path_contents_equal(p1, p2)); + + path_free(p1); + path_free(p2); +}) + +TEST_CREATE(path_parent_test_10, { + Path * p1 = path_from_string("/test"); + Path * p2 = path_from_string("/"); + + path_parent(p1); + + ASSERT(path_contents_equal(p1, p2)); + + path_free(p1); + path_free(p2); +}) + +TEST_CREATE(path_is_absolute_test, { + Path * p1 = path_from_string("/test"); + + ASSERT(path_is_absolute(p1)); + + path_free(p1); +}) + +TEST_CREATE(path_is_relative_test_1, { + Path * p1 = path_from_string("./test"); + + ASSERT(path_is_relative(p1)); + + path_free(p1); +}) + +TEST_CREATE(path_is_relative_test_2, { + Path * p1 = path_from_string("test"); + + ASSERT(path_is_relative(p1)); + + path_free(p1); +}) + +TEST_CREATE(path_clone_test, { + Path * p1 = path_from_string("/test"); + Path * p2 = path_clone(p1); + + ASSERT(path_contents_equal(p1, p2)); + + path_free(p1); + path_free(p2); +}) + +TEST_CREATE(path_find_file_test, { + Vfs * test_vfs = vfs_create(); + tmpfs_init(test_vfs); + + create_tmpfs_root(test_vfs); + + DirEntry * root = vfs_get_root(test_vfs); + + DirEntry * newfile = create_direntry(qstr_from_null_terminated_string("test"), root); + + VfsErr err = OK; + root->inode->fs_identifier->operations->create_file(root, newfile, &err); + ASSERT_EQ(err, OK); + + + Path * p = path_from_string("/test"); + + DirEntry * d = path_get_direntry(test_vfs, p, &err); + ASSERT_EQ(err, OK); + + + + ASSERT(qstr_eq_null_terminated(&d->name, "test")); + + path_free(p); + vfs_free(test_vfs); +}) + +TEST_CREATE(path_filename_test, { + Path * p = path_from_string("/test/test.txt"); + path_filename(p); + + + ASSERT_EQ(strncmp((char *)p->array, "test.txt", p->length), 0); + path_free(p); + +}) + +TEST_CREATE(path_filename_test_trailing, { + Path * p = path_from_string("/test/test/"); + path_filename(p); + + + ASSERT_EQ(strncmp((char *)p->array, "test", p->length), 0); + path_free(p); +}) + +TEST_CREATE(path_filename_test_1, { + Path * p = path_from_string("../test/test/."); + path_filename(p); + + ASSERT_EQ(strncmp((char *)p->array, "test", p->length), 0); + path_free(p); +}) + +TEST_CREATE(path_filename_test_2, { + Path * p = path_from_string("foo.txt/.//"); + path_filename(p); + + ASSERT_EQ(strncmp((char *)p->array, "foo.txt", p->length), 0); + path_free(p); +}) + +TEST_CREATE(path_filename_test_3, { + Path * p = path_from_string("/"); + path_filename(p); + ASSERT_EQ(p->length, 0); + path_free(p); +}) + +TEST_CREATE(path_filename_test_4, { + Path * p = path_from_string("asd/.."); + path_filename(p); + ASSERT_EQ(p->length, 0); + path_free(p); +}) diff --git a/kernel/src/fs/tmpfs/include/tmpfs.h b/kernel/src/fs/tmpfs/include/tmpfs.h new file mode 100644 index 00000000..b935a922 --- /dev/null +++ b/kernel/src/fs/tmpfs/include/tmpfs.h @@ -0,0 +1,30 @@ + +#ifndef TMPFS_H +#define TMPFS_H + +#include +#include +#include +#include + +const static int TMPFS_DEFAULT_FILE_ALLOC_SIZE = 16; +const static int TMPFS_DEFAULT_DIR_ALLOC_SIZE = 4; + +typedef struct { + Inode base; + + union { + U8ArrayList * filedata; // if it's a file + VPArrayList * direntries; // if it's a directory + } data; +} TmpfsInode; + +// Initializes tmpfs and registers it to the vfs +VfsErr tmpfs_init(Vfs * vfs); + +// Creates a tmpfs root dir on the vfs; +TmpfsInode * create_tmpfs_root(Vfs * vfs); + +const FsOperations tmpfs_inode_ops; +const struct FsIdentifier * FS_TMPFS; +#endif \ No newline at end of file diff --git a/kernel/src/fs/tmpfs/test/test.c b/kernel/src/fs/tmpfs/test/test.c new file mode 100644 index 00000000..966ed995 --- /dev/null +++ b/kernel/src/fs/tmpfs/test/test.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include +#include + +TEST_CREATE(test_create_file, { + Vfs * test_vfs = vfs_create(); + tmpfs_init(test_vfs); + + TmpfsInode * root = (TmpfsInode *) create_tmpfs_root(test_vfs); // PARTIAL + ASSERT_EQ(root->base.inode_type, DIRECTORY); + + DirEntry * newfile = create_direntry(qstr_from_null_terminated_string("test"), root->base.direntry); + + + VfsErr err = OK; + root->base.fs_identifier->operations->create_file(root->base.direntry, newfile, &err); + ASSERT_EQ(err, OK); + + + ASSERT_EQ(root->data.direntries->array[0], newfile); + ASSERT_EQ(newfile->inode->inode_type, FILE); + + vfs_free(test_vfs); +}) + +TEST_CREATE(test_create_dir, { + Vfs * test_vfs = vfs_create(); + tmpfs_init(test_vfs); + + TmpfsInode * root = (TmpfsInode *) create_tmpfs_root(test_vfs); + ASSERT_EQ(root->base.inode_type, DIRECTORY); + + DirEntry * newdir = create_direntry(qstr_from_null_terminated_string("test"), root->base.direntry); + + VfsErr err = OK; + root->base.fs_identifier->operations->create_dir(root->base.direntry, newdir, &err); + + ASSERT_EQ(err, OK); + ASSERT_EQ(root->data.direntries->array[0], newdir); + ASSERT_EQ(newdir->inode->inode_type, DIRECTORY); + + vfs_free(test_vfs); +}) + +TEST_CREATE(test_create_rw_file, { + Vfs * test_vfs = vfs_create(); + tmpfs_init(test_vfs); + + TmpfsInode * root = (TmpfsInode *) create_tmpfs_root(test_vfs); + ASSERT_EQ(root->base.inode_type, DIRECTORY); + + DirEntry * newfile = create_direntry(qstr_from_null_terminated_string("test"), root->base.direntry); + + VfsErr err = OK; + root->base.fs_identifier->operations->create_file(root->base.direntry, newfile, &err); + + ASSERT_EQ(err, OK); + ASSERT_EQ(root->data.direntries->array[0], newfile); + ASSERT_EQ(newfile->inode->inode_type, FILE); + + File * file = newfile->inode->fs_identifier->operations->open(newfile->inode, &err); + + ASSERT_EQ(err, OK); + ASSERT_EQ(file->file_position, 0); + + char * data = "The TMPFS works!"; + size_t length = strlen(data) + 1; + size_t retlen1 = file->operations->write(file, (uint8_t *) data, length, &err); + ASSERT_EQ(err, OK); + ASSERT_EQ(length, retlen1); + + // Check if it didn't change the original string. Might be the same literal though + // So might be always-true + ASSERT_EQ(strcmp(data, "The TMPFS works!"), 0); + + // Reset the file pointer + file->file_position = 0; + + char read_data[length]; + + size_t retlen2 = file->operations->read(file, (uint8_t *)read_data, length, &err); + ASSERT_EQ(err, OK); + ASSERT_EQ(length, retlen2); + ASSERT_EQ(strcmp(read_data, "The TMPFS works!"), 0); + + // Close file + file->operations->close(file, &err); + ASSERT_EQ(err, OK); + + vfs_free(test_vfs); +}) + +TEST_CREATE(test_listdir, { + Vfs * test_vfs = vfs_create(); + tmpfs_init(test_vfs); + + create_tmpfs_root(test_vfs); + + DirEntry * root = vfs_get_root(test_vfs); + + DirEntry * newfile = create_direntry(qstr_from_null_terminated_string("test"), root); + + + VfsErr err = OK; + root->inode->fs_identifier->operations->create_file(root, newfile, &err); + ASSERT_EQ(err, OK); + + VPArrayList * list = root->inode->fs_identifier->operations->list_dir(root, &err); + ASSERT_EQ(err, OK); + + DirEntry * first = vpa_get(list, 0); + + ASSERT(qstr_eq_null_terminated(&first->name, "test")); + + vfs_free(test_vfs); +}) \ No newline at end of file diff --git a/kernel/src/fs/tmpfs/tmpfs.c b/kernel/src/fs/tmpfs/tmpfs.c new file mode 100644 index 00000000..ae1b9bfa --- /dev/null +++ b/kernel/src/fs/tmpfs/tmpfs.c @@ -0,0 +1,209 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +VfsErr tmpfs_init(Vfs * vfs) { + return vfs_register(vfs, FS_TMPFS); +} + +TmpfsInode * create_tmpfs_root(Vfs * vfs) { + Qstr name = qstr_from_null_terminated_string("/"); + + DirEntry * entry = create_direntry(name, NULL); + + + Inode * root = (Inode *) kmalloc(1 * sizeof(TmpfsInode)); + + *root = create_inode_base(vfs, DIRECTORY, FS_TMPFS, entry); + + TmpfsInode * t_root = (TmpfsInode *) root; + + t_root->data.direntries = vpa_create(TMPFS_DEFAULT_DIR_ALLOC_SIZE); + + entry->inode = root; + + // Set head/tail + vfs->head = root; + vfs->tail = root; + root->next = NULL; + + return (TmpfsInode *) root; +} + +void add_entry_to_directory(DirEntry * parent, DirEntry * child, enum VfsErr * err) { + TmpfsInode * parent_inode = (TmpfsInode *) parent->inode; + + if (parent_inode->base.inode_type != DIRECTORY) { + if(err != NULL && *err == OK) { + *err = ERR_NOT_DIR; + } + return; + } + + vpa_push(parent_inode->data.direntries, child); + child->parent = parent; +} + +Inode * tmpfs_create_dir(DirEntry * parent, DirEntry * entry, enum VfsErr * err) { + Vfs * vfs = parent->inode->vfs; + + TmpfsInode * inode = kmalloc(1 * sizeof(TmpfsInode)); + + if (inode == NULL){ + if(*err != OK) { + *err = ERR_ALLOC_FAILED; + } + return NULL; + } + + *inode = (TmpfsInode) { + .base = create_inode_base(vfs, DIRECTORY, FS_TMPFS, entry), + .data.direntries = vpa_create(TMPFS_DEFAULT_DIR_ALLOC_SIZE), + }; + + entry->inode = (Inode *)inode; + + add_entry_to_directory(parent, entry, err); + if (*err != OK) { + return NULL; + } + + + vfs_add_inode(vfs, (Inode *)inode); + + return (Inode *) inode; +} + +Inode * tmpfs_create_file( DirEntry * parent, DirEntry * entry, enum VfsErr * err) { + Vfs * vfs = parent->inode->vfs; + + TmpfsInode * inode = kmalloc(1 * sizeof(TmpfsInode)); + + if (inode == NULL){ + if(*err != OK) { + *err = ERR_ALLOC_FAILED; + } + return NULL; + } + + *inode = (TmpfsInode) { + .base = create_inode_base(vfs, FILE, FS_TMPFS, entry), + .data.filedata = u8a_create(TMPFS_DEFAULT_FILE_ALLOC_SIZE), + }; + + entry->inode = (Inode *)inode; + + add_entry_to_directory(parent, entry, err); + if (*err != OK) { + return NULL; + } + + vfs_add_inode(vfs, (Inode *)inode); + + return (Inode *) inode; +} + +File * tmpfs_open_file(Inode * inode, enum VfsErr * err) { + File * file = (File *) kmalloc(sizeof(File)); + if (file == NULL){ + if(*err != OK) { + *err = ERR_ALLOC_FAILED; + } + return NULL; + } + + inode->refcount++; + file->dentry = inode->direntry; + file->operations = inode->fs_identifier->operations; + file->file_position = 0; + + return file; +} + + +void tmpfs_close_file(File * file, enum VfsErr * err) { + Inode * inode = file->dentry->inode; + --inode->refcount; + if(inode->should_delete && inode->refcount <= 0) { + inode->fs_identifier->operations->remove_file(file->dentry, err); + } + + kfree(file); +} + +size_t tmpfs_read_file(File * fp, uint8_t * buf, size_t count, enum VfsErr * err) { + TmpfsInode * inode = (TmpfsInode *) fp->dentry->inode; + U8ArrayList * array = inode->data.filedata; + + uint8_t * bpos = array->array + fp->file_position; + uint8_t * last = memcpy(buf, bpos, min(count, array->length - fp->file_position)); + + size_t numb = last - buf; + fp->file_position += numb; + + return numb; +} + + +size_t tmpfs_write_file(File * fp, uint8_t * buf, size_t count, enum VfsErr * err) { + TmpfsInode * inode = (TmpfsInode *) fp->dentry->inode; + U8ArrayList * array = inode->data.filedata; + + u8a_resize(array, array->capacity + count); + + memcpy(array->array + fp->file_position, buf, count); + fp->file_position += count; + + // Set the length of the array to be as long as what was already in it plus what we wrote to it. + array->length = fp->file_position; + + return count; +} + +void tmpfs_remove_file (DirEntry * entry, enum VfsErr * err) { + +} + +VPArrayList * tmpfs_list_dir (DirEntry * entry, enum VfsErr * err) { + TmpfsInode * inode = (TmpfsInode *)entry->inode; + return inode->data.direntries; +} + +void tmpfs_free_inode (Inode * inode) { + TmpfsInode * tmpfsInode = (TmpfsInode *) inode; + if(tmpfsInode->base.inode_type == FILE) { + u8a_free(tmpfsInode->data.filedata); + } else if(tmpfsInode->base.inode_type == DIRECTORY) { + vpa_free(tmpfsInode->data.direntries, NULL); + } + + kfree(tmpfsInode); +} + +const FsOperations tmpfs_fs_ops = { + .create_file = tmpfs_create_file, + .create_dir = tmpfs_create_dir, + + .remove_file = tmpfs_remove_file, + .list_dir = tmpfs_list_dir, + + .free_inode = tmpfs_free_inode, + + .open = tmpfs_open_file, + .close = tmpfs_close_file, + .read = tmpfs_read_file, + .write = tmpfs_write_file, +}; + +const FsIdentifier tmpfs_id = { + .fsname = "tmpfs", + .operations = &tmpfs_fs_ops, +}; + +const FsIdentifier * FS_TMPFS = &tmpfs_id; diff --git a/kernel/src/fs/vfs.c b/kernel/src/fs/vfs.c new file mode 100644 index 00000000..261180d4 --- /dev/null +++ b/kernel/src/fs/vfs.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include + +Vfs * vfs_create() { + Vfs * res = kmalloc(1 * sizeof(Vfs)); + + res->head = NULL; + res->tail = NULL; + + res->filesystems_size = 10; + res->filesystems_filled = 0; + res->filesystems = kmalloc(res->filesystems_size * sizeof(FsIdentifier *)); + +// create_root(res); + + return res; +} + +void vfs_free(Vfs * vfs) { + Inode * curr = vfs->head; + if (vfs->head == NULL) { + // If no inode was ever made + assert(vfs->tail == NULL); + } else if (curr == vfs->tail) { + + if (curr->direntry != NULL) { + free_direntry(curr->direntry); + } + + curr->fs_identifier->operations->free_inode(curr); + } else { + while (curr != NULL) { + + if(curr->direntry != NULL) { + free_direntry(curr->direntry); + } + + Inode * last = curr; + curr = curr->next; + last->fs_identifier->operations->free_inode(last); + } + } + + kfree(vfs->filesystems); + kfree(vfs); +} + + +VfsErr vfs_add_inode(Vfs * vfs, Inode * inode) { + // inode is already present + if (inode->next != NULL || vfs->tail == inode) { + return ERR_EXISTS; + } + + vfs->tail->next = inode; + vfs->tail = inode; + + return OK; +} + +VfsErr vfs_register(Vfs * vfs, const FsIdentifier * ident) { + vfs->filesystems[vfs->filesystems_filled++] = ident; + if (vfs->filesystems_filled >= vfs->filesystems_size) { + vfs->filesystems_size *= 2; + vfs->filesystems = krealloc(vfs->filesystems, vfs->filesystems_size * sizeof(FsIdentifier *)); + + if (vfs->filesystems == NULL) { + return ERR_ALLOC_FAILED; + } + } + + return OK; +} + + +DirEntry * vfs_get_root(Vfs * vfs) { + + Inode * curr = vfs->head; + do { + DirEntry * direntry = curr->direntry; + + if (qstr_eq_null_terminated(&direntry->name, "/")) { + return direntry; + } + + curr = curr->next; + } while (curr != vfs->tail); + + return NULL; +} \ No newline at end of file diff --git a/kernel/src/klibc/alloc.c b/kernel/src/klibc/alloc.c new file mode 100644 index 00000000..3d690d06 --- /dev/null +++ b/kernel/src/klibc/alloc.c @@ -0,0 +1,136 @@ +#include +#include +#include +#include + +void *kmalloc_aligned(uint32_t size, uint32_t alignment) { + void *block; + void *ptr; + + switch (alignment) { + case 4: + block = kmalloc(size + 4); + ptr = (void *) (((uint32_t) block + 4) & ~0x3); + return ptr; + case 1024: + block = kmalloc(size + 1024); + ptr = (void *) (((uint32_t) block + 1024) & ~0x1ff); + return ptr; + case 4096: + block = kmalloc(size + 4096); + ptr = (void *) (((uint32_t) block + 4096) & ~0x7ff); + return ptr; + case 16 * 1024: + block = kmalloc(size + 16 * 1024); + ptr = (void *) (((uint32_t) block + 16 * 1024) & ~0x1fff); + return ptr; + default: + return kmalloc(size); + } +} + +void kfree(void *ptr) { + deallocate((uint32_t *) ptr); +} + +void *kmalloc(uint32_t size) { + void *block = (void *) allocate(size); + return block; +} + + +// Allocates n * size portion of memory (set to 0) and returns it +void *kcalloc(uint32_t n, uint32_t size) { + uint32_t total_size = n * size; + void *block = kmalloc(total_size); + + return block ? memset(block, 0, total_size) : NULL; +} + +uint32_t kmalloc_size(void* ptr) { + return allocation_size(ptr); +} + +// FIXME: Implement kmalloc_size() (or something like it) +// TODO: Implement in-place realloc if the next block is free. +// Resize memory pointed to by ptr to new size +void * krealloc(void *ptr, uint32_t newsize) { +// os_printf("Size: %u, newsize: %u\n", kmalloc_size(ptr), size); + + uint32_t oldsize = kmalloc_size(ptr); + + if (newsize == 0) { + kfree(ptr); + return NULL; + } else if (ptr == NULL) { + return kmalloc(newsize); + } else if (newsize <= oldsize) { + return ptr; + } else { + void *newptr = kmalloc(newsize); + if (newptr) { + memcpy(newptr, ptr, oldsize); + kfree(ptr); + } + return newptr; + } +} + +/** + * umalloc allocates memory on the user heap + * + * @param size of the block of memory allocated + * @param uint32_t size + * @return returns a pointer to the allocated block of memory + */ +void *umalloc(uint32_t size) { + void *block = (void *) proc_allocate(size); + return block; +} + +/** + * ualigned alloc allocates memory on the user heap + * according to a specified alignemnt + * + * @param size of the block of memory allocated, and alignment desired + * @param uint32_t size, uint32_alignment + * @return returns a pointer to the allocated block of memory + * that is a multiple of the specified allignement + */ + +void *ualigned_alloc(uint32_t size, uint32_t alignment) { + void *block; + void *ptr; + + switch (alignment) { + case 4: + block = umalloc(size + 4); + ptr = (void *) (((uint32_t) block + 4) & ~0x3); + return ptr; + case 1024: + block = umalloc(size + 1024); + ptr = (void *) (((uint32_t) block + 1024) & ~0x1ff); + return ptr; + case 4096: + block = umalloc(size + 4096); + ptr = (void *) (((uint32_t) block + 4096) & ~0x7ff); + return ptr; + case 16 * 1024: + block = umalloc(size + 16 * 1024); + ptr = (void *) (((uint32_t) block + 16 * 1024) & ~0x1fff); + return ptr; + default: + return umalloc(size); + } +} + +/** + * free's an allocated block of memory on the heap + * + * @param pointer to a block of memeory on the heap + * @param void* ptr + * @return nothing returned + */ +void ufree(void *ptr) { + proc_deallocate((uint32_t *) ptr); +} diff --git a/kernel/src/klibc/include/klibc.h b/kernel/src/klibc/include/klibc.h index 33de2f0c..30d6365b 100644 --- a/kernel/src/klibc/include/klibc.h +++ b/kernel/src/klibc/include/klibc.h @@ -21,7 +21,7 @@ * os_strspn, and os_strcspn from MUSL - Sheldon * 4/21 Added os_memcpy for loader - Kaelen * --------------Spring 2015--------------- - * 4/15/15: Added implementation of assert() + * 4/15/15: Added implementation of assert() */ #ifndef __KLIBC_H__ #define __KLIBC_H__ @@ -37,38 +37,13 @@ #endif // TODO: previously in global_defs -#define NBBY 8 #define STATUS_OK 0 #define STATUS_FAIL -1 // END TODO typedef unsigned int os_size_t; -// useful macros -#define MAX(a, b) ((a) > (b) ? a : b) -#define MIN(a, b) ((a) < (b) ? a : b) - -// basic constants -#define M_E 2.71828182845904523536 -#define M_LOG2E 1.44269504088896340736 -#define M_LOG10E 0.434294481903251827651 -#define M_LN2 0.693147180559945309417 -#define M_LN10 2.30258509299404568402 -#define M_PI 3.14159265358979323846 -#define M_PI_2 1.57079632679489661923 -#define M_PI_4 0.785398163397448309616 -#define M_1_PI 0.318309886183790671538 -#define M_2_PI 0.636619772367581343076 -#define M_1_SQRTPI 0.564189583547756286948 -#define M_2_SQRTPI 1.12837916709551257390 -#define M_SQRT2 1.41421356237309504880 -#define M_SQRT_2 0.707106781186547524401 - -#define os_printf(...) printf(__VA_ARGS__) - -/* string.h type functionality for comparing strings or mem blocks */ -int os_memcmp(const void *left, const void *right, os_size_t num); -int os_strcmp(const char *left, const char *right); + //4-17-15: Working assert implementation - Prakash @@ -76,74 +51,21 @@ int os_strcmp(const char *left, const char *right); if ( (X) || _assert_fail(__FILE__, __LINE__, #X));\ } -/** - * Note: os_printf is restricted to printing only 256 characters. - * Supported format string conversions: - * X: upper-case hexadecimal print. - * x: lower-case hexadecimal print. - * d: signed integer. - * u: unsigned integer. - * c: ASCII character. - * s: string. - * %: the percent sign itself. - * - * Supported options: - * 0: zero-pad the result (applies to X,x,d,u). For example: - * os_printf("'%05d %05d %05u'\n", 15, -15, -15); - * prints '00015 -0015 4294967281' - */ -int os_vsnprintf(char *buf, int buflen, const char *str_buf, va_list args); -int os_snprintf(char *buf, int buflen, const char *fmt_string, ...); -int os_printf(const char *str_buf, ...); - -void *os_memset(void *dest, char c, os_size_t n); -char *__strchrnul(const char *s, char c); -char *os_strcpy(char *dest, const char *src); -char *os_strncpy(char *dest, const char *src, os_size_t n); -os_size_t os_strlen(const char *s); -char *os_strtok(char *s, const char *sep); -os_size_t os_strspn(const char *s, const char *accept); -os_size_t os_strcspn(const char *s, const char *reject); + + +char *__strchrnul(char *s, char c); +char *os_strtok(char *s, char *sep); +os_size_t os_strspn(char *s, char *accept); +os_size_t os_strcspn(char *s, char *reject); void os_memcpy(uint32_t * source, uint32_t * dest, os_size_t size); /* TODO: create print function for kernel debugging purposes */ -void* kmalloc(uint32_t size); -void* kmalloc_aligned(uint32_t size, uint32_t alignment); -void kfree(void* ptr); + uint32_t km_size(); uint32_t kmcheck(); -/** - * umalloc allocates memory on the user heap - * - * @param size of the block of memory allocated - * @param uint32_t size - * @return returns a pointer to the allocated block of memory - */ -void* umalloc(uint32_t size); //does user level malloc work - -/** - * ualigned alloc allocates memory on the user heap - * according to a specified alignemnt - * - * @param size of the block of memory allocated, and alignment desired - * @param uint32_t size, uint32_alignment - * @return returns a pointer to the allocated block of memory - * that is a multiple of the specified allignement - */ -void* ualigned_alloc(uint32_t size, uint32_t alignment); //does user level aligned_alloc work - -/** - * free's an allocated block of memory on the heap - * - * @param pointer to a block of memeory on the heap - * @param void* ptr - * @return nothing returned - */ -void ufree(void*); //does user level free work -int32_t abs(int32_t); unsigned int rand(); // as the codebase grows, it is important to use these macros diff --git a/kernel/src/klibc/include/math.h b/kernel/src/klibc/include/math.h new file mode 100644 index 00000000..99e11070 --- /dev/null +++ b/kernel/src/klibc/include/math.h @@ -0,0 +1,10 @@ +#ifndef MATH_H +#define MATH_H + +// useful macros +#define max(a, b) ((a) > (b) ? a : b) +#define min(a, b) ((a) < (b) ? a : b) +#define abs(a) ((a) > 0 ? (a) : -(a)) + + +#endif \ No newline at end of file diff --git a/kernel/src/klibc/include/stdint.h b/kernel/src/klibc/include/stdint.h index ad6aaead..ad2b6564 100644 --- a/kernel/src/klibc/include/stdint.h +++ b/kernel/src/klibc/include/stdint.h @@ -35,6 +35,10 @@ typedef uint16_t uint_least16_t; typedef uint32_t uint_least32_t; typedef uint64_t uint_least64_t; +typedef uint32_t size_t; +typedef int32_t isize_t; + + #define INT8_MIN (-1-0x7f) #define INT16_MIN (-1-0x7fff) #define INT32_MIN (-1-0x7fffffff) diff --git a/kernel/src/klibc/include/stdio.h b/kernel/src/klibc/include/stdio.h index f68ee9ea..55cf56df 100644 --- a/kernel/src/klibc/include/stdio.h +++ b/kernel/src/klibc/include/stdio.h @@ -8,6 +8,29 @@ #define UNUSED(x) (void)(x) +#include #include +/** + * Note: os_printf is restricted to printing only 256 characters. + * Supported format string conversions: + * X: upper-case hexadecimal print. + * x: lower-case hexadecimal print. + * d: signed integer. + * u: unsigned integer. + * c: ASCII character. + * s: string. + * %: the percent sign itself. + * + * Supported options: + * 0: zero-pad the result (applies to X,x,d,u). For example: + * os_printf("'%05d %05d %05u'\n", 15, -15, -15); + * prints '00015 -0015 4294967281' + */ +int os_vsnprintf(char *buf, int buflen, const char *str_buf, va_list args); +int os_snprintf(char *buf, int buflen, const char *fmt_string, ...); +int os_printf(const char *str_buf, ...); + + + #endif diff --git a/kernel/src/klibc/include/stdlib.h b/kernel/src/klibc/include/stdlib.h new file mode 100644 index 00000000..437f0bff --- /dev/null +++ b/kernel/src/klibc/include/stdlib.h @@ -0,0 +1,42 @@ +#ifndef STDLIB_H +#define STDLIB_H + +#include + +void* kmalloc(uint32_t size); +void* kmalloc_aligned(uint32_t size, uint32_t alignment); +void kfree(void* ptr); +void *krealloc(void *ptr, uint32_t size); + +/** + * umalloc allocates memory on the user heap + * + * @param size of the block of memory allocated + * @param uint32_t size + * @return returns a pointer to the allocated block of memory + */ +void* umalloc(uint32_t size); //does user level malloc work + +/** + * ualigned alloc allocates memory on the user heap + * according to a specified alignemnt + * + * @param size of the block of memory allocated, and alignment desired + * @param uint32_t size, uint32_alignment + * @return returns a pointer to the allocated block of memory + * that is a multiple of the specified allignement + */ +void* ualigned_alloc(uint32_t size, uint32_t alignment); //does user level aligned_alloc work + +/** + * free's an allocated block of memory on the heap + * + * @param pointer to a block of memeory on the heap + * @param void* ptr + * @return nothing returned + */ +void ufree(void*); //does user level free work + + + +#endif \ No newline at end of file diff --git a/kernel/src/klibc/include/string.h b/kernel/src/klibc/include/string.h new file mode 100644 index 00000000..71e98601 --- /dev/null +++ b/kernel/src/klibc/include/string.h @@ -0,0 +1,19 @@ + +#ifndef STRING_H +#define STRING_H + +#include +#include + +char * strcpy(char * dst, char * src); +char *strncpy(char *dest, char *src, size_t n); +uint32_t strcmp(char * s1, char * s2); +uint32_t strlen(char * str); +uint32_t strncmp(char * s1, char * s2, size_t n); + +void * memcpy(void * dest, void *src, size_t count); +void * memset(void * dest, uint32_t val, size_t count); +uint16_t * memsetw(uint16_t * dest, uint16_t val, size_t count); +void * memmove(void * dest, const void * src, size_t n); + +#endif \ No newline at end of file diff --git a/kernel/src/klibc/klibc.c b/kernel/src/klibc/klibc.c index 08db888c..c2b24233 100644 --- a/kernel/src/klibc/klibc.c +++ b/kernel/src/klibc/klibc.c @@ -16,11 +16,11 @@ * Notes: The following were adapted directly from musl-libc: * memcmp, memset, strcmp, strchrnul, strcpy, strlen, strtok ********************************************************************/ -#include #include #include +#include -#include +#include #include #include @@ -38,430 +38,61 @@ #define HIGHS (ONES * (UCHAR_MAX/2+1)) #define HASZERO(x) (((x)-ONES) & (~(x)) & HIGHS) -static char lower_case_digits[16] = "0123456789abcdef"; -static char upper_case_digits[16] = "0123456789ABCDEF"; - -/*4-17-15: - Prakash +/*4-17-15: - Prakash * panic() added - Currrently states the panic and stalls the machine */ -void panic() -{ - disable_interrupts() - ; - os_printf("Kernel panic!\n"); - os_printf("\n ) ( \n"); - os_printf(" ( /( ( )\\ ) \n"); - os_printf(" )\\()) ( ( ( )\\ (()/( ) ( \n"); - os_printf("|((_)\\ ))\\ )( ( ))((_) /(_)| /( ( )\\ ( \n"); - os_printf("|_ ((_)((_|()\\ )\\ ) /((_) (_)) )(_)) )\\ |(_) )\\ \n"); - os_printf("| |/ (_)) ((_)_(_/((_))| | | _ ((_)_ _(_/((_)((_) \n"); - os_printf(" ' 0) - { - for (i = 0; i < padding - ndigits - negate; i++) - { - *buf = pad_char; - buf++; - max_len--; - if (max_len == 0) - return orig_max_len; - } - } - - // Output the digits - for (i = ndigits - 1; i >= 0; i--) - { - *buf = tmp_buf[i]; - buf++; - max_len--; - if (max_len == 0) - return orig_max_len; - } - if (ndigits == 0 && padding <= 0) - { - *buf = '0'; - buf++; - max_len--; - if (max_len == 0) - return orig_max_len; - } - - return orig_max_len - max_len; -} - -// args must already have been started -int os_vsnprintf(char *buf, int buflen, const char *str_buf, va_list args) -{ - if (buflen == 0) - return 0; - buflen--; - if (buflen == 0) - { - buf[0] = 0; - return 1; - } - int nwritten = 0; - int t_arg; - char* str_arg; - int padding = -1; - char pad_char = 0; - while (*str_buf != '\0') - { - int n; - if (*str_buf == '%') - { - str_buf++; - // This label is where we go after we've read an option. - reread_switch: ; - switch (*str_buf) - { - case '0': - // Zero-padding... Read all the numbers. - // Then restart the switch statement. - padding = 0; - pad_char = '0'; - while (*str_buf <= '9' && *str_buf >= '0') - { - padding *= 10; - padding += *str_buf - '0'; - str_buf++; - } - goto reread_switch; - break; - case 'X': - t_arg = va_arg(args, int); - n = print_int(buf, buflen, t_arg, 16, 1, padding, pad_char, 1); - break; - case 'x': - t_arg = va_arg(args, int); - n = print_int(buf, buflen, t_arg, 16, 1, padding, pad_char, 0); - break; - case 'd': - t_arg = va_arg(args, int); - n = print_int(buf, buflen, t_arg, 10, 0, padding, pad_char, 0); - break; - case 'u': - t_arg = va_arg(args, int); - n = print_int(buf, buflen, t_arg, 10, 1, padding, pad_char, 0); - break; - case 'c': - t_arg = va_arg(args, int); - *buf = t_arg; - n = 1; - break; - case 's': - str_arg = va_arg(args, char*); - os_strncpy(buf, str_arg, buflen); - n = os_strlen(str_arg); - if (n > buflen) - { - n = buflen; - } - break; - case '%': - *buf = '%'; - n = 1; - break; - } - // Reset all the options - padding = -1; - } - else - { - *buf = *str_buf; - n = 1; - } - buf += n; - buflen -= n; - nwritten += n; - if (buflen <= 0) - { - //Return! - break; - } - str_buf++; - } - buf[0] = 0; - nwritten++; - - return nwritten; +int _assert_fail(char *_file, unsigned int _line, char *_func) { + os_printf("ASSERT FAILURE: %s:%u: %s\n", _file, _line, _func); + panic(); + return 1; } -int os_snprintf(char *buf, int buflen, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - int n = os_vsnprintf(buf, buflen, fmt, args); - va_end(args); - return n; -} -int os_printf(const char *str_buf, ...){ - va_list args; - va_start(args, str_buf); - char buf[256]; - int n = os_vsnprintf(buf, 255, str_buf, args); - va_end(args); - print_uart0(buf); - return n; -} - -/* Set the first n bytes of dest to be the value c.*/ -void *os_memset(void *dest, char c, os_size_t n) -{ - unsigned char *s = dest; - os_size_t k; - - /* Fill head and tail with minimal branching. Each - * conditional ensures that all the subsequently used - * offsets are well-defined and in the dest region. */ - - if (!n) - return dest; - s[0] = s[n - 1] = c; - if (n <= 2) - return dest; - s[1] = s[n - 2] = c; - s[2] = s[n - 3] = c; - if (n <= 6) - return dest; - s[3] = s[n - 4] = c; - if (n <= 8) - return dest; - - /* Advance pointer to align it at a 4-byte boundary, - * and truncate n to a multiple of 4. The previous code - * already took care of any head/tail that get cut off - * by the alignment. */ - - k = -(uintptr_t) s & 3; - s += k; - n -= k; - n &= -4; - -#ifdef __GNUC__ - typedef uint32_t __attribute__((__may_alias__)) u32; - typedef uint64_t __attribute__((__may_alias__)) u64; - - u32 c32 = ((u32) -1) / 255 * (unsigned char) c; - - /* In preparation to copy 32 bytes at a time, aligned on - * an 8-byte bounary, fill head/tail up to 28 bytes each. - * As in the initial byte-based head/tail fill, each - * conditional below ensures that the subsequent offsets - * are valid (e.g. !(n<=24) implies n>=28). */ - - *(u32 *) (s + 0) = c32; - *(u32 *) (s + n - 4) = c32; - if (n <= 8) - return dest; - *(u32 *) (s + 4) = c32; - *(u32 *) (s + 8) = c32; - *(u32 *) (s + n - 12) = c32; - *(u32 *) (s + n - 8) = c32; - if (n <= 24) - return dest; - *(u32 *) (s + 12) = c32; - *(u32 *) (s + 16) = c32; - *(u32 *) (s + 20) = c32; - *(u32 *) (s + 24) = c32; - *(u32 *) (s + n - 28) = c32; - *(u32 *) (s + n - 24) = c32; - *(u32 *) (s + n - 20) = c32; - *(u32 *) (s + n - 16) = c32; - - /* Align to a multiple of 8 so we can fill 64 bits at a time, - * and avoid writing the same bytes twice as much as is - * practical without introducing additional branching. */ - - k = 24 + ((uintptr_t) s & 4); - s += k; - n -= k; - - /* If this loop is reached, 28 tail bytes have already been - * filled, so any remainder when n drops below 32 can be - * safely ignored. */ - - u64 c64 = c32 | ((u64) c32 << 32); - for (; n >= 32; n -= 32, s += 32) - { - *(u64 *) (s + 0) = c64; - *(u64 *) (s + 8) = c64; - *(u64 *) (s + 16) = c64; - *(u64 *) (s + 24) = c64; - } -#else - /* Pure C fallback with no aliasing violations. */ - for (; n; n--, s++) *s = c; -#endif - - return dest; -} /* Returns a pointer to the first instance of c in s, like indexOf(). If c is not found, then return a pointer to the NULL character at the end of String s. */ -char *__strchrnul(const char *s, char c) -{ - os_size_t *w, k; - - if (!c) - return (char *) s + os_strlen(s); - - for (; (uintptr_t) s % ALIGN; s++) - if (!*s || *(unsigned char *) s == c) - return (char *) s; - k = ONES * c; - for (w = (void *) s; !HASZERO(*w) && !HASZERO(*w ^ k); w++) - ; - for (s = (void *) w; *s && *(unsigned char *) s != c; s++) - ; - return (char *) s; -} - -/* Copies the String src to dest */ -char *os_strcpy(char *dest, const char *src) -{ - const unsigned char *s = (const unsigned char*) src; - unsigned char *d = (unsigned char*) dest; - while ((*d++ = *s++)) - ; - return dest; -} +char *__strchrnul(char *s, char c) { + os_size_t *w, k; -/* Copies the String src to dest */ -char *os_strncpy(char *dest, const char *src, os_size_t n) -{ - const unsigned char *s = (const unsigned char*) src; - unsigned char *d = (unsigned char*) dest; - while ((*d++ = *s++) && n--) - ; - return dest; -} + if (!c) + return (char *) s + strlen(s); -/* Return the length of s */ -os_size_t os_strlen(const char *s) -{ - const char *a = s; - const os_size_t *w; - for (; (uintptr_t) s % ALIGN; s++) - if (!*s) - return s - a; - for (w = (const void *) s; !HASZERO(*w); w++) - ; - for (s = (const void *) w; *s; s++) - ; - return s - a; + for (; (uintptr_t) s % ALIGN; s++) + if (!*s || *(unsigned char *) s == c) + return (char *) s; + k = ONES * c; + for (w = (void *) s; !HASZERO(*w) && !HASZERO(*w ^ k); w++); + for (s = (void *) w; *s && *(unsigned char *) s != c; s++); + return (char *) s; } /* A re-entrant function that returns a substring of s. The substring starts @@ -469,191 +100,152 @@ os_size_t os_strlen(const char *s) delimiter characters (indicated by sep). The substring ends at the next delimeter character (indicated by sep). */ -char *os_strtok(char *s, const char *sep) -{ - static char *p; - if (!s && !(s = p)) - return NULL; - s += os_strspn(s, sep); - if (!*s) - return p = 0; - p = s + os_strcspn(s, sep); - if (*p) - *p++ = 0; - else - p = 0; - return s; +char *os_strtok(char *s, char *sep) { + static char *p; + if (!s && !(s = p)) + return NULL; + s += os_strspn(s, sep); + if (!*s) + return p = 0; + p = s + os_strcspn(s, sep); + if (*p) + *p++ = 0; + else + p = 0; + return s; } /* Returns the length of the initial segment of s that only includes the characters in c. */ -os_size_t os_strspn(const char *s, const char *accept) -{ - char c = s[0]; // The character in s being checked - int length = 0; - - // Check each character in s - while (c != 0) - { - bool ok = false; - - // Check against each character in accept - int i; - for (i = 0; i < os_strlen(accept); i++) - { - if (c == accept[i]) - { - ok = true; - } - } - - if (ok == true) - { - // If c matched any character in accept, continue - length++; - c = s[length]; - } - else - { - // If did not match any character in accept, we are done - return length; - } - } - return length; +os_size_t os_strspn(char *s, char *accept) { + char c = s[0]; // The character in s being checked + int length = 0; + + // Check each character in s + while (c != 0) { + bool ok = false; + + // Check against each character in accept + int i; + for (i = 0; i < strlen(accept); i++) { + if (c == accept[i]) { + ok = true; + } + } + + if (ok == true) { + // If c matched any character in accept, continue + length++; + c = s[length]; + } else { + // If did not match any character in accept, we are done + return length; + } + } + return length; } /* Returns the length of the initial segment of s that does not contain any characters in string c. */ -os_size_t os_strcspn(const char *s, const char *reject) -{ - char c = s[0]; // The character in s being checked - int length = 0; - - // Check each character in s - while (c != 0) - { - // Check against each character in reject - int i; - for (i = 0; i < os_strlen(reject); i++) - { - if (c == reject[i]) - { - return length; - } - } - - // If c did not match any reject characters, continue - length++; - c = s[length]; - } - return length; -} - -int32_t abs(int32_t val) -{ - const int32_t mask = val >> sizeof(int32_t) * (NBBY - 1); - return (val + mask) ^ mask; +os_size_t os_strcspn(char *s, char *reject) { + char c = s[0]; // The character in s being checked + int length = 0; + + // Check each character in s + while (c != 0) { + // Check against each character in reject + int i; + for (i = 0; i < strlen(reject); i++) { + if (c == reject[i]) { + return length; + } + } + + // If c did not match any reject characters, continue + length++; + c = s[length]; + } + return length; } // Return string converted to int form, or 0 if not applicable // Necessary comments provided in atof() (next function) -int katoi(const char *string) -{ - if (!string) - return 0; - - int integer = 0; - int sign = 1; - - if (*string == '-') - { - sign = -1; - string++; - } - else if (*string == '+') - { - string++; - } - - while (*string != '\0') - { - if (*string >= '0' && *string <= '9') - { - integer *= 10; - integer += (*string - '0'); - } - else - { - return 0; - } - } - return sign * integer; +int katoi(char *string) { + if (!string) + return 0; + + int integer = 0; + int sign = 1; + + if (*string == '-') { + sign = -1; + string++; + } else if (*string == '+') { + string++; + } + + while (*string != '\0') { + if (*string >= '0' && *string <= '9') { + integer *= 10; + integer += (*string - '0'); + } else { + return 0; + } + } + return sign * integer; } // Return string converted to double form, or 0 if not applicable -double katof(const char *string) -{ - if (!string) - return 0.0; - - double integer = 0.0; // before decimal - double fraction = 0.0; // after decimal - int sign = 1; // positive or negative? - int divisor = 1; // used to push fraction past decimal point - bool after_decimal = false; // decimal point reached? - - // Check if string includes sign (including a "+") - if (*string == '-') - { - sign = -1; - string++; // progress to next char - } - else if (*string == '+') - { - string++; - } - - while (*string != '\0') - { - if (*string >= '0' && *string <= '9') - { - if (after_decimal) - { - fraction *= 10; // progress to next position in integer - fraction += (*string - '0'); // add integer form of current number in string - divisor *= 10; - } - else - { - integer *= 10; // progress to next position in integer - integer += (*string - '0'); // add integer form of current number in string - } - } - else if (*string == '.') - { - if (after_decimal) - return 0.0; // more than one '.' - after_decimal = true; - } - else - { - return 0.0; // current char in string is not a number or '.' - } - string++; - } - return sign * (integer + (fraction / divisor)); +double katof(char *string) { + if (!string) + return 0.0; + + double integer = 0.0; // before decimal + double fraction = 0.0; // after decimal + int sign = 1; // positive or negative? + int divisor = 1; // used to push fraction past decimal point + bool after_decimal = false; // decimal point reached? + + // Check if string includes sign (including a "+") + if (*string == '-') { + sign = -1; + string++; // progress to next char + } else if (*string == '+') { + string++; + } + + while (*string != '\0') { + if (*string >= '0' && *string <= '9') { + if (after_decimal) { + fraction *= 10; // progress to next position in integer + fraction += (*string - '0'); // add integer form of current number in string + divisor *= 10; + } else { + integer *= 10; // progress to next position in integer + integer += (*string - '0'); // add integer form of current number in string + } + } else if (*string == '.') { + if (after_decimal) + return 0.0; // more than one '.' + after_decimal = true; + } else { + return 0.0; // current char in string is not a number or '.' + } + string++; + } + return sign * (integer + (fraction / divisor)); } // Return string converted to long int form, or 0 if not applicable -long int katol(const char *string) -{ - return (long int) katoi(string); +long int katol(char *string) { + return (long int) katoi(string); } /* -// Same as katof, but makes endptr point to the string which comes after the number +// Same a +#include "../../old/include/klibc.h"s katof, but makes endptr point to the string which comes after the number double kstrtod(const char *string, char **endptr) { if (!string) @@ -714,210 +306,55 @@ return result; */ //Same as katol, but makes endptr point to the string which comes after the number -long int kstrtol(const char *string, char **endptr) -{ -if (!string) - return 0; - -long int integer = 0; -long int result = 0; -bool result_found = false; -int sign = 1; - -if (*string == '-') -{ - sign = -1; - string++; -} -else if (*string == '+') -{ - string++; -} - -while (!result_found) -{ - if (*string >= '0' && *string <= '9') - { - integer *= 10; - integer += (*string - '0'); - string++; - } - else - { - result = sign * integer; - result_found = true; - } -} -*endptr = (char*) string; - -return result; -} - -void *kmalloc(uint32_t size) -{ -void* block = (void*) allocate(size, 0 /* unused */, 0 /* unused */); -return block; -} - -// Allocates n * size portion of memory (set to 0) and returns it -void *kcalloc(uint32_t n, uint32_t size) -{ -uint32_t total_size = n * size; -void* block = kmalloc(total_size); - -return block ? os_memset(block, 0, total_size) : NULL; -} - -uint32_t kmcheck() -{ -return mem_check(); +long int kstrtol(char *string, char **endptr) { + if (!string) + return 0; + + long int integer = 0; + long int result = 0; + bool result_found = false; + int sign = 1; + + if (*string == '-') { + sign = -1; + string++; + } else if (*string == '+') { + string++; + } + + while (!result_found) { + if (*string >= '0' && *string <= '9') { + integer *= 10; + integer += (*string - '0'); + string++; + } else { + result = sign * integer; + result_found = true; + } + } + *endptr = (char *) string; + + return result; } // NOTE potentially expand these features. offer more // memory stats -uint32_t km_size() -{ -return mem_get_heap_size(); -} - -void* kmalloc_aligned(uint32_t size, uint32_t alignment) -{ -void* block; -void* ptr; - -switch (alignment) -{ -case 4: - block = kmalloc(size + 4); - ptr = (void*) (((uint32_t) block + 4) & ~0x3); - return ptr; -case 1024: - block = kmalloc(size + 1024); - ptr = (void*) (((uint32_t) block + 1024) & ~0x1ff); - return ptr; -case 4096: - block = kmalloc(size + 4096); - ptr = (void*) (((uint32_t) block + 4096) & ~0x7ff); - return ptr; -case 16 * 1024: - block = kmalloc(size + 16 * 1024); - ptr = (void*) (((uint32_t) block + 16 * 1024) & ~0x1fff); - return ptr; -default: - return kmalloc(size); -} -} - -void kfree(void* ptr) -{ -deallocate((uint32_t*) ptr, 0 /* unused */, 0 /* unused */); -} - -// FIXME: Implement kmalloc_size() (or something like it) -// Resize memory pointed to by ptr to new size -void *krealloc(void *ptr, uint32_t size) -{ -if (!ptr) - return kmalloc(size); - -if (size == 0) -{ - kfree(ptr); - return NULL; -} - -/* I'm not sure how to implement kmalloc_size(), - * which returns the size of the block pointed - * to by a pointer, without keeping track of - * the size of the block pointed to whenever - * kmalloc() is called, or by defining it - - uint32_t msize = kmalloc_size(ptr); - if (msize >= size) - return ptr; - - - void *new_ptr = kmalloc(size); - os_memcpy(new_ptr, ptr, msize); - return new_ptr; */ - -return ptr; -} - -unsigned int rand() -{ -static unsigned int z1 = 12345, z2 = 67891, z3 = 11121, z4 = 31415; -unsigned int b; -b = ((z1 << 6) ^ z1) >> 13; -z1 = ((z1 & 4294967294U) << 18) ^ b; -b = ((z2 << 2) ^ z2) >> 27; -z2 = ((z2 & 4294967288U) << 2) ^ b; -b = ((z3 << 13) ^ z3) >> 21; -z3 = ((z3 & 4294967280U) << 7) ^ b; -b = ((z4 << 3) ^ z4) >> 12; -z4 = ((z4 & 4294967168U) << 13) ^ b; -return (z1 ^ z2 ^ z3 ^ z4); -} - -/** - * umalloc allocates memory on the user heap - * - * @param size of the block of memory allocated - * @param uint32_t size - * @return returns a pointer to the allocated block of memory - */ -void* umalloc(uint32_t size) -{ -void* block = (void*) proc_allocate(size); -return block; +uint32_t km_size() { + return mem_get_heap_size(); } -/** - * ualigned alloc allocates memory on the user heap - * according to a specified alignemnt - * - * @param size of the block of memory allocated, and alignment desired - * @param uint32_t size, uint32_alignment - * @return returns a pointer to the allocated block of memory - * that is a multiple of the specified allignement - */ - -void* ualigned_alloc(uint32_t size, uint32_t alignment) -{ -void* block; -void* ptr; -switch (alignment) -{ -case 4: - block = umalloc(size + 4); - ptr = (void*) (((uint32_t) block + 4) & ~0x3); - return ptr; -case 1024: - block = umalloc(size + 1024); - ptr = (void*) (((uint32_t) block + 1024) & ~0x1ff); - return ptr; -case 4096: - block = umalloc(size + 4096); - ptr = (void*) (((uint32_t) block + 4096) & ~0x7ff); - return ptr; -case 16 * 1024: - block = umalloc(size + 16 * 1024); - ptr = (void*) (((uint32_t) block + 16 * 1024) & ~0x1fff); - return ptr; -default: - return umalloc(size); -} -} -/** - * free's an allocated block of memory on the heap - * - * @param pointer to a block of memeory on the heap - * @param void* ptr - * @return nothing returned - */ -void ufree(void* ptr) -{ -proc_deallocate((uint32_t*) ptr); +unsigned int rand() { + static unsigned int z1 = 12345, z2 = 67891, z3 = 11121, z4 = 31415; + unsigned int b; + b = ((z1 << 6) ^ z1) >> 13; + z1 = ((z1 & 4294967294U) << 18) ^ b; + b = ((z2 << 2) ^ z2) >> 27; + z2 = ((z2 & 4294967288U) << 2) ^ b; + b = ((z3 << 13) ^ z3) >> 21; + z3 = ((z3 & 4294967280U) << 7) ^ b; + b = ((z4 << 3) ^ z4) >> 12; + z4 = ((z4 & 4294967168U) << 13) ^ b; + return (z1 ^ z2 ^ z3 ^ z4); } diff --git a/kernel/src/klibc/mem.c b/kernel/src/klibc/mem.c new file mode 100644 index 00000000..9869d518 --- /dev/null +++ b/kernel/src/klibc/mem.c @@ -0,0 +1,30 @@ +#include + +void * memcpy(void *dest, void *src, size_t count) +{ + const char *sp = (const char *)src; + char *dp = (char *)dest; + for(; count != 0; count--) *dp++ = *sp++; + return dp; +} + +void * memset(void *dest, uint32_t val, size_t count) { + char *temp = (char *)dest; + for( ; count != 0; count--) *temp++ = (char)val; + return dest; +} + +uint16_t * memsetw(uint16_t *dest, uint16_t val, size_t count) { + uint16_t *temp = (uint16_t *)dest; + for( ; count != 0; count--) *temp++ = val; + return dest; +} + +void * memmove(void * dest, const void * src, size_t n) { + unsigned char tmp[n]; + + memcpy(tmp, (void *) src, n); + memcpy(dest, tmp, n); + + return dest; +} \ No newline at end of file diff --git a/kernel/src/klibc/printf.c b/kernel/src/klibc/printf.c new file mode 100644 index 00000000..dfa2eb7d --- /dev/null +++ b/kernel/src/klibc/printf.c @@ -0,0 +1,178 @@ +#include +#include +#include + +static char lower_case_digits[16] = "0123456789abcdef"; +static char upper_case_digits[16] = "0123456789ABCDEF"; + +// base is between 2 and 16, inclusive +int print_int(char *buf, int buflen, int val, int base, int is_unsigned, + int padding, char pad_char, int is_uppercase) { + int max_len = buflen; + int orig_max_len = max_len; + int negate = 0; + if (val < 0 && !is_unsigned) { + val = -val; + negate = 1; + } + unsigned int temp = val; + + if (max_len == 0) + return orig_max_len - max_len; + if (negate) { + *buf = '-'; + buf++; + max_len--; + if (max_len == 0) + return orig_max_len - max_len; + } + + char tmp_buf[64]; + int ndigits = 0; + while (temp != 0) { + if (is_uppercase) { + tmp_buf[ndigits] = upper_case_digits[temp % base]; + } else { + tmp_buf[ndigits] = lower_case_digits[temp % base]; + } + temp = temp / base; + ndigits++; + } + + // Zero-pad the output + int i; + if (padding > 0) { + for (i = 0; i < padding - ndigits - negate; i++) { + *buf = pad_char; + buf++; + max_len--; + if (max_len == 0) + return orig_max_len; + } + } + + // Output the digits + for (i = ndigits - 1; i >= 0; i--) { + *buf = tmp_buf[i]; + buf++; + max_len--; + if (max_len == 0) + return orig_max_len; + } + if (ndigits == 0 && padding <= 0) { + *buf = '0'; + buf++; + max_len--; + if (max_len == 0) + return orig_max_len; + } + + return orig_max_len - max_len; +} + +// args must already have been started +int os_vsnprintf(char *buf, int buflen, const char *str_buf, va_list args) { + if (buflen == 0) + return 0; + buflen--; + if (buflen == 0) { + buf[0] = 0; + return 1; + } + int nwritten = 0; + int t_arg; + char *str_arg; + int padding = -1; + char pad_char = 0; + while (*str_buf != '\0') { + int n = 0; + if (*str_buf == '%') { + str_buf++; + // This label is where we go after we've read an option. + reread_switch:; + switch (*str_buf) { + case '0': + // Zero-padding... Read all the numbers. + // Then restart the switch statement. + padding = 0; + pad_char = '0'; + while (*str_buf <= '9' && *str_buf >= '0') { + padding *= 10; + padding += *str_buf - '0'; + str_buf++; + } + goto reread_switch; + break; + case 'X': + t_arg = va_arg(args, int); + n = print_int(buf, buflen, t_arg, 16, 1, padding, pad_char, 1); + break; + case 'x': + t_arg = va_arg(args, int); + n = print_int(buf, buflen, t_arg, 16, 1, padding, pad_char, 0); + break; + case 'd': + case 'i': + t_arg = va_arg(args, int); + n = print_int(buf, buflen, t_arg, 10, 0, padding, pad_char, 0); + break; + case 'u': + t_arg = va_arg(args, int); + n = print_int(buf, buflen, t_arg, 10, 1, padding, pad_char, 0); + break; + case 'c': + t_arg = va_arg(args, int); + *buf = t_arg; + n = 1; + break; + case 's': + str_arg = va_arg(args, char*); + strncpy(buf, str_arg, buflen); + n = strlen(str_arg); + if (n > buflen) { + n = buflen; + } + break; + case '%': + *buf = '%'; + n = 1; + break; + } + // Reset all the options + padding = -1; + } else { + *buf = *str_buf; + n = 1; + } + buf += n; + buflen -= n; + nwritten += n; + if (buflen <= 0) { + //Return! + break; + } + str_buf++; + } + buf[0] = 0; + nwritten++; + + return nwritten; +} + +int os_snprintf(char *buf, int buflen, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + int n = os_vsnprintf(buf, buflen, fmt, args); + va_end(args); + return n; +} + +int os_printf(const char *str_buf, ...) { + va_list args; + va_start(args, str_buf); + char buf[256]; + int n = os_vsnprintf(buf, 255, str_buf, args); + va_end(args); + print_uart0(buf); + return n; +} \ No newline at end of file diff --git a/kernel/src/klibc/string.c b/kernel/src/klibc/string.c new file mode 100644 index 00000000..14dbf66e --- /dev/null +++ b/kernel/src/klibc/string.c @@ -0,0 +1,79 @@ +#include + +char * strcpy(char *dst, char *src){ + uint32_t i; + for(i=0; src[i] != 0; i++){ + dst[i] = src[i]; + } + dst[i] = 0; + return dst; +} + +char *strncpy(char *dest, char *src, size_t n) { + char *s = (char *) src; + char *d = (char *) dest; + while ((*d++ = *s++) && n--); + return dest; +} + +char * strcat(char *dst, char *src){ + uint32_t i = 0; + uint32_t j = 0; + for (i = 0; dst[i] != 0; i++); + for (j = 0; src[j] != 0; j++){ + dst[i+j] = src[j]; + } + dst[i+j] = 0; + return dst; +} + +char * strcatc(char *dst, char src){ + uint32_t i = 0; + for (i = 0; dst[i] != 0; i++); + dst[i+0] = src; + dst[i+1] = 0; + return dst; +} + +uint32_t strcmp(char *s1, char *s2){ + for (uint32_t i = 0; ; i++){ + if (s1[i] != s2[i]){ + return s1[i] < s2[i] ? -1 : 1; + } + + if (s1[i] == '\0'){ + return 0; + } + } +} + + +uint32_t strncmp( char * s1, char * s2, size_t n ){ + while (n && *s1 && ( *s1 == *s2 )){ + ++s1; + ++s2; + --n; + } + if (n == 0){ + return 0; + }else{ + return ( *(uint8_t *)s1 - *(uint8_t *)s2 ); + } +} + +uint32_t strlen(char *str){ + for (uint32_t i = 0;; i++){ + if (str[i] == '\0'){ + return i; + } + } + return 0; +} + + +bool starts_with(char *s1, char* s2){ + if(strncmp(s1, s2, strlen(s2)) == 0){ + return true; + } + return false; +} \ No newline at end of file diff --git a/kernel/src/kthread/kthreads.c.old b/kernel/src/kthread/kthreads.c similarity index 75% rename from kernel/src/kthread/kthreads.c.old rename to kernel/src/kthread/kthreads.c index c8ad2be3..f90d6dc9 100644 --- a/kernel/src/kthread/kthreads.c.old +++ b/kernel/src/kthread/kthreads.c @@ -6,7 +6,7 @@ */ #include -#include +#include #include kthread_handle* kthread_create(kthread_callback_handler cb_handler) @@ -18,7 +18,7 @@ kthread_handle* kthread_create(kthread_callback_handler cb_handler) uint32_t kthread_start(kthread_handle * kthread) { - sched_task * task = sched_create_task(kthread); - sched_add_task(task); + sched_task * task = sched_create_task_from_kthread(kthread, 0); + return sched_add_task(task); } diff --git a/kernel/src/memory/allocator.c b/kernel/src/memory/allocator.c index 94ed5cc8..7c5367e6 100644 --- a/kernel/src/memory/allocator.c +++ b/kernel/src/memory/allocator.c @@ -1,323 +1,237 @@ -#include +// Adapted from https://github.com/CCareaga/heap_allocator + + #include +#include + +int offset = sizeof(uint32_t) * 2; +uint32_t overhead = sizeof(footer_t) + sizeof(node_t); + +// ======================================================== +// this function initializes a new heap structure, provided +// an empty heap struct, and a place to start the heap +// +// NOTE: this function uses HEAP_INIT_SIZE to determine +// how large the heap is so make sure the same constant +// is used when allocating memory for your heap! +// ======================================================== +void create_heap(heap_t *heap, uint32_t start) { + // first we create the initial region, this is the "wilderness" chunk + // the heap starts as just one big chunk of allocatable memory + node_t *init_region = (node_t *) start; + init_region->hole = 1; + init_region->size = (HEAP_INIT_SIZE) - sizeof(node_t) - sizeof(footer_t); + + create_foot(init_region); // create a foot (size must be defined) + + // now we add the region to the correct bin and setup the heap struct + add_node(heap->bins[get_bin_index(init_region->size)], init_region); + + heap->start = start; + heap->end = start + HEAP_INIT_SIZE; + +#ifdef MEM_DEBUG + heap->bytes_allocated = 0; +#endif +} -uint32_t* __alloc_extend_heap(alloc_handle*allocator, uint32_t amount); - -/* - * The kernel heap is organized in blocks. Each block has a header and a - * footer each a 4 byte integer, at the beginning and end of the block. - * The header and footer both specify the size of the block in question. - * Used blocks are indicated by the heap header and the heap footer being - * negative. - * - * To allocate a block, we start at the first block and walk through each - * one, finding the first free block large enough to support a header, - * footer, and the size requested. - * - * To free a block, we do a bunch of merging stuff to check to see if we - * should merge with the blocks on the left or right of us, respectively. - */ -alloc_handle* alloc_create(uint32_t * buffer, uint32_t buffer_size, - heap_extend_handler extend_handler) { - - if (buffer_size <= sizeof(alloc_handle)) { - return 0; +// ======================================================== +// this is the allocation function of the heap, it takes +// the heap struct pointer and the size of the chunk we +// want. this function will search through the bins until +// it finds a suitable chunk. it will then split the chunk +// if neccesary and return the start of the chunk +// ======================================================== +void *heap_alloc(heap_t *heap, uint32_t size) { + // first get the bin index that this chunk size should be in + int index = get_bin_index(size); + // now use this bin to try and find a good fitting chunk! + bin_t *temp = (bin_t *) heap->bins[index]; + + node_t *found = get_best_fit(temp, size); + + // while no chunk if found advance through the bins until we + // find a chunk or get to the wilderness + while (found == NULL) { + if (index + 1 >= BIN_COUNT) + return NULL; + + temp = heap->bins[++index]; + found = get_best_fit(temp, size); } - alloc_handle* alloc_handle_ptr = (alloc_handle*) buffer; + // if the difference between the found chunk and the requested chunk + // is bigger than the overhead (metadata size) + the min alloc size + // then we should split this chunk, otherwise just return the chunk + if ((found->size - size) > (overhead + MIN_ALLOC_SZ)) { + // do the math to get where to split at, then set its metadata + node_t *split = (node_t *)(((char *) found + overhead) + size); + split->size = found->size - size - (overhead); + split->hole = 1; - // storing the alloc_handle struct - // inside the heading of the buffer - alloc_handle_ptr->heap = ((void*) buffer) + sizeof(alloc_handle); - alloc_handle_ptr->heap_size = buffer_size - sizeof(alloc_handle); - alloc_handle_ptr->extend_handler = extend_handler; + create_foot(split); // create a footer for the split - uint32_t* heap_header = alloc_handle_ptr->heap; - uint32_t* heap_footer = (uint32_t*) ((void*) alloc_handle_ptr->heap - + alloc_handle_ptr->heap_size - sizeof(int)); + // now we need to get the new index for this split chunk + // place it in the correct bin + int new_idx = get_bin_index(split->size); + add_node(heap->bins[new_idx], split); - *heap_header = alloc_handle_ptr->heap_size - 2 * sizeof(uint32_t); - *heap_footer = alloc_handle_ptr->heap_size - 2 * sizeof(uint32_t); + found->size = size; // set the found chunks size + create_foot(found); // since size changed, remake foot + } - return alloc_handle_ptr; -} -alloc_handle* alloc_create_fixed(uint32_t * buffer, uint32_t buffer_size) { - return alloc_create(buffer, buffer_size, NULL); -} + found->hole = 0; // not a hole anymore + remove_node(heap->bins[index], found); // remove it from its bin -// TODO: what if there's an error allocating the page? -// Returns a pointer to the new (big) free block's header -uint32_t* __alloc_extend_heap(alloc_handle*allocator, uint32_t amount) { - if(!allocator->extend_handler) { - return 0; + // these following lines are checks to determine if the heap should + // be expanded or contracted + // ========================================== + node_t *wild = get_wilderness(heap); + if (wild->size < MIN_WILDERNESS) { + int success = expand(heap, 0x1000); + if (success == 0) { + return NULL; + } } + else if (wild->size > MAX_WILDERNESS) { + contract(heap, 0x1000); + } + // ========================================== - uint32_t start_size = allocator->heap_size; - uint32_t amount_added = allocator->extend_handler(amount); + // since we don't need the prev and next fields when the chunk + // is in use by the user, we can clear these and return the + // address of the next field + found->prev = NULL; + found->next = NULL; - if (amount_added <= 0) { - return 0; - } - // Now extend the footer block - int32_t *orig_footer = (int32_t*) ((void*) allocator->heap + start_size - - sizeof(uint32_t)); - - allocator->heap_size += amount_added; - - // If it's free, simply move it (and update the header) - // If it's used, add a free block to the end - if (*orig_footer > 0) { - uint32_t *orig_header = (uint32_t*) ((void*) allocator->heap - + start_size - 2 * sizeof(uint32_t) - *orig_footer); - uint32_t *new_footer = (uint32_t*) ((void*) allocator->heap - + allocator->heap_size - sizeof(uint32_t)); - - *new_footer = *orig_footer + amount_added; - *orig_header += amount_added; - return orig_header; - } else { - - uint32_t *new_header = (uint32_t*) ((void*) allocator->heap + start_size); - uint32_t *new_footer = (uint32_t*) ((void*) allocator->heap - + allocator->heap_size - sizeof(uint32_t)); - *new_header = amount_added - 2 * sizeof(uint32_t); - *new_footer = amount_added - 2 * sizeof(uint32_t); - return new_header; - } +#ifdef MEM_DEBUG + heap->bytes_allocated += found->size; + os_printf("MEM_DEBUG: ALLOC %i bytes at 0x%x\n", found->size, &found->next); +#endif - return 0x0; + return &found->next; } -void* alloc_allocate(alloc_handle * allocator, uint32_t size) { - int32_t i, ret_ptr; - - for (i = 0; i < allocator->heap_size;) { - uint32_t* header_addr = (uint32_t*) ((void*) allocator->heap + i); - int32_t header = *header_addr; - - uint32_t* footer_addr = (uint32_t*) ((void*) allocator->heap + i - + sizeof(int32_t) + size); - - //free and >= request - if (header > 0 && header >= size) { - //cannot split this block - if (header < (size + 2 * sizeof(int32_t) + sizeof(char))) { - footer_addr = (uint32_t*) ((void*) allocator->heap + i - + sizeof(int32_t) + abs(header)); - - ret_ptr = i + sizeof(int32_t); - //mark header as used - *header_addr = header * (-1); - //insert a footer at end of block - *footer_addr = header * (-1); - return (uint32_t*) ((void*) allocator->heap + ret_ptr); - - } - - //can split this block - else { - ret_ptr = i + sizeof(int32_t); - - int32_t old_space = header; - int32_t occ_space = size + 2 * sizeof(int32_t); - //mark header as used - *header_addr = size * (-1); - //insert footer - *footer_addr = size * (-1); - - //insert new free block header - uint32_t* new_header = (uint32_t*) ((void*) allocator->heap + i - + 2 * sizeof(int32_t) + size); - *new_header = old_space - occ_space; - //insert new free block footer - uint32_t* new_footer = (uint32_t*) ((void*) allocator->heap + i - + sizeof(int32_t) + old_space); - *new_footer = old_space - occ_space; - - return (uint32_t*) ((void*) allocator->heap + ret_ptr); - } - } - //jump to the next block - else { - i = i + abs(header) + 2 * sizeof(int32_t); - } +// ======================================================== +// this is the free function of the heap, it takes the +// heap struct pointer and the pointer provided by the +// heap_alloc function. the given chunk will be possibly +// coalesced and then placed in the correct bin +// ======================================================== +void heap_free(heap_t *heap, void *p) { + bin_t *list; + footer_t *new_foot, *old_foot; + + node_t *head = (node_t *) ((char *) p - offset); + +#ifdef MEM_DEBUG + heap->bytes_allocated -= head->size; + os_printf("MEM_DEBUG: FREE %i bytes\n", head->size); +#endif + + if (head == (node_t *) (uintptr_t) heap->start) { + head->hole = 1; + add_node(heap->bins[get_bin_index(head->size)], head); + return; } - // Allocate some more memory. - uint32_t new_amt = size + 2 * sizeof(uint32_t); - uint32_t *header = __alloc_extend_heap(allocator, new_amt); + node_t *next = (node_t *) ((char *) get_foot(head) + sizeof(footer_t)); + footer_t *f = (footer_t *) ((char *) head - sizeof(footer_t)); + node_t *prev = f->header; - if (header == 0) { - return 0; - } + if (prev->hole) { + list = heap->bins[get_bin_index(prev->size)]; + remove_node(list, prev); - // Recursive call. TODO: (relatively) Inefficient - return alloc_allocate(allocator, size); -} + prev->size += overhead + head->size; + new_foot = get_foot(head); + new_foot->header = prev; -void alloc_deallocate(alloc_handle* allocator, void* ptr) { - uint32_t first_block = 0; - uint32_t last_block = 0; + head = prev; + } - uint32_t* header_addr = (uint32_t*) ((void*) ptr - sizeof(int32_t)); - uint32_t size = abs(*header_addr); + if (next->hole) { + list = heap->bins[get_bin_index(next->size)]; + remove_node(list, next); - uint32_t* footer_addr = (uint32_t*) ((void*) ptr + size); + head->size += overhead + next->size; - if (header_addr == allocator->heap) { - first_block = 1; - } + old_foot = get_foot(next); + old_foot->header = 0; + next->size = 0; + next->hole = 0; - if (footer_addr + sizeof(int32_t) - == (void*) allocator->heap + allocator->heap_size) { - last_block = 1; + new_foot = get_foot(head); + new_foot->header = head; } - //os_printf("Freeing %d-sized block at %X. first/last=%d/%d\n", size, header_addr, first_block,last_block); - - //only check and coalesce right block - if (first_block) { - uint32_t* right_header_addr = (uint32_t*) ((void*) footer_addr - + sizeof(int32_t)); - int32_t right_block_size = *right_header_addr; - - //free right block - if (right_block_size > 0) { - //set new header at freed blocks header - *header_addr = size + right_block_size + 2 * sizeof(int32_t); - //set new footer at right blocks footer - uint32_t* right_footer_addr = (uint32_t*) ((void*) footer_addr - + 2 * sizeof(int32_t) + right_block_size); - *right_footer_addr = size + right_block_size + 2 * sizeof(int32_t); - } else { - //make freed blocks header and footer positive - *header_addr = size; - *footer_addr = size; - } - } + head->hole = 1; + add_node(heap->bins[get_bin_index(head->size)], head); +} - //only check and coalesce left block - if (last_block) { - uint32_t* left_block_header = (uint32_t*) ((void*) header_addr - - sizeof(int32_t)); - int32_t left_block_size = *left_block_header; - - //free left block - if (left_block_size > 0) { - //set new header at left blocks header - uint32_t* left_header_addr = (uint32_t*) ((void*) header_addr - - 2 * sizeof(int32_t) - left_block_size); - *left_header_addr = size + left_block_size + 2 * sizeof(int32_t); - //set new footer at freed blocks footer - *footer_addr = size + left_block_size + 2 * sizeof(int32_t); - } else { - *header_addr = size; - *footer_addr = size; - } - } - //check and coalesce both adjacent blocks - if (!first_block && !last_block) { - uint32_t* right_block_header = (uint32_t*) ((void*) footer_addr - + sizeof(int32_t)); - int32_t right_block_size = *right_block_header; - - uint32_t* left_block_header = (uint32_t*) ((void*) header_addr - - sizeof(int32_t)); - int32_t left_block_size = *left_block_header; - //os_printf("left/right sizes are %d/%d, size=%d\n", left_block_size, right_block_size, size); - - //both adjacent blocks are free - if (right_block_size > 0 && left_block_size > 0) { - int32_t new_size = size + right_block_size + left_block_size - + 4 * sizeof(int32_t); - - //set new header at left blocks header - uint32_t* left_header_addr = (uint32_t*) ((void*) header_addr - - 2 * sizeof(int32_t) - left_block_size); - *left_header_addr = new_size; - //set new footer at right blocks footer - uint32_t* right_footer_addr = (uint32_t*) ((void*) footer_addr - + 2 * sizeof(int32_t) + right_block_size); - *right_footer_addr = new_size; - } +// these are left here to implement contraction / expansion +uint32_t expand(heap_t *heap, uint32_t sz) { + os_printf("Trying to expand\n"); + return 0; // fail for now +} - //only right free block - else if (right_block_size > 0 && left_block_size < 0) { - //set new header at freed blocks header - *header_addr = size + right_block_size + 2 * sizeof(int32_t); - //set new footer at right blocks footer - uint32_t* right_footer_addr = (uint32_t*) ((void*) footer_addr - + 2 * sizeof(int32_t) + right_block_size); - *right_footer_addr = size + right_block_size + 2 * sizeof(int32_t); - } - //only left free block - else if (left_block_size > 0 && right_block_size < 0) { - //set new header at left blocks header - uint32_t* left_header_addr = (uint32_t*) ((void*) header_addr - - 2 * sizeof(int32_t) - left_block_size); - *left_header_addr = size + left_block_size + 2 * sizeof(int32_t); - //set new footer at freed blocks footer - *footer_addr = size + left_block_size + 2 * sizeof(int32_t); - } else { - *header_addr = size; - *footer_addr = size; - } +void contract(heap_t *heap, uint32_t sz) { - } } -/** - * Returns 0 on success. -1 on error. - */ -int alloc_check(alloc_handle* allocator) { - char* ptr = (char*) allocator->heap; - uint32_t* end_ptr = (uint32_t*) ((void*) allocator->heap - + allocator->heap_size); - int i, block = 0; - - LOG("Checking memory...\n"); - for (i = 0; i < allocator->heap_size; i += 0) { - uint32_t* block_addr = (uint32_t*) (ptr + sizeof(int32_t)); - - uint32_t* header_addr = (uint32_t*) ptr; - int32_t block_header = *header_addr; - int32_t block_size = abs(block_header); - - uint32_t* footer_addr = (uint32_t*) (ptr + sizeof(int32_t) + block_size); - int32_t block_footer = *footer_addr; - - if (block_header == block_footer && block_header <= 0) { - LOG("Block %d Allocated:", block); - LOG("\tsize = %d, address = %x\n", block_size, block_addr); - } else if (block_header == block_footer && block_header > 0) { - LOG("Block %d Free:", block); - LOG("\tsize = %d, address = %x\n", block_size, block_addr); - } else { - ERROR("INCONSISTENT HEAP\n"); - ERROR("block_header = %d\n", block_header); - ERROR("block_footer = %d\n", block_footer); - ERROR("header addr = %x\n", header_addr); - ERROR("footer addr = %x\n", footer_addr); - return -1; - } +// ======================================================== +// this function is the hashing function that converts +// size => bin index. changing this function will change +// the binning policy of the heap. right now it just +// places any allocation < 8 in bin 0 and then for anything +// above 8 it bins using the log base 2 of the size +// ======================================================== +uint32_t get_bin_index(uint32_t sz) { + int index = 0; + sz = sz < 4 ? 4 : sz; + + while (sz >>= 1) index++; + index -= 2; + + if (index > BIN_MAX_IDX) index = BIN_MAX_IDX; + + return index; +} + +// ======================================================== +// this function will create a footer given a node +// the node's size must be set to the correct value! +// ======================================================== +void create_foot(node_t *head) { + footer_t *foot = get_foot(head); + foot->header = head; +} - ptr = ptr + block_size + 2 * sizeof(int32_t); - block++; - if ((uint32_t*) ptr == end_ptr) { - return 0; - } - } - return 0; +// ======================================================== +// this function will get the footer pointer given a node +// ======================================================== +footer_t *get_foot(node_t *node) { + return (footer_t *) ((char *) node + sizeof(node_t) + node->size); } -uint32_t* alloc_get_heap(alloc_handle* allocator) { - return allocator->heap; +// ======================================================== +// this function will get the wilderness node given a +// heap struct pointer +// +// NOTE: this function banks on the heap's end field being +// correct, it simply uses the footer at the end of the +// heap because that is always the wilderness +// ======================================================== +node_t *get_wilderness(heap_t *heap) { + footer_t *wild_foot = (footer_t *) ((char *) heap->end - sizeof(footer_t)); + return wild_foot->header; } -uint32_t alloc_get_heap_size(alloc_handle* allocator) { - return allocator->heap_size; +uint32_t get_alloc_size(void * ptr) { + node_t *head = (node_t *) (ptr - offset); + return head->size; } diff --git a/kernel/src/memory/allocator.c.old b/kernel/src/memory/allocator.c.old new file mode 100644 index 00000000..08c34275 --- /dev/null +++ b/kernel/src/memory/allocator.c.old @@ -0,0 +1,333 @@ +#include +#include "allocator.h.old" +#include + +uint32_t *__alloc_extend_heap(alloc_handle *allocator, uint32_t amount); + +/* + * The kernel heap is organized in blocks. Each block has a header and a + * footer each a 4 byte integer, at the beginning and end of the block. + * The header and footer both specify the size of the block in question. + * Used blocks are indicated by the heap header and the heap footer being + * negative. + * + * To allocate a block, we start at the first block and walk through each + * one, finding the first free block large enough to support a header, + * footer, and the size requested. + * + * To free a block, we do a bunch of merging stuff to check to see if we + * should merge with the blocks on the left or right of us, respectively. + */ +alloc_handle *alloc_create(uint32_t *buffer, uint32_t buffer_size, + heap_extend_handler extend_handler) { + + if (buffer_size <= sizeof(alloc_handle)) { + return 0; + } + + alloc_handle *alloc_handle_ptr = (alloc_handle *) buffer; + + // storing the alloc_handle struct + // inside the heading of the buffer + alloc_handle_ptr->heap = ((void *) buffer) + sizeof(alloc_handle); + alloc_handle_ptr->heap_size = buffer_size - sizeof(alloc_handle); + alloc_handle_ptr->extend_handler = extend_handler; + + uint32_t *heap_header = alloc_handle_ptr->heap; + uint32_t *heap_footer = (uint32_t *) ((void *) alloc_handle_ptr->heap + + alloc_handle_ptr->heap_size - sizeof(int)); + + *heap_header = alloc_handle_ptr->heap_size - 2 * sizeof(uint32_t); + *heap_footer = alloc_handle_ptr->heap_size - 2 * sizeof(uint32_t); + + return alloc_handle_ptr; +} + +alloc_handle *alloc_create_fixed(uint32_t *buffer, uint32_t buffer_size) { + return alloc_create(buffer, buffer_size, NULL); +} + +// TODO: what if there's an error allocating the page? +// Returns a pointer to the new (big) free block's header +uint32_t *__alloc_extend_heap(alloc_handle *allocator, uint32_t amount) { + if (!allocator->extend_handler) { + return 0; + } + + uint32_t start_size = allocator->heap_size; + uint32_t amount_added = allocator->extend_handler(amount); + + if (amount_added <= 0) { + return 0; + } + + // Now extend the footer block + int32_t *orig_footer = (int32_t *) ((void *) allocator->heap + start_size + - sizeof(uint32_t)); + + allocator->heap_size += amount_added; + + // If it's free, simply move it (and update the header) + // If it's used, add a free block to the end + if (*orig_footer > 0) { + uint32_t *orig_header = (uint32_t *) ((void *) allocator->heap + + start_size - 2 * sizeof(uint32_t) - *orig_footer); + uint32_t *new_footer = (uint32_t *) ((void *) allocator->heap + + allocator->heap_size - sizeof(uint32_t)); + + *new_footer = *orig_footer + amount_added; + *orig_header += amount_added; + return orig_header; + } else { + + uint32_t *new_header = (uint32_t *) ((void *) allocator->heap + start_size); + uint32_t *new_footer = (uint32_t *) ((void *) allocator->heap + + allocator->heap_size - sizeof(uint32_t)); + *new_header = amount_added - 2 * sizeof(uint32_t); + *new_footer = amount_added - 2 * sizeof(uint32_t); + return new_header; + } + + return 0x0; +} + +void *alloc_allocate(alloc_handle *allocator, uint32_t size) { + int32_t i, ret_ptr; + + for (i = 0; i < allocator->heap_size;) { + uint32_t *header_addr = (uint32_t *) ((void *) allocator->heap + i); + int32_t header = *header_addr; + + uint32_t *footer_addr = (uint32_t *) ((void *) allocator->heap + i + + sizeof(int32_t) + size); + + //free and >= request + if (header > 0 && header >= size) { + //cannot split this block + if (header < (size + 2 * sizeof(int32_t) + sizeof(char))) { + footer_addr = (uint32_t *) ((void *) allocator->heap + i + + sizeof(int32_t) + abs(header)); + + ret_ptr = i + sizeof(int32_t); + //mark header as used + *header_addr = header * (-1); + //insert a footer at end of block + *footer_addr = header * (-1); + return (uint32_t *) ((void *) allocator->heap + ret_ptr); + + } else { //can split this block + ret_ptr = i + sizeof(int32_t); + + int32_t old_space = header; + int32_t occ_space = size + 2 * sizeof(int32_t); + //mark header as used + *header_addr = size * (-1); + //insert footer + *footer_addr = size * (-1); + + //insert new free block header + uint32_t *new_header = (uint32_t *) ((void *) allocator->heap + i + + 2 * sizeof(int32_t) + size); + *new_header = old_space - occ_space; + //insert new free block footer + uint32_t *new_footer = (uint32_t *) ((void *) allocator->heap + i + + sizeof(int32_t) + old_space); + *new_footer = old_space - occ_space; + + return (uint32_t *) ((void *) allocator->heap + ret_ptr); + } + } + //jump to the next block + else { + i = i + abs(header) + 2 * sizeof(int32_t); + } + } + + // Allocate some more memory. + uint32_t new_amt = size + 2 * sizeof(uint32_t); + uint32_t *header = __alloc_extend_heap(allocator, new_amt); + + if (header == 0) { + return 0; + } + + // Recursive call. TODO: (relatively) Inefficient + return alloc_allocate(allocator, size); +} + +void alloc_deallocate(alloc_handle *allocator, void *ptr) { + + uint32_t first_block = 0; + uint32_t last_block = 0; + + uint32_t *header_addr = (uint32_t *) ((void *) ptr - sizeof(int32_t)); + uint32_t size = *header_addr; + + os_printf("test, ptr: 0x%x, size: %u\n", header_addr, size); + + uint32_t *footer_addr = (uint32_t *) ((void *) ptr + size); + + if (header_addr == allocator->heap) { + first_block = 1; + } + + if (footer_addr + sizeof(int32_t) + == (void *) allocator->heap + allocator->heap_size) { + last_block = 1; + } + + //os_printf("Freeing %d-sized block at %X. first/last=%d/%d\n", size, header_addr, first_block,last_block); + + //only check and coalesce right block + if (first_block) { + uint32_t *right_header_addr = (uint32_t *) ((void *) footer_addr + + sizeof(int32_t)); + int32_t right_block_size = *right_header_addr; + + //free right block + if (right_block_size > 0) { + //set new header at freed blocks header + *header_addr = size + right_block_size + 2 * sizeof(int32_t); + //set new footer at right blocks footer + uint32_t *right_footer_addr = (uint32_t *) ((void *) footer_addr + + 2 * sizeof(int32_t) + right_block_size); + *right_footer_addr = size + right_block_size + 2 * sizeof(int32_t); + } else { + //make freed blocks header and footer positive + *header_addr = size; + *footer_addr = size; + } + } + + //only check and coalesce left block + if (last_block) { + uint32_t *left_block_header = (uint32_t *) ((void *) header_addr + - sizeof(int32_t)); + int32_t left_block_size = *left_block_header; + + //free left block + if (left_block_size > 0) { + //set new header at left blocks header + uint32_t *left_header_addr = (uint32_t *) ((void *) header_addr + - 2 * sizeof(int32_t) - left_block_size); + *left_header_addr = size + left_block_size + 2 * sizeof(int32_t); + //set new footer at freed blocks footer + *footer_addr = size + left_block_size + 2 * sizeof(int32_t); + } else { + *header_addr = size; + *footer_addr = size; + } + } + + //check and coalesce both adjacent blocks + if (!first_block && !last_block) { + uint32_t *right_block_header = (uint32_t *) ((void *) footer_addr + + sizeof(int32_t)); + int32_t right_block_size = *right_block_header; + + uint32_t *left_block_header = (uint32_t *) ((void *) header_addr + - sizeof(int32_t)); + int32_t left_block_size = *left_block_header; + //os_printf("left/right sizes are %d/%d, size=%d\n", left_block_size, right_block_size, size); + + //both adjacent blocks are free + if (right_block_size > 0 && left_block_size > 0) { + int32_t new_size = size + right_block_size + left_block_size + + 4 * sizeof(int32_t); + + //set new header at left blocks header + uint32_t *left_header_addr = (uint32_t *) ((void *) header_addr + - 2 * sizeof(int32_t) - left_block_size); + *left_header_addr = new_size; + //set new footer at right blocks footer + uint32_t *right_footer_addr = (uint32_t *) ((void *) footer_addr + + 2 * sizeof(int32_t) + right_block_size); + *right_footer_addr = new_size; + } + + //only right free block + else if (right_block_size > 0 && left_block_size < 0) { + //set new header at freed blocks header + *header_addr = size + right_block_size + 2 * sizeof(int32_t); + //set new footer at right blocks footer + uint32_t *right_footer_addr = (uint32_t *) ((void *) footer_addr + + 2 * sizeof(int32_t) + right_block_size); + *right_footer_addr = size + right_block_size + 2 * sizeof(int32_t); + } + //only left free block + else if (left_block_size > 0 && right_block_size < 0) { + //set new header at left blocks header + uint32_t *left_header_addr = (uint32_t *) ((void *) header_addr + - 2 * sizeof(int32_t) - left_block_size); + *left_header_addr = size + left_block_size + 2 * sizeof(int32_t); + //set new footer at freed blocks footer + *footer_addr = size + left_block_size + 2 * sizeof(int32_t); + } else { + *header_addr = size; + *footer_addr = size; + } + + } +} + +/** + * Returns 0 on success. -1 on error. + */ +int alloc_check(alloc_handle *allocator) { + char *ptr = (char *) allocator->heap; + uint32_t *end_ptr = (uint32_t *) ((void *) allocator->heap + + allocator->heap_size); + int i, block = 0; + + LOG("Checking memory...\n"); + for (i = 0; i < allocator->heap_size; i += 0) { + uint32_t *block_addr = (uint32_t *) (ptr + sizeof(int32_t)); + + uint32_t *header_addr = (uint32_t *) ptr; + int32_t block_header = *header_addr; + int32_t block_size = abs(block_header); + + uint32_t *footer_addr = (uint32_t *) (ptr + sizeof(int32_t) + block_size); + int32_t block_footer = *footer_addr; + + if (block_header == block_footer && block_header <= 0) { + LOG("Block %d Allocated:", block); + LOG("\tsize = %d, address = %x\n", block_size, block_addr); + } else if (block_header == block_footer && block_header > 0) { + LOG("Block %d Free:", block); + LOG("\tsize = %d, address = %x\n", block_size, block_addr); + } else { + ERROR("INCONSISTENT HEAP\n"); + ERROR("block_header = %d\n", block_header); + ERROR("block_footer = %d\n", block_footer); + ERROR("header addr = %x\n", header_addr); + ERROR("footer addr = %x\n", footer_addr); + return -1; + } + + ptr = ptr + block_size + 2 * sizeof(int32_t); + block++; + if ((uint32_t *) ptr == end_ptr) { + return 0; + } + } + + return 0; +} + +// Returns the size of the block located at the pointer +uint32_t alloc_allocation_size(void *ptr) { + + uint32_t *header_addr = (uint32_t *) ((void *) ptr - sizeof(int32_t)); + uint32_t size = abs(*header_addr); + + return size; +} + +uint32_t *alloc_get_heap(alloc_handle *allocator) { + return allocator->heap; +} + +uint32_t alloc_get_heap_size(alloc_handle *allocator) { + return allocator->heap_size; +} diff --git a/kernel/src/memory/include/allocator.h b/kernel/src/memory/include/allocator.h index b26efc3f..6e0f8306 100644 --- a/kernel/src/memory/include/allocator.h +++ b/kernel/src/memory/include/allocator.h @@ -1,31 +1,74 @@ -/* - Log - 4/2: Adjusted bump allocation algorithm: Sean V, Faseeh A, John G, Taylor S - 4/7: Fixed mem_alloc again works properly: Sean V, Faseeh A, Taylor S. +#ifndef ALLOCATOR_H +#define ALLOCATOR_H - */ -#ifndef __ALLOCATOR_H__ -#define __ALLOCATOR_H__ +#include -#include "stdint.h" +#define HEAP_INIT_SIZE 0x10000 +#define HEAP_MAX_SIZE 0xF0000 +#define HEAP_MIN_SIZE 0x10000 -#define MEM_START 0x500000 +#define MIN_ALLOC_SZ 4 -typedef uint32_t (*heap_extend_handler)(uint32_t amount); +#define MIN_WILDERNESS 0x2000 +#define MAX_WILDERNESS 0x1000000 -typedef struct alloc_handle { - uint32_t *heap; - uint32_t heap_size; - heap_extend_handler extend_handler; -} alloc_handle; +#define BIN_COUNT 9 +#define BIN_MAX_IDX (BIN_COUNT - 1) -alloc_handle* alloc_create(uint32_t * heap, uint32_t size, - heap_extend_handler extend_handler); -alloc_handle* alloc_create_fixed(uint32_t * buffer, uint32_t buffer_size); -void* alloc_allocate(alloc_handle * allocator, uint32_t size); -void alloc_deallocate(alloc_handle* allocator, void* ptr); -uint32_t* alloc_get_heap(alloc_handle* allocator); -uint32_t alloc_get_heap_size(alloc_handle* allocator); -int alloc_check(alloc_handle* allocator); +/// Heap +typedef struct node_t { + uint32_t hole; + uint32_t size; + struct node_t* next; + struct node_t* prev; +} node_t; + +typedef struct { + node_t *header; +} footer_t; + +typedef struct { + node_t* head; +} bin_t; + +typedef struct { + uint32_t start; + uint32_t end; + bin_t *bins[BIN_COUNT]; + +#ifdef MEM_DEBUG + size_t bytes_allocated; #endif +} heap_t; + +uint32_t overhead; + +void create_heap(heap_t *heap, uint32_t start); + +void *heap_alloc(heap_t *heap, uint32_t size); +void heap_free(heap_t *heap, void *p); +uint32_t expand(heap_t *heap, uint32_t sz); +void contract(heap_t *heap, uint32_t sz); + +uint32_t get_bin_index(uint32_t sz); +void create_foot(node_t *head); +footer_t *get_foot(node_t *head); + +node_t *get_wilderness(heap_t *heap); + +uint32_t get_alloc_size(void * ptr); + +/// Linked list + +void add_node(bin_t *bin, node_t *node); + +void remove_node(bin_t *bin, node_t *node); + +node_t *get_best_fit(bin_t *list, uint32_t size); +node_t *get_last_node(bin_t *list); + +node_t *next(node_t *current); +node_t *prev(node_t *current); + +#endif \ No newline at end of file diff --git a/kernel/src/memory/include/allocator.h.old b/kernel/src/memory/include/allocator.h.old new file mode 100644 index 00000000..3a3b1c5b --- /dev/null +++ b/kernel/src/memory/include/allocator.h.old @@ -0,0 +1,32 @@ +/* + Log + 4/2: Adjusted bump allocation algorithm: Sean V, Faseeh A, John G, Taylor S + 4/7: Fixed mem_alloc again works properly: Sean V, Faseeh A, Taylor S. + + */ +#ifndef __ALLOCATOR_H__ +#define __ALLOCATOR_H__ + +#include "stdint.h" + +#define MEM_START 0x500000 + +typedef uint32_t (*heap_extend_handler)(uint32_t amount); + +typedef struct alloc_handle { + uint32_t *heap; + uint32_t heap_size; + heap_extend_handler extend_handler; +} alloc_handle; + +alloc_handle* alloc_create(uint32_t * heap, uint32_t size, + heap_extend_handler extend_handler); +alloc_handle* alloc_create_fixed(uint32_t * buffer, uint32_t buffer_size); +void* alloc_allocate(alloc_handle * allocator, uint32_t size); +void alloc_deallocate(alloc_handle* allocator, void* ptr); +uint32_t* alloc_get_heap(alloc_handle* allocator); +uint32_t alloc_allocation_size(void* ptr); +uint32_t alloc_get_heap_size(alloc_handle* allocator); +int alloc_check(alloc_handle* allocator); + +#endif diff --git a/kernel/src/memory/include/mem_alloc.h b/kernel/src/memory/include/mem_alloc.h index 98ecef6c..7b3865c1 100644 --- a/kernel/src/memory/include/mem_alloc.h +++ b/kernel/src/memory/include/mem_alloc.h @@ -1,9 +1,3 @@ -/* -Log -4/2: Adjusted bump allocation algorithm: Sean V, Faseeh A, John G, Taylor S -4/7: Fixed mem_alloc again works properly: Sean V, Faseeh A, Taylor S. - -*/ #ifndef __MEM_ALLOC_H__ #define __MEM_ALLOC_H__ @@ -11,22 +5,23 @@ Log #include #define MEM_START 0x500000 -#define PROC_START 0x90000000 +#define PROC_START 0x90000000 +struct vas; uint32_t init_heap(); -void *allocate(uint32_t, uint32_t* /*unused*/, int32_t/*unused*/); -void deallocate(void*, uint32_t*/*unused*/, int32_t/*unused*/); +void *allocate(uint32_t size); +void deallocate(void *ptr); /** - * Initializes a processes heap, in the same manner that the + * Initializes a processes heap, in the same manner that the * kernel heap is initialized * * @param pointer to virtual address space (the process's VAS) * @param struct vas* vas * @return returns status code (for error or for ok) */ -uint32_t init_process_heap(); +uint32_t init_process_heap(struct vas* vas); /** * Allocates memory on the heap for a process @@ -45,8 +40,11 @@ void *proc_allocate(uint32_t); * @return nothing */ void proc_deallocate(void*); -alloc_handle* mem_get_allocator(); -int mem_check(); +heap_t* mem_get_allocator(); uint32_t mem_get_heap_size(); +// get size of allocated blocks +uint32_t allocation_size(void* ptr); +uint32_t proc_blocksize(void* ptr); + #endif diff --git a/kernel/src/memory/llist.c b/kernel/src/memory/llist.c new file mode 100644 index 00000000..75ee5b72 --- /dev/null +++ b/kernel/src/memory/llist.c @@ -0,0 +1,88 @@ +#include +#include + +void add_node(bin_t *bin, node_t* node) { + node->next = NULL; + node->prev = NULL; + + if (bin->head == NULL) { + bin->head = node; + return; + } + + // we need to save next and prev while we iterate + node_t *current = bin->head; + node_t *previous = NULL; + // iterate until we get the the end of the list or we find a + // node whose size is + while (current != NULL && current->size <= node->size) { + previous = current; + current = current->next; + } + + if (current == NULL) { // we reached the end of the list + previous->next = node; + node->prev = previous; + } + else { + if (previous != NULL) { // middle of list, connect all links! + node->next = current; + previous->next = node; + + node->prev = previous; + current->prev = node; + } + else { // head is the only element + node->next = bin->head; + bin->head->prev = node; + bin->head = node; + } + } +} + +void remove_node(bin_t * bin, node_t *node) { + if (bin->head == NULL) return; + if (bin->head == node) { + bin->head = bin->head->next; + return; + } + + node_t *temp = bin->head->next; + while (temp != NULL) { + if (temp == node) { // found the node + if (temp->next == NULL) { // last item + temp->prev->next = NULL; + } + else { // middle item + temp->prev->next = temp->next; + temp->next->prev = temp->prev; + } + // we dont worry about deleting the head here because we already checked that + return; + } + temp = temp->next; + } +} + +node_t *get_best_fit(bin_t *bin, uint32_t size) { + if (bin->head == NULL) return NULL; // empty list! + + node_t *temp = bin->head; + + while (temp != NULL) { + if (temp->size >= size) { + return temp; // found a fit! + } + temp = temp->next; + } + return NULL; // no fit! +} + +node_t *get_last_node(bin_t *bin) { + node_t *temp = bin->head; + + while (temp->next != NULL) { + temp = temp->next; + } + return temp; +} diff --git a/kernel/src/memory/mem_alloc.c b/kernel/src/memory/mem_alloc.c index ab9a20bf..16bec0f7 100644 --- a/kernel/src/memory/mem_alloc.c +++ b/kernel/src/memory/mem_alloc.c @@ -1,14 +1,17 @@ + + #include "klibc.h" -#include "mem_alloc.h" -#include "vm.h" -#include "allocator.h" +#include +#include +#include +#include uint32_t *nextBlock = (uint32_t*) MEM_START; uint32_t buffer_size; -alloc_handle * allocator; +heap_t * allocator; uint32_t __mem_extend_heap(uint32_t amt); -alloc_handle * proc_allocator; +heap_t * proc_allocator; uint32_t proc_buffer_size; uint32_t __mem_extend_proc_heap(uint32_t amt); @@ -64,42 +67,77 @@ uint32_t __mem_extend_heap(uint32_t amt) uint32_t init_heap() { - int retval = vm_allocate_page(KERNEL_VAS, (void*) MEM_START, - VM_PERM_PRIVILEGED_RW); + // Allocate space for the heap_t struct. is too large but at least big enough. + int retval = vm_allocate_page(KERNEL_VAS, (void*) MEM_START, VM_PERM_PRIVILEGED_RW); if (retval) { os_printf("ERROR: vm_allocate_page returned %d\n", retval); return STATUS_FAIL; } - buffer_size = BLOCK_SIZE; - allocator = alloc_create((uint32_t*) MEM_START, buffer_size, &__mem_extend_heap); + heap_t * heap = (heap_t * ) MEM_START; + memset(heap, 0, sizeof(heap_t)); + + uint32_t addr = (uint32_t)((void *) MEM_START + sizeof(heap_t)); + + for(int i = 0; i < BIN_COUNT; i++) { + heap->bins[i] = (bin_t *) addr; + memset(heap->bins[0], 0, sizeof(bin_t)); + addr += sizeof(bin_t); + } + + assert(MEM_START + sizeof(heap_t) + BIN_COUNT * sizeof(bin_t) == addr) + + + // Find the next page boundary above addr + addr = (addr & ~(BLOCK_SIZE-1)) + BLOCK_SIZE; + + void * ret = vm_allocate_pages(KERNEL_VAS, (void *) addr, HEAP_INIT_SIZE, VM_PERM_PRIVILEGED_RW); + if(addr + HEAP_INIT_SIZE != (uint32_t) ret) { + os_printf("ERROR: vm_allocate_pages allocated a different amount than requested\n"); + return STATUS_FAIL; + } + + // allocator = alloc_create((uint32_t*) MEM_START, buffer_size, &__mem_extend_heap); + create_heap(heap, addr); + allocator = heap; return STATUS_OK; } -uint32_t init_process_heap(struct vas* vas) -{ +uint32_t init_process_heap(struct vas* vas) { int retval = vm_allocate_page(vas, (void*) PROC_START, VM_PERM_USER_RW); - vm_map_shared_memory(KERNEL_VAS, (void*)PROC_START, vas, (void*)PROC_START, VM_PERM_USER_RW); if (retval) { os_printf("ERROR: vm_allocate_page returned %d\n", retval); return STATUS_FAIL; } - else{ - os_printf("Page allocated for process heap at %x:\n",PROC_START); + + heap_t * heap = (heap_t * ) PROC_START; + uint32_t addr = (uint32_t)((void *) PROC_START + sizeof(heap_t)); + + for(int i = 0; i < BIN_COUNT; i++) { + heap->bins[i] = (bin_t *) addr; + addr += sizeof(bin_t); } - proc_buffer_size = BLOCK_SIZE; - proc_allocator = alloc_create((uint32_t*) PROC_START, proc_buffer_size, &__mem_extend_proc_heap); - vm_free_mapping(KERNEL_VAS,(void*)PROC_START); + // Find the next page boundary above addr + addr = (addr & ~(BLOCK_SIZE-1)) + BLOCK_SIZE; + + void * ret = vm_allocate_pages(vas, (void *) addr, HEAP_INIT_SIZE, VM_PERM_USER_RW); + if(addr + HEAP_INIT_SIZE != (uint32_t) ret){ + os_printf("ERROR: vm_allocate_pages allocated a different amount than requested\n"); + return STATUS_FAIL; + } + + create_heap(heap, addr); + proc_allocator = heap; + vm_free_mapping(KERNEL_VAS, (void*) PROC_START); // ? return STATUS_OK; } -uint32_t __mem_extend_proc_heap(uint32_t amt) -{ +uint32_t __mem_extend_proc_heap(uint32_t amt) { struct vas* pvas = vm_get_current_vas(); uint32_t amt_added = 0; - while (amt_added < amt) + while (amt_added < amt) { int retval = vm_allocate_page(pvas, (void*) PROC_START, VM_PERM_USER_RW); vm_map_shared_memory(KERNEL_VAS, (void*)PROC_START, pvas, (void*)PROC_START, VM_PERM_USER_RW); @@ -113,39 +151,41 @@ uint32_t __mem_extend_proc_heap(uint32_t amt) amt_added += BLOCK_SIZE; proc_buffer_size += BLOCK_SIZE; } - + vm_free_mapping(KERNEL_VAS,(void*)PROC_START); return amt_added; } void* proc_allocate(uint32_t size) { - return alloc_allocate(proc_allocator, size); + return heap_alloc(proc_allocator, size); } void proc_deallocate(void* ptr) { - return alloc_deallocate(proc_allocator, ptr); + return heap_free(proc_allocator, ptr); } -void* allocate(uint32_t size, uint32_t* heap, int32_t heap_size) -{ - return alloc_allocate(allocator, size); +void *allocate(uint32_t size) { + return heap_alloc(allocator, size); } -void deallocate(void* ptr, uint32_t* heap, int32_t heap_size) -{ - return alloc_deallocate(allocator, ptr); +void deallocate(void *ptr) { + return heap_free(allocator, ptr); +} + +uint32_t allocation_size(void* ptr) { + return get_alloc_size(ptr); } -alloc_handle * mem_get_allocator(){ +heap_t * mem_get_allocator(){ return allocator; } -int mem_check(){ - return alloc_check(allocator); +heap_t * mem_get_proc_allocator(){ + return proc_allocator; } uint32_t mem_get_heap_size(){ - return alloc_get_heap_size(allocator); + return allocator->end - allocator->start; } diff --git a/kernel/src/memory/mmap.c b/kernel/src/memory/mmap.c index 6e99de78..cbe21ec4 100644 --- a/kernel/src/memory/mmap.c +++ b/kernel/src/memory/mmap.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -23,8 +24,7 @@ extern struct vm_free_list *vm_vas_free_list; extern struct vm_free_list *vm_l1pt_free_list; extern struct vm_free_list *vm_l2pt_free_list; -void mmap(void *p_bootargs) -{ +void mmap(void *p_bootargs) { //char *cmdline_args = read_cmdline_tag(p_bootargs); //print_uart0(cmdline_args); //print_uart0("\n"); @@ -51,13 +51,12 @@ void mmap(void *p_bootargs) //first_level_pt = 0x00200000 + 0x4000 = 0x00204000 os_printf("first_level_pt=%X\n", first_level_pt); - int i; - for (i = 0; i < PAGE_TABLE_SIZE >> 2; i++) - { + int i = 0; + for (; i < PAGE_TABLE_SIZE >> 2; i++) { first_level_pt[i] = 0; } - //temporarily map where it is until we copy it in VAS + //temporarily map where it is until we copy it in VAS first_level_pt[P_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; //first_level_pt[0x07f00000>>20] = first_level_pt[7F] = 0x07f00000 = 0x07f04010 // 0x00004000 @@ -82,8 +81,7 @@ void mmap(void *p_bootargs) //map 752MB of PCI interface one-to-one unsigned int pci_bus_addr = PCIBASE; - for (i = (PCIBASE >> 20); i < (PCITOP >> 20); i++) - { + for (i = (PCIBASE >> 20); i < (PCITOP >> 20); i++) { first_level_pt[i] = pci_bus_addr | 0x0400 | 2; pci_bus_addr += 0x100000; } @@ -97,8 +95,7 @@ void mmap(void *p_bootargs) // This is where we allocate frames from. Except for the first one. unsigned int phys_addr = P_KERNTOP; // +1 to skip L1PTBASE - for (i = (PMAPBASE >> 20); i < (PMAPTOP >> 20); i++) - { + for (i = (PMAPBASE >> 20); i < (PMAPTOP >> 20); i++) { first_level_pt[i] = phys_addr | 0x0400 | 2; phys_addr += 0x100000; } diff --git a/kernel/src/memory/test/test_allocator.c b/kernel/src/memory/test/test_allocator.c new file mode 100644 index 00000000..a01e84ef --- /dev/null +++ b/kernel/src/memory/test/test_allocator.c @@ -0,0 +1,30 @@ +#include +#include + +TEST_CREATE(test_alloc_free, { + uint32_t * a = kmalloc(sizeof(uint32_t)); + *a = 42; + kfree(a); +}) + +TEST_CREATE(test_alloc_free_large, { + uint32_t * a = kmalloc(100 * sizeof(uint32_t)); + for (int i = 0; i < 100; i++) { + a[i] = 42; + } + kfree(a); +}) + +TEST_CREATE(test_alloc_realloc_free, { + uint32_t * a = kmalloc(5 * sizeof(uint32_t)); + for (int i = 0; i < 5; i++) { + a[i] = 42; + } + + a = krealloc(a, 100 * sizeof(uint32_t)); + for (int i = 5; i < 100; i++) { + a[i] = 42; + } + + kfree(a); +}) \ No newline at end of file diff --git a/kernel/src/memory/vm/include/vm.h b/kernel/src/memory/vm/include/vm.h index e9c8b63f..cbddb68f 100644 --- a/kernel/src/memory/vm/include/vm.h +++ b/kernel/src/memory/vm/include/vm.h @@ -7,7 +7,7 @@ #include //#define BLOCK_SIZE (1<<20) -#define BLOCK_SIZE (1<<12) +#define BLOCK_SIZE ((uint32_t)(1<<12)) #define PAGE_TABLE_SIZE (1<<14) #define L2_PAGE_TABLE_SIZE (1<<12) diff --git a/kernel/src/memory/vm/vm.c b/kernel/src/memory/vm/vm.c index 20629d66..e2aba8ed 100644 --- a/kernel/src/memory/vm/vm.c +++ b/kernel/src/memory/vm/vm.c @@ -1,13 +1,13 @@ -#include "vm.h" -#include "memory.h" -#include "klibc.h" -#include "include/frame.h" +#include +#include +#include +#include #define CHECK_VPTR if ((unsigned int)vptr & (BLOCK_SIZE-1)) return VM_ERR_BADV; #define CHECK_PPTR if ((unsigned int)pptr & (BLOCK_SIZE-1)) return VM_ERR_BADP; -static const int perm_mapping[16] = -{ 0, // 0000 Nothing +static const int perm_mapping[16] = { + 0, // 0000 Nothing 5, // 0001 Privileged RO, nothing otherwise 6, // 0010 User RO, privileged RO. 6, // 0011 User RO, privileged RO. @@ -107,7 +107,7 @@ uint32_t *vm_alloc_coarse_page_table() return NULL; } vm_l2pt_free_list = ((struct vm_free_list*) vptr)->next; - os_memset((void*) vptr, 0, L2_PAGE_TABLE_SIZE); + memset((void*) vptr, 0, L2_PAGE_TABLE_SIZE); return vptr; } @@ -145,8 +145,7 @@ void vm_use_kernel_vas() vm_enable_vas((struct vas*) V_L1PTBASE); } -int vm_allocate_page(struct vas *vas, void *vptr, int permission) -{ +int vm_allocate_page(struct vas *vas, void *vptr, int permission) { CHECK_VPTR; // We have to save the current VAS and switch to the kernel VAS @@ -179,23 +178,25 @@ int vm_allocate_page(struct vas *vas, void *vptr, int permission) return 0; } -void *vm_allocate_pages(struct vas *vas, void *vptr, uint32_t nbytes, - int permission) -{ - int rc; - unsigned char *p = (unsigned char*) vptr; - while (p - (unsigned char*) vptr < nbytes) - { - rc = vm_allocate_page(vas, p, permission); - assert(rc == 0); - p += BLOCK_SIZE; - } - return p; +void *vm_allocate_pages(struct vas *vas, void *vptr, uint32_t nbytes, int permission) { + int rc; + unsigned char *p = (unsigned char*) vptr; + while (p - (unsigned char*) vptr < nbytes) { + rc = vm_allocate_page(vas, p, permission); + if(rc != STATUS_OK) { + os_printf("Allocate page failed with code %i\n", rc); + os_printf("vptr: 0x%x", (uint32_t)p); + + panic(); + } + + p += BLOCK_SIZE; + } + return p; } -int vm_free_page(struct vas *vas, void *vptr) -{ +int vm_free_page(struct vas *vas, void *vptr) { CHECK_VPTR; // We have to save the current VAS @@ -417,7 +418,7 @@ struct vas *vm_new_vas() - (V_L1PTBASE - P_L1PTBASE)); // Zero out the page table - os_memset(p->l1_pagetable, 0, PAGE_TABLE_SIZE); + memset(p->l1_pagetable, 0, PAGE_TABLE_SIZE); // Setup the static mappings... // The kernel (high & low addresses) diff --git a/kernel/src/process/elf.c b/kernel/src/process/elf.c index 51946281..6c9eb500 100644 --- a/kernel/src/process/elf.c +++ b/kernel/src/process/elf.c @@ -1,12 +1,12 @@ /* Worked on by Jeremy Wenzel, Kaelen Haag, and Sam Allen */ -#include "elf.h" -#include "klibc.h" -#include "../../src/klibc//include/stdint.h" // Probably going to be removed +#include +#include +#include unsigned char* filePointer; unsigned char* startPointer; //OVERHAUL TO MAKE EVERYTHING PASSED BY REFERENCE RATHER THAN VALUE. -//I THINK WE SHOULD JUST COMMENT OUT ALL THE SECTION HEADER STUFF BECAUSE IT'S NOT USED AND WILL BE A PAINTO MESS WITH. NEED TO MAKE PROGRAM HEADER ARRAY PASS BY VALUE AND NEED TO FIX get_value to take in refernce rather than value. DO TONIGHT OR TOMORROW - KAELEN +//I THINK WE SHOULD JUST COMMENT OUT ALL THE SECTION HEADER STUFF BECAUSE IT'S NOT USED AND WILL BE A PAINTO MESS WITH. NEED TO MAKE PROGRAM HEADER ARRAY PASS BY VALUE AND NEED TO FIX get_value to take in refernce rather than value. DO TONIGHT OR TOMORROW - KAELEN /* Gets the value of the bytes on a big endian system */ uint32_t do_big_endian(uint32_t size) @@ -81,7 +81,7 @@ int32_t read_elf_header(Elf_Ehdr *h, unsigned char *pointer) //os_printf("Size of char: %d\n", sizeof(char)); //os_printf("Size of get_value(1, h): %d\n", sizeof((char)get_value(1, h))); char temp = get_value(1, h); - //os_printf("Size of temp: %d\n", sizeof(temp)); + //os_printf("Size of temp: %d\n", sizeof(temp)); h->e_ident[EI_CLASS] = temp; // get_value(1, h); // get class temp = get_value(1, h); @@ -217,35 +217,35 @@ void parse_section_header_names(Elf_Ehdr *eh, Elf_Shdr sh[], uint32_t *pointer) filePointer++; while (i < eh->e_shnum) { - if (os_strcmp(((char*) filePointer), ".symtab") == 0) + if (strcmp(((char*) filePointer), ".symtab") == 0) { // checks if symbol table sh[i].sh_numname = SYMTAB; } - else if (os_strcmp(((char*) filePointer), ".text") == 0) + else if (strcmp(((char*) filePointer), ".text") == 0) { // checks if .text table sh[i].sh_numname = TEXT; } - else if (os_strcmp(((char*) filePointer), ".comment") == 0) + else if (strcmp(((char*) filePointer), ".comment") == 0) { // checks if comment table sh[i].sh_numname = COMMENT; } - else if (os_strcmp(((char*) filePointer), ".strtab") == 0) + else if (strcmp(((char*) filePointer), ".strtab") == 0) { // checks if string table sh[i].sh_numname = STRTAB; } - else if (os_strcmp(((char*) filePointer), ".shstrtab") == 0) + else if (strcmp(((char*) filePointer), ".shstrtab") == 0) { // checks if section header string table sh[i].sh_numname = SHSTRTAB; } - else if (os_strcmp(((char*) filePointer), ".rodata") == 0) + else if (strcmp(((char*) filePointer), ".rodata") == 0) { // checks if read only data sh[i].sh_numname = RODATA; } - else if (os_strcmp(((char*) filePointer), ".data") == 0) + else if (strcmp(((char*) filePointer), ".data") == 0) { // checks if initialized data sh[i].sh_numname = DATA; } - else if (os_strcmp(((char*) filePointer), ".bss") == 0) + else if (strcmp(((char*) filePointer), ".bss") == 0) { // checks if unitialized data sh[i].sh_numname = BSS; } diff --git a/kernel/src/process/include/process.h b/kernel/src/process/include/process.h index 1e063af4..3a9c75cc 100644 --- a/kernel/src/process/include/process.h +++ b/kernel/src/process/include/process.h @@ -63,8 +63,7 @@ typedef enum PROCESS_STATE #define HEAP_BASE 0x90000000 -typedef struct pcb -{ +typedef struct pcb { //ID data char* name; /* for debugging purposes */ uint32_t PID; diff --git a/kernel/src/process/loader.c b/kernel/src/process/loader.c index 22d30196..f469eaa0 100644 --- a/kernel/src/process/loader.c +++ b/kernel/src/process/loader.c @@ -1,9 +1,9 @@ -#include "../../src/klibc//include/stdint.h" -#include "loader.h" -#include "mem_alloc.h" -#include "klibc.h" -#include "process.h" -#include "elf.h" +#include +#include +#include +#include +#include +#include //Worked on by Kaelen Haag and Jeremy Wenzel //We determine what the size of our process is going to be diff --git a/kernel/src/process/process.c b/kernel/src/process/process.c index a7e7b989..0c869f50 100644 --- a/kernel/src/process/process.c +++ b/kernel/src/process/process.c @@ -1,7 +1,8 @@ #include -#include +#include #include #include +#include //#include #include @@ -131,8 +132,7 @@ void __process_elf_init(pcb* pcb_p, const char* name) { @param pcb* pcb_p */ -void __process_stack_init(pcb * pcb_p) -{ +void __process_stack_init(pcb * pcb_p) { int retval = 0; for (int i = 0; i < (STACK_SIZE / BLOCK_SIZE); i++) { @@ -163,7 +163,7 @@ void __process_stack_init(pcb * pcb_p) stack_top[-5] = STACK_BASE; stack_top[-6] = 1; - os_strcpy((char*) STACK_BASE, pcb_p->name); + strcpy((char*) STACK_BASE, pcb_p->name); // We need to set sp (r13) to stack_top - 12 pcb_p->R13 = STACK_TOP - 4 * 6; @@ -172,20 +172,20 @@ void __process_stack_init(pcb * pcb_p) vm_free_mapping(KERNEL_VAS, (void*) (STACK_BASE + (i * BLOCK_SIZE))); } } -void __process_heap_init(pcb* pcb_p) -{ + +void __process_heap_init(pcb* pcb_p) { //from mem_alloc.c init_process_heap(pcb_p->stored_vas); os_printf("User Level Heap for Process PID %d initialized\n", pcb_p->PID); } + /* Saves all of the Registers on the machine to the PCB @param Process ID @return 0 if failed @return 1 for success */ -void process_save_state(pcb* pcb_p) -{ +void process_save_state(pcb* pcb_p) { assert(pcb_p); asm("MOV %0, r0":"=r"(pcb_p->R0)::); diff --git a/kernel/src/process/scheduler.c b/kernel/src/process/scheduler.c index 5b25be05..71eeb17c 100644 --- a/kernel/src/process/scheduler.c +++ b/kernel/src/process/scheduler.c @@ -1,12 +1,13 @@ #include #include #include -#include +#include #include #include #include #include #include +#include #define MAX_TASKS 100 // in the future, cap will be removed #define MAX_ACTIVE_TASKS 4 // in the future, will dynamically change based on load @@ -16,7 +17,7 @@ #define TASK_STATE_INACTIVE 2 // task is in the wait queue (about to be executed) #define TASK_STATE_ACTIVE 1 // task is part of the running tasks; it is being interleaved and executed atm #define TASK_STATE_NONE 0 // task is just created (no real state) -#define SAFE_NICE(n) MAX(MIN(MAX_NICENESS, n), n) +#define SAFE_NICE(n) max(min(MAX_NICENESS, n), n) #define KTHREAD 0 #define PROCESS 1 @@ -429,7 +430,7 @@ uint32_t sched_set_niceness(uint32_t pid, uint32_t niceness) { __sched_pause_timer_irq(); - prq_handle * tasks; + prq_handle * tasks = NULL; switch (task->state) { case TASK_STATE_ACTIVE: @@ -442,7 +443,7 @@ uint32_t sched_set_niceness(uint32_t pid, uint32_t niceness) { break; } - if (tasks) { + if (tasks != NULL) { prq_remove(tasks, task->node); // remove the running task from queue task->node->priority = SAFE_NICE(niceness); prq_enqueue(tasks, task->node); // add it again to see if its position in the queue diff --git a/kernel/src/test/generate_tests.sh b/kernel/src/test/generate_tests.sh index 9e4f095e..1a4b2301 100755 --- a/kernel/src/test/generate_tests.sh +++ b/kernel/src/test/generate_tests.sh @@ -34,4 +34,6 @@ done echo " os_printf(\"TESTS COMPLETE\n\"); -}" >> "$DIR/test.c" \ No newline at end of file +}" >> "$DIR/test.c" + + diff --git a/kernel/src/test/include/test.h b/kernel/src/test/include/test.h index 2c57555c..712b103a 100644 --- a/kernel/src/test/include/test.h +++ b/kernel/src/test/include/test.h @@ -6,29 +6,67 @@ #define TEST_FAIL 0 #include +#include +#include // Only compile test definitions if enabled -#if ENABLE_TESTS - -#define TEST_CREATE(name, block) \ - int __internal_test_##name() block \ - int test_##name() { \ - os_printf("Testing %s\n", #name); \ - int res = __internal_test_##name(); \ - if (res == TEST_PASS) { \ - os_printf("PASSED\n"); \ - return 1; \ - } else { \ - os_printf("FAILED\n"); \ - return 0; \ - } \ +#ifdef ENABLE_TESTS + +#ifdef MEM_DEBUG +#define TEST_CREATE(name, block) \ + int __internal_test_##name() { \ + heap_t * heap = mem_get_allocator(); \ + isize_t nbytes = heap->bytes_allocated; \ + block; \ + if (nbytes != (isize_t)heap->bytes_allocated) { \ + os_printf( \ + "FAILED (MEMORY LEAK: %i bytes) \n",\ + heap->bytes_allocated - nbytes \ + ); \ + return TEST_FAIL; \ + } \ + return TEST_PASS; \ + } \ + int test_##name() { \ + os_printf("Testing %s\n", #name); \ + int res = __internal_test_##name(); \ + if (res == TEST_PASS) { \ + os_printf("PASSED\n"); \ + return 1; \ + } else { \ + os_printf("FAILED\n"); \ + return 0; \ + } \ + } +#else +#define TEST_CREATE(name, block) \ + int __internal_test_##name() { \ + block; \ + return TEST_PASS; \ + } \ + int test_##name() { \ + os_printf("Testing %s\n", #name); \ + int res = __internal_test_##name(); \ + if (res == TEST_PASS) { \ + os_printf("PASSED\n"); \ + return 1; \ + } else { \ + os_printf("FAILED\n"); \ + return 0; \ + } \ } +#endif #define PASS() return TEST_PASS #define FAIL() return TEST_FAIL -#define ASSERT(expr) do { if(!expr) { return TEST_FAIL } } while(0) -#define ASSERT_EQ(l, r) do { if(l != r) { return TEST_FAIL } } while(0) - +#define ASSERT(expr) do { if(!expr) { os_printf("failed assertion: %s at ASSERT(%s)\n", __FILE__, #expr); return TEST_FAIL; } } while(0) +#define ASSERT_EQ(l, r) do { if(l != r) { os_printf("failed assertion: %s at ASSERT_EQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_GT(l, r) do { if(l <= r) { os_printf("failed assertion: %s at ASSERT_GT(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_GTEQ(l, r) do { if(l < r) { os_printf("failed assertion: %s at ASSERT_GTEQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_LT(l, r) do { if(l >= r) { os_printf("failed assertion: %s at ASSERT_LT(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_LTEQ(l, r) do { if(l > r) { os_printf("failed assertion: %s at ASSERT_LTEQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_NEQ(l, r) do { if(l == r) { os_printf("failed assertion: %s at ASSERT_NEQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_NOT_NULL(e) do { if(e == NULL) { os_printf("failed assertion: %s\n at ASSERT_NOT_NULL(%s)", __FILE__, #e); return TEST_FAIL; } } while(0) #else diff --git a/kernel/src/test/monitor_tests.sh b/kernel/src/test/monitor_tests.sh index e7c653da..8a864cc8 100755 --- a/kernel/src/test/monitor_tests.sh +++ b/kernel/src/test/monitor_tests.sh @@ -7,10 +7,15 @@ do if [[ $line == *"TESTS COMPLETE"* ]]; then echo "COMPLETE" exit 0 - + elif [[ $line == *"MEMORY LEAK"* ]]; then + echo "FAILED (MEMORY: $line)" + exit 1 elif [[ $line == *"FAILED"* ]]; then echo "FAILED" - exit 1 + exit 2 + elif [[ $line == *"DATA ABORT HANDLER"* ]]; then + echo "FAILED (EXCEPTION: $line)" + exit 3 else echo "$line" fi diff --git a/kernel/src/test/test.c b/kernel/src/test/test.c index 94f983d2..c21d6c84 100644 --- a/kernel/src/test/test.c +++ b/kernel/src/test/test.c @@ -5,11 +5,97 @@ #include -int test_first(); -int test_second(); +int test_u8a_push_get_pop_test(); +int test_u8a_push_set_pop_test(); +int test_u8a_resize_test(); +int test_u8a_push_string_test(); +int test_u8a_clone_test(); +int test_vpa_push_get_pop_test(); +int test_vpa_push_set_pop_test(); +int test_vpa_resize_test(); +int test_test_compare_nonequal_length(); +int test_test_compare_equal_length(); +int test_test_compare_equal_length_eq(); +int test_test_compare_equal_length_eq_null(); +int test_test_compare_various(); +int test_test_alloc_free(); +int test_test_alloc_free_large(); +int test_test_alloc_realloc_free(); +int test_test_create_file(); +int test_test_create_dir(); +int test_test_create_rw_file(); +int test_test_listdir(); +int test_test_create_vfs(); +int test_test_get_root(); +int test_path_create_test(); +int test_path_equal_test_1(); +int test_path_parent_test_1(); +int test_path_parent_test_2(); +int test_path_parent_test_3(); +int test_path_parent_test_4(); +int test_path_parent_test_5(); +int test_path_parent_test_6(); +int test_path_parent_test_7(); +int test_path_parent_test_8(); +int test_path_parent_test_9(); +int test_path_parent_test_10(); +int test_path_is_absolute_test(); +int test_path_is_relative_test_1(); +int test_path_is_relative_test_2(); +int test_path_clone_test(); +int test_path_find_file_test(); +int test_path_filename_test(); +int test_path_filename_test_trailing(); +int test_path_filename_test_1(); +int test_path_filename_test_2(); +int test_path_filename_test_3(); +int test_path_filename_test_4(); void test_main(){ - if (!test_first()) {return;} - if (!test_second()) {return;} + if (!test_u8a_push_get_pop_test()) {return;} + if (!test_u8a_push_set_pop_test()) {return;} + if (!test_u8a_resize_test()) {return;} + if (!test_u8a_push_string_test()) {return;} + if (!test_u8a_clone_test()) {return;} + if (!test_vpa_push_get_pop_test()) {return;} + if (!test_vpa_push_set_pop_test()) {return;} + if (!test_vpa_resize_test()) {return;} + if (!test_test_compare_nonequal_length()) {return;} + if (!test_test_compare_equal_length()) {return;} + if (!test_test_compare_equal_length_eq()) {return;} + if (!test_test_compare_equal_length_eq_null()) {return;} + if (!test_test_compare_various()) {return;} + if (!test_test_alloc_free()) {return;} + if (!test_test_alloc_free_large()) {return;} + if (!test_test_alloc_realloc_free()) {return;} + if (!test_test_create_file()) {return;} + if (!test_test_create_dir()) {return;} + if (!test_test_create_rw_file()) {return;} + if (!test_test_listdir()) {return;} + if (!test_test_create_vfs()) {return;} + if (!test_test_get_root()) {return;} + if (!test_path_create_test()) {return;} + if (!test_path_equal_test_1()) {return;} + if (!test_path_parent_test_1()) {return;} + if (!test_path_parent_test_2()) {return;} + if (!test_path_parent_test_3()) {return;} + if (!test_path_parent_test_4()) {return;} + if (!test_path_parent_test_5()) {return;} + if (!test_path_parent_test_6()) {return;} + if (!test_path_parent_test_7()) {return;} + if (!test_path_parent_test_8()) {return;} + if (!test_path_parent_test_9()) {return;} + if (!test_path_parent_test_10()) {return;} + if (!test_path_is_absolute_test()) {return;} + if (!test_path_is_relative_test_1()) {return;} + if (!test_path_is_relative_test_2()) {return;} + if (!test_path_clone_test()) {return;} + if (!test_path_find_file_test()) {return;} + if (!test_path_filename_test()) {return;} + if (!test_path_filename_test_trailing()) {return;} + if (!test_path_filename_test_1()) {return;} + if (!test_path_filename_test_2()) {return;} + if (!test_path_filename_test_3()) {return;} + if (!test_path_filename_test_4()) {return;} os_printf("TESTS COMPLETE\n"); } diff --git a/kernel/src/test/test_main.c b/kernel/src/test/test_main.c deleted file mode 100644 index 21c1b759..00000000 --- a/kernel/src/test/test_main.c +++ /dev/null @@ -1,17 +0,0 @@ - -#include - - -TEST_CREATE(first, { - os_printf("test"); - - - PASS(); -}) - -TEST_CREATE(second, { - os_printf("test"); - - - PASS(); -}) From 8416baf67228ddcbbedcf79884ac19104fad814c Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Tue, 25 Feb 2020 00:06:36 +0100 Subject: [PATCH 015/104] test framework ignores commented tests. Implemented a SLL. qstrings now have a hash function. stated a hashmap. freeing null now doesn't pagefault. Co-authored-by: Victor Roest --- kernel/old/tests/test_hash_map.c | 4 +- kernel/src/common/argparse.c | 26 +- kernel/src/common/hw_handlers.c | 92 ++--- kernel/src/common/interrupt.c | 10 +- kernel/src/common/start.c | 10 +- kernel/src/drivers/mmci/mmci.c | 2 +- kernel/src/drivers/time/timer.c | 10 +- kernel/src/ds/include/ds.h | 16 + kernel/src/ds/include/qstr.h | 3 + kernel/src/ds/include/vp_array_list.h | 2 +- kernel/src/ds/include/vp_hash_map.h | 10 + kernel/src/ds/include/vp_singly_linked_list.h | 42 +++ kernel/src/ds/qstr.c | 6 +- kernel/src/ds/test/qstr_test.c | 25 ++ kernel/src/ds/test/u8_array_list_test.c | 6 +- kernel/src/ds/test/vp_array_list_test.c | 87 ++--- kernel/src/ds/test/vp_hash_map_test.c | 0 .../src/ds/test/vp_singly_linked_list_test.c | 144 ++++++++ kernel/src/ds/vp_hash_map.c | 1 + kernel/src/ds/vp_singly_linked_list.c | 128 +++++++ kernel/src/fs/include/vfs.h | 10 +- kernel/src/fs/path.c | 8 +- kernel/src/fs/test/test.c | 1 - kernel/src/fs/test/test_path.c | 20 +- kernel/src/fs/tmpfs/test/test.c | 11 +- kernel/src/klibc/include/klibc.h | 10 +- kernel/src/klibc/include/math.h | 3 +- kernel/src/klibc/include/stdio.h | 2 +- kernel/src/klibc/klibc.c | 30 +- kernel/src/klibc/printf.c | 2 +- kernel/src/memory/allocator.c | 11 +- kernel/src/memory/allocator.c.old | 333 ------------------ kernel/src/memory/include/allocator.h.old | 32 -- kernel/src/memory/mem_alloc.c | 14 +- kernel/src/memory/mmap.c | 19 +- kernel/src/memory/test/test_allocator.c | 6 +- kernel/src/memory/vm/frame.c | 2 +- kernel/src/memory/vm/include/vm.h | 4 +- kernel/src/memory/vm/test/test.c | 6 + kernel/src/memory/vm/vm.c | 16 +- kernel/src/process/loader.c | 6 +- kernel/src/process/process.c | 10 +- kernel/src/process/scheduler.c | 4 +- kernel/src/test/generate_tests.sh | 14 +- kernel/src/test/include/test.h | 30 +- kernel/src/test/monitor_tests.sh | 2 +- kernel/src/test/test.c | 66 ++-- 47 files changed, 643 insertions(+), 653 deletions(-) create mode 100644 kernel/src/ds/include/ds.h create mode 100644 kernel/src/ds/include/vp_hash_map.h create mode 100644 kernel/src/ds/include/vp_singly_linked_list.h create mode 100644 kernel/src/ds/test/vp_hash_map_test.c create mode 100644 kernel/src/ds/test/vp_singly_linked_list_test.c create mode 100644 kernel/src/ds/vp_hash_map.c create mode 100644 kernel/src/ds/vp_singly_linked_list.c delete mode 100644 kernel/src/memory/allocator.c.old delete mode 100644 kernel/src/memory/include/allocator.h.old create mode 100644 kernel/src/memory/vm/test/test.c diff --git a/kernel/old/tests/test_hash_map.c b/kernel/old/tests/test_hash_map.c index 9d76fda6..1de3f2e2 100644 --- a/kernel/old/tests/test_hash_map.c +++ b/kernel/old/tests/test_hash_map.c @@ -15,12 +15,12 @@ int test_hmap_1() { hmap_handle* hmap2 = hmap_create_fixed(3); if (!hmap1) { - os_printf("expected value"); + kprintf("expected value"); return TEST_FAIL; } if (!hmap2) { - os_printf("expected value"); + kprintf("expected value"); return TEST_FAIL; } diff --git a/kernel/src/common/argparse.c b/kernel/src/common/argparse.c index 0c88324d..7dd350f4 100644 --- a/kernel/src/common/argparse.c +++ b/kernel/src/common/argparse.c @@ -12,9 +12,9 @@ void argparse_process(uint32_t *p_bootargs) { for (atag_iterator(tag, p_bootargs)) { - os_printf("tag (+%d) %d\n", - (((uint32_t) ((uint32_t*) tag)) - ((uint32_t) p_bootargs)), - tag->header.tag); + kprintf("tag (+%d) %d\n", + (((uint32_t) ((uint32_t *) tag)) - ((uint32_t) p_bootargs)), + tag->header.tag); atag_print(tag); if (tag->header.tag == ATAG_CMDLINE) { @@ -30,21 +30,21 @@ void atag_print(struct atag *t) case ATAG_CORE: if (t->header.size == 2) { - os_printf("ATAG_CORE\n"); + kprintf("ATAG_CORE\n"); } else { - os_printf("ATAG_CORE (FLAGS=%d, PAGESIZE=%d, ROOTDEV=%d)\n", - t->content.core.flags, t->content.core.pagesize, - t->content.core.rootdev); + kprintf("ATAG_CORE (FLAGS=%d, PAGESIZE=%d, ROOTDEV=%d)\n", + t->content.core.flags, t->content.core.pagesize, + t->content.core.rootdev); } break; case ATAG_MEM: - os_printf("ATAG_MEM (SIZE=%d, START=%d)\n", t->content.mem.size, - t->content.mem.start); + kprintf("ATAG_MEM (SIZE=%d, START=%d)\n", t->content.mem.size, + t->content.mem.start); break; case ATAG_CMDLINE: - os_printf("ATAG_CMDLINE (%s)\n", &t->content.cmdline.cmdline); + kprintf("ATAG_CMDLINE (%s)\n", &t->content.cmdline.cmdline); break; } } @@ -68,7 +68,7 @@ static void argparse_parse(char *cmdline) while (token != NULL) { - os_printf("token: %s\n", token); + kprintf("token: %s\n", token); if (strcmp("-load", token) == 0) { @@ -81,8 +81,8 @@ static void argparse_parse(char *cmdline) } else if (strcmp("-test", token) == 0) { - os_printf("RUNNING TESTS\n"); - os_printf("Running tests...\n"); + kprintf("RUNNING TESTS\n"); + kprintf("Running tests...\n"); // Test *tests[2]; // tests[0] = create_test("This passes", &test1); // tests[1] = create_test("This fails", &test2); diff --git a/kernel/src/common/hw_handlers.c b/kernel/src/common/hw_handlers.c index 23ff8844..08a23b40 100644 --- a/kernel/src/common/hw_handlers.c +++ b/kernel/src/common/hw_handlers.c @@ -52,7 +52,7 @@ void init_vector_table(void) /* handlers */ void reset_handler(void) { - os_printf("RESET HANDLER\n"); + kprintf("RESET HANDLER\n"); _Reset(); } @@ -63,7 +63,7 @@ void __attribute__((interrupt("UNDEF"))) undef_instruction_handler(void) asm volatile("mrs %0, spsr" : "=r"(spsr)); asm volatile("mov %0, lr" : "=r" (lr)); - os_printf("UNDEFINED INSTRUCTION HANDLER\n"); + kprintf("UNDEFINED INSTRUCTION HANDLER\n"); int thumb = spsr & 0x20; int pc = thumb ? lr - 0x2 : lr - 0x4; @@ -71,19 +71,19 @@ void __attribute__((interrupt("UNDEF"))) undef_instruction_handler(void) int copro = (*(int*)pc & 0xf00000) >> 24; if (spsr & 0x20) { - os_printf("THUMB mode\n"); + kprintf("THUMB mode\n"); } else { - os_printf("ARM mode\n"); + kprintf("ARM mode\n"); } if (spsr & 0x1000000) { - os_printf("JAZELLE enabled\n"); + kprintf("JAZELLE enabled\n"); } - os_printf("COPRO: %x\n", copro); - os_printf("violating instruction (at %x): %x\n", pc, *((int*) pc)); + kprintf("COPRO: %x\n", copro); + kprintf("violating instruction (at %x): %x\n", pc, *((int *) pc)); if (pc >= V_KERNBASE && pc < V_KERNTOP) { - os_printf("(instruction is in kernel address range)\n"); + kprintf("(instruction is in kernel address range)\n"); } panic(); @@ -99,16 +99,16 @@ long __attribute__((interrupt("SWI"))) software_interrupt_handler(void) asm volatile ("MOV %0, r2":"=r"(r2)::); asm volatile ("MOV %0, r3":"=r"(r3)::); - os_printf("SOFTWARE INTERRUPT HANDLER\n"); + kprintf("SOFTWARE INTERRUPT HANDLER\n"); // Print out syscall # for debug purposes - os_printf("Syscall #: "); - os_printf("%d\n", callNumber); - os_printf("arg0=%d\n", r0); - os_printf("arg1=%d\n", r1); - os_printf("arg2=%d\n", r2); - os_printf("arg3=%d\n", r3); - os_printf("\n"); + kprintf("Syscall #: "); + kprintf("%d\n", callNumber); + kprintf("arg0=%d\n", r0); + kprintf("arg1=%d\n", r1); + kprintf("arg2=%d\n", r2); + kprintf("arg3=%d\n", r3); + kprintf("\n"); // System Call Handler switch (callNumber) @@ -124,90 +124,90 @@ long __attribute__((interrupt("SWI"))) software_interrupt_handler(void) // NOTE: All FS syscalls have been *DISABLED* until the filesystem works again. case SYSCALL_CREATE: - os_printf("Create system call called!\n"); + kprintf("Create system call called!\n"); return -1; // return (long) kcreate((char*) r0, r1, 0); case SYSCALL_DELETE: - os_printf("Delete system call called!\n"); + kprintf("Delete system call called!\n"); return -1; // return (long) kdelete((char*) r0, 1); case SYSCALL_OPEN: - os_printf("Open system call called!\n"); + kprintf("Open system call called!\n"); return -1; // return (long) kopen((char*) r0, r1); case SYSCALL_MKDIR: - os_printf("Mkdir system call called!\n"); + kprintf("Mkdir system call called!\n"); return -1; // return (long) kcreate((char*) r0, 'w', 1); case SYSCALL_READ: - os_printf("Read system call called!\n"); + kprintf("Read system call called!\n"); return -1; // return (long) kread(r0, (void*) r1, r2); case SYSCALL_WRITE: - os_printf("Write system call called!\n"); + kprintf("Write system call called!\n"); return -1; // return (long) kwrite(r0, (void*) r1, r2); case SYSCALL_CLOSE: - os_printf("Close system call called!\n"); + kprintf("Close system call called!\n"); return -1; // return (long) kclose(r0); case SYSCALL_SEEK: - os_printf("Seek system call called!\n"); + kprintf("Seek system call called!\n"); return -1; // return (long) kseek(r0, r1); case SYSCALL_COPY: - os_printf("Copy system call called!\n"); + kprintf("Copy system call called!\n"); return -1; // return (long) kcopy((char*) r0, (char*) r1, r2); case SYSCALL_LS: - os_printf("Ls system call called!\n"); + kprintf("Ls system call called!\n"); return -1; // return (long) kls((char*) r0); case SYSCALL_SET_PERM: - os_printf("Set permission system call called!\n"); - os_printf("Yet to be implemented\n"); + kprintf("Set permission system call called!\n"); + kprintf("Yet to be implemented\n"); return -1; case SYSCALL_MEM_MAP: - os_printf("Memory map system call called!\n"); - os_printf("Yet to be implemented\n"); + kprintf("Memory map system call called!\n"); + kprintf("Yet to be implemented\n"); return -1; case SYSCALL_MALLOC: - os_printf("malloc system call called!\n"); + kprintf("malloc system call called!\n"); void *ptr = umalloc(r0); - os_printf("malloc is about to return %x\n", ptr); + kprintf("malloc is about to return %x\n", ptr); return (long) ptr; case SYSCALL_ALIGNED_ALLOC: - os_printf("aligned_alloc system call called!\n"); + kprintf("aligned_alloc system call called!\n"); void *ptr2 = ualigned_alloc(r0, r1); - os_printf("ualigned_alloc is about to return %x\n", ptr2); + kprintf("ualigned_alloc is about to return %x\n", ptr2); return (long) ptr2; case SYSCALL_FREE: - os_printf("Free system call called!\n"); + kprintf("Free system call called!\n"); ufree((void*) r0); return 0L; case SYSCALL_PRINTF: - os_printf("Printf system call called!\n"); + kprintf("Printf system call called!\n"); - os_printf((const char*) r0); + kprintf((const char *) r0); return 0L; default: - os_printf("That wasn't a syscall you knob!\n"); + kprintf("That wasn't a syscall you knob!\n"); return -1L; } } @@ -218,7 +218,7 @@ void __attribute__((interrupt("ABORT"))) prefetch_abort_handler(void) asm volatile("mov %0, lr" : "=r" (lr)); - os_printf("PREFETCH ABORT HANDLER, violating address: %x\n", (lr - 4)); + kprintf("PREFETCH ABORT HANDLER, violating address: %x\n", (lr - 4)); panic(); } @@ -232,13 +232,13 @@ void __attribute__((interrupt("ABORT"))) data_abort_handler(void) int far; asm volatile("mrc p15, 0, %0, c6, c0, 0" : "=r" (far)); - os_printf("DATA ABORT HANDLER (Page Fault)\n"); - os_printf("faulting address: 0x%x\n", far); + kprintf("DATA ABORT HANDLER (Page Fault)\n"); + kprintf("faulting address: 0x%x\n", far); if (far >= V_KDSBASE) { - os_printf("(address is in kernel address range)\n"); + kprintf("(address is in kernel address range)\n"); } - os_printf("violating instruction (at 0x%x): %x\n", pc, *((int*) pc)); + kprintf("violating instruction (at 0x%x): %x\n", pc, *((int *) pc)); // Get the DSFR int dsfr; @@ -259,14 +259,14 @@ void __attribute__((interrupt("ABORT"))) data_abort_handler(void) void reserved_handler(void) { - os_printf("RESERVED HANDLER\n"); + kprintf("RESERVED HANDLER\n"); } // the attribute automatically saves and restores state void __attribute__((interrupt("IRQ"))) irq_handler(void) { - os_printf("IRQ HANDLER\n"); + kprintf("IRQ HANDLER\n"); int cpsr = disable_interrupt_save(IRQ); // os_printf("disabled CSPR:%X\n",cpsr); // Discover source of interrupt @@ -291,7 +291,7 @@ void __attribute__((interrupt("IRQ"))) irq_handler(void) void __attribute__((interrupt("FIQ"))) fiq_handler(void) { - os_printf("FIQ HANDLER\n"); + kprintf("FIQ HANDLER\n"); int cpsr = disable_interrupt_save(FIQ); diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index 74ba2ec0..9b2988ba 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -58,14 +58,14 @@ int register_interrupt_handler(int num, interrupt_handler_t *handler) // lazy initialization if (initialized != -1) { - os_printf("INITIALIZING THE INTERRUPT SYSTEM\n"); + kprintf("INITIALIZING THE INTERRUPT SYSTEM\n"); for(int i=0; ihandler); + kprintf("Jumping to %X...\n", handlers[interrupt_vector]->handler); handlers[interrupt_vector]->handler((void *) interrupt_vector); } diff --git a/kernel/src/common/start.c b/kernel/src/common/start.c index 493d9fcc..4ad456af 100644 --- a/kernel/src/common/start.c +++ b/kernel/src/common/start.c @@ -54,7 +54,7 @@ void start(uint32_t *p_bootargs) { // Initialize the virtual memory print_uart0("Enabling MMU...\n"); vm_init(); - os_printf("Initialized VM datastructures.\n"); + kprintf("Initialized VM datastructures.\n"); mmap(p_bootargs); } @@ -103,13 +103,12 @@ void start2(uint32_t *p_bootargs) { // initialize the timers initialize_timers(); - //assert(1==2 && "Test assert please ignore"); process_init(); sched_init(); // FIXME: temporary - os_printf("Programming the timer interrupt\n"); + kprintf("Programming the timer interrupt\n"); start_timer_interrupts(0, 10); #ifndef ENABLE_TESTS @@ -131,6 +130,11 @@ void start2(uint32_t *p_bootargs) { // init_q(); //common(); + // TODO: + // * Mount vfs + // * Load initramfs into tmpfs + // * execute userland init program + SLEEP; } diff --git a/kernel/src/drivers/mmci/mmci.c b/kernel/src/drivers/mmci/mmci.c index c31e4096..93ce065b 100644 --- a/kernel/src/drivers/mmci/mmci.c +++ b/kernel/src/drivers/mmci/mmci.c @@ -110,7 +110,7 @@ int init_sd() // Eventually print some status message here if the SD card // failed to initialize properly but for now just print // that it was loaded OK - os_printf("\nSD card ready for transfer\n"); + kprintf("\nSD card ready for transfer\n"); return status(); } diff --git a/kernel/src/drivers/time/timer.c b/kernel/src/drivers/time/timer.c index 3b94f986..01e17a40 100644 --- a/kernel/src/drivers/time/timer.c +++ b/kernel/src/drivers/time/timer.c @@ -15,7 +15,7 @@ void (*handlers[4])(void *args); * using any of the timer functions */ void initialize_timers() { - os_printf("initializing timers\n"); + kprintf("initializing timers\n"); volatile rasp_pi_timer *TIMER_0 = (rasp_pi_timer *) 0x101e2000; volatile rasp_pi_timer *TIMER_1 = (rasp_pi_timer *) 0x101e2020; volatile rasp_pi_timer *TIMER_2 = (rasp_pi_timer *) 0x101e3000; @@ -201,7 +201,7 @@ int print_control_status(int timer_index) { CHECK_TIMER_INDEX(timer_index); - os_printf("control byte:%x", timer_pointers[timer_index]->control); + kprintf("control byte:%x", timer_pointers[timer_index]->control); return 0; } @@ -220,7 +220,7 @@ int start_timer_interrupts(int timer_index, int milliseconds) int clicks = conversion(timer_index, milliseconds); - os_printf("CLICKS ARE %d\n", clicks); + kprintf("CLICKS ARE %d\n", clicks); set_background_load_value(timer_index, clicks); set_periodic_mode(timer_index); @@ -247,7 +247,7 @@ void timer_irq_handler(void* args) { clear_interrupt(0); - os_printf("@@@@@@ RECEIVED TIMER INTERRUPT\n"); + kprintf("@@@@@@ RECEIVED TIMER INTERRUPT\n"); // TODO: find out which timer fired. For the moment, hard-code to 0 if (handlers[0] != NULL) @@ -266,7 +266,7 @@ void timer_test() os_printf("fn ptr: %X\n", simple_timer_handler); register_interrupt_handler(4, tmr_handler);*/ - os_printf("FIQ status: %X\n", mmio_read(VIC_FIQ_STATUS)); + kprintf("FIQ status: %X\n", mmio_read(VIC_FIQ_STATUS)); initialize_timers(); start_timer_interrupts(0, 10); //print_control_status(1); diff --git a/kernel/src/ds/include/ds.h b/kernel/src/ds/include/ds.h new file mode 100644 index 00000000..56ed5b9e --- /dev/null +++ b/kernel/src/ds/include/ds.h @@ -0,0 +1,16 @@ +#ifndef DS_H +#define DS_H + +#include + +// used across datastructures +typedef void (*FreeFunc)(void * data); +typedef bool (*CompareFunc)(void * in, void * other); + +#include +#include +#include +#include +#include + +#endif \ No newline at end of file diff --git a/kernel/src/ds/include/qstr.h b/kernel/src/ds/include/qstr.h index d10b1c43..40e7cdc4 100644 --- a/kernel/src/ds/include/qstr.h +++ b/kernel/src/ds/include/qstr.h @@ -32,4 +32,7 @@ bool qstr_eq(Qstr * left, Qstr * right); // Also calculates hash of left to speed up further stringcompares. bool qstr_eq_null_terminated(Qstr * left, char * right); +// Hash the qstring +void qstr_hash(Qstr * q); + #endif \ No newline at end of file diff --git a/kernel/src/ds/include/vp_array_list.h b/kernel/src/ds/include/vp_array_list.h index 3bcd46ee..fbe9b3a4 100644 --- a/kernel/src/ds/include/vp_array_list.h +++ b/kernel/src/ds/include/vp_array_list.h @@ -1,8 +1,8 @@ #ifndef VP_ARRAYLIST_H #define VP_ARRAYLIST_H #include +#include -typedef void (*FreeFunc)(void * data); typedef struct VPArrayList { uint32_t length; diff --git a/kernel/src/ds/include/vp_hash_map.h b/kernel/src/ds/include/vp_hash_map.h new file mode 100644 index 00000000..d4e1043a --- /dev/null +++ b/kernel/src/ds/include/vp_hash_map.h @@ -0,0 +1,10 @@ +#ifndef HASH_MAP_H +#define HASH_MAP_H + +#include + +struct HashMap { + +}; + +#endif \ No newline at end of file diff --git a/kernel/src/ds/include/vp_singly_linked_list.h b/kernel/src/ds/include/vp_singly_linked_list.h new file mode 100644 index 00000000..e5917141 --- /dev/null +++ b/kernel/src/ds/include/vp_singly_linked_list.h @@ -0,0 +1,42 @@ + +#ifndef VP_SINGLY_LINKED_LIST_H +#define VP_SINGLY_LINKED_LIST_H + +#include + +struct VPSinglyLinkedListLink { + struct VPSinglyLinkedListLink * next; + void * data; +}; + +typedef struct VPSinglyLinkedList { + struct VPSinglyLinkedListLink * head; + size_t length; +} VPSinglyLinkedList; + + +// Iterator over a SLL +typedef struct VPSinglyLinkedListLink * VPSinglyLinkedListIterator; + +VPSinglyLinkedListIterator vpslli_create(VPSinglyLinkedList * lst); +void * vpslli_next(VPSinglyLinkedListIterator * lsti); +bool vpslli_empty(VPSinglyLinkedListIterator lsti); + +VPSinglyLinkedList * vpsll_create(); +void vpsll_free(VPSinglyLinkedList * lst, FreeFunc freef); +void vpsll_push(VPSinglyLinkedList * lst, void * data); +void * vpsll_pop(VPSinglyLinkedList * lst); +// Remove the first item for which compf returns true. +void * vpsll_remove(VPSinglyLinkedList * lst, void * data, CompareFunc compf); +void * vpsll_get(VPSinglyLinkedList * lst, size_t index); + +// returns the old value to free +void * vpsll_set(VPSinglyLinkedList * lst, size_t index, void * value); + +// Returns if the compf returns true for any item in the list (compared with the value). +bool vpsll_contains(VPSinglyLinkedList * lst, void * value, CompareFunc compf); + +size_t vpsll_length(VPSinglyLinkedList * lst); + +#define VPSLL_FOREACH(lst, i) for (VPSinglyLinkedListIterator i = vpslli_create(lst); !vpslli_empty(i); vpslli_next(&i)) +#endif \ No newline at end of file diff --git a/kernel/src/ds/qstr.c b/kernel/src/ds/qstr.c index c6defc22..369c39f3 100644 --- a/kernel/src/ds/qstr.c +++ b/kernel/src/ds/qstr.c @@ -48,7 +48,7 @@ static inline bool __eq(Qstr * left, Qstr * right, bool fake) { while ((c = *(leftstr++)) != '\0') { hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ - if (c != (*rightstr++)) { + if (equal && c != (*rightstr++)) { equal = false; } } @@ -69,6 +69,10 @@ bool qstr_eq(Qstr * left, Qstr * right) { return __eq(left, right, false); } +void qstr_hash(Qstr * q) { + __eq(q, (Qstr *)"", true); +} + bool qstr_eq_null_terminated(Qstr * left, char * right) { return __eq(left, (Qstr *) right, true); } diff --git a/kernel/src/ds/test/qstr_test.c b/kernel/src/ds/test/qstr_test.c index fd0f1e6e..4cf6b7dd 100644 --- a/kernel/src/ds/test/qstr_test.c +++ b/kernel/src/ds/test/qstr_test.c @@ -1,5 +1,6 @@ #include #include +#include TEST_CREATE(test_compare_nonequal_length, { Qstr a = qstr_from_null_terminated_string("test"); @@ -61,3 +62,27 @@ TEST_CREATE(test_compare_various, { qstr_free(&b); qstr_free(&c); }) + +TEST_CREATE(test_hash, { + Qstr a = qstr_from_null_terminated_string("toast"); + Qstr b = qstr_from_null_terminated_string("toast"); + + qstr_eq(&b, &a); + + a.hash = 0; + + qstr_hash(&a); + + ASSERT_NEQ(a.hash, 0); + ASSERT_EQ(a.hash, b.hash); + + qstr_free(&a); + qstr_free(&b); + + isize_t o = 1; + isize_t n = -1; + n = abs(n); + + ASSERT_EQ(o, n); +}) + diff --git a/kernel/src/ds/test/u8_array_list_test.c b/kernel/src/ds/test/u8_array_list_test.c index 068129c0..c31bc76d 100644 --- a/kernel/src/ds/test/u8_array_list_test.c +++ b/kernel/src/ds/test/u8_array_list_test.c @@ -13,7 +13,7 @@ TEST_CREATE(u8a_push_get_pop_test, { ASSERT_EQ(arr->length, length); ASSERT_GTEQ(arr->capacity, length); - for (int i = 0; i < length; i++){ + for (int i = 0; i < length; i++) { uint8_t a = u8a_get(arr, i); ASSERT_EQ(a, i % 0xff); } @@ -40,7 +40,7 @@ TEST_CREATE(u8a_push_set_pop_test, { ASSERT_EQ(arr->length, 1000); ASSERT_GTEQ(arr->capacity, 1000); - for (int i = 0; i < 1000; i++){ + for (int i = 0; i < 1000; i++) { u8a_set(arr, i, 42); } @@ -63,7 +63,7 @@ TEST_CREATE(u8a_resize_test, { ASSERT_EQ(list->capacity, 8); u8a_resize(list, 4); - ASSERT_EQ(list->length,0); + ASSERT_EQ(list->length, 0); ASSERT_EQ(list->capacity, 4); u8a_free(list); diff --git a/kernel/src/ds/test/vp_array_list_test.c b/kernel/src/ds/test/vp_array_list_test.c index 82208c1a..fbe9b3a4 100644 --- a/kernel/src/ds/test/vp_array_list_test.c +++ b/kernel/src/ds/test/vp_array_list_test.c @@ -1,74 +1,35 @@ -#include -#include -#include +#ifndef VP_ARRAYLIST_H +#define VP_ARRAYLIST_H +#include +#include -void freefunc(void * data) { - if ((*(int *)data != 42)) { - panic(); - } -} -int data[] = {1, 2, 3, 4, 5, 6, 7, 8}; +typedef struct VPArrayList { + uint32_t length; + uint32_t capacity; + void ** array; +} VPArrayList; -TEST_CREATE(vpa_push_get_pop_test, { - uint32_t length = 30; +VPArrayList * vpa_create(uint32_t initial_cap); - VPArrayList * arr = vpa_create(1); - for (int i = 0; i < length; i++){ - vpa_push(arr, &data[i % 8]); - } +// Frees the list. +void vpa_free(VPArrayList * arr, FreeFunc freef); - ASSERT_EQ(arr->length, length); - ASSERT_GTEQ(arr->capacity, length); +// Gets element of specified index; +void * vpa_get(VPArrayList * list, uint32_t index); - for (int i = 0; i < length; i++){ - int * a = vpa_get(arr, i); +// Sets element to specific data +void vpa_set(VPArrayList * list, uint32_t index, void * data); - ASSERT_EQ(*a, data[i % 8]); - } +// Inserts data at the end of the list +uint32_t vpa_push(VPArrayList * list, void * data); - ASSERT_EQ(arr->length, length); - ASSERT_GTEQ(arr->capacity, length); +// Returns the topmost element and removes it fromhe list. +void * vpa_pop(VPArrayList * list); - for (int i = length - 1; i >= 0; i--){ - ASSERT_EQ(*(int *)vpa_pop(arr), data[i % 8]); - } +// Truncates the list to specified size +void vpa_resize(VPArrayList * list, uint32_t new_size, FreeFunc freeFunc); - ASSERT_EQ(arr->length, 0); - ASSERT_LT(arr->capacity, length); +void * vpa_remove(VPArrayList * list, size_t index); - vpa_free(arr, NULL); -}) - -TEST_CREATE(vpa_push_set_pop_test, { - VPArrayList * arr = vpa_create(1); - for (int i = 0; i < 1000; i++){ - vpa_push(arr, &data[i % 8]); - } - - ASSERT_EQ(arr->length, 1000); - ASSERT_GTEQ(arr->capacity, 1000); - - int intdata = 42; - - for (int i = 0; i < 1000; i++){ - vpa_set(arr, i, &intdata); - } - - ASSERT_EQ(arr->length, 1000); - ASSERT_GTEQ(arr->capacity, 1000); - - vpa_free(arr, freefunc); -}) - -TEST_CREATE(vpa_resize_test, { - VPArrayList * list = vpa_create(8); - ASSERT_EQ(list->length,0); - ASSERT_EQ(list->capacity, 8); - - vpa_resize(list, 4, NULL); - ASSERT_EQ(list->length,0); - ASSERT_EQ(list->capacity, 4); - - vpa_free(list, NULL); -}) \ No newline at end of file +#endif \ No newline at end of file diff --git a/kernel/src/ds/test/vp_hash_map_test.c b/kernel/src/ds/test/vp_hash_map_test.c new file mode 100644 index 00000000..e69de29b diff --git a/kernel/src/ds/test/vp_singly_linked_list_test.c b/kernel/src/ds/test/vp_singly_linked_list_test.c new file mode 100644 index 00000000..070d63bc --- /dev/null +++ b/kernel/src/ds/test/vp_singly_linked_list_test.c @@ -0,0 +1,144 @@ +#include +#include + + +TEST_CREATE(test_create_ll, { + VPSinglyLinkedList * lst = vpsll_create(); + + uint32_t num = 10; + + for (uint32_t i = 0; i < num; i++) { + vpsll_push(lst, (void *)i); + } + + ASSERT_EQ(vpsll_length(lst), num); + + for (int32_t i = num - 1; i >= 0; i--) { + ASSERT_EQ((int32_t)vpsll_pop(lst), i); + } + + vpsll_free(lst, NULL); +}) + + +TEST_CREATE(test_iter_ll, { + VPSinglyLinkedList * lst = vpsll_create(); + + uint32_t num = 10; + + for (uint32_t i = 0; i < num; i++) { + vpsll_push(lst, (void *)i); + } + + ASSERT_EQ(vpsll_length(lst), num); + + size_t index = num - 1; + VPSLL_FOREACH(lst, i) { + ASSERT_EQ((size_t)i->data, index--); + } + + vpsll_free(lst, NULL); +}) + +TEST_CREATE(test_get_ll, { + VPSinglyLinkedList * lst = vpsll_create(); + + uint32_t num = 10; + + for (uint32_t i = 0; i < num; i++) { + vpsll_push(lst, (void *)i); + } + + ASSERT_EQ(vpsll_length(lst), num); + + isize_t index = 0; + for (isize_t i = num - 1; i >= 0; i--) { + ASSERT_EQ((isize_t)vpsll_get(lst, index++), i); + } + + vpsll_free(lst, NULL); +}) + +#ifdef ENABLE_TESTS +bool __compareInt(void * a, void * b) { + // ^- me wishing for lambdas in C + return *(int *)a == *(int *)b; +} +#endif + +TEST_CREATE(test_contains_true, { + VPSinglyLinkedList * lst = vpsll_create(); + + int a = 3; + int b = 5; + int c = 7; + + int f = 5; + + vpsll_push(lst, &a); + vpsll_push(lst, &b); + vpsll_push(lst, &c); + + ASSERT(vpsll_contains(lst, &f, __compareInt)); + ASSERT_EQ(vpsll_length(lst), 3); + + vpsll_free(lst, NULL); +}) + +TEST_CREATE(test_contains_false, { + VPSinglyLinkedList * lst = vpsll_create(); + + int a = 3; + int b = 5; + int c = 7; + + int f = 9; + + vpsll_push(lst, &a); + vpsll_push(lst, &b); + vpsll_push(lst, &c); + + ASSERT(!vpsll_contains(lst, &f, __compareInt)); + ASSERT_EQ(vpsll_length(lst), 3); + + vpsll_free(lst, NULL); +}) + +TEST_CREATE(test_vpsll_remove, { + VPSinglyLinkedList * lst = vpsll_create(); + + int a = 3; + int b = 5; + int c = 7; + + int f = 5; + + vpsll_push(lst, &a); + vpsll_push(lst, &b); + vpsll_push(lst, &c); + + ASSERT_EQ(vpsll_remove(lst, &f, __compareInt), &b); + ASSERT_EQ(vpsll_length(lst), 2); + + vpsll_free(lst, NULL); +}) + +TEST_CREATE(test_vpsll_set, { + VPSinglyLinkedList * lst = vpsll_create(); + + int a = 3; + int b = 5; + int c = 7; + + int f = 5; + + vpsll_push(lst, &a); + vpsll_push(lst, &b); + vpsll_push(lst, &c); + + vpsll_set(lst, 1, &f); + ASSERT_EQ(vpsll_get(lst,1), &f); + ASSERT_EQ(vpsll_length(lst), 3); + + vpsll_free(lst, NULL); +}) diff --git a/kernel/src/ds/vp_hash_map.c b/kernel/src/ds/vp_hash_map.c new file mode 100644 index 00000000..555bef1b --- /dev/null +++ b/kernel/src/ds/vp_hash_map.c @@ -0,0 +1 @@ +#include \ No newline at end of file diff --git a/kernel/src/ds/vp_singly_linked_list.c b/kernel/src/ds/vp_singly_linked_list.c new file mode 100644 index 00000000..5c29fc09 --- /dev/null +++ b/kernel/src/ds/vp_singly_linked_list.c @@ -0,0 +1,128 @@ +#include +#include +#include + +VPSinglyLinkedList * vpsll_create() { + VPSinglyLinkedList * res = kmalloc(sizeof(VPSinglyLinkedList)); + res->head = NULL; + res->length = 0; + return res; +} + +void vpsll_free(VPSinglyLinkedList * lst, FreeFunc freef) { + struct VPSinglyLinkedListLink * curr = lst->head; + while (curr != NULL) { + struct VPSinglyLinkedListLink * last = curr; + curr = curr->next; + if (freef != NULL) { + freef(last->data); + } + kfree(last); + } + + kfree(lst); +} + +void vpsll_push(VPSinglyLinkedList * lst, void * data) { + struct VPSinglyLinkedListLink * node = kmalloc(sizeof(struct VPSinglyLinkedListLink)); + node->data = data; + + node->next = lst->head; + lst->head = node; + + lst->length++; +} + +void * vpsll_pop(VPSinglyLinkedList * lst) { + + struct VPSinglyLinkedListLink * oldhead = lst->head; + void * contents = oldhead->data; + + lst->head = oldhead->next; + kfree(oldhead); + + lst->length--; + + return contents; +} + + +// Remove the first item for which compf returns true. +void * vpsll_remove(VPSinglyLinkedList * lst, void * data, CompareFunc compf) { + + struct VPSinglyLinkedListLink * prev = NULL; + VPSLL_FOREACH(lst, i) { + if (compf(i->data, data)) { + void * value = i->data; + if (prev == NULL) { + lst->head = i->next; + } else { + prev->next = i->next; + kfree(i); + } + lst->length--; + return value; + } + prev = i; + } + + return NULL; +} + +inline static struct VPSinglyLinkedListLink * __link_at_index(VPSinglyLinkedList * lst, size_t index) { + if(index > lst->length) { + return NULL; + } + VPSLL_FOREACH(lst, i) { + if (index-- == 0) { + return i; + } + } + + return NULL; +} + +void * vpsll_get(VPSinglyLinkedList * lst, size_t index) { + return __link_at_index(lst, index)->data; +} + +// returns the old value to free +void * vpsll_set(VPSinglyLinkedList * lst, size_t index, void * value) { + struct VPSinglyLinkedListLink * link = __link_at_index(lst, index); + if (link == NULL) { + return NULL; + } + + void * old = link->data; + link->data = value; + + return old; +} + +// Returns if the compf returns true for any item in the list (compared with the value). +bool vpsll_contains(VPSinglyLinkedList * lst, void * value, CompareFunc compf) { + VPSLL_FOREACH(lst, i) { + if(compf(i->data, value)) { + return true; + } + } + return false; +} + +size_t vpsll_length(VPSinglyLinkedList * lst) { + return lst->length; +} + +VPSinglyLinkedListIterator vpslli_create(VPSinglyLinkedList * lst) { + return lst->head; +} + +void * vpslli_next(VPSinglyLinkedListIterator * lsti) { + void * nxt = (*lsti)->data; + *lsti = (*lsti)->next; + return nxt; +} + +bool vpslli_empty(VPSinglyLinkedListIterator lsti) { + return lsti == NULL; +} diff --git a/kernel/src/fs/include/vfs.h b/kernel/src/fs/include/vfs.h index 085b00b9..5b8b4073 100644 --- a/kernel/src/fs/include/vfs.h +++ b/kernel/src/fs/include/vfs.h @@ -30,7 +30,6 @@ typedef struct FsOperations { } FsOperations; - typedef struct FsIdentifier { char * fsname; const FsOperations * operations; @@ -39,7 +38,7 @@ typedef struct FsIdentifier { typedef struct Vfs { uint32_t filesystems_size; uint32_t filesystems_filled; - const FsIdentifier ** filesystems; + const FsIdentifier ** filesystems; // TODO: change to vpa? // Inodes start at the head and are added at the tail end. // The linked list starts at head. @@ -55,10 +54,15 @@ typedef enum VfsErr{ ERR_NO_PARENT, } VfsErr; +// Create and returns a VFS instance Vfs * vfs_create(); -VfsErr vfs_add_inode(Vfs * vfs, struct Inode * inode); +// Adds an inode to the internal vfs inode list +VfsErr vfs_add_inode(Vfs * vfs, struct Inode * node); +// Register a new filesystem against the vfs VfsErr vfs_register(Vfs * vfs, const FsIdentifier * fs_identifier); +// Frees all vfs related constructs: inodes,dentries, etc. void vfs_free(Vfs * vfs); +// Get the direntry for the root of the filesystem: '/' struct DirEntry * vfs_get_root(Vfs * vfs); #endif diff --git a/kernel/src/fs/path.c b/kernel/src/fs/path.c index 833304c8..00b4cb2a 100644 --- a/kernel/src/fs/path.c +++ b/kernel/src/fs/path.c @@ -49,7 +49,7 @@ struct DirEntry *path_get_direntry(struct Vfs *vfs, Path *path, enum VfsErr *err pathpointer = path->array + 1; } else { - os_printf("Inode lookup only supports absolute path right now."); + kprintf("Inode lookup only supports absolute path right now."); panic(); curr = NULL; pathpointer = path->array; @@ -156,11 +156,11 @@ bool path_contents_equal(Path * a, Path * b) { } void path_print(Path * path) { - os_printf("Path: (%i) \"", path->length); + kprintf("Path: (%i) \"", path->length); for (int i = 0; i < path->length; i++){ - os_printf("%c", path->array[i]); + kprintf("%c", path->array[i]); } - os_printf("\"\n"); + kprintf("\"\n"); } bool path_is_absolute(Path * path) { diff --git a/kernel/src/fs/test/test.c b/kernel/src/fs/test/test.c index c8e5fc01..a8dded29 100644 --- a/kernel/src/fs/test/test.c +++ b/kernel/src/fs/test/test.c @@ -18,6 +18,5 @@ TEST_CREATE(test_get_root, { Inode * root2 = vfs_get_root(test_vfs)->inode; ASSERT_EQ(root1->id, root2->id); - vfs_free(test_vfs); }) diff --git a/kernel/src/fs/test/test_path.c b/kernel/src/fs/test/test_path.c index d5b222c2..23ea9128 100644 --- a/kernel/src/fs/test/test_path.c +++ b/kernel/src/fs/test/test_path.c @@ -36,7 +36,6 @@ TEST_CREATE(path_parent_test_1, { path_parent(p1); ASSERT(path_contents_equal(p1, p2)); - path_free(p1); path_free(p2); }) @@ -48,7 +47,6 @@ TEST_CREATE(path_parent_test_2, { path_parent(p1); ASSERT(path_contents_equal(p1, p2)); - path_free(p1); path_free(p2); }) @@ -60,7 +58,6 @@ TEST_CREATE(path_parent_test_3, { path_parent(p1); ASSERT(path_contents_equal(p1, p2)); - path_free(p1); path_free(p2); }) @@ -72,7 +69,6 @@ TEST_CREATE(path_parent_test_4, { path_parent(p1); ASSERT(path_contents_equal(p1, p2)); - path_free(p1); path_free(p2); }) @@ -84,7 +80,6 @@ TEST_CREATE(path_parent_test_5, { path_parent(p1); ASSERT(path_contents_equal(p1, p2)); - path_free(p1); path_free(p2); }) @@ -96,7 +91,6 @@ TEST_CREATE(path_parent_test_6, { path_parent(p1); ASSERT(path_contents_equal(p1, p2)); - path_free(p1); path_free(p2); }) @@ -108,7 +102,6 @@ TEST_CREATE(path_parent_test_7, { path_parent(p1); ASSERT(path_contents_equal(p1, p2)); - path_free(p1); path_free(p2); }) @@ -120,7 +113,6 @@ TEST_CREATE(path_parent_test_8, { path_parent(p1); ASSERT(path_contents_equal(p1, p2)); - path_free(p1); path_free(p2); }) @@ -132,7 +124,6 @@ TEST_CREATE(path_parent_test_9, { path_parent(p1); ASSERT(path_contents_equal(p1, p2)); - path_free(p1); path_free(p2); }) @@ -144,7 +135,6 @@ TEST_CREATE(path_parent_test_10, { path_parent(p1); ASSERT(path_contents_equal(p1, p2)); - path_free(p1); path_free(p2); }) @@ -153,7 +143,6 @@ TEST_CREATE(path_is_absolute_test, { Path * p1 = path_from_string("/test"); ASSERT(path_is_absolute(p1)); - path_free(p1); }) @@ -161,7 +150,6 @@ TEST_CREATE(path_is_relative_test_1, { Path * p1 = path_from_string("./test"); ASSERT(path_is_relative(p1)); - path_free(p1); }) @@ -169,7 +157,6 @@ TEST_CREATE(path_is_relative_test_2, { Path * p1 = path_from_string("test"); ASSERT(path_is_relative(p1)); - path_free(p1); }) @@ -178,7 +165,6 @@ TEST_CREATE(path_clone_test, { Path * p2 = path_clone(p1); ASSERT(path_contents_equal(p1, p2)); - path_free(p1); path_free(p2); }) @@ -196,11 +182,9 @@ TEST_CREATE(path_find_file_test, { VfsErr err = OK; root->inode->fs_identifier->operations->create_file(root, newfile, &err); ASSERT_EQ(err, OK); + Path *p = path_from_string("/test"); - - Path * p = path_from_string("/test"); - - DirEntry * d = path_get_direntry(test_vfs, p, &err); + DirEntry *d = path_get_direntry(test_vfs, p, &err); ASSERT_EQ(err, OK); diff --git a/kernel/src/fs/tmpfs/test/test.c b/kernel/src/fs/tmpfs/test/test.c index 966ed995..065fa038 100644 --- a/kernel/src/fs/tmpfs/test/test.c +++ b/kernel/src/fs/tmpfs/test/test.c @@ -11,7 +11,7 @@ TEST_CREATE(test_create_file, { TmpfsInode * root = (TmpfsInode *) create_tmpfs_root(test_vfs); // PARTIAL ASSERT_EQ(root->base.inode_type, DIRECTORY); - DirEntry * newfile = create_direntry(qstr_from_null_terminated_string("test"), root->base.direntry); + DirEntry *newfile = create_direntry(qstr_from_null_terminated_string("test"), root->base.direntry); VfsErr err = OK; @@ -31,8 +31,7 @@ TEST_CREATE(test_create_dir, { TmpfsInode * root = (TmpfsInode *) create_tmpfs_root(test_vfs); ASSERT_EQ(root->base.inode_type, DIRECTORY); - - DirEntry * newdir = create_direntry(qstr_from_null_terminated_string("test"), root->base.direntry); + DirEntry *newdir = create_direntry(qstr_from_null_terminated_string("test"), root->base.direntry); VfsErr err = OK; root->base.fs_identifier->operations->create_dir(root->base.direntry, newdir, &err); @@ -50,8 +49,7 @@ TEST_CREATE(test_create_rw_file, { TmpfsInode * root = (TmpfsInode *) create_tmpfs_root(test_vfs); ASSERT_EQ(root->base.inode_type, DIRECTORY); - - DirEntry * newfile = create_direntry(qstr_from_null_terminated_string("test"), root->base.direntry); + DirEntry *newfile = create_direntry(qstr_from_null_terminated_string("test"), root->base.direntry); VfsErr err = OK; root->base.fs_identifier->operations->create_file(root->base.direntry, newfile, &err); @@ -106,8 +104,7 @@ TEST_CREATE(test_listdir, { VfsErr err = OK; root->inode->fs_identifier->operations->create_file(root, newfile, &err); ASSERT_EQ(err, OK); - - VPArrayList * list = root->inode->fs_identifier->operations->list_dir(root, &err); + VPArrayList *list = root->inode->fs_identifier->operations->list_dir(root, &err); ASSERT_EQ(err, OK); DirEntry * first = vpa_get(list, 0); diff --git a/kernel/src/klibc/include/klibc.h b/kernel/src/klibc/include/klibc.h index 30d6365b..d0e74cee 100644 --- a/kernel/src/klibc/include/klibc.h +++ b/kernel/src/klibc/include/klibc.h @@ -73,11 +73,11 @@ unsigned int rand(); // development #define LOG_LEVEL 5 -#define DEBUG(...) if(LOG_LEVEL >= 5) os_printf(__VA_ARGS__) -#define LOG(...) if(LOG_LEVEL >= 4) os_printf(__VA_ARGS__) -#define INFO(...) if(LOG_LEVEL >= 3) os_printf(__VA_ARGS__) -#define WARN(...) if(LOG_LEVEL >= 2) os_printf(__VA_ARGS__) -#define ERROR(...) if(LOG_LEVEL >= 1) os_printf(__VA_ARGS__) +#define DEBUG(...) if(LOG_LEVEL >= 5) kprintf(__VA_ARGS__) +#define LOG(...) if(LOG_LEVEL >= 4) kprintf(__VA_ARGS__) +#define INFO(...) if(LOG_LEVEL >= 3) kprintf(__VA_ARGS__) +#define WARN(...) if(LOG_LEVEL >= 2) kprintf(__VA_ARGS__) +#define ERROR(...) if(LOG_LEVEL >= 1) kprintf(__VA_ARGS__) //4-17-15: Initial panic * assert_fail functions added void panic(); diff --git a/kernel/src/klibc/include/math.h b/kernel/src/klibc/include/math.h index 99e11070..34fb7c6a 100644 --- a/kernel/src/klibc/include/math.h +++ b/kernel/src/klibc/include/math.h @@ -4,7 +4,8 @@ // useful macros #define max(a, b) ((a) > (b) ? a : b) #define min(a, b) ((a) < (b) ? a : b) -#define abs(a) ((a) > 0 ? (a) : -(a)) +#define abs(a) __builtin_abs(a) +//#define abs(a) ((a) > 0 ? (a) : -(a)) #endif \ No newline at end of file diff --git a/kernel/src/klibc/include/stdio.h b/kernel/src/klibc/include/stdio.h index 55cf56df..ae68237f 100644 --- a/kernel/src/klibc/include/stdio.h +++ b/kernel/src/klibc/include/stdio.h @@ -29,7 +29,7 @@ */ int os_vsnprintf(char *buf, int buflen, const char *str_buf, va_list args); int os_snprintf(char *buf, int buflen, const char *fmt_string, ...); -int os_printf(const char *str_buf, ...); +int kprintf(const char *str_buf, ...); diff --git a/kernel/src/klibc/klibc.c b/kernel/src/klibc/klibc.c index c2b24233..9a84f75d 100644 --- a/kernel/src/klibc/klibc.c +++ b/kernel/src/klibc/klibc.c @@ -44,24 +44,24 @@ */ void panic() { disable_interrupts(); - os_printf("Kernel panic!\n"); - os_printf("\n ) ( \n"); - os_printf(" ( /( ( )\\ ) \n"); - os_printf(" )\\()) ( ( ( )\\ (()/( ) ( \n"); - os_printf("|((_)\\ ))\\ )( ( ))((_) /(_)| /( ( )\\ ( \n"); - os_printf("|_ ((_)((_|()\\ )\\ ) /((_) (_)) )(_)) )\\ |(_) )\\ \n"); - os_printf("| |/ (_)) ((_)_(_/((_))| | | _ ((_)_ _(_/((_)((_) \n"); - os_printf(" ' bytes_allocated += found->size; - os_printf("MEM_DEBUG: ALLOC %i bytes at 0x%x\n", found->size, &found->next); + kprintf("MEM_DEBUG: ALLOC %i bytes at 0x%x\n", found->size, &found->next); #endif return &found->next; @@ -121,6 +121,11 @@ void *heap_alloc(heap_t *heap, uint32_t size) { // coalesced and then placed in the correct bin // ======================================================== void heap_free(heap_t *heap, void *p) { + if (p == NULL) { + return; + } + + bin_t *list; footer_t *new_foot, *old_foot; @@ -128,7 +133,7 @@ void heap_free(heap_t *heap, void *p) { #ifdef MEM_DEBUG heap->bytes_allocated -= head->size; - os_printf("MEM_DEBUG: FREE %i bytes\n", head->size); + kprintf("MEM_DEBUG: FREE %i bytes\n", head->size); #endif if (head == (node_t *) (uintptr_t) heap->start) { @@ -174,7 +179,7 @@ void heap_free(heap_t *heap, void *p) { // these are left here to implement contraction / expansion uint32_t expand(heap_t *heap, uint32_t sz) { - os_printf("Trying to expand\n"); + kprintf("Trying to expand\n"); return 0; // fail for now } diff --git a/kernel/src/memory/allocator.c.old b/kernel/src/memory/allocator.c.old deleted file mode 100644 index 08c34275..00000000 --- a/kernel/src/memory/allocator.c.old +++ /dev/null @@ -1,333 +0,0 @@ -#include -#include "allocator.h.old" -#include - -uint32_t *__alloc_extend_heap(alloc_handle *allocator, uint32_t amount); - -/* - * The kernel heap is organized in blocks. Each block has a header and a - * footer each a 4 byte integer, at the beginning and end of the block. - * The header and footer both specify the size of the block in question. - * Used blocks are indicated by the heap header and the heap footer being - * negative. - * - * To allocate a block, we start at the first block and walk through each - * one, finding the first free block large enough to support a header, - * footer, and the size requested. - * - * To free a block, we do a bunch of merging stuff to check to see if we - * should merge with the blocks on the left or right of us, respectively. - */ -alloc_handle *alloc_create(uint32_t *buffer, uint32_t buffer_size, - heap_extend_handler extend_handler) { - - if (buffer_size <= sizeof(alloc_handle)) { - return 0; - } - - alloc_handle *alloc_handle_ptr = (alloc_handle *) buffer; - - // storing the alloc_handle struct - // inside the heading of the buffer - alloc_handle_ptr->heap = ((void *) buffer) + sizeof(alloc_handle); - alloc_handle_ptr->heap_size = buffer_size - sizeof(alloc_handle); - alloc_handle_ptr->extend_handler = extend_handler; - - uint32_t *heap_header = alloc_handle_ptr->heap; - uint32_t *heap_footer = (uint32_t *) ((void *) alloc_handle_ptr->heap - + alloc_handle_ptr->heap_size - sizeof(int)); - - *heap_header = alloc_handle_ptr->heap_size - 2 * sizeof(uint32_t); - *heap_footer = alloc_handle_ptr->heap_size - 2 * sizeof(uint32_t); - - return alloc_handle_ptr; -} - -alloc_handle *alloc_create_fixed(uint32_t *buffer, uint32_t buffer_size) { - return alloc_create(buffer, buffer_size, NULL); -} - -// TODO: what if there's an error allocating the page? -// Returns a pointer to the new (big) free block's header -uint32_t *__alloc_extend_heap(alloc_handle *allocator, uint32_t amount) { - if (!allocator->extend_handler) { - return 0; - } - - uint32_t start_size = allocator->heap_size; - uint32_t amount_added = allocator->extend_handler(amount); - - if (amount_added <= 0) { - return 0; - } - - // Now extend the footer block - int32_t *orig_footer = (int32_t *) ((void *) allocator->heap + start_size - - sizeof(uint32_t)); - - allocator->heap_size += amount_added; - - // If it's free, simply move it (and update the header) - // If it's used, add a free block to the end - if (*orig_footer > 0) { - uint32_t *orig_header = (uint32_t *) ((void *) allocator->heap - + start_size - 2 * sizeof(uint32_t) - *orig_footer); - uint32_t *new_footer = (uint32_t *) ((void *) allocator->heap - + allocator->heap_size - sizeof(uint32_t)); - - *new_footer = *orig_footer + amount_added; - *orig_header += amount_added; - return orig_header; - } else { - - uint32_t *new_header = (uint32_t *) ((void *) allocator->heap + start_size); - uint32_t *new_footer = (uint32_t *) ((void *) allocator->heap - + allocator->heap_size - sizeof(uint32_t)); - *new_header = amount_added - 2 * sizeof(uint32_t); - *new_footer = amount_added - 2 * sizeof(uint32_t); - return new_header; - } - - return 0x0; -} - -void *alloc_allocate(alloc_handle *allocator, uint32_t size) { - int32_t i, ret_ptr; - - for (i = 0; i < allocator->heap_size;) { - uint32_t *header_addr = (uint32_t *) ((void *) allocator->heap + i); - int32_t header = *header_addr; - - uint32_t *footer_addr = (uint32_t *) ((void *) allocator->heap + i - + sizeof(int32_t) + size); - - //free and >= request - if (header > 0 && header >= size) { - //cannot split this block - if (header < (size + 2 * sizeof(int32_t) + sizeof(char))) { - footer_addr = (uint32_t *) ((void *) allocator->heap + i - + sizeof(int32_t) + abs(header)); - - ret_ptr = i + sizeof(int32_t); - //mark header as used - *header_addr = header * (-1); - //insert a footer at end of block - *footer_addr = header * (-1); - return (uint32_t *) ((void *) allocator->heap + ret_ptr); - - } else { //can split this block - ret_ptr = i + sizeof(int32_t); - - int32_t old_space = header; - int32_t occ_space = size + 2 * sizeof(int32_t); - //mark header as used - *header_addr = size * (-1); - //insert footer - *footer_addr = size * (-1); - - //insert new free block header - uint32_t *new_header = (uint32_t *) ((void *) allocator->heap + i - + 2 * sizeof(int32_t) + size); - *new_header = old_space - occ_space; - //insert new free block footer - uint32_t *new_footer = (uint32_t *) ((void *) allocator->heap + i - + sizeof(int32_t) + old_space); - *new_footer = old_space - occ_space; - - return (uint32_t *) ((void *) allocator->heap + ret_ptr); - } - } - //jump to the next block - else { - i = i + abs(header) + 2 * sizeof(int32_t); - } - } - - // Allocate some more memory. - uint32_t new_amt = size + 2 * sizeof(uint32_t); - uint32_t *header = __alloc_extend_heap(allocator, new_amt); - - if (header == 0) { - return 0; - } - - // Recursive call. TODO: (relatively) Inefficient - return alloc_allocate(allocator, size); -} - -void alloc_deallocate(alloc_handle *allocator, void *ptr) { - - uint32_t first_block = 0; - uint32_t last_block = 0; - - uint32_t *header_addr = (uint32_t *) ((void *) ptr - sizeof(int32_t)); - uint32_t size = *header_addr; - - os_printf("test, ptr: 0x%x, size: %u\n", header_addr, size); - - uint32_t *footer_addr = (uint32_t *) ((void *) ptr + size); - - if (header_addr == allocator->heap) { - first_block = 1; - } - - if (footer_addr + sizeof(int32_t) - == (void *) allocator->heap + allocator->heap_size) { - last_block = 1; - } - - //os_printf("Freeing %d-sized block at %X. first/last=%d/%d\n", size, header_addr, first_block,last_block); - - //only check and coalesce right block - if (first_block) { - uint32_t *right_header_addr = (uint32_t *) ((void *) footer_addr - + sizeof(int32_t)); - int32_t right_block_size = *right_header_addr; - - //free right block - if (right_block_size > 0) { - //set new header at freed blocks header - *header_addr = size + right_block_size + 2 * sizeof(int32_t); - //set new footer at right blocks footer - uint32_t *right_footer_addr = (uint32_t *) ((void *) footer_addr - + 2 * sizeof(int32_t) + right_block_size); - *right_footer_addr = size + right_block_size + 2 * sizeof(int32_t); - } else { - //make freed blocks header and footer positive - *header_addr = size; - *footer_addr = size; - } - } - - //only check and coalesce left block - if (last_block) { - uint32_t *left_block_header = (uint32_t *) ((void *) header_addr - - sizeof(int32_t)); - int32_t left_block_size = *left_block_header; - - //free left block - if (left_block_size > 0) { - //set new header at left blocks header - uint32_t *left_header_addr = (uint32_t *) ((void *) header_addr - - 2 * sizeof(int32_t) - left_block_size); - *left_header_addr = size + left_block_size + 2 * sizeof(int32_t); - //set new footer at freed blocks footer - *footer_addr = size + left_block_size + 2 * sizeof(int32_t); - } else { - *header_addr = size; - *footer_addr = size; - } - } - - //check and coalesce both adjacent blocks - if (!first_block && !last_block) { - uint32_t *right_block_header = (uint32_t *) ((void *) footer_addr - + sizeof(int32_t)); - int32_t right_block_size = *right_block_header; - - uint32_t *left_block_header = (uint32_t *) ((void *) header_addr - - sizeof(int32_t)); - int32_t left_block_size = *left_block_header; - //os_printf("left/right sizes are %d/%d, size=%d\n", left_block_size, right_block_size, size); - - //both adjacent blocks are free - if (right_block_size > 0 && left_block_size > 0) { - int32_t new_size = size + right_block_size + left_block_size - + 4 * sizeof(int32_t); - - //set new header at left blocks header - uint32_t *left_header_addr = (uint32_t *) ((void *) header_addr - - 2 * sizeof(int32_t) - left_block_size); - *left_header_addr = new_size; - //set new footer at right blocks footer - uint32_t *right_footer_addr = (uint32_t *) ((void *) footer_addr - + 2 * sizeof(int32_t) + right_block_size); - *right_footer_addr = new_size; - } - - //only right free block - else if (right_block_size > 0 && left_block_size < 0) { - //set new header at freed blocks header - *header_addr = size + right_block_size + 2 * sizeof(int32_t); - //set new footer at right blocks footer - uint32_t *right_footer_addr = (uint32_t *) ((void *) footer_addr - + 2 * sizeof(int32_t) + right_block_size); - *right_footer_addr = size + right_block_size + 2 * sizeof(int32_t); - } - //only left free block - else if (left_block_size > 0 && right_block_size < 0) { - //set new header at left blocks header - uint32_t *left_header_addr = (uint32_t *) ((void *) header_addr - - 2 * sizeof(int32_t) - left_block_size); - *left_header_addr = size + left_block_size + 2 * sizeof(int32_t); - //set new footer at freed blocks footer - *footer_addr = size + left_block_size + 2 * sizeof(int32_t); - } else { - *header_addr = size; - *footer_addr = size; - } - - } -} - -/** - * Returns 0 on success. -1 on error. - */ -int alloc_check(alloc_handle *allocator) { - char *ptr = (char *) allocator->heap; - uint32_t *end_ptr = (uint32_t *) ((void *) allocator->heap - + allocator->heap_size); - int i, block = 0; - - LOG("Checking memory...\n"); - for (i = 0; i < allocator->heap_size; i += 0) { - uint32_t *block_addr = (uint32_t *) (ptr + sizeof(int32_t)); - - uint32_t *header_addr = (uint32_t *) ptr; - int32_t block_header = *header_addr; - int32_t block_size = abs(block_header); - - uint32_t *footer_addr = (uint32_t *) (ptr + sizeof(int32_t) + block_size); - int32_t block_footer = *footer_addr; - - if (block_header == block_footer && block_header <= 0) { - LOG("Block %d Allocated:", block); - LOG("\tsize = %d, address = %x\n", block_size, block_addr); - } else if (block_header == block_footer && block_header > 0) { - LOG("Block %d Free:", block); - LOG("\tsize = %d, address = %x\n", block_size, block_addr); - } else { - ERROR("INCONSISTENT HEAP\n"); - ERROR("block_header = %d\n", block_header); - ERROR("block_footer = %d\n", block_footer); - ERROR("header addr = %x\n", header_addr); - ERROR("footer addr = %x\n", footer_addr); - return -1; - } - - ptr = ptr + block_size + 2 * sizeof(int32_t); - block++; - if ((uint32_t *) ptr == end_ptr) { - return 0; - } - } - - return 0; -} - -// Returns the size of the block located at the pointer -uint32_t alloc_allocation_size(void *ptr) { - - uint32_t *header_addr = (uint32_t *) ((void *) ptr - sizeof(int32_t)); - uint32_t size = abs(*header_addr); - - return size; -} - -uint32_t *alloc_get_heap(alloc_handle *allocator) { - return allocator->heap; -} - -uint32_t alloc_get_heap_size(alloc_handle *allocator) { - return allocator->heap_size; -} diff --git a/kernel/src/memory/include/allocator.h.old b/kernel/src/memory/include/allocator.h.old deleted file mode 100644 index 3a3b1c5b..00000000 --- a/kernel/src/memory/include/allocator.h.old +++ /dev/null @@ -1,32 +0,0 @@ -/* - Log - 4/2: Adjusted bump allocation algorithm: Sean V, Faseeh A, John G, Taylor S - 4/7: Fixed mem_alloc again works properly: Sean V, Faseeh A, Taylor S. - - */ -#ifndef __ALLOCATOR_H__ -#define __ALLOCATOR_H__ - -#include "stdint.h" - -#define MEM_START 0x500000 - -typedef uint32_t (*heap_extend_handler)(uint32_t amount); - -typedef struct alloc_handle { - uint32_t *heap; - uint32_t heap_size; - heap_extend_handler extend_handler; -} alloc_handle; - -alloc_handle* alloc_create(uint32_t * heap, uint32_t size, - heap_extend_handler extend_handler); -alloc_handle* alloc_create_fixed(uint32_t * buffer, uint32_t buffer_size); -void* alloc_allocate(alloc_handle * allocator, uint32_t size); -void alloc_deallocate(alloc_handle* allocator, void* ptr); -uint32_t* alloc_get_heap(alloc_handle* allocator); -uint32_t alloc_allocation_size(void* ptr); -uint32_t alloc_get_heap_size(alloc_handle* allocator); -int alloc_check(alloc_handle* allocator); - -#endif diff --git a/kernel/src/memory/mem_alloc.c b/kernel/src/memory/mem_alloc.c index 16bec0f7..28f219e9 100644 --- a/kernel/src/memory/mem_alloc.c +++ b/kernel/src/memory/mem_alloc.c @@ -54,7 +54,7 @@ uint32_t __mem_extend_heap(uint32_t amt) int retval = vm_allocate_page(KERNEL_VAS, (void*) (MEM_START + buffer_size), VM_PERM_PRIVILEGED_RW); if (retval) { - os_printf("ERROR: vm_allocate_page(,%d,) returned %d\n", + kprintf("ERROR: vm_allocate_page(,%d,) returned %d\n", MEM_START + amt_added, retval); break; } @@ -70,7 +70,7 @@ uint32_t init_heap() // Allocate space for the heap_t struct. is too large but at least big enough. int retval = vm_allocate_page(KERNEL_VAS, (void*) MEM_START, VM_PERM_PRIVILEGED_RW); if (retval) { - os_printf("ERROR: vm_allocate_page returned %d\n", retval); + kprintf("ERROR: vm_allocate_page returned %d\n", retval); return STATUS_FAIL; } @@ -93,7 +93,7 @@ uint32_t init_heap() void * ret = vm_allocate_pages(KERNEL_VAS, (void *) addr, HEAP_INIT_SIZE, VM_PERM_PRIVILEGED_RW); if(addr + HEAP_INIT_SIZE != (uint32_t) ret) { - os_printf("ERROR: vm_allocate_pages allocated a different amount than requested\n"); + kprintf("ERROR: vm_allocate_pages allocated a different amount than requested\n"); return STATUS_FAIL; } @@ -106,7 +106,7 @@ uint32_t init_heap() uint32_t init_process_heap(struct vas* vas) { int retval = vm_allocate_page(vas, (void*) PROC_START, VM_PERM_USER_RW); if (retval) { - os_printf("ERROR: vm_allocate_page returned %d\n", retval); + kprintf("ERROR: vm_allocate_page returned %d\n", retval); return STATUS_FAIL; } @@ -123,7 +123,7 @@ uint32_t init_process_heap(struct vas* vas) { void * ret = vm_allocate_pages(vas, (void *) addr, HEAP_INIT_SIZE, VM_PERM_USER_RW); if(addr + HEAP_INIT_SIZE != (uint32_t) ret){ - os_printf("ERROR: vm_allocate_pages allocated a different amount than requested\n"); + kprintf("ERROR: vm_allocate_pages allocated a different amount than requested\n"); return STATUS_FAIL; } @@ -142,11 +142,11 @@ uint32_t __mem_extend_proc_heap(uint32_t amt) { int retval = vm_allocate_page(pvas, (void*) PROC_START, VM_PERM_USER_RW); vm_map_shared_memory(KERNEL_VAS, (void*)PROC_START, pvas, (void*)PROC_START, VM_PERM_USER_RW); if (retval) { - os_printf("ERROR: vm_allocate_page returned %d\n", retval); + kprintf("ERROR: vm_allocate_page returned %d\n", retval); return STATUS_FAIL; } else{ - os_printf("Page allocated for process heap at %x:\n",PROC_START); + kprintf("Page allocated for process heap at %x:\n", PROC_START); } amt_added += BLOCK_SIZE; proc_buffer_size += BLOCK_SIZE; diff --git a/kernel/src/memory/mmap.c b/kernel/src/memory/mmap.c index cbe21ec4..83224574 100644 --- a/kernel/src/memory/mmap.c +++ b/kernel/src/memory/mmap.c @@ -19,7 +19,7 @@ int vm_build_free_frame_list(void *start, void *end); -unsigned int * first_level_pt = (unsigned int*) P_L1PTBASE; +volatile unsigned int * first_level_pt = (unsigned int*) P_L1PTBASE; extern struct vm_free_list *vm_vas_free_list; extern struct vm_free_list *vm_l1pt_free_list; extern struct vm_free_list *vm_l2pt_free_list; @@ -33,7 +33,7 @@ void mmap(void *p_bootargs) { //stash register state on the stack asm volatile("push {r0-r11}"); - os_printf("%X\n", p_bootargs); + kprintf("%X\n", p_bootargs); /* int pte; @@ -49,10 +49,9 @@ void mmap(void *p_bootargs) { //TODO:. Collin LOOOK HERE first_level_pt = (unsigned int *) (P_L1PTBASE + PAGE_TABLE_SIZE); //first_level_pt = 0x00200000 + 0x4000 = 0x00204000 - os_printf("first_level_pt=%X\n", first_level_pt); + kprintf("first_level_pt=%X\n", first_level_pt); - int i = 0; - for (; i < PAGE_TABLE_SIZE >> 2; i++) { + for (int i = 0; i < PAGE_TABLE_SIZE >> 2; i++) { first_level_pt[i] = 0; } @@ -81,7 +80,7 @@ void mmap(void *p_bootargs) { //map 752MB of PCI interface one-to-one unsigned int pci_bus_addr = PCIBASE; - for (i = (PCIBASE >> 20); i < (PCITOP >> 20); i++) { + for (int i = (PCIBASE >> 20); i < (PCITOP >> 20); i++) { first_level_pt[i] = pci_bus_addr | 0x0400 | 2; pci_bus_addr += 0x100000; } @@ -95,7 +94,7 @@ void mmap(void *p_bootargs) { // This is where we allocate frames from. Except for the first one. unsigned int phys_addr = P_KERNTOP; // +1 to skip L1PTBASE - for (i = (PMAPBASE >> 20); i < (PMAPTOP >> 20); i++) { + for (int i = (PMAPBASE >> 20); i < (PMAPTOP >> 20); i++) { first_level_pt[i] = phys_addr | 0x0400 | 2; phys_addr += 0x100000; } @@ -122,7 +121,7 @@ void mmap(void *p_bootargs) { unsigned int pt_addr = (unsigned int) first_level_pt; - os_printf("0x%X\n", first_level_pt[(PMAPBASE + 0x100000) >> 20]); + kprintf("0x%X\n", first_level_pt[(PMAPBASE + 0x100000) >> 20]); //TTBR0 asm volatile("mcr p15, 0, %[addr], c2, c0, 0" : : [addr] "r" (pt_addr)); @@ -151,12 +150,10 @@ void mmap(void *p_bootargs) { control |= 0x1007; //0b01000000000111 (No high vectors) control |= 1 << 23; // Enable ARMv6 //control |= 1<<29; // Enable ForceAP - os_printf("control reg: 0x%x\n", control); + kprintf("control reg: 0x%x\n", control); //Write back value into the register asm volatile("mcr p15, 0, %[control], c1, c0, 0" : : [control] "r" (control)); - os_printf("Got here\n"); - // Build the free frame list vm_build_free_frame_list((void*) PMAPBASE + 0x100000, (void*) PMAPTOP); //(void*)PMAPBASE+(unsigned int)((PMAPTOP)-(PMAPBASE))); diff --git a/kernel/src/memory/test/test_allocator.c b/kernel/src/memory/test/test_allocator.c index a01e84ef..b21c66a5 100644 --- a/kernel/src/memory/test/test_allocator.c +++ b/kernel/src/memory/test/test_allocator.c @@ -2,13 +2,13 @@ #include TEST_CREATE(test_alloc_free, { - uint32_t * a = kmalloc(sizeof(uint32_t)); + uint32_t *a = kmalloc(sizeof(uint32_t)); *a = 42; kfree(a); }) TEST_CREATE(test_alloc_free_large, { - uint32_t * a = kmalloc(100 * sizeof(uint32_t)); + uint32_t *a = kmalloc(100 * sizeof(uint32_t)); for (int i = 0; i < 100; i++) { a[i] = 42; } @@ -16,7 +16,7 @@ TEST_CREATE(test_alloc_free_large, { }) TEST_CREATE(test_alloc_realloc_free, { - uint32_t * a = kmalloc(5 * sizeof(uint32_t)); + uint32_t *a = kmalloc(5 * sizeof(uint32_t)); for (int i = 0; i < 5; i++) { a[i] = 42; } diff --git a/kernel/src/memory/vm/frame.c b/kernel/src/memory/vm/frame.c index 37616303..d4cf962c 100644 --- a/kernel/src/memory/vm/frame.c +++ b/kernel/src/memory/vm/frame.c @@ -42,7 +42,7 @@ void vm_release_frame(void *p) p += 0xf0000000; // Convert from PPTR to VPTR struct vm_free_frame *flist = p; flist->next = vm_free_list; - os_printf("%X %X\n", flist, vm_free_list); + kprintf("%X %X\n", flist, vm_free_list); vm_free_list = p; } diff --git a/kernel/src/memory/vm/include/vm.h b/kernel/src/memory/vm/include/vm.h index cbddb68f..a7f05e3c 100644 --- a/kernel/src/memory/vm/include/vm.h +++ b/kernel/src/memory/vm/include/vm.h @@ -14,8 +14,8 @@ struct vas { // A pointer to the first level of the pagetable. - unsigned int *l1_pagetable; - unsigned int *l1_pagetable_phys; // The physical address to it + volatile unsigned int *l1_pagetable; + volatile unsigned int *l1_pagetable_phys; // The physical address to it // A pointer to the next VAS (it's a linked list) struct vas *next; diff --git a/kernel/src/memory/vm/test/test.c b/kernel/src/memory/vm/test/test.c new file mode 100644 index 00000000..e651107b --- /dev/null +++ b/kernel/src/memory/vm/test/test.c @@ -0,0 +1,6 @@ +#include +#include + +TEST_CREATE(test_free_null, { + kfree(NULL); +}) diff --git a/kernel/src/memory/vm/vm.c b/kernel/src/memory/vm/vm.c index e2aba8ed..c26ecdbc 100644 --- a/kernel/src/memory/vm/vm.c +++ b/kernel/src/memory/vm/vm.c @@ -116,7 +116,7 @@ uint32_t *vm_vtop(struct vas *vas, uint32_t *vptr) // Hack. Assume it's all linearly mapped, and vas == KERNEL_VAS if (vas != KERNEL_VAS) { - os_printf("vas is not KERNEL_VAS in vm_vtop. :-(\n"); + kprintf("vas is not KERNEL_VAS in vm_vtop. :-(\n"); while (1) ; } @@ -128,7 +128,7 @@ uint32_t *vm_ptov(struct vas *vas, uint32_t *vptr) // Hack. Assume it's all linearly mapped, and vas == KERNEL_VAS if (vas != KERNEL_VAS) { - os_printf("vas is not KERNEL_VAS in vm_vtop. :-(\n"); + kprintf("vas is not KERNEL_VAS in vm_vtop. :-(\n"); while (1) ; } @@ -161,14 +161,14 @@ int vm_allocate_page(struct vas *vas, void *vptr, int permission) { return VM_ERR_UNKNOWN; // For now, just fail } - os_printf("mapping VA %x to PA %x\n", vptr, pptr); + kprintf("mapping VA %x to PA %x\n", vptr, pptr); //LOG("Free frame is at: %X\n", pptr); int retval = vm_set_mapping(vas, vptr, pptr, permission); if (retval) { // Release the frame to prevent a memory leak - os_printf("vm_set_mapping returned %d for 0x%X\n", retval, vptr); + kprintf("vm_set_mapping returned %d for 0x%X\n", retval, vptr); vm_release_frame(pptr); vm_enable_vas(prev_vas); return retval; @@ -184,8 +184,8 @@ void *vm_allocate_pages(struct vas *vas, void *vptr, uint32_t nbytes, int permis while (p - (unsigned char*) vptr < nbytes) { rc = vm_allocate_page(vas, p, permission); if(rc != STATUS_OK) { - os_printf("Allocate page failed with code %i\n", rc); - os_printf("vptr: 0x%x", (uint32_t)p); + kprintf("Allocate page failed with code %i\n", rc); + kprintf("vptr: 0x%x", (uint32_t) p); panic(); } @@ -410,7 +410,7 @@ struct vas *vm_new_vas() struct vas *p = (struct vas*) vm_vas_free_list; vm_vas_free_list = vm_vas_free_list->next; - os_printf("vm_l1pt_free_list=%X\n", vm_l1pt_free_list); + kprintf("vm_l1pt_free_list=%X\n", vm_l1pt_free_list); p->l1_pagetable = (uint32_t*) vm_l1pt_free_list; vm_l1pt_free_list = vm_l1pt_free_list->next; @@ -418,7 +418,7 @@ struct vas *vm_new_vas() - (V_L1PTBASE - P_L1PTBASE)); // Zero out the page table - memset(p->l1_pagetable, 0, PAGE_TABLE_SIZE); + memset((unsigned int *)p->l1_pagetable, 0, PAGE_TABLE_SIZE); // Setup the static mappings... // The kernel (high & low addresses) diff --git a/kernel/src/process/loader.c b/kernel/src/process/loader.c index f469eaa0..3a6640dd 100644 --- a/kernel/src/process/loader.c +++ b/kernel/src/process/loader.c @@ -38,18 +38,18 @@ os_size_t det_proc_size(Elf_Ehdr *h, Elf_Phdr ph[]) Elf_Ehdr* load_file(pcb * pcb_p, uint32_t * file_pointer) { Elf_Ehdr *h = (Elf_Ehdr *) kmalloc(sizeof(Elf_Ehdr)); // Get elf header - os_printf("elf header= %x\n", h); + kprintf("elf header= %x\n", h); int i = read_elf_header(h, (unsigned char *) file_pointer); if (i == -1) { - os_printf("File is Not an ELF File. Exiting\n"); + kprintf("File is Not an ELF File. Exiting\n"); return 0; } if (h->e_phnum == 0) { - os_printf("No Program headers in ELF file. Exiting\n"); + kprintf("No Program headers in ELF file. Exiting\n"); return 0; } diff --git a/kernel/src/process/process.c b/kernel/src/process/process.c index 0c869f50..c89c42b3 100644 --- a/kernel/src/process/process.c +++ b/kernel/src/process/process.c @@ -140,14 +140,14 @@ void __process_stack_init(pcb * pcb_p) { (void*) (STACK_BASE + (i * BLOCK_SIZE)), VM_PERM_USER_RW); if (retval) { - os_printf("vm_allocate_page error code: %d\n", retval); + kprintf("vm_allocate_page error code: %d\n", retval); break; } else { - os_printf( - "A page have been allocated for process stack at vptr: 0x%x\n", - (STACK_BASE + (i * BLOCK_SIZE))); + kprintf( + "A page have been allocated for process stack at vptr: 0x%x\n", + (STACK_BASE + (i * BLOCK_SIZE))); } vm_map_shared_memory(KERNEL_VAS, (void*) (STACK_BASE + (i * BLOCK_SIZE)), pcb_p->stored_vas, @@ -176,7 +176,7 @@ void __process_stack_init(pcb * pcb_p) { void __process_heap_init(pcb* pcb_p) { //from mem_alloc.c init_process_heap(pcb_p->stored_vas); - os_printf("User Level Heap for Process PID %d initialized\n", pcb_p->PID); + kprintf("User Level Heap for Process PID %d initialized\n", pcb_p->PID); } /* diff --git a/kernel/src/process/scheduler.c b/kernel/src/process/scheduler.c index 71eeb17c..c2776ecd 100644 --- a/kernel/src/process/scheduler.c +++ b/kernel/src/process/scheduler.c @@ -55,7 +55,7 @@ void __sched_dispatch(void); void timer_handler(void *args) { - os_printf("scheduler received timer interrupt, need to switch tasks...\n"); + kprintf("scheduler received timer interrupt, need to switch tasks...\n"); } void __sched_register_timer_irq(void) @@ -93,7 +93,7 @@ uint32_t sched_init(void) { sched_tid = 0; - os_printf("Initializing scheduler\n"); + kprintf("Initializing scheduler\n"); last_err = "No error"; inactive_tasks = prq_create_fixed(MAX_TASKS); active_tasks = prq_create_fixed(MAX_ACTIVE_TASKS); diff --git a/kernel/src/test/generate_tests.sh b/kernel/src/test/generate_tests.sh index 1a4b2301..e5d8422a 100755 --- a/kernel/src/test/generate_tests.sh +++ b/kernel/src/test/generate_tests.sh @@ -13,11 +13,14 @@ echo " // DO NOT EDIT // this file is generated by generate_tests.sh +#ifdef ENABLE_TESTS + #include " >> "$DIR/test.c" -TESTFNS=$(grep -hr --include "*.c" -oP "(?<=TEST_CREATE\()(.*)(?=,)") +#TESTFNS=$(grep -hr --include "*.c" -oP "(?<=TEST_CREATE\()(.*)(?=,)") +TESTFNS=$(grep -hr --include "*.c" -vP "^\s*\/\/.+" | grep -oP "(?<=TEST_CREATE\()(.*)(?=,)") for FNNAME in $TESTFNS do @@ -26,14 +29,19 @@ done echo "void test_main(){" >> "$DIR/test.c" +len=0 for FNNAME in $TESTFNS do echo " if (!test_$FNNAME()) {return;}" >> "$DIR/test.c" + ((len++)) done +# shellcheck disable=SC2028 echo " - os_printf(\"TESTS COMPLETE\n\"); -}" >> "$DIR/test.c" + kprintf(\"TESTS COMPLETE. Passed %i tests\n\", "$len"); +} +#endif +" >> "$DIR/test.c" diff --git a/kernel/src/test/include/test.h b/kernel/src/test/include/test.h index 712b103a..c5f569c4 100644 --- a/kernel/src/test/include/test.h +++ b/kernel/src/test/include/test.h @@ -19,7 +19,7 @@ isize_t nbytes = heap->bytes_allocated; \ block; \ if (nbytes != (isize_t)heap->bytes_allocated) { \ - os_printf( \ + kprintf( \ "FAILED (MEMORY LEAK: %i bytes) \n",\ heap->bytes_allocated - nbytes \ ); \ @@ -28,13 +28,13 @@ return TEST_PASS; \ } \ int test_##name() { \ - os_printf("Testing %s\n", #name); \ + kprintf("Testing %s\n", #name); \ int res = __internal_test_##name(); \ if (res == TEST_PASS) { \ - os_printf("PASSED\n"); \ + kprintf("PASSED\n"); \ return 1; \ } else { \ - os_printf("FAILED\n"); \ + kprintf("FAILED\n"); \ return 0; \ } \ } @@ -45,13 +45,13 @@ return TEST_PASS; \ } \ int test_##name() { \ - os_printf("Testing %s\n", #name); \ + kprintf("Testing %s\n", #name); \ int res = __internal_test_##name(); \ if (res == TEST_PASS) { \ - os_printf("PASSED\n"); \ + kprintf("PASSED\n"); \ return 1; \ } else { \ - os_printf("FAILED\n"); \ + kprintf("FAILED\n"); \ return 0; \ } \ } @@ -59,14 +59,14 @@ #define PASS() return TEST_PASS #define FAIL() return TEST_FAIL -#define ASSERT(expr) do { if(!expr) { os_printf("failed assertion: %s at ASSERT(%s)\n", __FILE__, #expr); return TEST_FAIL; } } while(0) -#define ASSERT_EQ(l, r) do { if(l != r) { os_printf("failed assertion: %s at ASSERT_EQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) -#define ASSERT_GT(l, r) do { if(l <= r) { os_printf("failed assertion: %s at ASSERT_GT(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) -#define ASSERT_GTEQ(l, r) do { if(l < r) { os_printf("failed assertion: %s at ASSERT_GTEQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) -#define ASSERT_LT(l, r) do { if(l >= r) { os_printf("failed assertion: %s at ASSERT_LT(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) -#define ASSERT_LTEQ(l, r) do { if(l > r) { os_printf("failed assertion: %s at ASSERT_LTEQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) -#define ASSERT_NEQ(l, r) do { if(l == r) { os_printf("failed assertion: %s at ASSERT_NEQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) -#define ASSERT_NOT_NULL(e) do { if(e == NULL) { os_printf("failed assertion: %s\n at ASSERT_NOT_NULL(%s)", __FILE__, #e); return TEST_FAIL; } } while(0) +#define ASSERT(expr) do { if(!expr) { kprintf("failed assertion: %s at ASSERT(%s)\n", __FILE__, #expr); return TEST_FAIL; } } while(0) +#define ASSERT_EQ(l, r) do { if(l != r) { kprintf("failed assertion: %s at ASSERT_EQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_GT(l, r) do { if(l <= r) { kprintf("failed assertion: %s at ASSERT_GT(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_GTEQ(l, r) do { if(l < r) { kprintf("failed assertion: %s at ASSERT_GTEQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_LT(l, r) do { if(l >= r) { kprintf("failed assertion: %s at ASSERT_LT(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_LTEQ(l, r) do { if(l > r) { kprintf("failed assertion: %s at ASSERT_LTEQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_NEQ(l, r) do { if(l == r) { kprintf("failed assertion: %s at ASSERT_NEQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_NOT_NULL(e) do { if(e == NULL) { kprintf("failed assertion: %s\n at ASSERT_NOT_NULL(%s)", __FILE__, #e); return TEST_FAIL; } } while(0) #else diff --git a/kernel/src/test/monitor_tests.sh b/kernel/src/test/monitor_tests.sh index 8a864cc8..ee1d2062 100755 --- a/kernel/src/test/monitor_tests.sh +++ b/kernel/src/test/monitor_tests.sh @@ -5,7 +5,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" tail -f -n +1 "$DIR/../../test.log" | while read line do if [[ $line == *"TESTS COMPLETE"* ]]; then - echo "COMPLETE" + echo "$line" exit 0 elif [[ $line == *"MEMORY LEAK"* ]]; then echo "FAILED (MEMORY: $line)" diff --git a/kernel/src/test/test.c b/kernel/src/test/test.c index c21d6c84..2e9de922 100644 --- a/kernel/src/test/test.c +++ b/kernel/src/test/test.c @@ -2,29 +2,33 @@ // DO NOT EDIT // this file is generated by generate_tests.sh +#ifdef ENABLE_TESTS + #include -int test_u8a_push_get_pop_test(); -int test_u8a_push_set_pop_test(); -int test_u8a_resize_test(); -int test_u8a_push_string_test(); -int test_u8a_clone_test(); -int test_vpa_push_get_pop_test(); -int test_vpa_push_set_pop_test(); -int test_vpa_resize_test(); int test_test_compare_nonequal_length(); int test_test_compare_equal_length(); int test_test_compare_equal_length_eq(); int test_test_compare_equal_length_eq_null(); int test_test_compare_various(); +int test_test_hash(); +int test_u8a_push_get_pop_test(); +int test_u8a_push_set_pop_test(); +int test_u8a_resize_test(); +int test_u8a_push_string_test(); +int test_u8a_clone_test(); +int test_test_create_ll(); +int test_test_iter_ll(); +int test_test_get_ll(); +int test_test_contains_true(); +int test_test_contains_false(); +int test_test_vpsll_remove(); +int test_test_vpsll_set(); +int test_test_free_null(); int test_test_alloc_free(); int test_test_alloc_free_large(); int test_test_alloc_realloc_free(); -int test_test_create_file(); -int test_test_create_dir(); -int test_test_create_rw_file(); -int test_test_listdir(); int test_test_create_vfs(); int test_test_get_root(); int test_path_create_test(); @@ -50,27 +54,33 @@ int test_path_filename_test_1(); int test_path_filename_test_2(); int test_path_filename_test_3(); int test_path_filename_test_4(); +int test_test_create_file(); +int test_test_create_dir(); +int test_test_create_rw_file(); +int test_test_listdir(); void test_main(){ - if (!test_u8a_push_get_pop_test()) {return;} - if (!test_u8a_push_set_pop_test()) {return;} - if (!test_u8a_resize_test()) {return;} - if (!test_u8a_push_string_test()) {return;} - if (!test_u8a_clone_test()) {return;} - if (!test_vpa_push_get_pop_test()) {return;} - if (!test_vpa_push_set_pop_test()) {return;} - if (!test_vpa_resize_test()) {return;} if (!test_test_compare_nonequal_length()) {return;} if (!test_test_compare_equal_length()) {return;} if (!test_test_compare_equal_length_eq()) {return;} if (!test_test_compare_equal_length_eq_null()) {return;} if (!test_test_compare_various()) {return;} + if (!test_test_hash()) {return;} + if (!test_u8a_push_get_pop_test()) {return;} + if (!test_u8a_push_set_pop_test()) {return;} + if (!test_u8a_resize_test()) {return;} + if (!test_u8a_push_string_test()) {return;} + if (!test_u8a_clone_test()) {return;} + if (!test_test_create_ll()) {return;} + if (!test_test_iter_ll()) {return;} + if (!test_test_get_ll()) {return;} + if (!test_test_contains_true()) {return;} + if (!test_test_contains_false()) {return;} + if (!test_test_vpsll_remove()) {return;} + if (!test_test_vpsll_set()) {return;} + if (!test_test_free_null()) {return;} if (!test_test_alloc_free()) {return;} if (!test_test_alloc_free_large()) {return;} if (!test_test_alloc_realloc_free()) {return;} - if (!test_test_create_file()) {return;} - if (!test_test_create_dir()) {return;} - if (!test_test_create_rw_file()) {return;} - if (!test_test_listdir()) {return;} if (!test_test_create_vfs()) {return;} if (!test_test_get_root()) {return;} if (!test_path_create_test()) {return;} @@ -96,6 +106,12 @@ void test_main(){ if (!test_path_filename_test_2()) {return;} if (!test_path_filename_test_3()) {return;} if (!test_path_filename_test_4()) {return;} + if (!test_test_create_file()) {return;} + if (!test_test_create_dir()) {return;} + if (!test_test_create_rw_file()) {return;} + if (!test_test_listdir()) {return;} - os_printf("TESTS COMPLETE\n"); + kprintf("TESTS COMPLETE. Passed %i tests\n", 51); } +#endif + From 9403ee1c9602b2467d042989090b2df0c0e3eedb Mon Sep 17 00:00:00 2001 From: Dany Sluijk Date: Wed, 26 Feb 2020 12:27:17 +0100 Subject: [PATCH 016/104] chore: ignore emitted files by the build process --- .gitignore | 3 ++ kernel/src/test/test.c | 108 +---------------------------------------- 2 files changed, 4 insertions(+), 107 deletions(-) diff --git a/.gitignore b/.gitignore index 5f1972e3..3e8b88ba 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ /kernel/flash.bin /kernel/boot-commands /kernel/card.sd +/kernel/src/test/test.c /toolchain/target/ /u-boot/u-boot-* /qemu/ @@ -22,6 +23,8 @@ build/ *~ *.swp /user/hello/hello +/user/hello/hello1 +/user/hello/hello2 /user/libc/libc.a [._]*.s[a-w][a-z] diff --git a/kernel/src/test/test.c b/kernel/src/test/test.c index 2e9de922..fdd9a191 100644 --- a/kernel/src/test/test.c +++ b/kernel/src/test/test.c @@ -1,4 +1,3 @@ - // DO NOT EDIT // this file is generated by generate_tests.sh @@ -6,112 +5,7 @@ #include - -int test_test_compare_nonequal_length(); -int test_test_compare_equal_length(); -int test_test_compare_equal_length_eq(); -int test_test_compare_equal_length_eq_null(); -int test_test_compare_various(); -int test_test_hash(); -int test_u8a_push_get_pop_test(); -int test_u8a_push_set_pop_test(); -int test_u8a_resize_test(); -int test_u8a_push_string_test(); -int test_u8a_clone_test(); -int test_test_create_ll(); -int test_test_iter_ll(); -int test_test_get_ll(); -int test_test_contains_true(); -int test_test_contains_false(); -int test_test_vpsll_remove(); -int test_test_vpsll_set(); -int test_test_free_null(); -int test_test_alloc_free(); -int test_test_alloc_free_large(); -int test_test_alloc_realloc_free(); -int test_test_create_vfs(); -int test_test_get_root(); -int test_path_create_test(); -int test_path_equal_test_1(); -int test_path_parent_test_1(); -int test_path_parent_test_2(); -int test_path_parent_test_3(); -int test_path_parent_test_4(); -int test_path_parent_test_5(); -int test_path_parent_test_6(); -int test_path_parent_test_7(); -int test_path_parent_test_8(); -int test_path_parent_test_9(); -int test_path_parent_test_10(); -int test_path_is_absolute_test(); -int test_path_is_relative_test_1(); -int test_path_is_relative_test_2(); -int test_path_clone_test(); -int test_path_find_file_test(); -int test_path_filename_test(); -int test_path_filename_test_trailing(); -int test_path_filename_test_1(); -int test_path_filename_test_2(); -int test_path_filename_test_3(); -int test_path_filename_test_4(); -int test_test_create_file(); -int test_test_create_dir(); -int test_test_create_rw_file(); -int test_test_listdir(); void test_main(){ - if (!test_test_compare_nonequal_length()) {return;} - if (!test_test_compare_equal_length()) {return;} - if (!test_test_compare_equal_length_eq()) {return;} - if (!test_test_compare_equal_length_eq_null()) {return;} - if (!test_test_compare_various()) {return;} - if (!test_test_hash()) {return;} - if (!test_u8a_push_get_pop_test()) {return;} - if (!test_u8a_push_set_pop_test()) {return;} - if (!test_u8a_resize_test()) {return;} - if (!test_u8a_push_string_test()) {return;} - if (!test_u8a_clone_test()) {return;} - if (!test_test_create_ll()) {return;} - if (!test_test_iter_ll()) {return;} - if (!test_test_get_ll()) {return;} - if (!test_test_contains_true()) {return;} - if (!test_test_contains_false()) {return;} - if (!test_test_vpsll_remove()) {return;} - if (!test_test_vpsll_set()) {return;} - if (!test_test_free_null()) {return;} - if (!test_test_alloc_free()) {return;} - if (!test_test_alloc_free_large()) {return;} - if (!test_test_alloc_realloc_free()) {return;} - if (!test_test_create_vfs()) {return;} - if (!test_test_get_root()) {return;} - if (!test_path_create_test()) {return;} - if (!test_path_equal_test_1()) {return;} - if (!test_path_parent_test_1()) {return;} - if (!test_path_parent_test_2()) {return;} - if (!test_path_parent_test_3()) {return;} - if (!test_path_parent_test_4()) {return;} - if (!test_path_parent_test_5()) {return;} - if (!test_path_parent_test_6()) {return;} - if (!test_path_parent_test_7()) {return;} - if (!test_path_parent_test_8()) {return;} - if (!test_path_parent_test_9()) {return;} - if (!test_path_parent_test_10()) {return;} - if (!test_path_is_absolute_test()) {return;} - if (!test_path_is_relative_test_1()) {return;} - if (!test_path_is_relative_test_2()) {return;} - if (!test_path_clone_test()) {return;} - if (!test_path_find_file_test()) {return;} - if (!test_path_filename_test()) {return;} - if (!test_path_filename_test_trailing()) {return;} - if (!test_path_filename_test_1()) {return;} - if (!test_path_filename_test_2()) {return;} - if (!test_path_filename_test_3()) {return;} - if (!test_path_filename_test_4()) {return;} - if (!test_test_create_file()) {return;} - if (!test_test_create_dir()) {return;} - if (!test_test_create_rw_file()) {return;} - if (!test_test_listdir()) {return;} - - kprintf("TESTS COMPLETE. Passed %i tests\n", 51); + kprintf("TESTS COMPLETE. Passed %i tests\n", 51); } #endif - From bc579a0224bcfecfc2fa7adda0f8ce3ae2dc9957 Mon Sep 17 00:00:00 2001 From: Dany Sluijk Date: Wed, 26 Feb 2020 12:27:29 +0100 Subject: [PATCH 017/104] chore: add editorconfig --- .editorconfig | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..a882442c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 From cd6d43be945370c0cc3c1f45c74fbdbf922f7973 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Thu, 27 Feb 2020 18:53:11 +0100 Subject: [PATCH 018/104] Added a hashmap (from linux/facebook), improved uart api. Co-authored-by: Victor Roest --- kernel/Makefile | 10 +- kernel/old/fs/cmdline/buildfs | Bin 0 -> 71056 bytes kernel/old/include/.DS_Store | Bin 0 -> 6148 bytes .../old/tests/testingsuite_example/.DS_Store | Bin 0 -> 6148 bytes kernel/src/common/include/interrupt.h | 97 ++++--- kernel/src/common/interrupt.c | 54 ++-- kernel/src/drivers/time/timer.c | 5 +- kernel/src/drivers/uart/include/uart.h | 41 +++ kernel/src/drivers/uart/uart.c | 117 ++------ kernel/src/drivers/uart/uart_qemu.c | 106 ++++++++ kernel/src/ds/bpf/HashMap.c | 252 ++++++++++++++++++ kernel/src/ds/bpf/include/HashMap.h | 189 +++++++++++++ kernel/src/ds/bpf/test/hashmap_test.c | 50 ++++ kernel/src/ds/include/ds.h | 4 +- kernel/src/ds/include/vp_hash_map.h.old | 51 ++++ kernel/src/ds/vp_hash_map.c | 1 - kernel/src/ds/vp_hash_map.c.old | 118 ++++++++ kernel/src/ds/vp_singly_linked_list.c | 2 +- kernel/src/klibc/alloc.c | 12 +- kernel/src/klibc/include/klibc.h | 2 +- kernel/src/klibc/include/stdint.h | 12 + kernel/src/klibc/include/stdlib.h | 1 + kernel/src/klibc/klibc.c | 1 + kernel/src/memory/allocator.c | 2 +- kernel/src/memory/include/mmap.h | 15 +- kernel/src/memory/test/test_allocator.c | 14 + kernel/src/memory/vm/test/test.c | 6 - kernel/src/test/test.c | 114 +++++++- 28 files changed, 1080 insertions(+), 196 deletions(-) create mode 100755 kernel/old/fs/cmdline/buildfs create mode 100644 kernel/old/include/.DS_Store create mode 100644 kernel/old/tests/testingsuite_example/.DS_Store create mode 100644 kernel/src/drivers/uart/uart_qemu.c create mode 100644 kernel/src/ds/bpf/HashMap.c create mode 100644 kernel/src/ds/bpf/include/HashMap.h create mode 100644 kernel/src/ds/bpf/test/hashmap_test.c create mode 100644 kernel/src/ds/include/vp_hash_map.h.old delete mode 100644 kernel/src/ds/vp_hash_map.c create mode 100644 kernel/src/ds/vp_hash_map.c.old delete mode 100644 kernel/src/memory/vm/test/test.c diff --git a/kernel/Makefile b/kernel/Makefile index c0b0f80a..7a852bed 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -41,6 +41,9 @@ INCLUDEDIRS := $(sort $(foreach dir, $(foreach dir1, $(DIRS), $(shell dirname $ CFLAGS += $(foreach dir, $(INCLUDEDIRS), -I./$(dir)) CFLAGS += $(foreach def, $(DEFINITIONS), -D$(def)) +build: $(BUILDDIR)/card.sd $(BUILDDIR)/flash.bin | builddir +build_pi: $(BUILDDIR)/kernelPi.img | builddir + test: build | builddir ${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" > test.log & echo $$! > server.PID; # montior the output, save exit code, remove logfile, kill qemu, @@ -49,10 +52,11 @@ test: build | builddir run: build | builddir - ${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" + # nographic to turn off the gui + # monitor none to disable stdio monitoring so + # serial stdio works + ${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -monitor none -serial stdio -kernel build/flash.bin -append "-load 0x410000 0x14000" -build: $(BUILDDIR)/card.sd $(BUILDDIR)/flash.bin | builddir -build_pi: $(BUILDDIR)/kernelPi.img | builddir $(BUILDDIR)/flash.bin: $(BUILDDIR)/kernel.img $(BUILDDIR)/bootloader.img dd if=/dev/zero of=$@ bs=4k count=1536 diff --git a/kernel/old/fs/cmdline/buildfs b/kernel/old/fs/cmdline/buildfs new file mode 100755 index 0000000000000000000000000000000000000000..5715423131c1ae8fd663e7eb3a8009fd89f291a6 GIT binary patch literal 71056 zcmeFa34D~*)j$5sa%ag-CLv)THVuMd5fCIm0t^hBAQA-u1B8S`LPC=Xi!4Egw2VVE zQP9{@h?dr<*wQL3vS>hSQtMl>wVJlJrhTDK3T;!NHEq%Peb2e~nI(kQ_y7Jr{r^9o zKcmdO=bm%VIrrRi&)uG9QstUA(`Ybg`p2YA(FoemLzZMK#JRXIO|~{ci`BBV!P+3r z0=yajbh@r-kr7CI^wcIn&4iTdH7b19w6CJmQ(ZcxRPTD9R=dRLsg@*RswXI`;I8TZ zyCt2T>iCen4HB<)N!t`ZJ&mkKwh7e8dV#M;r{`6>SCS#Ev}ONv*IA3L&S&8;QHrInj+-8^CZt>edLR+MFq;dZA$5i;ehJ9D*@4-OoB zvi~oC^`)X=zj(Ue_&*L!e*9(9n{*(4L_;5UGK&U#Hx8o${xzQ~uTKlz)zL zC;oN)tU^I|cA&EE%FC`(zU(^Xy{}Wg<2vQ>hVJ$BgMJYHUGssz=aYMn*D5^a`5U%q zlql^74z;Ud z3s{}?8&FCbl3YkxzpA)Yt0>)2UR>%aq-q7)ta-DiP0t&XIeKg;8_tc%9H-^YUOYc< zO+k6V+TsdNLHXkO(@V-q3l^_hT~Yw%YuA^RD&~2Tv|B=$jYhCB;y+VFp2{gMhVlA{ zH(>OmOZ2d-?W=nN;moX^QDrH`#qks&-d1pB?_$g>M(usT^wHzF9)DLVr|MAgS}#vh zYuiV@tmFrUzm1H!~x293KJ_isys)4>`xsX}@p3ooxqK}*>vLng~r+?fHGDl^)ji_W{ z1AR;WYHDYANdqUWPmIj+_sWQJinaQus6pn4f1F;3bVGv#s2m+0`fP5HSt?Hmm1^3~ zh;n^SBlMn#^2qp78&U2cLiMR{kQw4nbC>>UXplK7Pt^;NHa19r%6rNze;;j-0F|f7 z?2Ydm7Pw)78y2`>fg2Y1w-&gZ*#94H?s&WD?sq5- z4n2?W!~xmJ5nM#L_O>8CLw`vyEg{;^G5k}4X(`j*#PC}L(^8`SD8pw7rX@ss1H&f> z76jKa{5^tc$8*VO!_N>*ON92741bkiS{k%3WcV?HX-UwY&G5qn(^8;) z6vMj+rX@hTli>#mrm4R@iQ#gBY07Wc7=D1@M1ng$N5Rn51k=>t-p25K1k+Ni{T#!K z2&N@KdlSQR2&SpO{U~6v_vk;)_Pu+*+xI)S_k72~#q(;!-|m9xYvQXoncR9OES@^; z5ly>N>#mtR3=G^gVh|-0J3XoBs{X)HSJ{JYi34_mxAwY9LH~C`){Ogvl3|~_eI4#I zf12t((`j-W-gLkFxhDk-{#qj$*n(|^i34VY>yv&vCm%yyt@5^9w|DYSL8-ZY7d-K9 z|Kvwd9!zaQQ6L|-cvI{}fnmk#g_(&1c9R;~>xJPw`3v!DUkln?@NhqLsRN#{#_cx` z&0w~!&e2U!dDjYXJo8yF*j(+r8Vr&*HCGQo?mMr(_?zbH4CFND)7Iwd5tM^-HCKQ=8w*^zpYv=cT~fc5(GR88|&Q=8AU*?ngf2jBao-$B%D zu3iWnF>kJ3ta9Coc@K=j&8JEy>Y=3D$71%d7&7R!Vs2*zrC}j;8c2_mK(~K>=Nk8I zaqJBq5lBGoAHB}5;=SbbZNKEJ4ES=-`(2lO;(@(rhAZF`1;{ju0r;j*vskKf%rS5V zysMik6W~?Z*t`eU{WBQ67zgM+f>r?XZa=SiVkC7TY$f~ti7C_)aTOc#<79c&2yqbw z(pDdF^TjVw;Lnb8`%}+RZch4BpZ?t^wjqykb()bWXk#q~75I5%`8T<|FUmK|@|RK2 z?CPKvTucYAc|_pqaQof|&6Qc2=5=)#z_5fXrc88oZ2JYkp#a^!H(#TAfrTJLS#e}p z7Rvm>f+A`_bKteftVSx)AZ{S>XQ#O9&$O91Vd325|Et^WvF_GyJqYUNn2os5GMDEJO8Kd zGrvQGJLj%R8SVBZUF-v-^%`U|RfBD>kZqHgD{Oluajy*_$}f^pBJK8-EV7%c6J+f^ z65dxg+Iq%_f1*@3+C$*!7e7Y{cx}HIb&heJ5zy?+@9c(izB8~Ix9ptT52h&LF|!vP zpkrE4?ORkWsx|&xP`{-&=*!pOqZ%}orS|0pm7qb=$M;b$*GztF3Hg7gDh-XYB#5LJLJH~smJXbH=^rtyVa-|U%-PG)A#Ha{1 zyN;3?GVULo0EK+6kAGK9Z66VqeO$_JK`WbG zFH_}(ak*w4HDs8-q2>w1~G_qadXJkj-X z;@&N2;YCBOjyyuhdIbH6t|N(i2T3H+lP|q;J8^4t`&R@o4foZj;jdi50?7MD(Xtgh z7vGI_TLya0?K|Cy`P1z?b`D8b+g5j=kUq`T8m4iXyMi*ZOmp=mm1}>Aov@lX`S(+) zG;@)EMs1vrtGa9Uw_#rP*AO49M2J+z%L6Eo-S+W#(x=)MrjUcoS8Ya7b9JXKE(zlN z47%(6yQ>3WtelrC%RV%d6ZrQtw;EnDVo;s94T{4`Zr{6?-QR4kzN)kQ8ubB#*YDj9H%P}a z5_tB6Y9jHm=`Z&3vQ7p+uXHCekhu45bcFXb_d{hLFB<|BWS&WEs>Hp&!3q-&1F_tG zxWzN$5C~PBL0;}Uc#-Tf4rLR$EOGBxS=G-9boHW~Ptb^m-XPCWj)bAP5<~O2ukvMI z?ol{?W26&dD}bTnbG^~*YGI#|N&9cfe_U@{hbA&?Ls?s)<1}MEa(C>PiI)(h( zaL%9mcFmk%;`fu>`DgYl7U#U+5=D^seJyLGr?+?e+s>+#u9)3TmEWZ@tT@2UpWEnn zy&+@mO75Oq64Qth8c7eK2&#LxzoBjEiQyZGJ5GJ1a1PAG8QA6pe%67R7>MA-VP01Y z)H>=77$&+}68F+JG)mlG{-GxAuFK_*z#|kXvtij51U*DKwoS9^LpF`yg;H0b+117t z8U>{TX!q_W&#fw(HL^0^>uNRVBxbLx&EWRB0tT<^LxXpF+khQ!!9o14wqdRh{jLwa zO$M~M0K)@}J5VeO7R!RpX4iR^G#Jrc_C*W#1%S8EE{u=2Ab*e1i{KBENv;pK{X9ep z?726oza@_hKdt^hL=fdpjbcO#qi9BL+s=g;0ZWX~#3p}kE6+boEZw&dVc13aPPcDi zQh2Hvh5ZKX*XGL&_~w5&!{=(9;hX=STBJjXn%W?CnV7}hXU}xTQJYS+HCX#wF-V3Mmdaqk19@RKOS+#KCH zEHEO}RTFN6x>vER?W*n~Y_7xVez7`!S%=l_0d?2k33ZSEk=4Cug3i*tX$HbF4F0x# zkFRpK+qZu+RF4cEJiG4$iJI1%u`!2tVrp~k!Q|)dTvO%dyjqG?-k~rx3o+PSd!pz1 zzio$2BIo)>Im$mAjTloTXP^Qpp&`t*#!cgv3uFiW@vk(JT@9F;rI-eYQOk+PuOng$ zL^Qkhadda>_K~AjQ)A&KNnMr&Pm%@^SPaVNP=rtep^Xsg?X)L8x}WSOVZ@I{8c5eJ zO|T^KV@cw}62*rliXTf7Kb9muOjSNCQT(}W7%Lfyja*MQ`WBi|0PEVkO&LB~4epU+ ztI-b*;(Ob=x8ZQ8*nUiqQsUd7q3F2_Ybc+q-n+eC+cFMr;GYLK`0hovULz4CjRc{0 zdxPe|#@p3EMW1D2*^T)p*zRX$sjEn!t6qlav6#_iKb;00JmDzn9Sto&T}S=7^&AwW zcjPBN`gdukJ-iVD9&I4E_>tRt#_U_Xhk^#t%EqIm*e-!88#b7K^nYnoVk7w;y{=JN zA+cg>7o#4Pj`=<{lJpq`t4<&yUf*X@j@S1ykh^wqZ^W$C-VYPBcl$oAQaSeCTiIX@ z$_u&OJZi4-@A%8t_wSb;?4qd}LQhFeX-s%KwIr|U05~+Tfq7zZSG!PN@%M+C2emR2Nwf*wI z-_bACbc9Dv$Hw<|Iuakv<07#Mm1qde#e&f1I^f-YKn|ON*%&qt2ExPU7sEjqJ#5}Y zksLOQ!AuU3uM!#dK#+DkJVcKBa}V$kIUdeBe$5?jYJHeA`BlI zwyGui2vXb8|KK1>?YWsvdK{+>^>SNw&W$|I1q!gA?%dQZ)}MR)6+X}Pk8%4(A+qBb zy=I4vGVi;+Z^BDAcDQ|;a4NOg=JtNv=^lpv&l=8nf7|J6ITJAXns|+P2Ac>7ISC{M*wLmVcdert zK4oV)PTq867$!GbpN^UZH@fZjSaec&y*LsYVzJ&F@Phz(4#-u=Q_u*<O({9hc_57d?01u`z7M_CG+V-}Rms+gr?g#Xt2rZM)oO{@^s6J@XICna%;j⁣z zT$h-U+}XG;ZKw5|V~3K{2o7?TcrqZ7j|8Dh?j={HSAsATfW>5tc2J7bjL7=??By7j3qkcwQ}n&j^iS%m9bu!QET(LuAp02R#Io; z&_pdCsSt;W=$XIVOwGI!+6$0%1L^?EH@|J3&qWL4r_TH#&2Vlg?HpMwim>Vfq}H@{ zh@sQR(6P=!^gl0hJGCt~h-#-rxoqn>83ca}oA6rks56 zDA@l0#*qKoYQ5pRy43`%c5!i($?BoDZnA#pG#v5NOzt;B_x?Wr4euvIUhJpaj8D~+ z;RZo*Zshe;l)lzIT-Yi_3_FvTeGk!JyX5ms}-3QR8Ep@`3h zdaTu5lV$MFms;TXVLlD9z-(WO?_Ia=ALR8*;GV1iX*`)-?G>rb_TgVd_B+^qqdwSj ztBwpImDP>|M-?(eb?kAyhbgobCvE7b`e_J_>A%$j)JVAZPDC)q?IYaPHXY{xuGtlU z9kkczHZCw0{1HDoUQ0(&;3f%?X{ljwOg={#i7h=T3zIq;n@ zoJ8;;9Y+3fk*LhuChP z!x_1E`-j?Q`$OA5q(0n1cK%)t)IR!=Zp)WoF?7N?Y3Sz(`FIHV1d!B0RWx@!MYv5m z?&9`l*Cn87rZ`8o$2K0S>`|iwrJXoI$SU{r*R!iV#HEC|j3zEPdI?^yaT?AE|SH63j;e`BnLx=dE0T z=JT34W`Ayz+U*gMT&o6nws?Gsg# zZD^58^cG%f_9U$%mzpiICmtm&{o>OSy`g`k95>W-y@tMe2@S0>L~6x*m3z2I{1_ZK zpkR5ZAA*t#HfEtCfATB6Be%g)=(DerJpGt;0~Qz3dVlXvOgL0`gf}QyLcPHoln&W+ zUM+>1j=-pz-XWVF@asDc)z?K-Uv5p*6`kJQOejU~kfJf}c>?N)oQ(GqjzTaZgE+gc zi%mPFO(zXtBA#Mqa|Q7vk+LJzP>${U4a!x%ajhfWFONYu+SpP5B3Z9y60BGIOWk@? zU~9VY;njExnfs%DVCOnK$#tq~BVA=-K9uV8f;#@(!*oENPj1%c=7kZWBi~4$rFxO{ z+aMB*41AQ<$}#RR$GBF+ICjK^Hp27T!ne@Y>^cm8)Gls|;_?mRl6&fUQs;G*YGJ9T zAl2_WHOzGwf~4$IA=yCi(fqlP5)y~OYV&SCtR+554|_0@x@YhM(4d>E%L8nv#!#rH zr%veTljfsK9HVJM7)0Lc`~~byljz0q^h8Q?;BN?wbRh$RG!XFaCvYE8fhc&9rT|dI zfC>vf+*?Ko!J{qFa;RT_L;ZTZRmo{@fhE1$12WuyK)3@T+!5fUfLCBFj1IV{n$9X| zVZbxnCZ5iYQO(s+tPQLb|6q1>bABJQwC=8aWT%M^X-b zpd02j#QmM8sggubBJ|D>x&dfBN=9gWR z#ZdEA(|x#~zb`s5=KnMv&hv+#hDeFiOmI3bdm;MS$K;=5xd~Pa@lg z0;OLw)AchB(%R%fnmKgNm0AzZI9rh8HGs*D@1t26JjH^e2I+<8;mmGKd+M&Z{Sh8z z#1c2n^yE$vuG-?DX$JArSG%rDbaqGc67RQTdWLrCuoD?PmsW>TnGVE{SXQP(Dzl80 z31DMRJ%aIhB<6i(FYVWW;}9 zHNr-eJrR1C$yd2Aa(2XRr?f$vgKcnBt-9JjBGdEJONVu{%BPoxKv2jAG%u@j-LuLi#@=EJ=a9nzQpQDQWw75+Kh%@hjC2`>{N*>w0GRT7Wv2& zC3s{C=GP_8!KU**%v$=RGjq}bJ24w)xP8+w!ub+G-mxAH-xFa7nW8=jmBRr1M8z>6FKek*9>cB%haH{1~0|61oM$$v^eAvY^^Z& zceoTDEhIlgfOVQD?h=0NO>i-l)dtsT&5m8WDWV*!}TcExo1akA4}Zn zNvN(DN7~yc3qOX4BUvZiYv3TQ4SbN|P!SiU>M%XA`bjwf1b9_(+j44SMrf*c1!TZK zA|*4Cz9+83wkUKYkD2RcJfaX7^J7-Gjl|R?fSK#+#aWQs#_Zo));;_Al0Da2hFa2W ziByjmxg{e#x<7QOo^%waW!k@kve)SSjlkF9Ne5R$bM-c&z^DBZo028_ z_fu(9R21*u7vVszeg52iXrQ_mKaM6gyLK|0N0`n02ES|P|8hpbHMiW;{0R$M3UoY7 z^?THJuy&$?kg?br^{@u?Vi$e~)x55q6g?Z*Pj@1sqFr8YGm2$f5m&h&aqs7$(7H`Z zY;1Pz=0;8Dh$ZQBcT2S7-Lgk2T+pLJeT!Cs{*PgI#_jIu> z8i~-L3~M8+yLN|6t^&mF#J$hT{%Ry&A3&<0uPE<8p2tzw0P#^XI{2YCXbfF@v#gex zvSr6(xMcweJue}36LUa9ooF@wg>GWL$$NFI^VCgDz|Uc)6^{eUo0wa$3spBUTjrr6 z2c)&cOx>|8lX)=3p#j=4Hw-5cJV}R+;ZBNe^Ks`y0TwN74!GV^jie_U z-(r`=0+}1gelQkiY%l_;NaXY)ro=V}mg|yK^XG+O)+9@ZQEwFI#g2Pm1>Ti=D97go z45zJJOP=DXB-E0FI1ABR@|etr zY`QB9b4$u~7%eH}ym%QJ$d)`$Ic`bQ^|aawPlDDvxem2tBiEspjJ;l+S*U}Sgm!ET zF*UYeYHaeI+v7T=o|A5Ny+^S^o_D=$MT__v2YW7lDwx}S8nIIji^nAab#GgQ*S{x; zmDi6&IKa&iUB+#>6LaOZVVFTIZ-kw(fVj|fr@B2i470IZIt*h?M4qSq_ASx@1K4lk z!CUq0a^kD=aZ}U^ZcTCldjer?~^E;s=&gnsL7*7d+0H{u){|m1Eh>Y?VWIkm7 zpNC=A?}s`J+EMmYv_azZ=lc-9mZ=0T9HjzyxdHQ zx5-A&%it+;*p+ACz_un@Gm&JxMY0$~cohUd;@XDV_jvf2wSOlg6IWlEO)7nzeWN~Dr3T)7GkBpV%`3UG&>XTr&8Lfb!+lO z?%IE2a{Yzvc4=|~|1&0kZisGj`)g!!k{mKQ0lLYljbw6eF)g#GAaQRetmS3%hx$XV zv{aYW0IzD%ApMT)0dhzJrSpWwN}a^Yu`S2Sj;JCYE9)YPz+*YUZkKHtuR;i33_`5w zvTUR0L86|Sq2H#Wcq}6g_brFbsFm73X`e_Za@TuiW+%3Ccv6L~+qTSxJAa1rxxk{+ zT&shc`(1V#`EUopPlsV{S)C38SB*UG-7XeFBrcv2mtE%~Z=ui0eLqmNMF&I_EM>0F zMa>+zv!bX?%LqDQFwdO zmwO2+ljEveY<1h4a1A5e$mQaZCp_Cl&)s1HzCs$xk#-c!yNKmCGw~!0&qEyTU-%+K zZ=Sq{6LV+|Tn%Bk_3{NoedkY4G}es!+CZ48X7ZCr0yU6E6Dgh(BOOk_YVa4n$zDw; zxunOu_^!O6fI9(?mzNkRC(mMtj5amdEg*$uN@2Hfs=-(J#^k>^uy`0u;D$eu?A+m50^`bAYc6*(M1z%ZU^X%fSLhy=mRP ziyG?}cA&a@*?Ki_f1J||j@%Rb4qWz%|GFL?qP8KKaH>e>Ak>uK{u@NgeG-z$PY)MuUdWll%8MQqj-LbLa*fdhmn@3sm@3wVl56ThGP-X3%> zE;+K%|J-PGJ`W#C!IRdn4Xj&&hGU;#5yT6~pI^HKLl?lZr|DSiu3{zW!^A};)JWw^g7 z_Tqq4y*~G}Y-BF;@A3ly%7A}R1{{4o8a{9(?@hc81-aj=IP(L^rCHR{E`oqQ#OPE( z9Q0T0S74Y%I3MD%cl%X-P=q~vhn0~RGr)F#cWn7a4(-$6!(@FmfDvo--$u9-RqyM* zst3<&h$-FS$SmX|I3t*NR=@L0ju?77o@2$NxSV@)?#ao`S**WO=R3U(J`%auZ^7kK zI@Akzu_Jc-T(y2ax$(9Qz|&^ce*wnrYjgWvm&IoS!gmH2H+Xv$v`3M{%{O^nb2Xh$ zf?DIUg|ci(xU43Hrc&)VIW|`}oO_k>GKhcrH}|@xB=<19a@&T5sL6dMVC35&zU0_T zH7_Qk)i~MS+ib2S*z4Mh6%sWEN=AKpKm=-N~M>u?j_!|^b>piwok@w!cvPq{_35%+H`c>jNF=>7kf!KtR8 zby?2xoE16u=j2J(QSZlsKaK|`x-M1RiA4qVKfj33MsbB+A2{2>7ePS9eW zEPsh}2CUTi$B*dggCx8ZQ~nqq(_F_h=IZvrB&YXrXE&!_8;LzhM&c)4+Q@@E=`$Ic;%jH>iQXE@p* zWX-rg^(4~fz)!wQwABGB^`53gs~mtIf}4VeQRL50)Qo$BXlo`@66jC#_<0Br@{oG9 z9F`+SPq$)+(;S$93tokPb(2D6zC#BnZK!gwpMU>(r0$xU4kUgql;=r{aYlnJHY-w7 zO;}zsqeZWhE0BmWM~M&B$B7HRwW{w*4!||Z=i0bBz%-B|%DU*cz2q;w;kUi0e#lnY zHbmvqZ*#;t)`X;ssZNkoUhZ;W4Ya>RoBUP~5~95~)`&1BRj)^!{UORUw3`?q^w3%a zT0H$7YDG2On!&h~XqB`6O)Wa?Se~k;`M{&Zp=NRs3IcU?66z_glcc3obe?iZv<>g`0EFh)EBfFvCP2}^m9EW$I71WcPhz`Sq zKnxQkT4MEgXpa=884Mb)^bl#sN!8?DiF@C}K7+;4-Z%2c=AM3$95V9f3TJ5idxbgo z&a0XH<2!JLaL;Vt`#HI@eSghaoa4Ki>#n)=6pHVjH|#Tn2V3B^BT(VYXC}{p(Z5o^ zzc|nL$voemX81nN38sAH_P%a#PyBV|AL#cqm#xre)5zaQq~Aw;9k!#Cc!qy@6NNWE zH!N_&0yivh!vZ%faKi#OEO5gDH!N_&0yix1f6)R4`q>S9Xj?tI)VZ#(BCoKleElj9 zmtwCo!#RCb`5I?&X|bmme7>7Q@*OSVtuj4Syt{WFUT(_-dLb1q8Y^%>sXGqhH@1f zR^=Bs%QhC2J2jnT!G?nJRi5IqQYZZxE^u63kiV)DT9RhYqE!{(xhkL9yMEPXC;ic_ zP1ICp1^s2M*`*utC$>-re~N3Jv$S&k>H<37;g4bm1(i}!RL-GmVzkmSC;oO@seFCe8psG4L}P72rX1lc*o@wVf!6Wg79)ZAt4aw^uya+I?+EC)~Zrq)&Qkg?gg>*%kq zbtQp8!qy-S!?uf1lPusWFE1+}DBY>75P!fZi^5=2w=N7nFL! zZi^65jPOA1kQx`4I*U2PMd`E(B1&&9SiixuC0uuev!cwYhQn%TQczOhL1WZM`Q!Am z$`a}I_&a%PsB#_@fd4>HNx{Z~lDx_ddBvp|hKOp@X3ugiT(n@?JlA{`Jt+>tp@*)y zR?vu02tiDO-BjC3$TbT}W3+W7P_lMbA{6S8*$HpNaP$;(DP3FO!C&30$S*J6fI!g& zscG!~*LDwvFm)FhZ-lO62|8Z+54ZIW=gSjq`om231j z0yFcqLhV{xshBmiB1XGAXNL2R44R4v8d@=OXoXhd%yQ1pS&}z%_B>bKojLPedGlO% zYJ{=p;7=mLks%mE7vHdM4EGE?j!eo@sld?3G>QI(>15<5JQWPm!$*6*8Vn{OedufW zBOpkRd_5T4fHe7O9A6_Xd?pw?iuAkR2nNp~y@0d>>4a|vgDED|do~!Hfb>_5!Qc|4 zeV-2oHzPgqLNHj5)Q3asQ%FC?b=rqWM}0pSyo&T^Nc);KZ3NDfvyl2<2?m!V-GpaD zwjmvaXY39j{R+}kNO$8A#t)G;;*syGNHg%*dtaex-@}t{Sx8^|uV8Q`(%PQ{gFBJ_ zHxBa;BmL!j!QdN62Ye6=o=5uCUj>6UJo0ezL$n|1&yc#2{t0Oj(!RgOoA^lQAZ)~ zkuE{HryX`jnt@*;sYhCmv<)eJaMsKp!-I=7!{#JIpE#?n7JfkGc=b=)P#+AAB#IeU zx_j1!;NMvMvpor)0G*bQG&3Q6PGamP+fHq2?@71ZHe?V=xh~!?(uTp8hQlYcoP?w= z8>h!xOg9-Jg7Mo>JQluHh&~VFSDAGD0Te%YFc@4+azgbN7ic!R?p9GdoTQMebqVQQE{BD#V_*O7@Fbe+^<4K3ZDDRCi^bUL^#GiCHYvsoD zMR5ygeu#UN`=fX)4ao?g+=Sb)*-`izA-oOk8}Yqh@EhP2l3_d;;!pA5JHRiEs=qi? z-wk{K<2f%1e_se+1pLj%g278s{67xy-vj(*;9tNv49PcrOArCIuMzkiCxgL)sQN2I z^;>{{9r(|p@SP!i0QiPe!QhZ6{sTh%ZScXvh$B0r>TeCz&j8+hHW++3s(sbmJ}2t9 zfiHbM7>tkPPrhVg5!{9n(A8q+7CF?A03gm;2LR}?;*@g$=I_}dWwwjxf3>XVF8bEvH;z&(uDCk95fwQr~| z#{%!ijb=Jngm~P|)mg{Izf4WQ_zP8fsc*E&kWE=*>>;~S} z77W%!+RL<;$LtJLISl+BtO*K;;mm}jM~$-+(jPIo5}Y+=S3<^KF(YBrmo4su30~{0 zgzVCU2{{R)auPD8B{-)gq)$sonwDUrr(?BC;Bypw(ET?)H!N_&0yivh!vZ%faKi#O zEO5gDH!N_&0yix1|62>JOqNYgQYmfK=%c6jjT`ylQ&3IA56$prPrgihDLC+Tnc=e! zWa+GtK77`Iv_s+PoPa(${;!|Q?KGW3(MR8-)vFA)vHYQPDEi1#e4ME%1^KK3<$NZC z6c1NNeN;6Zg2`gqYSO1o)z{B~u|?z$9OReyCAJYM<1OqJfF(n6JPROy#h`h-fq zrPA-K^i7q%uhQSE^lvJ)^pKK!s`Mt6j#ueSmENP$LY3329YX5E=P z%sDZ0Oy+3km{DU!jT(L1D22%>&o6S$D=w|vEb+s2{H$jvIieVw?zj3#uXw@B{O9e?^>(uGD=1PKcoZWTzk@UTW==6VFDyi<(2U3?xl0IXY zPCp}05}dw{!wrPyQnbym2n~8{~MgDnnzY&2R+!Om#5&cX07+N>^043-4O zi5w&*vnVe0Xy$t%UF-)t<1IZWA#b#a5)fN#R@)8&4VF|;n<+1z1evLKN=3#q5s`$L%JCI-y*o599%GXpkzECCq|#M!?FO)bM1NV5NuFt;#} zV*fpqvJ7V+-Tq}_J%WM0_MSv`D+5k@C6Q$^FvLz5h?Y?dWZ0ch!!nwI5n9YQfU+4a z6KyxcBKFhJ*K!BrG<#1{brJ(+`z7L+#emIDKP_XK%s`yIiTF)nAjv+C$fh!oVt<&l z%eD~b^w`@7lf#%sL+qD{_cY7xKpio}&Lw`+6J`OzfQTbY5hi{bGWilF9K#OS``0Ls zSpXKA(K6HK1Qq-gOMvG#lNhq+5H~{y>%J z7dfoSR#Hc^pGVuQ4hJD@cKV$!Yl@xvj)nwzeqs&Aj5WQt1(vj%IvS`F3T$zJt*k`i zJSynJJ#RNo`-sD2RobT0PAA$as`R{G`UGrcn5s&%bq=H8E{1GX+M?5zP-%`T?W@y%6U{VC zQ>8;xY0}KQHG?aq7r5I^NvhClYlq&6WEaECcxt`f)T%RYfq4zHROu+4IsNjFVRq6g z<`Yn~R_>(43~JDvUfUUG3(4>Tw%X={d*UThc&@6g={%c>=e$(3-!+St2{ zbxRyJf}gV`krx^3Ryw{#^v~N;?_&BQ$7>|=h)%y8EvSYtD?7f`Mq?snT}g#zxL0ar zy_0mpT`_D)AH#v)!WvSmdu^$tm8q^}t7N-GvNhGcw^i!3R4)i@b+F?1NkvR`9b2WQ z%cZ8Ky3Vbs#hRg1uh6>HL62P+%51ic5NoR2xy><`RDaOciwtk7+q2DaiQ2kVuX1T? z&-)j!lG>kTqCEgz9rKB*+}4XCjH#|^Tj~Rvp~7Y*zciE+r>VvZcwMI9`=ZKiGwW;j-XpRq|j& zJ``k8Kbz`~RLQ>TAj?WiFayGe)V zIeJn3F}B_`{>TNh2|rnOq_M6@>v1Rb>&;|9W8DndhLcu~kH)&i(%nw!@IvWauUXYFSmJn>tkR^zE2TG{wWh0Kq4oHfl+2Sl zZFWhW_|lto>VyrGnMa=0Nkhw2*SaH_$6B6ssw_CSLu$3k%7f8V7uezGpwO{eFSxoR z?Q_NYd5EJAIsFE!a>h$L94}FYFX;uls~qo>Ugg%_qye0~!YAzI2~))Z;t z2EH=2+GteupdZLJWXc|Uc7_!Bu99pxun2Rd?4V5RAQ=po$R5nJPLl9K*b1uTGWB`0)v34F^VJ)gpQR#B!6=Xiru0z2urdv5b>rTko=SmR_>U8dR6O zYf*u#v5GqVXBOop`>M!HKeMnao9gPhhks__Rhy~qKvmDAY^eu7=7DTHv~V<$&{j*R zf3&pm(Ez#)ZkwQYfsI%}bgh>2$V+1ATCSAe&cfxkZ}DomQd9=%FL} zq^{8nhb-}O94>UcMd9b07AJWd#x}L=TRL`e&uyymFj-e?Ce`mJ8$V;|Az7@^(%#WE zQBFGCf%WcZ>bRWe*j#XWvWl}cqxYbQ&}oiag3E(o=> z)Y4D36k%x%DHagi`6Ux1F+ZDwtl@w+0oLK!I3PGI(G(6+HItsh#Mq;O2H{K6W@Wca5ueEfHhZ6J)+R|3W%n#kewyUG zB>G5r2^;8?=qG0jbc2g5_?ToFqgWP%SoTW9@|kS~l60+pWo90xy1iBDc;KDt^jFJ`DyiqM%sl0wud7(mfLST(cKnk} z{AaToxBIFb-=uEp&=nO@KcnN;w(UO=-wnLDT#9H>g$ub9$b?W2!_ zJ;5Z@Y;d&7kwYzu)e9P`((dQS74Z~}?mQQ02G0<&)B~ovm#Z9SsO=*~e;Ef>rm{7s zh7n;ZqgnaNJlQFY=6=dxvQHY#H_4uNJLss! zaLml3%UHKu8ug+ufLb;uv&kwFo)LPyzIT-9KHTtsnajkdfY>%OqVL1yj7~i zPc*Vhbd;0)v?S>-Bh`{*+8d(EaA}3b(n{&(iPB1LX{B`YG>Km*-K@86l_F`iKDrJo z(|YhzZv-8TI7-LMrcp}A zWa;{*DY}lglaF0C-Klg;=Am%el&5-Hdivi?s%O_oH~v(IiyZ%;q4ZB3#+ZMOj8rFe zd}p{+j-M=LJDv&YSZCs?8^cT5vCec`l#X?#99>5Pc}tz?t|%SrO!>Nwaiqgzx(+L) z&ii#(>HLHaE1kcl!_fKL#9)Ec`AfG*o%v~5*4c#v@Z>hK(*n~_X;*hLM}P$;UTx4q znEo=GVTI0fxm^COHt|{m6SAY4;z5CqUn%Watix-x9xqWNUo>*xJ~K$_z)$tE4sIOU z%QeA^#({FW>D-ab6Vi)D?p#ydl^t?d`l9h}T2AxAmqW;RjB47`7e(JQszs3=9A7f3 zMNw^)<7*`Fb)!S>fUp?cIz(zi8)*8-K=r;+ML(<`e@atJn^7%}5vaa*vm{*s1brMF zsO+W~>Ou<9R}35-O?8K>l3C{~2JRbET|-s!BUJl}VTtr-_+llA`Kv*B>&sQCt2D!> zI(WP)?O7%I*HQzGHer7^C_g+^<;dV*WZ+Xz%X>1?)S_imGIKd*xKp;IX%qGD_jN5k+$2|yKhO)>Hp%mk<9b2ICdZSc$18fl`Asq! zoG_%*DV3@2+}7SJAzz-XG#S*wu5%M@K+fpR32buE4_h0~>IGLe^{%B_e5CP1gF4bU zx|xjdra`S5E^SJi&<|Aj?30Nm&rwu;5)S4f9{>22wv&F&rquouxEP zwc$2t80@gvFx7^+(lFTL@}&D^y`9)H!BSt*!2?y&4tw+h?7&!epFu^R#wr#}&3;60 z<>9K{v?P&A*BZhbD~y`&(coWYuso&oRjVP4nnu!>wOM6Ikz=_;y4Na02I-Hnto2$) z-7>{sxf9g%;g>^@8V>XZN7>#fhMOh*l4Kq;Qw-xJzs1RX?lr}*Sgx(GB~xq+@G<(x zAU936gx0@WpZlo?P14H$z$l@QzIZbnm($&Wi#Nm|Al}Y1{T_1Ctw-_ zOYB<-n9=iI=(*CKMhs@A(DYkmuOz_DT5quTCbHQKc$nETK2eo5CJP$wfiYp)-G zE{6U#jCpuMY%>^HY;@ylu@NGU`i=C8C%>W6IRIjxW3nxj-HnQQj}}mqBUm9hVIWaTh^O`|3o^`g5-N0!pnHkWDB<6>Fc~ zgf%{iFI(>vio8h~sE!L5s-B=OuGb?^AHxCKg!G^*GQ-rKWFSo4J?`ZSL$4B}y2Z)Z z9p~6cO&YaHBZ+oAb9;I*Gtt7_4u`mnPmAI<{-y|S6GGe^^jCEZqnO(hiW_>4KZXNI z9}{*MW49@+3dGR-6Ua)zeZ{a;8W5~o8tNK`SP8yY(GQi(KtI|{^rJzLrYfXVi~%%I zLMyeTyGYys7B}Xa>KpXx19W*@eZYWF^{ZsI-d1Y2SyfltD@cEps&DX=gF;!R2$$xD z-UG>nu!u`3DJTV)kB%mi>e`c+xl{ZqgkgKU18RW z@U24aA3-2D$I}P*Lot4AAl+<9dIf-mo;WaDV|nFa zp(hT^wm3rAEUQRYJ7eg2l_<>g#DO`+w3`UzJ-(P|qtgKk&G16q<6G!%SEze@%Oyw< z>K-2t7ywZB_?9NH5$Yb_LihMW-Q!#69$#czh;zD~?(s2U(7f4bu+u%hm}V&h>WINk zcYI=cLKPs*sPP_#FtO7B=S!Gy4AVXSYb28Imn}VPCxEfg{jw$5`XwMV3*9eU91cR* zEOdro3EwaO7zA;2zidhG{XPgH@0ULWjB7%C$IT-?eOROL{c`;CsAqV9r|=z1Nfh2g zmI++`c63ex-;_KskVGT2Bw|6ZPF>xUXz_VeJ&&v3uBy)pRWCyIBs%ZQ>q$1^~g;dLF6`eeuV%H~- z%6g#@Uwk0m2{y)I{FINrEV}NXG%W&g}#Vg!W8`}Pcw$i_94jP=;ca71=o9#VhKJ)GC{rlRF7BY6@5t$oHj}}6(c2^ zh4J_S5ZoKHw&0p@n%HerV2KtNAb2UWk5lZa5%e(}7z7JReoF^Se(r?Xq~)>%DXl1> zmFh27{FW!IBEeLRjE?pMId#0iSOO0)!4JU>~oT7$OQsrEcpre=jyf{sGyV>s{( zDZ^FfMYnaH-qyr#s7kA49ZfcVp)NsccUPRQJ2z#K0!tu&EXkkB@{<&+?TQtQfo_-b zr}EY_Wb3K7DqAPsq$;h9l0Q9K{)}k(t_b;mC1Z|Z`HwG`Ji_vy3CSPRFRHKcXd=7J z!o=rPrD*x%qvhWoEq_9U{NIxNp)5Z`v0A5^g7#zN%JvV9ZvW6w`=_W%cSf~;ShW0G zqUDbW%a3`RaNrLlpJq0LZ4kBJRCj4d{Iq*CLrelyz{40-N#pL5 zlK-LaOlc;9=Jzp2jxrwW_qlo0iGiA1Nl1L0a7B z%%Bzww&0*!G3Znb`YHzXaM&KC9#JPxL&l859gF6mG6nAetQk2ReuQro4o^c(T9vO_l!^Vp*-#P>X52+ilP2X$)p-o>dxP>--1pq>u zJ{qT?P2UD!LYuy=079ESQYWi4yZ1hz8N5} z*a#6vokx1{ZF6j^N4+4`oBO7u-1=hdcT zkaXgWO)4|)(@zP+Vl}N>8EhSbc3y@Z3@De{TG02z2XZ%s@Y#4pm#iVfz7^~ zfC1^$1xfag2yi-RKb&l@Az)w()ptnc>4_a~Xi)1hWA-A=Ue)(L3Xyg25Ygx}{i0z%$OorRadj6i^1vWRD{=Q#Ce#S+f$dR}t|ZWzj*0GPVy{T`|jy%U343Cp=Q(h{Tn`3O$!FY}+kM+8YYIsUf>BYBqdDyF95Qv0xponw7NZO)e^1flG5k55v#|N31EKPeKnv zvNb6UacGDZ8#@I>;Ht8;1-eO_?Le^VshJY)h@BKWF_u6}B52`mln`ul7)%MVv68@m z0(*P}{REK4Fog(H#70pd?8O-jvmI17ejr4SM4bfA0F^j4g4@(y#&kF-ifp<E=uK)P{*$VN=R@UTdpxqkFLf^?rI!Irl$Ob%_IBf$!TDpqPj6;w$x}*QQg=x8u#yw+Wj~S8-vGN z*8ydT8ZOt4y@-(&J@znsV)T&}tBXp@qw#CP8e*n>PAhfCq{PvkTtL*tJMa26k3 z5FU;&<2Btwy%7p1RNoOPKgz%?#Y#Tzc`sEf18(KO&B!0QGY|s^Z{N5 z5XK84<+N}d61@+JltYwBIdn+$Vi?~803Bx^0xW`JfnbP&l&0fMU_(ph)zHA(f)%L6PDSw#~xm z5hl%OHjNa6D6vfv4y1-T!br)%<+jOUKJ*@1D;yp%r&8Q}LZloNwvANrmZd_R7xp?~ zd0*T;SCkzT>rM!-AybGfk(?<;dBn66LM#zQ-xfI@vFwB>$`YknVz=Rhc*t;&pwt#o zWXlr0=7`kgXjK*~VKi;>L~9{(O^LO_Su2*lC`O+Uy`TV^2mPTyp_sT-+;dPYDir2S zF)UM3b7rVMc;QC z2RkU8$dJuAIF+EZkwVxCMW3a@44$_U&*u>e!X_)s6Sj|uvah6cO3De{QC|31*bkBL zB2%ACk$}!ZPu}SjCYFkCC+T3a4HN^>4{<*dLl24tKO*!US@b=E(6<+g+YX9_nZlHH z8FWj&HYbB+} zEfte(PBHPI$R&ot{#TNdI#Sq-(;dQsmM6^>F_l8B6_!zAjA=`u7$_T0US#kH@$z6X zmfC9iQlaQAQS3?{VKyaU$P8wCPZmo}skVc*T4DJ;Mu`ohPuX{%ftiFB3d>oMVe-_n zcavVGc=VTPun-r-c-C)it<=vWUA+bR^?qO22MfbmQE2L8Yr#OXTqshmW?f27Z%5bm z8z~Z7M885BQle5g+`|5e7$95fBF^wgNYnwr^99l4cm)Jt%3BP>V<<2oZsjTV?y_h@@(f(jwq! z}F4a$VmoD^wj2V4za z(+joGJ27j886&TOybGqibFEmkOT@!TGsT!)BC}S+d&K;Y#a&!DBvXvuC2r+H%Ui@H z?j-AuNU=+H@En*So}3x#FIy|t?-FrY0`;bHy*Q7!?_*KIg@ZH2lwD#(tw5o8OPJSE zci5K+ypMOEsc$BGq?ocvB>qB}Jz^25yF^gGB4SOSE0%f0ge;MNUgRAVTX~3#whb1; zKOj%dwapcU9+876cSJmJP<$Do5QcJI7OC6BO>2emh{%Kw_dg=~?h*-8iT~io#2Al= zGiEzPFZAyrF#7fS8-cL9nY(#p)!)Y6!((nk*_z z@MoNZ+D40>XafyYFu|ZTBNtmF%unls%VdhFg+@z7>~4`o;tF}R7Y+aPcgQO+~P zXNrD^ca{%C;zr@zMUCn?mj<-?0b#2XafqMB;SOP2BVzwc^mt1o7&DTEZHh=H#O=u< zWfIM>VzWs0q5wE!wlcwJnkEHIW2z)K5eOeJ{YhE^ji?m2eL(gc4M$Hvb=!|cU)i)I zO5o&kF^GOaKm*okR}g0188z>U7Cn zRM;ruD#d`^!j5$q%ttcki2hQv2@(4wStH(d1%5t~x^s-F*B4?8Pl{_5Hjfx8Svn<4 z`&^NPxb-x`*Cv4%B^<3H_Enle;eSIhjaWUGX?zOXRM8J>L^ME#O#}vvndBuD_-rtG z5+XBd+$W}BVgc1qkGSg)wLp%~+l(2h6c%Pxij@axUDq2efQV(J1r}PA9266Fi#Z;V z{sE279FzTE)Bsy_IW(XUB{EWIR3ci@aJQ|cj<7a}dC=sR55&+H#l*+NT#xAWff(iy z!w-p>7y}?2h6U_7Vf{c1M`)N-_wdM*7ghoxBqRea*fO@kA7~{$BCsPH z5Xd${Kmxe2a568;YImig-Bq+J1fDkaV5ja!K14H3oBpwgrqgs2z8< zaVO49W9&G8xHHCaI@30ZlQfe*lKy_@-n;wW-IbHH5488a^X})l=bn4+IrrV8cUAR? zlwOYEdK~F1`hg+*LKym%UIl7^0G$7dzTx+QhPz12-;p`EBd@!G`X2n<5UgBqFW;7z zJ*Y_@Z@Mq&6~WIwnoQ~2f~V24R8HSr)eog8NVUGhe(R>3sGrg8Y`UX|W%D9~qnnd! zFl1h2#LYnuB3^4G93feB>xygaR!b=&Kvdwrp5593Ioo7EzyOSx!K3>949;sI0Wc^- zReoG~`=~ZF*G`!Q^fr!uxh0i+lj2Ws(UGvwG6&B^y#u347Am@XffLo*$mvzw9wfUN`Uy;VKDpa&Kx$pYN}9kw0(rw#9d zr!dc8LG_s45_Cb<0u_Si)rKkV?<1;5bsvMO?tzSnX%t*+9z+EGbCxJo7ZXe?;*q-B@+kQzRuljS{ikS{M1p`7h0r<==J|^$g8%;T_3^2!iNUwU8 zvF|^rM=*cvtLn~_ZYQqSkb{Z@Hem7sgq36_LM)?(BrAX=J|x@%avZ7D38cY%HC9|T zSg~+b{~Cxcr&lhLM)m~jQa{iSyrq+`QwZD*Q52OJs_IA0V&ENiSkE{(HWvd!df%t@ z5lEOr0DN!_bLzav(YWjg*~l^^9mZ5G0#omsx&z~QGm>M<0Y&b|+dWnN7={Q&F-YT{ zpjdShv0Y2ZI^vVwDq$L}lpk&Ak|q7Mz}yDwYbgS9!jA$dgKgJ0Bj?4r(s zpoaA3H$kJfk}KT!HS|%xKKzP4Sk+mP9~UFCr5HeFX3h4 ze+Ud_ghKb~gTY1$wH+XTRC@(Ql^^D{zQi%K=WmHgNUpoM>;utP_02#a3$Qn}8zH$8!#CZs9w}3)0$)Q4+l)70A(o;KH2bY5s9ABD=&iKje9STqURh>JS2;MtjUFsw($u9-LISm$Ak=n z1~48E&FMY!l#%*DwrB)uuWjvb5_t&UzKc9WiRu#N8A{@8od5bBOtI*`xyCnrf2KPj z#8UFOMrunW7q9B|SP-7q_+qIpSKWeX6tnEI>lgJ-XuHtsTfw*c5JGm20xLLb~aT7!R1gs(Nr--v>g*s%t&k*a~d{s9U%u)G#CoY7K;HlK*Bj z7nUeUAcZ;ufmLbS)@`-zpbJMyg#@R1i9=TioLr<>>WgNMeH@y z*e(6pUF%Qiz@Yfsh=~NOX^vf#fa*fJWlg&qAC`sFM#r@w8Y%xzHb_KTu6786=n_}xM&WvFs-L4P}u%|Sow zt97XY7DqWol}nd7=8hWQl2PcE&y~aM?CkVZxdK2_ZLrboe(pHSg0fn-KBHTn*(NHC ztHVZoN8^3T5(_xU3F{DajB-`7(cGOW!-`aZl7KT zo&ohVG+Ph>!E|?Q$AV;ysHvaPt1;^=LK?ZB)5Z$Xc-UfOiM3$HG73p?q>YMl3Ob9` zDEYkJJe1dW;oZ%n8lNvhSKsjr1hXOCi3J;nVsP%ft&3hCK#PUxbJKaoB`*Aehi|`8NT1TjZ7a{?d-=Sn4?g$9>JDT zeP2p(&iE|n=C(Kwu*rJSaJ@~68*xf9_U8I^Wy%I=3Wf}?rk*#`4ufU8juiMV+6(?mF50L6_ z9?+XH79bdo>$PYYB*{sQ)pF|>bVqP@RAce93Ybd-t&fTjmoPHYw;4e< zlJ5U^s%knhS-)yN|w;rlAfLoL3+>?6wWvvhCk(2tpmytD8D2aZt3NE{Xk2xUMB`*VXmjx}u zsY08&VLz*&a;=~T3i*kk;}sclosd7lK ze_@)*m6Q=yN?~R)UCd_{%*k`ptPp$`s$zDYk&JIca6-V0JvhwJt7#~1Oku4KrzTXr z#?dG;sfMNyw9!1W+=k2)JRRC%jYClD>X4D?rj`z472N_3j~(5A=(r-rB;T^Uwq9(R zNxdd2j$3$6Y`|{a-=-?h;lbei$RmftgGY`Y7zt188-^D`Q)YPLXt;mh{)b0QpTHBL zbeuYEoJ0a0#r$+OoXk!mBPG60L%K+nRtxS;8*MG>Sdm)S@Z3LHDrEbAqf|t1rHlRe zNUJ{sH<#sXSSt6Q&dwII)3EgSX9^P#IK(Oo670bRorCB12aB8}5sWGEhYLrjN-^o%7&p(;Zk z1}+3&o&eF!@&|r+rz+>{xQNmb$Azs5=s0cNWU4fFNu;O8vc){8zdTu*tZ#9313el9mM}HS#kZ z&)TwR@hd!8nw~%>Mq90nzgHp;qtm!JwZ+DB;@Ai&yjqf*&gM9PZCt@M2*i}5%All7 z)>c-qF4&Fd=(tdwLOCD~z~{3W2}_I$OWi2T^n5X001GmBH!YK{jUY-kmxL9#U=>u< z-zZScY&KVhL(lwFCM4@9m4)AcB1xpCtz&4a%1x*9hTSy|FX0X4$+^lzX}&0g3wDYf zH4dL-yuwQ22q-JV0kB_rWdDhGZ8TO^C2}ZaU^-jH9l#ozlIAP7#iw7E8W~k7RY*#7 ziVQrVDK)wTH=b3(!VTg`Ea2Io7bSe@c!<$%>SalqluTxZ-9QyOrADPNdQhc_>{;g< zRyA~?u(R;^!ILA1gDIuX*;pcdXCnuo$kdTulPmbj6y8=N^8#myIQo=vER7*wfWPcW zRMVJ9uN!i-h?D7tTbt?w#MXekCSF8rk~w&!Nk>JR#<{``(1;a#${TuD7D_aG%w!5bJaYKxv2jeenGBH@vVIuX z;lZOaUxxh3nF7gFQH8>=c_bJn06SesM1aCma0m~a!6UHz)J6}-0;?C*qST}Dt#n1P zR4)>q%>e`_L3L0K<}M(zluT)Qu7IiloQwe8I7Pr(6sfacR8B2vtljo-(-I1bHc*anZr9)H6448v-)Zor& zS4kJJ9I3pZ3}WWQdsH}AoGWK1wzJ;0si+mdQD^K^>C9=k$d=Tn3pmjT+@^*wky>pl zSZb|x5*-7_R8J&Al62j_HAj_sS>yQ}b0JtKbvnYhFq`sTqG60tAVJ9xz3Wi$>4*x5 zd|HNt;a)B;GFvrYnw?M|IC|`W;h_a+?J%slnGz!ln={eN>eQJKwPcW+nk`ozB(>n7 zQp!VGYtjz1NC-O_zlYWRf*;mV9&1erxJ%RQ-6Z(y#5ua3yZQ}55)y$7dpnBA+)HQln zpl-ysg&q)(fm*AcYYJbdUTzA<$0kj#pyrJy{xVSRhz=i)Z&jOIf!f#v%6i_s1pJl; zIFvWoL;n4r`!6_7o58U)9@O8i7QKGQHhF=+?7{D}aOc+uk8(YL-xhf5ad=}rcpb)H zOOt-A0M2rqpCrcR^#uM}n$QEgwORfDVhQ*cmwp?5WFSEnGbtAYMENj{DAe~*ptkD~_!-Z&oLFZnc%i+=_@ zp&I!{9`G*o*Arq6gHq78Vcx?1lSQAlaQ`6g&sw;DM)M^L_fJv1EN~BDc>J=B?`%TD zHp)vD?jJbF!)953|ICs90=%~|d-XUppS?}^LmTD;=5xcXCQ%jXd2JH7xsU!1+W7vV zje9NJKjes~PuY{yqS>eqE&(sueEj3-&Re+edEj>eUyXLXv>3}?eago7kICbSENriT z4)^B-9?yeMUs?kGlFi3I(C#C^Uss}WetB()eE!qs;~#wS<0ayE!LG>q`=_!D2)wcW zx7+ysAtI?I;vWFK6MXO0MU$7~5AR2Eqg*dqxR~t$ zad@VOrd|^z_WNDHi3k7aq@OaM#9H`FzMc|CR~VM!a7Q{5)*yW5Md9w!fSl z?hZeCV~KL#0i1Z=;I*p*>xxduE$(0?*WUGjvs|D5-y!kWsa`K1I(Z`f_(x#vvGAD> zo0_{rBMw-&?;2*z!u_-3k6HNV514!?Z}Cc7xbK%BZ{hwaOclV1hugjSe^%m~Jfpvt zZ9e`XQ-5dS{xOSRv2fqL%+~;Cxp&%f9i6{n;m%2wga5$h@mrk~k- zc6<5v;5<0?i+?`xE(`ZPgd7%l6a(fy4LJFLliOX40^q&wArd}q^Y;&4y1;yZhrPC* zj^3`=_-<(4~~Z{B-FQ)V>qY8o?|(cNWIo!VL9N6RBN0?%mNm z67(&_sZcaP);^n?rM+chu27(+F7gDG5OhJYsOBT#$R@LxzALI~viANaTBFqV-2?Zc zqy}{oUToiu7Y`oWcX%WmIdT9RChDakm4MFj!1$4UhY#+LzY$|MKrms3BM;jg9zJkP zg%6D#9o{z<9)0k^<0B`m0SXcM8FQE^&j~sj)bEWJh|?M9onV3#W1g|fP)NM{#>y+2dI7k)k%(-~E zrX;A(oDLV-&zZSOIUWo3O;5x@O%(gaoD*h6qifz%i(J>q=RksGui>Nu#E553>w8U| zYIL~q2sOoJ2*ooLyHMSq4s+?L>3X!Cb)43+LNcrQEEi{Hp|;G`_s@{7#+L{r?jQQLX&i%d*{%m&m6mBmfQQ4^S$Ya&K~ zsBRzFq1Myft473=AV{{8O@40d|dpaKH-E6CM z3qcs3D$_p0{)y~nVF3{{2D`Ynl>tl)dq})J7G_rlYE!o<{8Bdh9EW(k;>?8hgNT7G zx>=(>Ge|VEr%0&G3>7;-oq2&CAR}*$HO3G+8(H7!RHKc0Y_E}SCrwUlTk%SVA-JrY zTgZN!GG8>!npu8nd%m+q$#ezVT7$Vg3^QlboNm(7Q;&Q6Gu}dwqqmn!rOM|DKncRi ztO+OG9T;GCc1ER&rAju1jpV6Qb5qk3eb`!MK>LOd_Epk(CGRHFA-`y ziKch<9vAkyh&J@o9{~Kv@GbA^@9aV@boIwFO)j?%u#bvofYO%b(mVT+3wcH&FDwHD zPcFTaqkkQ6sA_8Iot?>rTRen$kBUcI{yb8DXOD6rPZ;Fo>hJ35!qa&7vq*Ypw{qcL zCdTF0-$0dm95=+N%g@=jT==|==*suo|CCKXY~wjQmiun=>d!8pm+%5wr&@YvZ~Wdbnf_IzC5ku(c{#h}Pi*=( zZ2KJ=UAe9w{~c)<#ie)l%U3_e+;I4-32MJCy$j#Mn`nBqXrnHe@HzYF0+-H(|BV;X z^iKczoK4^D657zEbKoE0hA>xur$>0nra$W<+R#t`Q@~mNfEUlDAM@ah%gcqvu4Z7- z-*p$v)Ayo4+`DuREZ!#FLnKW8p?OH9B0${w>2C(WhcU(A^ZZq6l#@&3^5atfG4S_WFdgWhuUvcrbX>B%znjMa#BJc4=h1xK+4X$?FWZZYtVESw`H9AQQYdO;wWrE%E?g_hjP%6{Wwfc zJncM+!nCahH4e+NExYL~4TrVLMp;yAo1?NA*6WqBSgWs(M$VOOEw8L@?FI7k`sViT z{^9XS)6L<_RI*@j49{SES^0(6i#swthsd~UoJ~j!5Cg=(G%;Y#IIA>Gi=wp<1H{0u zFo5TS07Y~SW*XJe0S*2>V!VKe0ye%S5QRb4V5SiwAY7LM>QZi=7+jZwUzj}CV5U)* zGp=Taam>uzyimBB9sEM2Gwy1nmKY!gJ~NQlT?g;~-Jjq8pNptR3=jiT#Q-ntcsmVP zlDS(a7KeAO06ham!Msf4dkGloDu!IVikCo@fM1{i=o-v4f(L|t1QZR_5Ceb8z#HTx BTAcs@ literal 0 HcmV?d00001 diff --git a/kernel/old/tests/testingsuite_example/.DS_Store b/kernel/old/tests/testingsuite_example/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..fb0c27234dee3e4ce91e84c76e4962d98b161887 GIT binary patch literal 6148 zcmeHK%}N6?5Kd~WRl5}FOb<`jPXj_Ut!E$?kcD1nXf-+hBLjGM1?I9AH23rUB~34kJ(zv-nxRb6Qt6fF#`5D6lU8AB8k;>c zby{o0om%Rq?WE$ij@3x|foJThn>Ie|{WuN>w(A|ppi{T!w&N&uWfZhNg`OPB$d5af zxE=Y)Nlou}DE+iix96*^-~vLcZWJ8IM0zrmY1b-XtJ@2`-eys(u9W*l(JPlrMX|O~ z>i6v{%UW7q-`YEB_Ajq*Ztw0N9-p4|ZEz$2WmdzWe;HV05Cg;jF)(rrn5WO09=Vgz zfrtTO;I|Cm`yfCO9fO%h^>jd|N&vt-xRrp7wFJfpgO0&WBg}ws9SW#JxhXNY4hO$5 z>l}lbMjg($DL%OQGB*_pS6_$yg<8(Iqmg=IfEf77z?dG|nE!WwuK&LV(TErz21bej zp5LkMRNzP^w+@@pi00m&;WD{W*Wf*LO%kE2I`1` HKV{$@LCs$; literal 0 HcmV?d00001 diff --git a/kernel/src/common/include/interrupt.h b/kernel/src/common/include/interrupt.h index e883c606..b2b83684 100644 --- a/kernel/src/common/include/interrupt.h +++ b/kernel/src/common/include/interrupt.h @@ -16,6 +16,8 @@ #include #include +volatile uint32_t * const PIC_ADDRESS; + // general syscall function extern int syscall(int number); @@ -68,19 +70,7 @@ typedef struct interrupt_handler_t #define disable_interrupts_save() \ disable_interrupt_save(ALL); -/* functions (e.g. passing a bad parameter), so we'll - refer to the macros above for adjusting specific interrupt status */ -void enable_interrupt(interrupt_t); -int enable_interrupt_save(interrupt_t); -void disable_interrupt(interrupt_t); -int disable_interrupt_save(interrupt_t); - -int get_proc_status(void); -void restore_proc_status(int); - -int register_interrupt_handler(int, interrupt_handler_t *); -void handle_irq_interrupt(int); /* VIC Interrupt Mappings */ #define VIC_IRQ_STATUS PIC_ADDRESS // status of pending irqs after masking (R) @@ -96,38 +86,57 @@ void handle_irq_interrupt(int); #define hw_interrupt_disable(n) mmio_write(VIC_INT_ENCLEAR, (1 << n)); #define vic_select_fiq(n) mmio_write(VIC_INT_SELECT, (1 << n)); +enum InterruptID { + WATCHDOG_IRQ = 0, /* watchdog controller */ + SWI_IRQ = 1, /* software interrupt */ + COMMS_RX_IRQ = 2, /* debug comms receive intercept */ + COMMS_TX_IRQ = 3, /* debug comms transmit intercept */ + TIMER_A_IRQ = 4, /* timer 0 or 1 */ + TIMER_B_IRQ = 5, /* timer 2 or 3 */ + GPIO_A_IRQ = 6, /* GPIO 0 */ + GPIO_B_IRQ = 7, /* GPIO 1 */ + GPIO_C_IRQ = 8, /* GPIO 2 */ + GPIO_D_IRQ = 9, /* GPIO 3 */ + RTC_IRQ = 10, /* Real Time Clock (RTC) */ + SSP_IRQ = 11, /* synchronous serial port */ + UART0_IRQ = 12, /* UART 0 */ + UART1_IRQ = 13, /* UART 1 */ + UART2_IRQ = 14, /* UART 2 */ + SCIO_IRQ = 15, /* smart card interface */ + CLCD_IRQ = 16, /* CLCD controller */ + DMA_IRQ = 17, /* DMA controller */ + PWRFAIL_IRQ = 18, /* power failure from FPGA */ + MBX_IRQ = 19, /* graphics processor */ + // IRQ 20 is reserved by the architecture + VICINTSOURCE_21 = 21, /* external interrupt signal from DiskOnChip flash device */ + VICINTSOURCE_22 = 22, /* external interrupt signal from MCIO A */ + // IRQ 23 is reserved by the architecture + VICINTSOURCE_24 = 24, /* external interrupt signal from AACI */ + VICINTSOURCE_25 = 25, /* Ethernet */ + VICINTSOURCE_26 = 26, /* USB */ + VICINTSOURCE_27 = 27, /* external interrupt signal from expansion connector */ + VICINTSOURCE_28 = 28, /* external interrupt signal from expansion connector */ + // IRQ 29 is reserved by the architecture + // IRQ 30 is reserved by the architecture + VICINTSOURCE_31 = 31, /* secondary interrupt controller (SIC) */ +}; + // Primary Interrupt Controller (PIC) -#define WATCHDOG_IRQ 0 /* watchdog controller */ -#define SWI_IRQ 1 /* software interrupt */ -#define COMMS_RX_IRQ 2 /* debug comms receive intercept */ -#define COMMS_TX_IRQ 3 /* debug comms transmit intercept */ -#define TIMER_A_IRQ 4 /* timer 0 or 1 */ -#define TIMER_B_IRQ 5 /* timer 2 or 3 */ -#define GPIO_A_IRQ 6 /* GPIO 0 */ -#define GPIO_B_IRQ 7 /* GPIO 1 */ -#define GPIO_C_IRQ 8 /* GPIO 2 */ -#define GPIO_D_IRQ 9 /* GPIO 3 */ -#define RTC_IRQ 10 /* Real Time Clock (RTC) */ -#define SSP_IRQ 11 /* synchronous serial port */ -#define UART0_IRQ 12 /* UART 0 */ -#define UART1_IRQ 13 /* UART 1 */ -#define UART2_IRQ 14 /* UART 2 */ -#define SCIO_IRQ 15 /* smart card interface */ -#define CLCD_IRQ 16 /* CLCD controller */ -#define DMA_IRQ 17 /* DMA controller */ -#define PWRFAIL_IRQ 18 /* power failure from FPGA */ -#define MBX_IRQ 19 /* graphics processor */ -// IRQ 20 is reserved by the architecture -#define VICINTSOURCE_21 21 /* external interrupt signal from DiskOnChip flash device */ -#define VICINTSOURCE_22 22 /* external interrupt signal from MCIO A */ -// IRQ 23 is reserved by the architecture -#define VICINTSOURCE_24 23 /* external interrupt signal from AACI */ -#define VICINTSOURCE_25 24 /* Ethernet */ -#define VICINTSOURCE_26 25 /* USB */ -#define VICINTSOURCE_27 26 /* external interrupt signal from expansion connector */ -#define VICINTSOURCE_28 27 /* external interrupt signal from expansion connector */ -// IRQ 29 is reserved by the architecture -// IRQ 30 is reserved by the architecture -#define VICINTSOURCE_31 31 /* secondary interrupt controller (SIC) */ + + +/* functions (e.g. passing a bad parameter), so we'll + refer to the macros above for adjusting specific interrupt status */ +void enable_interrupt(interrupt_t); +int enable_interrupt_save(interrupt_t); + +void disable_interrupt(interrupt_t); +int disable_interrupt_save(interrupt_t); + +int get_proc_status(void); +void restore_proc_status(int); + +int register_interrupt_handler(enum InterruptID, interrupt_handler_t *); +void handle_irq_interrupt(enum InterruptID); + #endif //__INTERRUPT_H__ diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index 9b2988ba..8715061c 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -6,6 +6,8 @@ #include #include +volatile uint32_t * const PIC_ADDRESS = (volatile uint32_t *)0x10140000; + // there are 32 kinds of interrupts on the VIC // this structure may need to be expanded if the secondary controller is incorporated static interrupt_handler_t *handlers[MAX_NUM_INTERRUPTS]; @@ -51,34 +53,33 @@ void init_fiqs() // when you register an interrupt handler it's line will be enabled in the VIC // telling the device itself to fire interrupts should be done in the driver // +// TODO: We do now ------------------------------V // also, since we don't really have a working malloc, the handler structure will // have to be built in the driver and passed to register_ -int register_interrupt_handler(int num, interrupt_handler_t *handler) -{ - // lazy initialization - if (initialized != -1) - { +int register_interrupt_handler(enum InterruptID num, interrupt_handler_t *handler) { + // lazy initialization + if (initialized != -1) { kprintf("INITIALIZING THE INTERRUPT SYSTEM\n"); - for(int i=0; i MAX_NUM_INTERRUPTS) // bad irq number - return -1; - else if (handlers[num] != 0) - { // something has already been registered there - kprintf("Already registered\n"); - return -1; - } - else if (handler == 0) // we need a NULL macro - return -1; + if (num < 0 || num > MAX_NUM_INTERRUPTS) { + kprintf("Register a handler between 0 and %i\n", MAX_NUM_INTERRUPTS); + panic(); + } else if (handlers[num] != NULL) { + kprintf("Tried to re-register interrupt handler %i\n", num); + panic(); + } else if (handler == NULL) { + kprintf("The interrupt handler can't be NULL\n"); + panic(); + } // put the handler in the array handlers[num] = handler; @@ -87,9 +88,10 @@ int register_interrupt_handler(int num, interrupt_handler_t *handler) hw_interrupt_enable(num); // check to see if this is an FIQ - if (check_if_fiq[num]) - // update the "select" register on the VIC - vic_select_fiq(num); + if (check_if_fiq[num]){ + // update the "select" register on the VIC + vic_select_fiq(num); + } // return a success value return 0; @@ -97,8 +99,7 @@ int register_interrupt_handler(int num, interrupt_handler_t *handler) // handle_interrupt takes a number (the interrupt from the VIC), looks into // the table of registered handlers, and calls the appropriate handler -void handle_irq_interrupt(int interrupt_vector) -{ +void handle_irq_interrupt(enum InterruptID interrupt_vector) { kprintf("handling interrupt %d\n", interrupt_vector); // go to handler routine kprintf("Jumping to %X...\n", handlers[interrupt_vector]->handler); @@ -107,8 +108,7 @@ void handle_irq_interrupt(int interrupt_vector) } /* enable IRQ and/or FIQ */ -void enable_interrupt(interrupt_t mask) -{ +void enable_interrupt(interrupt_t mask) { get_proc_status(); // enable interrupt on the core diff --git a/kernel/src/drivers/time/timer.c b/kernel/src/drivers/time/timer.c index 01e17a40..b51dfb97 100644 --- a/kernel/src/drivers/time/timer.c +++ b/kernel/src/drivers/time/timer.c @@ -32,7 +32,7 @@ void initialize_timers() interrupt_handler_t *tmr_handler = kmalloc(sizeof(interrupt_handler_t)); tmr_handler->handler = timer_irq_handler; - register_interrupt_handler(4, tmr_handler); + register_interrupt_handler(TIMER_A_IRQ, tmr_handler); } #define CHECK_TIMER_INDEX(index) { if (index < 0 || index > 4) return -1; } @@ -243,8 +243,7 @@ int unregister_handler(int timer_index) return 0; } -void timer_irq_handler(void* args) -{ +void timer_irq_handler(void* args) { clear_interrupt(0); kprintf("@@@@@@ RECEIVED TIMER INTERRUPT\n"); diff --git a/kernel/src/drivers/uart/include/uart.h b/kernel/src/drivers/uart/include/uart.h index 2de2a439..27dc456d 100644 --- a/kernel/src/drivers/uart/include/uart.h +++ b/kernel/src/drivers/uart/include/uart.h @@ -1,6 +1,47 @@ #ifndef UART_H #define UART_H +#include + void print_uart0(const char *); + +// http://infocenter.arm.com/help/topic/com.arm.doc.ddi0183f/DDI0183.pdf +// Section 3.2: Summary of registers +// https://balau82.wordpress.com/2010/11/30/emulating-arm-pl011-serial-ports/ +// This struct is memory mappend. I call them registers but they all live in memory. +typedef volatile struct UartInterface { + uint32_t DR; // Data Register + uint32_t RSR_ECR; // Receive Status Register / Error Clear Register + uint8_t reserved1[0x10]; // Reserved + const uint32_t FR; // Flag Register + uint8_t reserved2[0x4]; // Reserved + uint32_t LPR; // IrDA low power counter Register + uint32_t IBRD; // Integer Baud Rate Register + uint32_t FBRD; // Fractional Baud Rate Register + uint32_t LCR_H; // Line Control Register + uint32_t CR; // Control Register + uint32_t IFLS; // Interrupt FIFO Level Select Register + uint32_t IMSC; // Interrupt Mask Set/Clear Register + const uint32_t RIS; // Raw Interrupt Status Register + const uint32_t MIS; // Masked Interrupt Status Register + uint32_t ICR; // Interrupt Clear Register + uint32_t DMACR; // DMA Control Register +} UartInterface; + +volatile UartInterface * const UART0_ADDRESS; +volatile UartInterface * const UART1_ADDRESS; +volatile UartInterface * const UART2_ADDRESS; + +uint32_t uart_read_int(volatile UartInterface * interface); +void uart_write_int(volatile UartInterface * interface, volatile uint32_t value); +uint8_t uart_read_byte(volatile UartInterface * interface); +void uart_write_byte(volatile UartInterface * interface, volatile uint8_t value); + +void UART0_INTERRUPT_HANDLER(); +void UART1_INTERRUPT_HANDLER(); +void UART2_INTERRUPT_HANDLER(); + +void uart_init(); + #endif // ifndef UART_H diff --git a/kernel/src/drivers/uart/uart.c b/kernel/src/drivers/uart/uart.c index 7bfad9ec..ee6906ef 100644 --- a/kernel/src/drivers/uart/uart.c +++ b/kernel/src/drivers/uart/uart.c @@ -1,108 +1,31 @@ -// Only compile this file when **not** compiling for a raspberry pi -#ifndef RASPBERRY_PI +#include -#include -#include +volatile UartInterface * const UART0_ADDRESS = (volatile UartInterface *)0x101f1000; +volatile UartInterface * const UART1_ADDRESS = (volatile UartInterface *)0x101f2000; +volatile UartInterface * const UART2_ADDRESS = (volatile UartInterface *)0x101f3000; -void print_uart0(const char *s) -{ - while (*s != '\0') - { - mmio_write(UART0_ADDRESS, *s); - s++; - } -} -void print_char_uart0(char c) -{ - mmio_write(UART0_ADDRESS, c); -} +void UART0_INTERRUPT_HANDLER() { +// UART_ClearITPendingBit(UART0, UART_IT_Receive); +// UART_ClearITPendingBit(UART0, UART_IT_Transmit); +// while(UART_GetFlagStatus(UART0, UART_FLAG_TxFIFOFull) != RESET); +// UART_SendData(UART0, UART_ReceiveData(UART0)); +// VIC1->VAR=0xFF; -/* print the full 32 bits of a word at the given address */ -/* trailing newline... */ -void print_word_bits(uint32_t * c) -{ - int i; - for (i = 31; i >= 0; i--) - *c & (1 << i) ? print_uart0("1") : print_uart0("0"); - print_uart0("\n"); } -/* print the full 8-digit hex code of a word at the given address */ -/* no '0x' prefix, NO trailing newline */ -void print_word_hex(uint32_t * c) -{ - int i; - uint32_t a; - for (i = 0x7; i >= 0x0; i--) - { - a = *c & (0xf << (i * 0x4)); - a >>= (i * 0x4); - - if (a <= 9) - mmio_write(UART0_ADDRESS, (uint32_t )(a + (uint32_t )'0')); - else if (a <= 0xf) - mmio_write(UART0_ADDRESS, (uint32_t )((a - 0xa) + (uint32_t )'a')); - else - mmio_write(UART0_ADDRESS, (uint32_t )('?')); - } +uint32_t uart_read_int(volatile UartInterface * interface) { + return 0; } -/* display memory at given address */ -/* format is: "[address]: word1 word2 word3\n", etc. */ -/* displays 30 words (10 lines) */ -void md(uint32_t * start) -{ - int i, j; - uint32_t *addr = start; - for (i = 0; i < 10; i++) - { - print_uart0("0x"); - print_word_hex((uint32_t *) &addr); - print_uart0(": "); - for (j = 0; j < 3; j++) - { - print_word_hex(addr); - print_uart0(" "); - addr++; - } - print_uart0("\n"); - } +void uart_write_int(volatile UartInterface * interface, volatile uint32_t value) { + interface->DR = value; } -/*void print_uart0(const char *s) {*/ -/*while (uart->dd->uart0_inter_val == 0) {}*/ -/*if(uart.UARTCR & RXE > 0) */ -/*{*/ -/*while(*s != '\0') */ -/*{*/ -/**UART0 = (uint32_t)(*s);*/ -/*s++;*/ -/*}*/ -/*}*/ -/*}*/ - -/* We need to implement a lock here. klibc will be implementing the buffer - * we just need to ensure the FIFO isn't read out of order. - */ -/*char *read_uart0() */ -/*{*/ -/*uint32_t buffer[STD_IN_BUFFER_SIZE] = {0};*/ -/*while (uart->dd->uart0_inter_val == 0) {}*/ -/*uint32_t *iterator = buffer;*/ -/*do */ -/*{*/ -/*if(uart.UARTCR & TXE > 0) */ -/*{*/ -/*break;*/ -/*} */ -/*else */ -/*{*/ -/**iterator = uart.UARTDR;*/ -/*iterator++;*/ -/*}*/ -/*} while (*iterator != '\0');*/ -/*return buffer;*/ -/*}*/ +uint8_t uart_read_byte(volatile UartInterface * interface) { + return 0; +} -#endif // RASPBERRY_PI +void uart_write_byte(volatile UartInterface * interface, volatile uint8_t value) { + interface->DR = (uint32_t)value; +} \ No newline at end of file diff --git a/kernel/src/drivers/uart/uart_qemu.c b/kernel/src/drivers/uart/uart_qemu.c new file mode 100644 index 00000000..805ba09c --- /dev/null +++ b/kernel/src/drivers/uart/uart_qemu.c @@ -0,0 +1,106 @@ +// Only compile this file when **not** compiling for a raspberry pi +#ifndef RASPBERRY_PI + +#include +#include +#include + +void uart_init() { + // Register the uart interrupt handler. +// register_interrupt_handler(UART0_IRQ, UART0_INTERRUPT_HANDLER) +} + +void print_uart0(const char *s) { + while (*s != '\0') { + uart_write_byte(UART0_ADDRESS, *s); + s++; + } +} + +void print_char_uart0(char c) { + uart_write_byte(UART0_ADDRESS, c); +} + +/* print the full 32 bits of a word at the given address */ +/* trailing newline... */ +void print_word_bits(uint32_t * c) { + int i; + for (i = 31; i >= 0; i--) + *c & (1 << i) ? print_uart0("1") : print_uart0("0"); + print_uart0("\n"); +} + +/* print the full 8-digit hex code of a word at the given address */ +/* no '0x' prefix, NO trailing newline */ +void print_word_hex(uint32_t * c) { + int i; + uint32_t a; + for (i = 0x7; i >= 0x0; i--) + { + a = *c & (0xf << (i * 0x4)); + a >>= (i * 0x4); + + if (a <= 9) + uart_write_byte(UART0_ADDRESS, (uint32_t )(a + (uint32_t )'0')); + else if (a <= 0xf) + uart_write_byte(UART0_ADDRESS, (uint32_t )((a - 0xa) + (uint32_t )'a')); + else + uart_write_byte(UART0_ADDRESS, (uint32_t )('?')); + } +} + +/* display memory at given address */ +/* format is: "[address]: word1 word2 word3\n", etc. */ +/* displays 30 words (10 lines) */ +void md(uint32_t * start) { + int i, j; + uint32_t *addr = start; + for (i = 0; i < 10; i++) { + print_uart0("0x"); + print_word_hex((uint32_t *) &addr); + print_uart0(": "); + for (j = 0; j < 3; j++) { + print_word_hex(addr); + print_uart0(" "); + addr++; + } + print_uart0("\n"); + } +} + +/*void print_uart0(const char *s) {*/ +/*while (uart->dd->uart0_inter_val == 0) {}*/ +/*if(uart.UARTCR & RXE > 0) */ +/*{*/ +/*while(*s != '\0') */ +/*{*/ +/**UART0 = (uint32_t)(*s);*/ +/*s++;*/ +/*}*/ +/*}*/ +/*}*/ + +/* We need to implement a lock here. klibc will be implementing the buffer + * we just need to ensure the FIFO isn't read out of order. + */ +/*char *read_uart0() */ +/*{*/ +/*uint32_t buffer[STD_IN_BUFFER_SIZE] = {0};*/ +/*while (uart->dd->uart0_inter_val == 0) {}*/ +/*uint32_t *iterator = buffer;*/ +/*do */ +/*{*/ +/*if(uart.UARTCR & TXE > 0) */ +/*{*/ +/*break;*/ +/*} */ +/*else */ +/*{*/ +/**iterator = uart.UARTDR;*/ +/*iterator++;*/ +/*}*/ +/*} while (*iterator != '\0');*/ +/*return buffer;*/ +/*}*/ + +#endif // RASPBERRY_PI diff --git a/kernel/src/ds/bpf/HashMap.c b/kernel/src/ds/bpf/HashMap.c new file mode 100644 index 00000000..8881e6b4 --- /dev/null +++ b/kernel/src/ds/bpf/HashMap.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) + +/* + * Generic non-thread safe hash map implementation. + * + * Copyright (c) 2019 Facebook + * Copyright (c) 2020 Jonathan Dönszelmann and Victor Roest + */ + + +#include +#include +#include +#include "include/HashMap.h" +/* make sure libbpf doesn't use kernel-only integer typedefs */ +#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64 + +/* start with 4 buckets */ +#define HASHMAP_MIN_CAP_BITS 2 + +static void hashmap_add_entry(struct hashmap_entry **pprev, + struct hashmap_entry *entry) +{ + + + entry->next = *pprev; + *pprev = entry; +} + +static void hashmap_del_entry(struct hashmap_entry **pprev, + struct hashmap_entry *entry) +{ + *pprev = entry->next; + entry->next = NULL; +} + +void hashmap__init(struct HashMap *map, hashmap_hash_fn hash_fn, + hashmap_equal_fn equal_fn, FreeFunc free_key, + FreeFunc free_data, void *ctx) +{ + map->hash_fn = hash_fn; + map->equal_fn = equal_fn; + map->freeData = free_data; + map->freeKey = free_key; + map->ctx = ctx; + + map->buckets = NULL; + map->cap = 0; + map->cap_bits = 0; + map->sz = 0; +} + +struct HashMap *hashmap__new(hashmap_hash_fn hash_fn, + hashmap_equal_fn equal_fn, + FreeFunc free_key, + FreeFunc free_data, + void *ctx) +{ + struct HashMap *map = kmalloc(sizeof(struct HashMap)); + + if (!map) + return NULL; + hashmap__init(map, hash_fn, equal_fn, free_key, free_data, ctx); + return map; +} + +void hashmap__clear(struct HashMap *map) +{ + struct hashmap_entry *cur, *tmp; + int bkt; + + hashmap__for_each_entry_safe(map, cur, tmp, bkt) { + map->freeKey((void *) cur->key); + map->freeData(cur->value); + kfree(cur); + } + + kfree(map->buckets); + map->cap = map->cap_bits = map->sz = 0; +} + +void hashmap__free(struct HashMap *map) +{ + if (!map) + return; + + hashmap__clear(map); + kfree(map); +} + +size_t hashmap__size(const struct HashMap *map) +{ + return map->sz; +} + +size_t hashmap__capacity(const struct HashMap *map) +{ + return map->cap; +} + +static bool hashmap_needs_to_grow(struct HashMap *map) +{ + /* grow if empty or more than 75% filled */ + return (map->cap == 0) || ((map->sz + 1) * 4 / 3 > map->cap); +} + +static int hashmap_grow(struct HashMap *map) +{ + struct hashmap_entry **new_buckets; + struct hashmap_entry *cur, *tmp; + size_t new_cap_bits, new_cap; + size_t h; + int bkt; + + new_cap_bits = map->cap_bits + 1; + if (new_cap_bits < HASHMAP_MIN_CAP_BITS) + new_cap_bits = HASHMAP_MIN_CAP_BITS; + + new_cap = 1UL << new_cap_bits; + new_buckets = kcalloc(new_cap, sizeof(new_buckets[0])); + if (!new_buckets) + return -1; + + hashmap__for_each_entry_safe(map, cur, tmp, bkt) { + h = hash_bits(map->hash_fn(cur->key, map->ctx), new_cap_bits); + hashmap_add_entry(&new_buckets[h], cur); + } + + map->cap = new_cap; + map->cap_bits = new_cap_bits; + kfree(map->buckets); + map->buckets = new_buckets; + + return 0; +} + +static bool hashmap_find_entry(const struct HashMap *map, + const void *key, size_t hash, + struct hashmap_entry ***pprev, + struct hashmap_entry **entry) +{ + struct hashmap_entry *cur, **prev_ptr; + + if (!map->buckets) + return false; + + for (prev_ptr = &map->buckets[hash], cur = *prev_ptr; + cur; + prev_ptr = &cur->next, cur = cur->next) { + if (map->equal_fn(cur->key, key, map->ctx)) { + if (pprev) + *pprev = prev_ptr; + *entry = cur; + return true; + } + } + + return false; +} + +int hashmap__insert(struct HashMap *map, const void *key, void *value, + enum hashmap_insert_strategy strategy, + const void **old_key, void **old_value) +{ + struct hashmap_entry *entry; + size_t h; + int err; + + if (old_key) + *old_key = NULL; + if (old_value) + *old_value = NULL; + + h = hash_bits(map->hash_fn(key, map->ctx), map->cap_bits); + if (strategy != HASHMAP_APPEND && + hashmap_find_entry(map, key, h, NULL, &entry)) { + if (old_key) + *old_key = entry->key; + if (old_value) + *old_value = entry->value; + + if (strategy == HASHMAP_SET || strategy == HASHMAP_UPDATE) { + entry->key = key; + entry->value = value; + return 0; + } else if (strategy == HASHMAP_ADD) { + return -1; + } + } + + if (strategy == HASHMAP_UPDATE) + return -1; + + if (hashmap_needs_to_grow(map)) { + err = hashmap_grow(map); + if (err){ + return err; + } + + h = hash_bits(map->hash_fn(key, map->ctx), map->cap_bits); + } + + entry = kmalloc(sizeof(struct hashmap_entry)); + if (!entry) + return -1; + + + entry->key = key; + entry->value = value; + hashmap_add_entry(&map->buckets[h], entry); + + map->sz++; + + return 0; +} + +bool hashmap__find(const struct HashMap *map, const void *key, void **value) +{ + struct hashmap_entry *entry; + size_t h; + + h = hash_bits(map->hash_fn(key, map->ctx), map->cap_bits); + if (!hashmap_find_entry(map, key, h, NULL, &entry)) + return false; + + if (value) + *value = entry->value; + return true; +} + +bool hashmap__delete(struct HashMap *map, const void *key, + const void **old_key, void **old_value) +{ + struct hashmap_entry **pprev, *entry; + size_t h; + + h = hash_bits(map->hash_fn(key, map->ctx), map->cap_bits); + if (!hashmap_find_entry(map, key, h, &pprev, &entry)) + return false; + + if (old_key) + *old_key = entry->key; + if (old_value) + *old_value = entry->value; + + hashmap_del_entry(pprev, entry); + kfree(entry); + map->sz--; + + return true; +} + diff --git a/kernel/src/ds/bpf/include/HashMap.h b/kernel/src/ds/bpf/include/HashMap.h new file mode 100644 index 00000000..906006d8 --- /dev/null +++ b/kernel/src/ds/bpf/include/HashMap.h @@ -0,0 +1,189 @@ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ + +/* + * Generic non-thread safe hash map implementation. + * + * Copyright (c) 2019 Facebook + */ +#ifndef __LIBBPF_HASHMAP_H +#define __LIBBPF_HASHMAP_H + +#include +#include +#include + + +static inline size_t hash_bits(size_t h, int bits){ + + /* shuffle bits and return requested number of upper bits */ + return (size_t)(h * 11400714819323198485llu) >> (MACHINE_WORDSIZE - bits); +} + +typedef size_t (*hashmap_hash_fn)(const void *key, void *ctx); +typedef bool (*hashmap_equal_fn)(const void *key1, const void *key2, void *ctx); + +struct hashmap_entry { + const void *key; + void *value; + struct hashmap_entry *next; +}; + +typedef struct HashMap { + hashmap_hash_fn hash_fn; + hashmap_equal_fn equal_fn; + void *ctx; + + FreeFunc freeData; + FreeFunc freeKey; + + struct hashmap_entry **buckets; + size_t cap; + size_t cap_bits; + size_t sz; +} HashMap; + +#define HASHMAP_INIT(hash_fn, equal_fn, free_key, free_data, ctx) { \ + .hash_fn = (hash_fn), \ + .freeKey = (free_key) \ + .freeData = (free_data) \ + .equal_fn = (equal_fn), \ + .ctx = (ctx), \ + .buckets = NULL, \ + .cap = 0, \ + .cap_bits = 0, \ + .sz = 0, \ +} + +void hashmap__init( struct HashMap *map, + hashmap_hash_fn hash_fn, + hashmap_equal_fn equal_fn, + FreeFunc free_key, + FreeFunc free_data, + void *ctx); + + +struct HashMap *hashmap__new(hashmap_hash_fn hash_fn, + hashmap_equal_fn equal_fn, + FreeFunc free_key, + FreeFunc free_data, + void *ctx); + + +void hashmap__clear(struct HashMap *map); +void hashmap__free(struct HashMap *map); + +size_t hashmap__size(const struct HashMap *map); +size_t hashmap__capacity(const struct HashMap *map); + +/* + * Hashmap insertion strategy: + * - HASHMAP_ADD - only add key/value if key doesn't exist yet; + * - HASHMAP_SET - add key/value pair if key doesn't exist yet; otherwise, + * update value; + * - HASHMAP_UPDATE - update value, if key already exists; otherwise, do + * nothing and return -ENOENT; + * - HASHMAP_APPEND - always add key/value pair, even if key already exists. + * This turns hashmap into a multimap by allowing multiple values to be + * associated with the same key. Most useful read API for such hashmap is + * hashmap__for_each_key_entry() iteration. If hashmap__find() is still + * used, it will return last inserted key/value entry (first in a bucket + * chain). + */ +enum hashmap_insert_strategy { + HASHMAP_ADD, + HASHMAP_SET, + HASHMAP_UPDATE, + HASHMAP_APPEND, +}; + +/* + * hashmap__insert() adds key/value entry w/ various semantics, depending on + * provided strategy value. If a given key/value pair replaced already + * existing key/value pair, both old key and old value will be returned + * through old_key and old_value to allow calling code do proper memory + * management. + */ +int hashmap__insert(struct HashMap *map, const void *key, void *value, + enum hashmap_insert_strategy strategy, + const void **old_key, void **old_value); + +static inline int hashmap__add(struct HashMap *map, + const void *key, void *value) +{ + return hashmap__insert(map, key, value, HASHMAP_ADD, NULL, NULL); +} + +static inline int hashmap__set(struct HashMap *map, + const void *key, void *value, + const void **old_key, void **old_value) +{ + return hashmap__insert(map, key, value, HASHMAP_SET, + old_key, old_value); +} + +static inline int hashmap__update(struct HashMap *map, + const void *key, void *value, + const void **old_key, void **old_value) +{ + return hashmap__insert(map, key, value, HASHMAP_UPDATE, + old_key, old_value); +} + +static inline int hashmap__append(struct HashMap *map, + const void *key, void *value) +{ + return hashmap__insert(map, key, value, HASHMAP_APPEND, NULL, NULL); +} + +bool hashmap__delete(struct HashMap *map, const void *key, + const void **old_key, void **old_value); + +bool hashmap__find(const struct HashMap *map, const void *key, void **value); + +/* + * hashmap__for_each_entry - iterate over all entries in hashmap + * @map: hashmap to iterate + * @cur: struct hashmap_entry * used as a loop cursor + * @bkt: integer used as a bucket loop cursor + */ +#define hashmap__for_each_entry(map, cur, bkt) \ + for (bkt = 0; bkt < map->cap; bkt++) \ + for (cur = map->buckets[bkt]; cur; cur = cur->next) + +/* + * hashmap__for_each_entry_safe - iterate over all entries in hashmap, safe + * against removals + * @map: hashmap to iterate + * @cur: struct hashmap_entry * used as a loop cursor + * @tmp: struct hashmap_entry * used as a temporary next cursor storage + * @bkt: integer used as a bucket loop cursor + */ +#define hashmap__for_each_entry_safe(map, cur, tmp, bkt) \ + for (bkt = 0; bkt < map->cap; bkt++) \ + for (cur = map->buckets[bkt]; \ + cur && ({tmp = cur->next; true; }); \ + cur = tmp) + +/* + * hashmap__for_each_key_entry - iterate over entries associated with given key + * @map: hashmap to iterate + * @cur: struct hashmap_entry * used as a loop cursor + * @key: key to iterate entries for + */ +#define hashmap__for_each_key_entry(map, cur, _key) \ + for (cur = ({ size_t bkt = hash_bits(map->hash_fn((_key), map->ctx),\ + map->cap_bits); \ + map->buckets ? map->buckets[bkt] : NULL; }); \ + cur; \ + cur = cur->next) \ + if (map->equal_fn(cur->key, (_key), map->ctx)) + +#define hashmap__for_each_key_entry_safe(map, cur, tmp, _key) \ + for (cur = ({ size_t bkt = hash_bits(map->hash_fn((_key), map->ctx),\ + map->cap_bits); \ + cur = map->buckets ? map->buckets[bkt] : NULL; }); \ + cur && ({ tmp = cur->next; true; }); \ + cur = tmp) \ + if (map->equal_fn(cur->key, (_key), map->ctx)) + +#endif /* __LIBBPF_HASHMAP_H */ diff --git a/kernel/src/ds/bpf/test/hashmap_test.c b/kernel/src/ds/bpf/test/hashmap_test.c new file mode 100644 index 00000000..63fa7c66 --- /dev/null +++ b/kernel/src/ds/bpf/test/hashmap_test.c @@ -0,0 +1,50 @@ +#include +#include +#include + + +size_t int_hash_fn(const void *key, void *ctx) { + return (size_t) *(int *)key; +} + +bool int_compare_fn(const void *key1, const void *key2, void *ctx) { + return *(int *)key1 == *(int *)key2; +} + +void fakeFree(void * fake){ + UNUSED(fake); +} + +void simpleFree(void * val){ + kfree(val); +} + +TEST_CREATE(test_create_hm, { + HashMap * hm = hashmap__new(int_hash_fn, int_compare_fn, fakeFree, fakeFree, NULL); + + int key = 5; + int data = 42; + + hashmap__add(hm, &key, &data); + + ASSERT(hashmap__find(hm, &key, NULL)); + + hashmap__free(hm); +}) + + + +TEST_CREATE(test_free_entries_hm, { + HashMap * hm = hashmap__new(int_hash_fn, int_compare_fn, simpleFree, simpleFree, NULL); + + int * key = (int *) kmalloc(sizeof(int)); + int * value = (int *) kmalloc(sizeof(int)); + *key = 42; + *value = 69; + + hashmap__add(hm, key, value); + + hashmap__free(hm); + + // Test framework will assert that we won't leak. +}) diff --git a/kernel/src/ds/include/ds.h b/kernel/src/ds/include/ds.h index 56ed5b9e..afaa0834 100644 --- a/kernel/src/ds/include/ds.h +++ b/kernel/src/ds/include/ds.h @@ -2,14 +2,16 @@ #define DS_H #include +#include // used across datastructures typedef void (*FreeFunc)(void * data); typedef bool (*CompareFunc)(void * in, void * other); +typedef uint32_t (*HashFunc)(void * key); #include #include -#include +#include #include #include diff --git a/kernel/src/ds/include/vp_hash_map.h.old b/kernel/src/ds/include/vp_hash_map.h.old new file mode 100644 index 00000000..565d73d1 --- /dev/null +++ b/kernel/src/ds/include/vp_hash_map.h.old @@ -0,0 +1,51 @@ +#ifndef HASH_MAP_H +#define HASH_MAP_H + +#include + + +typedef struct HashSetElement { + uint32_t hash; + void * key; +} HashSetElement; + +typedef struct HashMapElement { + HashSetElement base; + void * data; +} HashMapElement; + +typedef struct HashMap { + HashFunc hashFunc; + CompareFunc compareFunc; + FreeFunc freeKey; + FreeFunc freeData; + struct VPSinglyLinkedList * buckets; + uint32_t n_buckets; +} HashMap; + +typedef HashMap HashSet; + +// Creates a new hashmap with given hash function and number of buckets +HashMap * hm_new(HashFunc hashf, FreeFunc datafreef, FreeFunc keyfreef, CompareFunc comparef, uint32_t n_buckets); +HashSet * hs_new(HashFunc hashf, FreeFunc datafreef, FreeFunc keyfreef, CompareFunc comparef, uint32_t n_buckets); + +// inserts an element into the hashmap/hashset +void hm_insert(HashMap * hm, void * key, void * data); +void hs_insert(HashSet * hs, void * key); + +// Gets the element associated with the key +void * hm_get(HashMap * hm, void * key); + +// Returns true if the element is included. +bool hm_contains(HashMap * hm, void * key); +bool hs_contains(HashSet * hm, void * key); + +// removes an element from the hashmap/hashset, returns the element so it can be freed +void * hm_remove(HashMap * hm, void * key); +void * hs_remove(HashSet * hs, void * key); + +// Frees the hashmap completely uses the FreeFunc to free any left over data. +void hm_free(HashMap * hm); +void hs_free(HashSet * hm); + +#endif diff --git a/kernel/src/ds/vp_hash_map.c b/kernel/src/ds/vp_hash_map.c deleted file mode 100644 index 555bef1b..00000000 --- a/kernel/src/ds/vp_hash_map.c +++ /dev/null @@ -1 +0,0 @@ -#include \ No newline at end of file diff --git a/kernel/src/ds/vp_hash_map.c.old b/kernel/src/ds/vp_hash_map.c.old new file mode 100644 index 00000000..05daea77 --- /dev/null +++ b/kernel/src/ds/vp_hash_map.c.old @@ -0,0 +1,118 @@ +#include +#include +#include + + +static inline HashMapElement * __hm_get_internal(HashMap * hm, void * key) { + size_t index = elem->base.hash; + + VPSLL_FOREACH(&hm->buckets[index], i) { + HashMapElement * elem = i->data; + if(compf(elem->base.key, key)) { + return elem; + } + } + return NULL; +} + +// Creates a new hashmap with given hash function and number of buckets +HashMap * hm_new(HashFunc hashf, FreeFunc datafreef, FreeFunc keyfreef, CompareFunc comparef, uint32_t n_buckets) { + HashMap * res = kmalloc(sizeof(HashMap)); + *res = (HashMap) { + // We can calloc/zero this memory since vpslls have an initial size of 0 and NULL pointer. + // Therefore a zeroed piece of memory *is* a vpsll + .buckets = kcalloc(n_buckets, sizeof(VPSinglyLinkedList)), + .hashFunc = hashf, + .compareFunc = comparef, + .freeData = datafreef, + .freeKey = keyfreef, + .n_buckets = n_buckets, + }; + + return res; +} + +HashSet * hs_new(HashFunc hashf, FreeFunc datafreef, FreeFunc keyfreef, CompareFunc comparef, uint32_t n_buckets) { return hm_new(hashf, datafreef, keyfreef, comparef, n_buckets); } + +static inline void __hm_insert_internal(HashMap * hm, struct HashMapElement * elem) { + size_t index = elem->base.hash; + + struct HashMapElement * old = __hm_get_internal(hm, ) + + vpsll_push(&hm->buckets[index], elem); + + return NULL; +} + +// inserts an element into the hashmap/hashset +void hm_insert(HashMap * hm, void * key, void * data) { + HashMapElement * hme = kmalloc(sizeof(HashMapElement)); + *hme = (HashMapElement) { + .base = (HashSetElement) { + .hash = hm->hashFunc(key), + .key = key, + }, + .data = data, + }; + + return __hm_insert_internal(hm, hme); +} + +void hs_insert(HashSet * hs, void * key) { + HashSetElement * hse = kmalloc(sizeof(HashSetElement)); + + *hse = (HashSetElement) { + .hash = hs->hashFunc(key), + .key = key, + }; + + return __hm_insert_internal(hs, hse); +} + +// Gets the element associated with the key +void * hm_get(HashMap * hm, void * key) { + HashMapElement * res = __hm_get_internal(hm, key); + if (res != NULL) { + return res->data; + } else { + return NULL; + } +} + +// Returns true if the element is included. +bool hm_contains(HashMap * hm, void * key) { + return __hm_get_internal(hm, key) != NULL; +} +bool hs_contains(HashSet * hs, void * key) {return hm_contains(hs, key)} + +// removes an element from the hashmap/hashset, returns the element so it can be freed +void * hm_remove(HashMap * hm, void * key) { + +} + +void * hs_remove(HashSet * hs, void * key) { return hm_remove(hs, key);} + + +void hm_free(HashMap * hm) { + for (int i = 0; i < hm->buckets; i++) { + + VPSinglyLinkedList * lst = &hm->buckets[i]; + + struct VPSinglyLinkedListLink * curr = lst->head; + while (curr != NULL) { + struct VPSinglyLinkedListLink * last = curr; + curr = curr->next; + if (freef != NULL) { + freef(last->data); + } + kfree(last); + } + + vpsll_free_inner(, ); + } + kfree(hm); +} + +void hs_free(HashSet * hs) { + return hm_free(hs); +} \ No newline at end of file diff --git a/kernel/src/ds/vp_singly_linked_list.c b/kernel/src/ds/vp_singly_linked_list.c index 5c29fc09..f92913e1 100644 --- a/kernel/src/ds/vp_singly_linked_list.c +++ b/kernel/src/ds/vp_singly_linked_list.c @@ -9,6 +9,7 @@ VPSinglyLinkedList * vpsll_create() { return res; } + void vpsll_free(VPSinglyLinkedList * lst, FreeFunc freef) { struct VPSinglyLinkedListLink * curr = lst->head; while (curr != NULL) { @@ -19,7 +20,6 @@ void vpsll_free(VPSinglyLinkedList * lst, FreeFunc freef) { } kfree(last); } - kfree(lst); } diff --git a/kernel/src/klibc/alloc.c b/kernel/src/klibc/alloc.c index 3d690d06..9f8e4674 100644 --- a/kernel/src/klibc/alloc.c +++ b/kernel/src/klibc/alloc.c @@ -40,18 +40,22 @@ void *kmalloc(uint32_t size) { // Allocates n * size portion of memory (set to 0) and returns it -void *kcalloc(uint32_t n, uint32_t size) { +void *kcalloc(size_t n, size_t size) { uint32_t total_size = n * size; - void *block = kmalloc(total_size); + void * block = kmalloc(total_size); - return block ? memset(block, 0, total_size) : NULL; + if (block == NULL) { + return NULL; + } else { + memset(block, 0, total_size); + return block; + } } uint32_t kmalloc_size(void* ptr) { return allocation_size(ptr); } -// FIXME: Implement kmalloc_size() (or something like it) // TODO: Implement in-place realloc if the next block is free. // Resize memory pointed to by ptr to new size void * krealloc(void *ptr, uint32_t newsize) { diff --git a/kernel/src/klibc/include/klibc.h b/kernel/src/klibc/include/klibc.h index d0e74cee..2e53e6fe 100644 --- a/kernel/src/klibc/include/klibc.h +++ b/kernel/src/klibc/include/klibc.h @@ -80,7 +80,7 @@ unsigned int rand(); #define ERROR(...) if(LOG_LEVEL >= 1) kprintf(__VA_ARGS__) //4-17-15: Initial panic * assert_fail functions added -void panic(); +void panic() __attribute__ ((noreturn)); int _assert_fail(char *_file, unsigned int _line, char *_func); //__attribute__ ((__noreturn__)); diff --git a/kernel/src/klibc/include/stdint.h b/kernel/src/klibc/include/stdint.h index ad2b6564..0183ea3b 100644 --- a/kernel/src/klibc/include/stdint.h +++ b/kernel/src/klibc/include/stdint.h @@ -35,8 +35,20 @@ typedef uint16_t uint_least16_t; typedef uint32_t uint_least32_t; typedef uint64_t uint_least64_t; +#define MACHINE_WORDSIZE 32 + +#if MACHINE_WORDSIZE == 32 typedef uint32_t size_t; typedef int32_t isize_t; +#else +#if MACHINE_WORDSIZE == 64 +#error "TODO: we declare some pointers as uint32_t meaning that this mode is not currently supported." +typedef uint64_t size_t; +typedef int64_t isize_t; +#else +#error "WORDSIZE not supported" +#endif +#endif #define INT8_MIN (-1-0x7f) diff --git a/kernel/src/klibc/include/stdlib.h b/kernel/src/klibc/include/stdlib.h index 437f0bff..83816469 100644 --- a/kernel/src/klibc/include/stdlib.h +++ b/kernel/src/klibc/include/stdlib.h @@ -7,6 +7,7 @@ void* kmalloc(uint32_t size); void* kmalloc_aligned(uint32_t size, uint32_t alignment); void kfree(void* ptr); void *krealloc(void *ptr, uint32_t size); +void *kcalloc(size_t n, size_t size); /** * umalloc allocates memory on the user heap diff --git a/kernel/src/klibc/klibc.c b/kernel/src/klibc/klibc.c index 9a84f75d..95cdea0c 100644 --- a/kernel/src/klibc/klibc.c +++ b/kernel/src/klibc/klibc.c @@ -54,6 +54,7 @@ void panic() { kprintf(" ' size; -} +} \ No newline at end of file diff --git a/kernel/src/memory/include/mmap.h b/kernel/src/memory/include/mmap.h index 5706b161..afb0ac16 100644 --- a/kernel/src/memory/include/mmap.h +++ b/kernel/src/memory/include/mmap.h @@ -2,23 +2,26 @@ * Memory Mapped I/O addresses */ -#ifndef __MMAP_H__ -#define __MMAP_H__ +#ifndef MMAP_H +#define MMAP_H + +#include +#include #define mmio_read(address) (*((volatile uint32_t *)(address))) #define mmio_write(address, value) (*((volatile uint32_t *)(address)) = (volatile uint32_t)(value)) + void mmap(void *p_bootargs); -#define PIC_ADDRESS ((volatile char *const) 0x10140000) /* interrupt controller peripheral */ -#define UART0_ADDRESS (volatile uint32_t *const) 0x101f1000 /* UART 0 base address */ + #define CLOCK_ADDRESS (volatile uint32_t *const) 0x101e8000 /* RTC base address */ /* Physical Hardware Addresses */ #define PERIPHERAL_BASE_PI (volatile uint32_t *const) 0x20000000 #define PIC_ADDRESS_PI (volatile uint32_t *const) 0x2000B000 /* interrupt controller peripheral */ -#define UART0_ADDRESS_PI (volatile uint32_t *const) 0x20201000 /* UART 0 base address */ +//#define UART0_ADDRESS_PI (volatile uint32_t *const) 0x20201000 /* UART 0 base address */ #define CLOCK_ADDRESS_PI (volatile uint32_t *const) 0x20003000 /* RTC base address */ #define GPIO_ADDRESS_PI (volatile uint32_t *const) 0x20200000 -#endif // __MMAP_H_ +#endif // MMAP_H diff --git a/kernel/src/memory/test/test_allocator.c b/kernel/src/memory/test/test_allocator.c index b21c66a5..eea83513 100644 --- a/kernel/src/memory/test/test_allocator.c +++ b/kernel/src/memory/test/test_allocator.c @@ -27,4 +27,18 @@ TEST_CREATE(test_alloc_realloc_free, { } kfree(a); +}) + +TEST_CREATE(test_free_null, { + kfree(NULL); +}) + +TEST_CREATE(test_calloc, { + int * test = kcalloc(100, sizeof(int)); + + for (int i = 0; i < 100; i++) { + ASSERT_EQ(test[i], 0); + } + + kfree(test); }) \ No newline at end of file diff --git a/kernel/src/memory/vm/test/test.c b/kernel/src/memory/vm/test/test.c deleted file mode 100644 index e651107b..00000000 --- a/kernel/src/memory/vm/test/test.c +++ /dev/null @@ -1,6 +0,0 @@ -#include -#include - -TEST_CREATE(test_free_null, { - kfree(NULL); -}) diff --git a/kernel/src/test/test.c b/kernel/src/test/test.c index fdd9a191..31b07d36 100644 --- a/kernel/src/test/test.c +++ b/kernel/src/test/test.c @@ -1,3 +1,4 @@ + // DO NOT EDIT // this file is generated by generate_tests.sh @@ -5,7 +6,118 @@ #include + +int test_test_alloc_free(); +int test_test_alloc_free_large(); +int test_test_alloc_realloc_free(); +int test_test_free_null(); +int test_test_calloc(); +int test_u8a_push_get_pop_test(); +int test_u8a_push_set_pop_test(); +int test_u8a_resize_test(); +int test_u8a_push_string_test(); +int test_u8a_clone_test(); +int test_test_compare_nonequal_length(); +int test_test_compare_equal_length(); +int test_test_compare_equal_length_eq(); +int test_test_compare_equal_length_eq_null(); +int test_test_compare_various(); +int test_test_hash(); +int test_test_create_ll(); +int test_test_iter_ll(); +int test_test_get_ll(); +int test_test_contains_true(); +int test_test_contains_false(); +int test_test_vpsll_remove(); +int test_test_vpsll_set(); +int test_test_create_hm(); +int test_test_free_entries_hm(); +int test_test_create_file(); +int test_test_create_dir(); +int test_test_create_rw_file(); +int test_test_listdir(); +int test_test_create_vfs(); +int test_test_get_root(); +int test_path_create_test(); +int test_path_equal_test_1(); +int test_path_parent_test_1(); +int test_path_parent_test_2(); +int test_path_parent_test_3(); +int test_path_parent_test_4(); +int test_path_parent_test_5(); +int test_path_parent_test_6(); +int test_path_parent_test_7(); +int test_path_parent_test_8(); +int test_path_parent_test_9(); +int test_path_parent_test_10(); +int test_path_is_absolute_test(); +int test_path_is_relative_test_1(); +int test_path_is_relative_test_2(); +int test_path_clone_test(); +int test_path_find_file_test(); +int test_path_filename_test(); +int test_path_filename_test_trailing(); +int test_path_filename_test_1(); +int test_path_filename_test_2(); +int test_path_filename_test_3(); +int test_path_filename_test_4(); void test_main(){ - kprintf("TESTS COMPLETE. Passed %i tests\n", 51); + if (!test_test_alloc_free()) {return;} + if (!test_test_alloc_free_large()) {return;} + if (!test_test_alloc_realloc_free()) {return;} + if (!test_test_free_null()) {return;} + if (!test_test_calloc()) {return;} + if (!test_u8a_push_get_pop_test()) {return;} + if (!test_u8a_push_set_pop_test()) {return;} + if (!test_u8a_resize_test()) {return;} + if (!test_u8a_push_string_test()) {return;} + if (!test_u8a_clone_test()) {return;} + if (!test_test_compare_nonequal_length()) {return;} + if (!test_test_compare_equal_length()) {return;} + if (!test_test_compare_equal_length_eq()) {return;} + if (!test_test_compare_equal_length_eq_null()) {return;} + if (!test_test_compare_various()) {return;} + if (!test_test_hash()) {return;} + if (!test_test_create_ll()) {return;} + if (!test_test_iter_ll()) {return;} + if (!test_test_get_ll()) {return;} + if (!test_test_contains_true()) {return;} + if (!test_test_contains_false()) {return;} + if (!test_test_vpsll_remove()) {return;} + if (!test_test_vpsll_set()) {return;} + if (!test_test_create_hm()) {return;} + if (!test_test_free_entries_hm()) {return;} + if (!test_test_create_file()) {return;} + if (!test_test_create_dir()) {return;} + if (!test_test_create_rw_file()) {return;} + if (!test_test_listdir()) {return;} + if (!test_test_create_vfs()) {return;} + if (!test_test_get_root()) {return;} + if (!test_path_create_test()) {return;} + if (!test_path_equal_test_1()) {return;} + if (!test_path_parent_test_1()) {return;} + if (!test_path_parent_test_2()) {return;} + if (!test_path_parent_test_3()) {return;} + if (!test_path_parent_test_4()) {return;} + if (!test_path_parent_test_5()) {return;} + if (!test_path_parent_test_6()) {return;} + if (!test_path_parent_test_7()) {return;} + if (!test_path_parent_test_8()) {return;} + if (!test_path_parent_test_9()) {return;} + if (!test_path_parent_test_10()) {return;} + if (!test_path_is_absolute_test()) {return;} + if (!test_path_is_relative_test_1()) {return;} + if (!test_path_is_relative_test_2()) {return;} + if (!test_path_clone_test()) {return;} + if (!test_path_find_file_test()) {return;} + if (!test_path_filename_test()) {return;} + if (!test_path_filename_test_trailing()) {return;} + if (!test_path_filename_test_1()) {return;} + if (!test_path_filename_test_2()) {return;} + if (!test_path_filename_test_3()) {return;} + if (!test_path_filename_test_4()) {return;} + + kprintf("TESTS COMPLETE. Passed %i tests\n", 54); } #endif + From 69d7ee0cda8dcfeed75670e8261f62919c4645fa Mon Sep 17 00:00:00 2001 From: Reinout Meliesie Date: Thu, 27 Feb 2020 21:41:42 +0100 Subject: [PATCH 019/104] Updated gitignore --- .gitignore | 6 ++++++ .vscode/settings.json | 7 ------- 2 files changed, 6 insertions(+), 7 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index 3e8b88ba..ff3f8ad3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,10 +9,16 @@ /qemu/ !/qemu/build.sh build/ +/cmake-build-*/ +/html/ +/latex/ +/course_os_docs.pdf .settings/ .cproject .project +/.idea/ +/.vscode/ #always exclude these from being pushed *.o diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index ba02a079..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files.associations": { - "string.h": "c", - "stdint.h": "c", - "stdio.h": "c" - } -} \ No newline at end of file From 530bc82e6e0882324b1ab26a8d8165fe49e218d2 Mon Sep 17 00:00:00 2001 From: Reinout Meliesie Date: Thu, 27 Feb 2020 21:57:19 +0100 Subject: [PATCH 020/104] Modernised build scripts --- kernel/offset.sh | 5 +- kernel/src/test/generate_tests.sh | 2 - kernel/uboot_configuration/generate.sh | 2 +- qemu/build.sh | 3 +- toolchain/build.sh | 74 +++++++++++++------------- 5 files changed, 41 insertions(+), 45 deletions(-) diff --git a/kernel/offset.sh b/kernel/offset.sh index 20932776..e1dc9889 100755 --- a/kernel/offset.sh +++ b/kernel/offset.sh @@ -1,8 +1,7 @@ #!/bin/bash if [ "$(uname)" == "Darwin" ]; then - printf "bootm 0x%X\n" $(expr $(stat -f%z ../u-boot/u-boot-$1/u-boot.bin) + 65536) + printf "bootm 0x%X\n" $(($(stat -f%z "../u-boot/u-boot-$1/u-boot.bin") + 65536)) else - printf "bootm 0x%X\n" $(expr $(stat -c%s ../u-boot/u-boot-$1/u-boot.bin) + 65536) + printf "bootm 0x%X\n" $(($(stat -c%s "../u-boot/u-boot-$1/u-boot.bin") + 65536)) fi - diff --git a/kernel/src/test/generate_tests.sh b/kernel/src/test/generate_tests.sh index e5d8422a..b40b2969 100755 --- a/kernel/src/test/generate_tests.sh +++ b/kernel/src/test/generate_tests.sh @@ -43,5 +43,3 @@ echo " } #endif " >> "$DIR/test.c" - - diff --git a/kernel/uboot_configuration/generate.sh b/kernel/uboot_configuration/generate.sh index edf2f5ed..ab0fc227 100755 --- a/kernel/uboot_configuration/generate.sh +++ b/kernel/uboot_configuration/generate.sh @@ -5,4 +5,4 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" echo " setenv bootargs $*@ bootm 0x210000 -" > "$DIR/uboot-commands.ubt" \ No newline at end of file +" > "$DIR/uboot-commands.ubt" diff --git a/qemu/build.sh b/qemu/build.sh index 481b0617..a9cce93b 100755 --- a/qemu/build.sh +++ b/qemu/build.sh @@ -1,6 +1,5 @@ #!/bin/bash -#QEMU_VERSION=1.6.2 QEMU_VERSION=2.4.1 qemu-system-arm --version || { @@ -13,5 +12,5 @@ qemu-system-arm --version || { tar xvf qemu-${QEMU_VERSION}.tar.bz2 fi - cd qemu-${QEMU_VERSION}; ./configure --prefix=`pwd`/../qemu --target-list=arm-softmmu && make all install + cd qemu-${QEMU_VERSION}; ./configure --prefix="$(pwd)/../qemu" --target-list=arm-softmmu && make all install } diff --git a/toolchain/build.sh b/toolchain/build.sh index 098c8478..7197d954 100755 --- a/toolchain/build.sh +++ b/toolchain/build.sh @@ -1,7 +1,7 @@ #!/bin/bash -PREFIX=`pwd`/arm-none-eabi -TARGET=`pwd`/target +PREFIX=$(pwd)/arm-none-eabi +TARGET=$(pwd)/target #TARGET=/tmp/course_os/target URL=ftp://ftp.gnu.org/gnu @@ -9,21 +9,21 @@ URL=ftp://ftp.gnu.org/gnu GCC_VERSION=4.8.1 BINUTILS_VERSION=2.24 NEWLIB_VERSION=2.0.0 -GDB_VERSION=7.7 +GDB_VERSION=9.1 GDB_EXT_VERSION=${GDB_VERSION} -if [ -e ${PREFIX} ]; then +if [ -e "${PREFIX}" ]; then exit 0; fi -rm -rf ${TARGET} +rm -rf "${TARGET}" -mkdir -p ${TARGET}/orig -mkdir -p ${TARGET}/src -mkdir -p ${TARGET}/build -mkdir -p ${TARGET}/buildroot +mkdir -p "${TARGET}/orig" +mkdir -p "${TARGET}/src" +mkdir -p "${TARGET}/build" +mkdir -p "${TARGET}/buildroot" -cd ${TARGET}/orig +cd "${TARGET}/orig" if [ ! -e gcc-${GCC_VERSION}.tar.gz ]; then wget ${URL}/gcc/gcc-${GCC_VERSION}/gcc-${GCC_VERSION}.tar.gz || exit 1; @@ -41,33 +41,33 @@ if [ ! -e newlib-${NEWLIB_VERSION}.tar.gz ]; then wget ftp://sources.redhat.com/pub/newlib/newlib-${NEWLIB_VERSION}.tar.gz || exit 1; fi -cd ${TARGET}/src +cd "${TARGET}/src" -if [ ! -d ${TARGET}/src/gcc-${GCC_VERSION} ]; then - tar xvf ../orig/gcc-${GCC_VERSION}.tar.gz || exit 1; +if [ ! -d "${TARGET}/src/gcc-${GCC_VERSION}" ]; then + tar xf ../orig/gcc-${GCC_VERSION}.tar.gz || exit 1; fi -if [ ! -d ${TARGET}/src/gdb-${GDB_EXT_VERSION} ]; then - tar xvf ../orig/gdb-${GDB_EXT_VERSION}.tar.gz || exit 1; +if [ ! -d "${TARGET}/src/gdb-${GDB_EXT_VERSION}" ]; then + tar xf ../orig/gdb-${GDB_EXT_VERSION}.tar.gz || exit 1; fi -if [ ! -d ${TARGET}/src/binutils-${BINUTILS_VERSION} ]; then - tar xvf ../orig/binutils-${BINUTILS_VERSION}.tar.bz2 || exit 1; +if [ ! -d "${TARGET}/src/binutils-${BINUTILS_VERSION}" ]; then + tar xf ../orig/binutils-${BINUTILS_VERSION}.tar.bz2 || exit 1; fi -if [ ! -d ${TARGET}/src/newlib-${NEWLIB_VERSION} ]; then - tar xvf ../orig/newlib-${NEWLIB_VERSION}.tar.gz || exit 1; +if [ ! -d "${TARGET}/src/newlib-${NEWLIB_VERSION}" ]; then + tar xf ../orig/newlib-${NEWLIB_VERSION}.tar.gz || exit 1; fi -if [ ! -e ${PREFIX}/bin/arm-none-eabi-ld ]; then - mkdir -p ${TARGET}/build/binutils-${BINUTILS_VERSION} +if [ ! -e "${PREFIX}/bin/arm-none-eabi-ld" ]; then + mkdir -p "${TARGET}/build/binutils-${BINUTILS_VERSION}" sed -i -e 's/@colophon/@@colophon/g' \ - -e 's/doc@cygnus.com/doc@@cygnus.com/g' ${TARGET}/src/binutil s-${BINUTILS_VERSION}/bfd/doc/bfd.texinfo - cd ${TARGET}/build/binutils-${BINUTILS_VERSION} + -e 's/doc@cygnus.com/doc@@cygnus.com/g' "${TARGET}/src/binutils-${BINUTILS_VERSION}/bfd/doc/bfd.texinfo" + cd "${TARGET}/build/binutils-${BINUTILS_VERSION}" ../../src/binutils-${BINUTILS_VERSION}/configure \ --target=arm-none-eabi \ - --prefix=${PREFIX} \ + --prefix="${PREFIX}" \ --enable-interwork \ --enable-multilib \ --with-gnu-as \ @@ -78,14 +78,14 @@ if [ ! -e ${PREFIX}/bin/arm-none-eabi-ld ]; then fi export PATH="$PATH:${PREFIX}/bin" -mkdir -p ${TARGET}/build/gcc-${GCC_VERSION} -sed -i 's/BUILD_INFO=info/BUILD_INFO =/g' ${TARGET}/src/gcc-${GCC_VERSION}/gcc/configure -cd ${TARGET}/src/gcc-${GCC_VERSION} +mkdir -p "${TARGET}/build/gcc-${GCC_VERSION}" +sed -i 's/BUILD_INFO=info/BUILD_INFO =/g' "${TARGET}/src/gcc-${GCC_VERSION}/gcc/configure" +cd "${TARGET}/src/gcc-${GCC_VERSION}" ./contrib/download_prerequisites -cd ${TARGET}/build/gcc-${GCC_VERSION} +cd "${TARGET}/build/gcc-${GCC_VERSION}" ../../src/gcc-${GCC_VERSION}/configure \ --target=arm-none-eabi \ - --prefix=${PREFIX} \ + --prefix="${PREFIX}" \ --enable-interwork \ --enable-multilib \ --disable-nls \ @@ -96,11 +96,11 @@ cd ${TARGET}/build/gcc-${GCC_VERSION} --with-headers=../../src/newlib-${NEWLIB_VERSION}/newlib/libc/include || exit 1; make all-gcc && make install-gcc || exit 1; -mkdir -p ${TARGET}/build/newlib-${NEWLIB_VERSION} -cd ${TARGET}/build/newlib-${NEWLIB_VERSION} +mkdir -p "${TARGET}/build/newlib-${NEWLIB_VERSION}" +cd "${TARGET}/build/newlib-${NEWLIB_VERSION}" ../../src/newlib-${NEWLIB_VERSION}/configure \ --target=arm-none-eabi \ - --prefix=${PREFIX} \ + --prefix="${PREFIX}" \ --enable-interwork \ --with-gnu-as \ --with-gnu-ld \ @@ -112,12 +112,12 @@ cd ${TARGET}/build/newlib-${NEWLIB_VERSION} --enable-multilib || exit 1; make all && make install || exit 1; -cd ${TARGET}/build/gcc-${GCC_VERSION} +cd "${TARGET}/build/gcc-${GCC_VERSION}" make all install || exit 1; -mkdir -p ${TARGET}/build/gdb-${GDB_VERSION} -cd ${TARGET}/build/gdb-${GDB_VERSION} -../../src/gdb-${GDB_VERSION}/configure --target=arm-none-eabi --prefix=${PREFIX} --disable-werror --enable-interwork --enable-multilib || exit 1; +mkdir -p "${TARGET}/build/gdb-${GDB_VERSION}" +cd "${TARGET}/build/gdb-${GDB_VERSION}" +../../src/gdb-${GDB_VERSION}/configure --target=arm-none-eabi --prefix="${PREFIX}" --disable-werror --enable-interwork --enable-multilib || exit 1; make all && make install || exit 1; -rm -rf ${TARGET} +rm -rf "${TARGET}" From cb56be947552b6a4c6dc9ab0e89885338c1d4320 Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Thu, 27 Feb 2020 22:25:07 +0100 Subject: [PATCH 021/104] Some cleanup and transfered the vm test to our new testing framework. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jonathan Dönszelmann --- .vscode/settings.json | 2 +- kernel/old/include/.DS_Store | Bin 6148 -> 0 bytes .../old/tests/testingsuite_example/.DS_Store | Bin 6148 -> 0 bytes kernel/src/common/hw_handlers.c | 11 +- kernel/src/ds/include/ds.h | 3 +- kernel/src/ds/include/vp_hash_map.h | 10 -- kernel/src/ds/include/vp_hash_map.h.old | 51 -------- kernel/src/ds/vp_hash_map.c.old | 118 ------------------ kernel/src/klibc/include/klibc.h | 27 +++- kernel/src/memory/test/test_allocator.c | 2 +- kernel/src/memory/vm/test/test_vm.c | 105 ++++++++++++++++ kernel/src/test/test.c | 60 ++++----- 12 files changed, 169 insertions(+), 220 deletions(-) delete mode 100644 kernel/old/include/.DS_Store delete mode 100644 kernel/old/tests/testingsuite_example/.DS_Store delete mode 100644 kernel/src/ds/include/vp_hash_map.h delete mode 100644 kernel/src/ds/include/vp_hash_map.h.old delete mode 100644 kernel/src/ds/vp_hash_map.c.old create mode 100644 kernel/src/memory/vm/test/test_vm.c diff --git a/.vscode/settings.json b/.vscode/settings.json index ba02a079..4a1c636a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,4 +4,4 @@ "stdint.h": "c", "stdio.h": "c" } -} \ No newline at end of file +} diff --git a/kernel/old/include/.DS_Store b/kernel/old/include/.DS_Store deleted file mode 100644 index b0f47a7fdf65b9111ba622d51689cf807f206003..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKPfNov6i>G4S_WFdgWhuUvcrbX>B%znjMa#BJc4=h1xK+4X$?FWZZYtVESw`H9AQQYdO;wWrE%E?g_hjP%6{Wwfc zJncM+!nCahH4e+NExYL~4TrVLMp;yAo1?NA*6WqBSgWs(M$VOOEw8L@?FI7k`sViT z{^9XS)6L<_RI*@j49{SES^0(6i#swthsd~UoJ~j!5Cg=(G%;Y#IIA>Gi=wp<1H{0u zFo5TS07Y~SW*XJe0S*2>V!VKe0ye%S5QRb4V5SiwAY7LM>QZi=7+jZwUzj}CV5U)* zGp=Taam>uzyimBB9sEM2Gwy1nmKY!gJ~NQlT?g;~-Jjq8pNptR3=jiT#Q-ntcsmVP zlDS(a7KeAO06ham!Msf4dkGloDu!IVikCo@fM1{i=o-v4f(L|t1QZR_5Ceb8z#HTx BTAcs@ diff --git a/kernel/old/tests/testingsuite_example/.DS_Store b/kernel/old/tests/testingsuite_example/.DS_Store deleted file mode 100644 index fb0c27234dee3e4ce91e84c76e4962d98b161887..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}N6?5Kd~WRl5}FOb<`jPXj_Ut!E$?kcD1nXf-+hBLjGM1?I9AH23rUB~34kJ(zv-nxRb6Qt6fF#`5D6lU8AB8k;>c zby{o0om%Rq?WE$ij@3x|foJThn>Ie|{WuN>w(A|ppi{T!w&N&uWfZhNg`OPB$d5af zxE=Y)Nlou}DE+iix96*^-~vLcZWJ8IM0zrmY1b-XtJ@2`-eys(u9W*l(JPlrMX|O~ z>i6v{%UW7q-`YEB_Ajq*Ztw0N9-p4|ZEz$2WmdzWe;HV05Cg;jF)(rrn5WO09=Vgz zfrtTO;I|Cm`yfCO9fO%h^>jd|N&vt-xRrp7wFJfpgO0&WBg}ws9SW#JxhXNY4hO$5 z>l}lbMjg($DL%OQGB*_pS6_$yg<8(Iqmg=IfEf77z?dG|nE!WwuK&LV(TErz21bej zp5LkMRNzP^w+@@pi00m&;WD{W*Wf*LO%kE2I`1` HKV{$@LCs$; diff --git a/kernel/src/common/hw_handlers.c b/kernel/src/common/hw_handlers.c index 08a23b40..422b294c 100644 --- a/kernel/src/common/hw_handlers.c +++ b/kernel/src/common/hw_handlers.c @@ -63,12 +63,17 @@ void __attribute__((interrupt("UNDEF"))) undef_instruction_handler(void) asm volatile("mrs %0, spsr" : "=r"(spsr)); asm volatile("mov %0, lr" : "=r" (lr)); - kprintf("UNDEFINED INSTRUCTION HANDLER\n"); - int thumb = spsr & 0x20; int pc = thumb ? lr - 0x2 : lr - 0x4; - int copro = (*(int*)pc & 0xf00000) >> 24; + if ((*(size_t *) pc) == UNDEFINED_INSTRUCTION_BYTES){ + kprintf("FATAL ERROR\n"); + panic(); + } + + kprintf("UNDEFINED INSTRUCTION HANDLER\n"); + + int copro = (*(int*)pc & 0xf00000) >> 24; if (spsr & 0x20) { kprintf("THUMB mode\n"); diff --git a/kernel/src/ds/include/ds.h b/kernel/src/ds/include/ds.h index afaa0834..cd9a06de 100644 --- a/kernel/src/ds/include/ds.h +++ b/kernel/src/ds/include/ds.h @@ -7,7 +7,6 @@ // used across datastructures typedef void (*FreeFunc)(void * data); typedef bool (*CompareFunc)(void * in, void * other); -typedef uint32_t (*HashFunc)(void * key); #include #include @@ -15,4 +14,4 @@ typedef uint32_t (*HashFunc)(void * key); #include #include -#endif \ No newline at end of file +#endif diff --git a/kernel/src/ds/include/vp_hash_map.h b/kernel/src/ds/include/vp_hash_map.h deleted file mode 100644 index d4e1043a..00000000 --- a/kernel/src/ds/include/vp_hash_map.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef HASH_MAP_H -#define HASH_MAP_H - -#include - -struct HashMap { - -}; - -#endif \ No newline at end of file diff --git a/kernel/src/ds/include/vp_hash_map.h.old b/kernel/src/ds/include/vp_hash_map.h.old deleted file mode 100644 index 565d73d1..00000000 --- a/kernel/src/ds/include/vp_hash_map.h.old +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef HASH_MAP_H -#define HASH_MAP_H - -#include - - -typedef struct HashSetElement { - uint32_t hash; - void * key; -} HashSetElement; - -typedef struct HashMapElement { - HashSetElement base; - void * data; -} HashMapElement; - -typedef struct HashMap { - HashFunc hashFunc; - CompareFunc compareFunc; - FreeFunc freeKey; - FreeFunc freeData; - struct VPSinglyLinkedList * buckets; - uint32_t n_buckets; -} HashMap; - -typedef HashMap HashSet; - -// Creates a new hashmap with given hash function and number of buckets -HashMap * hm_new(HashFunc hashf, FreeFunc datafreef, FreeFunc keyfreef, CompareFunc comparef, uint32_t n_buckets); -HashSet * hs_new(HashFunc hashf, FreeFunc datafreef, FreeFunc keyfreef, CompareFunc comparef, uint32_t n_buckets); - -// inserts an element into the hashmap/hashset -void hm_insert(HashMap * hm, void * key, void * data); -void hs_insert(HashSet * hs, void * key); - -// Gets the element associated with the key -void * hm_get(HashMap * hm, void * key); - -// Returns true if the element is included. -bool hm_contains(HashMap * hm, void * key); -bool hs_contains(HashSet * hm, void * key); - -// removes an element from the hashmap/hashset, returns the element so it can be freed -void * hm_remove(HashMap * hm, void * key); -void * hs_remove(HashSet * hs, void * key); - -// Frees the hashmap completely uses the FreeFunc to free any left over data. -void hm_free(HashMap * hm); -void hs_free(HashSet * hm); - -#endif diff --git a/kernel/src/ds/vp_hash_map.c.old b/kernel/src/ds/vp_hash_map.c.old deleted file mode 100644 index 05daea77..00000000 --- a/kernel/src/ds/vp_hash_map.c.old +++ /dev/null @@ -1,118 +0,0 @@ -#include -#include -#include - - -static inline HashMapElement * __hm_get_internal(HashMap * hm, void * key) { - size_t index = elem->base.hash; - - VPSLL_FOREACH(&hm->buckets[index], i) { - HashMapElement * elem = i->data; - if(compf(elem->base.key, key)) { - return elem; - } - } - return NULL; -} - -// Creates a new hashmap with given hash function and number of buckets -HashMap * hm_new(HashFunc hashf, FreeFunc datafreef, FreeFunc keyfreef, CompareFunc comparef, uint32_t n_buckets) { - HashMap * res = kmalloc(sizeof(HashMap)); - *res = (HashMap) { - // We can calloc/zero this memory since vpslls have an initial size of 0 and NULL pointer. - // Therefore a zeroed piece of memory *is* a vpsll - .buckets = kcalloc(n_buckets, sizeof(VPSinglyLinkedList)), - .hashFunc = hashf, - .compareFunc = comparef, - .freeData = datafreef, - .freeKey = keyfreef, - .n_buckets = n_buckets, - }; - - return res; -} - -HashSet * hs_new(HashFunc hashf, FreeFunc datafreef, FreeFunc keyfreef, CompareFunc comparef, uint32_t n_buckets) { return hm_new(hashf, datafreef, keyfreef, comparef, n_buckets); } - -static inline void __hm_insert_internal(HashMap * hm, struct HashMapElement * elem) { - size_t index = elem->base.hash; - - struct HashMapElement * old = __hm_get_internal(hm, ) - - vpsll_push(&hm->buckets[index], elem); - - return NULL; -} - -// inserts an element into the hashmap/hashset -void hm_insert(HashMap * hm, void * key, void * data) { - HashMapElement * hme = kmalloc(sizeof(HashMapElement)); - *hme = (HashMapElement) { - .base = (HashSetElement) { - .hash = hm->hashFunc(key), - .key = key, - }, - .data = data, - }; - - return __hm_insert_internal(hm, hme); -} - -void hs_insert(HashSet * hs, void * key) { - HashSetElement * hse = kmalloc(sizeof(HashSetElement)); - - *hse = (HashSetElement) { - .hash = hs->hashFunc(key), - .key = key, - }; - - return __hm_insert_internal(hs, hse); -} - -// Gets the element associated with the key -void * hm_get(HashMap * hm, void * key) { - HashMapElement * res = __hm_get_internal(hm, key); - if (res != NULL) { - return res->data; - } else { - return NULL; - } -} - -// Returns true if the element is included. -bool hm_contains(HashMap * hm, void * key) { - return __hm_get_internal(hm, key) != NULL; -} -bool hs_contains(HashSet * hs, void * key) {return hm_contains(hs, key)} - -// removes an element from the hashmap/hashset, returns the element so it can be freed -void * hm_remove(HashMap * hm, void * key) { - -} - -void * hs_remove(HashSet * hs, void * key) { return hm_remove(hs, key);} - - -void hm_free(HashMap * hm) { - for (int i = 0; i < hm->buckets; i++) { - - VPSinglyLinkedList * lst = &hm->buckets[i]; - - struct VPSinglyLinkedListLink * curr = lst->head; - while (curr != NULL) { - struct VPSinglyLinkedListLink * last = curr; - curr = curr->next; - if (freef != NULL) { - freef(last->data); - } - kfree(last); - } - - vpsll_free_inner(, ); - } - kfree(hm); -} - -void hs_free(HashSet * hs) { - return hm_free(hs); -} \ No newline at end of file diff --git a/kernel/src/klibc/include/klibc.h b/kernel/src/klibc/include/klibc.h index 2e53e6fe..4ad723e3 100644 --- a/kernel/src/klibc/include/klibc.h +++ b/kernel/src/klibc/include/klibc.h @@ -73,11 +73,28 @@ unsigned int rand(); // development #define LOG_LEVEL 5 -#define DEBUG(...) if(LOG_LEVEL >= 5) kprintf(__VA_ARGS__) -#define LOG(...) if(LOG_LEVEL >= 4) kprintf(__VA_ARGS__) -#define INFO(...) if(LOG_LEVEL >= 3) kprintf(__VA_ARGS__) -#define WARN(...) if(LOG_LEVEL >= 2) kprintf(__VA_ARGS__) -#define ERROR(...) if(LOG_LEVEL >= 1) kprintf(__VA_ARGS__) +//#if LOG_LEVEL >= 5 +#define DEBUG(...) kprintf("DEBUG: " __VA_ARGS__) // :+1: +//#else +//#define DEBUG(...) +//#endif +#define LOG(...) kprintf(__VA_ARGS__) +#define INFO(...) kprintf(__VA_ARGS__) +#define WARN(...) kprintf(__VA_ARGS__) // :+1: +#define ERROR(...) kprintf(__VA_ARGS__); + +#define ___asm_opcode_swab32(x) ( \ + (((x) << 24) & 0xFF000000) \ + | (((x) << 8) & 0x00FF0000) \ + | (((x) >> 8) & 0x0000FF00) \ + | (((x) >> 24) & 0x000000FF) \ +) + +// Defines an instruction that will raise an undefined instruction code on both ARM (and hopefully THUMB2) +#define UNDEFINED_INSTRUCTION_BYTES 0xF7F1A2F3 +#define STRINGIFY2(X) #X +#define STRINGIFY(X) STRINGIFY2(X) +#define FATAL() asm volatile(".long " STRINGIFY(UNDEFINED_INSTRUCTION_BYTES)); //4-17-15: Initial panic * assert_fail functions added void panic() __attribute__ ((noreturn)); diff --git a/kernel/src/memory/test/test_allocator.c b/kernel/src/memory/test/test_allocator.c index eea83513..2a72bb85 100644 --- a/kernel/src/memory/test/test_allocator.c +++ b/kernel/src/memory/test/test_allocator.c @@ -41,4 +41,4 @@ TEST_CREATE(test_calloc, { } kfree(test); -}) \ No newline at end of file +}) diff --git a/kernel/src/memory/vm/test/test_vm.c b/kernel/src/memory/vm/test/test_vm.c new file mode 100644 index 00000000..c80d9ae2 --- /dev/null +++ b/kernel/src/memory/vm/test/test_vm.c @@ -0,0 +1,105 @@ +#include +#include "klibc.h" +#include "memory.h" +#include "vm.h" + +// TODO: This test has many LOG calls, we should try and looking at improving the logging capabilities +TEST_CREATE(test_vm_1, { + struct vas *vas1 = vm_new_vas(); + LOG("Got new vas at 0x%X\n", vas1); + + // We're part of the kernel, which is already mapped into vas1. + // But our stack isn't, so let's add that mapping. + unsigned int mystack = (unsigned int) &vas1; + mystack &= 0xFFF00000; // Round down to nearest MB + LOG("Stack addr: 0x%X\n", mystack); + LOG("Created page table w/ 0xFFF00000's entry = 0x%X\n", + vas1->l1_pagetable[V_KDSBASE>>20]); + + vm_enable_vas(vas1); + + // Do we still have the stack? + // FIXME Update constant as necessary + #define STACK_ADDR 0xF020000C + // Invalid stack + ASSERT_EQ((unsigned int) vas1, STACK_ADDR); + + struct vas *vas2 = (struct vas*) V_L1PTBASE; + INFO("%X (%X)\n", vas2, &vas2); + INFO("%X\n", *((unsigned int* ) vas2)); + INFO("%X\n", vas2->l1_pagetable); + INFO("Entry: %x\n", + vas1->l1_pagetable[(unsigned int ) vas2->l1_pagetable >> 20]); + INFO("%X\n", vas2->l1_pagetable[0]); + INFO("(deref: entry at 0x200000: 0x%X)\n", + vas2->l1_pagetable[0x200000 >> 20]); + + // Test making a thing in this thing + struct vas *vas3 = vm_new_vas(); + vm_enable_vas(vas3); + INFO("%X and %X and %X\n", vas1, vas2, vas3); + + // Test allocating frames... + #define P3_BASE 0x24000000 + int retval = vm_allocate_page(vas3, (void*) P3_BASE,VM_PERM_PRIVILEGED_RW); + + // vm_allocate_page fails + ASSERT(!retval); + + int *p = (int*) 0xFFFFFFF0; + p[0] = 1; + + ASSERT_EQ(p[0], 1); + + // Oh man! We should be able to write to there! + p = (int*) P3_BASE; + p[0] = 1; + + LOG("%x %x\n", &p, p); + + ASSERT_EQ(p[0], 1); + + // Test shared memory... + LOG("Testing shared memory...\n"); + int *p_3 = (int*) P3_BASE;//0x24000000; + int *p_1 = (int*) 0x31000000; + retval = vm_map_shared_memory(vas1, p_1, vas3, p_3, VM_PERM_PRIVILEGED_RW); + LOG("map_shared_memory returned %d\n", retval); + + p_3[0] = 321; + vm_enable_vas(vas1); + ASSERT_EQ(p_1[0], 321); + p_1[1] = 456; + + vm_enable_vas(vas3); + ASSERT_EQ(p_3[1], 456); + + // Test allocating many frames... (this was commented but seems to work just fine) + *p += BLOCK_SIZE; + while (!vm_allocate_page(vas3, (void*) p, 0)) { + //LOG("Allocated memory...\n"); + p += BLOCK_SIZE; + } + + p -= BLOCK_SIZE; + kprintf("Highest frame allocated: 0x%X\n", p); + + while ((unsigned int) p > P3_BASE) { + //LOG("Freed memory...\n"); + vm_free_page(vas3, p); + p -= BLOCK_SIZE; + } + + // FIXME: This part of the test crashes the os, we should capture that in some way. + // Test the data abort... +// WARN("You should see a data abort...\n"); +// int i = p[-1]; +// LOG("%d\n", i); + + // Free the page! + LOG("Freeing page at %X\n", p); + vm_free_page(vas3, p); + + // Clean up & switch back to the kernel's VAS before we return. + vm_enable_vas((struct vas*) KERNEL_VAS); +}) diff --git a/kernel/src/test/test.c b/kernel/src/test/test.c index 31b07d36..329935be 100644 --- a/kernel/src/test/test.c +++ b/kernel/src/test/test.c @@ -7,22 +7,17 @@ #include -int test_test_alloc_free(); -int test_test_alloc_free_large(); -int test_test_alloc_realloc_free(); -int test_test_free_null(); -int test_test_calloc(); -int test_u8a_push_get_pop_test(); -int test_u8a_push_set_pop_test(); -int test_u8a_resize_test(); -int test_u8a_push_string_test(); -int test_u8a_clone_test(); int test_test_compare_nonequal_length(); int test_test_compare_equal_length(); int test_test_compare_equal_length_eq(); int test_test_compare_equal_length_eq_null(); int test_test_compare_various(); int test_test_hash(); +int test_u8a_push_get_pop_test(); +int test_u8a_push_set_pop_test(); +int test_u8a_resize_test(); +int test_u8a_push_string_test(); +int test_u8a_clone_test(); int test_test_create_ll(); int test_test_iter_ll(); int test_test_get_ll(); @@ -32,10 +27,12 @@ int test_test_vpsll_remove(); int test_test_vpsll_set(); int test_test_create_hm(); int test_test_free_entries_hm(); -int test_test_create_file(); -int test_test_create_dir(); -int test_test_create_rw_file(); -int test_test_listdir(); +int test_test_vm_1(); +int test_test_alloc_free(); +int test_test_alloc_free_large(); +int test_test_alloc_realloc_free(); +int test_test_free_null(); +int test_test_calloc(); int test_test_create_vfs(); int test_test_get_root(); int test_path_create_test(); @@ -61,23 +58,22 @@ int test_path_filename_test_1(); int test_path_filename_test_2(); int test_path_filename_test_3(); int test_path_filename_test_4(); +int test_test_create_file(); +int test_test_create_dir(); +int test_test_create_rw_file(); +int test_test_listdir(); void test_main(){ - if (!test_test_alloc_free()) {return;} - if (!test_test_alloc_free_large()) {return;} - if (!test_test_alloc_realloc_free()) {return;} - if (!test_test_free_null()) {return;} - if (!test_test_calloc()) {return;} - if (!test_u8a_push_get_pop_test()) {return;} - if (!test_u8a_push_set_pop_test()) {return;} - if (!test_u8a_resize_test()) {return;} - if (!test_u8a_push_string_test()) {return;} - if (!test_u8a_clone_test()) {return;} if (!test_test_compare_nonequal_length()) {return;} if (!test_test_compare_equal_length()) {return;} if (!test_test_compare_equal_length_eq()) {return;} if (!test_test_compare_equal_length_eq_null()) {return;} if (!test_test_compare_various()) {return;} if (!test_test_hash()) {return;} + if (!test_u8a_push_get_pop_test()) {return;} + if (!test_u8a_push_set_pop_test()) {return;} + if (!test_u8a_resize_test()) {return;} + if (!test_u8a_push_string_test()) {return;} + if (!test_u8a_clone_test()) {return;} if (!test_test_create_ll()) {return;} if (!test_test_iter_ll()) {return;} if (!test_test_get_ll()) {return;} @@ -87,10 +83,12 @@ void test_main(){ if (!test_test_vpsll_set()) {return;} if (!test_test_create_hm()) {return;} if (!test_test_free_entries_hm()) {return;} - if (!test_test_create_file()) {return;} - if (!test_test_create_dir()) {return;} - if (!test_test_create_rw_file()) {return;} - if (!test_test_listdir()) {return;} + if (!test_test_vm_1()) {return;} + if (!test_test_alloc_free()) {return;} + if (!test_test_alloc_free_large()) {return;} + if (!test_test_alloc_realloc_free()) {return;} + if (!test_test_free_null()) {return;} + if (!test_test_calloc()) {return;} if (!test_test_create_vfs()) {return;} if (!test_test_get_root()) {return;} if (!test_path_create_test()) {return;} @@ -116,8 +114,12 @@ void test_main(){ if (!test_path_filename_test_2()) {return;} if (!test_path_filename_test_3()) {return;} if (!test_path_filename_test_4()) {return;} + if (!test_test_create_file()) {return;} + if (!test_test_create_dir()) {return;} + if (!test_test_create_rw_file()) {return;} + if (!test_test_listdir()) {return;} - kprintf("TESTS COMPLETE. Passed %i tests\n", 54); + kprintf("TESTS COMPLETE. Passed %i tests\n", 55); } #endif From 11ab0e3d2000bad3ef23e1424cc1350e5ba679a4 Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Thu, 27 Feb 2020 22:30:25 +0100 Subject: [PATCH 022/104] remove accidentally added file :sweat_smile: --- kernel/src/test/test.c | 125 ----------------------------------------- 1 file changed, 125 deletions(-) delete mode 100644 kernel/src/test/test.c diff --git a/kernel/src/test/test.c b/kernel/src/test/test.c deleted file mode 100644 index 329935be..00000000 --- a/kernel/src/test/test.c +++ /dev/null @@ -1,125 +0,0 @@ - -// DO NOT EDIT -// this file is generated by generate_tests.sh - -#ifdef ENABLE_TESTS - -#include - - -int test_test_compare_nonequal_length(); -int test_test_compare_equal_length(); -int test_test_compare_equal_length_eq(); -int test_test_compare_equal_length_eq_null(); -int test_test_compare_various(); -int test_test_hash(); -int test_u8a_push_get_pop_test(); -int test_u8a_push_set_pop_test(); -int test_u8a_resize_test(); -int test_u8a_push_string_test(); -int test_u8a_clone_test(); -int test_test_create_ll(); -int test_test_iter_ll(); -int test_test_get_ll(); -int test_test_contains_true(); -int test_test_contains_false(); -int test_test_vpsll_remove(); -int test_test_vpsll_set(); -int test_test_create_hm(); -int test_test_free_entries_hm(); -int test_test_vm_1(); -int test_test_alloc_free(); -int test_test_alloc_free_large(); -int test_test_alloc_realloc_free(); -int test_test_free_null(); -int test_test_calloc(); -int test_test_create_vfs(); -int test_test_get_root(); -int test_path_create_test(); -int test_path_equal_test_1(); -int test_path_parent_test_1(); -int test_path_parent_test_2(); -int test_path_parent_test_3(); -int test_path_parent_test_4(); -int test_path_parent_test_5(); -int test_path_parent_test_6(); -int test_path_parent_test_7(); -int test_path_parent_test_8(); -int test_path_parent_test_9(); -int test_path_parent_test_10(); -int test_path_is_absolute_test(); -int test_path_is_relative_test_1(); -int test_path_is_relative_test_2(); -int test_path_clone_test(); -int test_path_find_file_test(); -int test_path_filename_test(); -int test_path_filename_test_trailing(); -int test_path_filename_test_1(); -int test_path_filename_test_2(); -int test_path_filename_test_3(); -int test_path_filename_test_4(); -int test_test_create_file(); -int test_test_create_dir(); -int test_test_create_rw_file(); -int test_test_listdir(); -void test_main(){ - if (!test_test_compare_nonequal_length()) {return;} - if (!test_test_compare_equal_length()) {return;} - if (!test_test_compare_equal_length_eq()) {return;} - if (!test_test_compare_equal_length_eq_null()) {return;} - if (!test_test_compare_various()) {return;} - if (!test_test_hash()) {return;} - if (!test_u8a_push_get_pop_test()) {return;} - if (!test_u8a_push_set_pop_test()) {return;} - if (!test_u8a_resize_test()) {return;} - if (!test_u8a_push_string_test()) {return;} - if (!test_u8a_clone_test()) {return;} - if (!test_test_create_ll()) {return;} - if (!test_test_iter_ll()) {return;} - if (!test_test_get_ll()) {return;} - if (!test_test_contains_true()) {return;} - if (!test_test_contains_false()) {return;} - if (!test_test_vpsll_remove()) {return;} - if (!test_test_vpsll_set()) {return;} - if (!test_test_create_hm()) {return;} - if (!test_test_free_entries_hm()) {return;} - if (!test_test_vm_1()) {return;} - if (!test_test_alloc_free()) {return;} - if (!test_test_alloc_free_large()) {return;} - if (!test_test_alloc_realloc_free()) {return;} - if (!test_test_free_null()) {return;} - if (!test_test_calloc()) {return;} - if (!test_test_create_vfs()) {return;} - if (!test_test_get_root()) {return;} - if (!test_path_create_test()) {return;} - if (!test_path_equal_test_1()) {return;} - if (!test_path_parent_test_1()) {return;} - if (!test_path_parent_test_2()) {return;} - if (!test_path_parent_test_3()) {return;} - if (!test_path_parent_test_4()) {return;} - if (!test_path_parent_test_5()) {return;} - if (!test_path_parent_test_6()) {return;} - if (!test_path_parent_test_7()) {return;} - if (!test_path_parent_test_8()) {return;} - if (!test_path_parent_test_9()) {return;} - if (!test_path_parent_test_10()) {return;} - if (!test_path_is_absolute_test()) {return;} - if (!test_path_is_relative_test_1()) {return;} - if (!test_path_is_relative_test_2()) {return;} - if (!test_path_clone_test()) {return;} - if (!test_path_find_file_test()) {return;} - if (!test_path_filename_test()) {return;} - if (!test_path_filename_test_trailing()) {return;} - if (!test_path_filename_test_1()) {return;} - if (!test_path_filename_test_2()) {return;} - if (!test_path_filename_test_3()) {return;} - if (!test_path_filename_test_4()) {return;} - if (!test_test_create_file()) {return;} - if (!test_test_create_dir()) {return;} - if (!test_test_create_rw_file()) {return;} - if (!test_test_listdir()) {return;} - - kprintf("TESTS COMPLETE. Passed %i tests\n", 55); -} -#endif - From 5461f8ec18dd8c2f72bdbcb50e9c057c7f46690f Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Fri, 28 Feb 2020 11:50:47 +0100 Subject: [PATCH 023/104] added some hashmap tests --- kernel/src/ds/bpf/test/hashmap_test.c | 94 +++++++++++++++++++++++++++ kernel/src/ds/test/vp_hash_map_test.c | 0 kernel/src/memory/vm/test/test_vm.c | 10 +-- 3 files changed, 99 insertions(+), 5 deletions(-) delete mode 100644 kernel/src/ds/test/vp_hash_map_test.c diff --git a/kernel/src/ds/bpf/test/hashmap_test.c b/kernel/src/ds/bpf/test/hashmap_test.c index 63fa7c66..1278cf54 100644 --- a/kernel/src/ds/bpf/test/hashmap_test.c +++ b/kernel/src/ds/bpf/test/hashmap_test.c @@ -48,3 +48,97 @@ TEST_CREATE(test_free_entries_hm, { // Test framework will assert that we won't leak. }) + +TEST_CREATE(test_find_hm, { + HashMap * hm = hashmap__new(int_hash_fn, int_compare_fn, fakeFree, fakeFree, NULL); + + int key = 5; + int data = 42; + + hashmap__add(hm, &key, &data); + + ASSERT_EQ(hashmap__size(hm), 1); + + int * ptr = NULL; + void ** dp = (void **) &ptr; + + ASSERT(hashmap__find(hm, &key, dp)); + ASSERT_EQ(&data, *dp); + ASSERT_EQ(data, *ptr); + + hashmap__free(hm); +}) + +TEST_CREATE(test_set_hm, { + HashMap * hm = hashmap__new(int_hash_fn, int_compare_fn, fakeFree, fakeFree, NULL); + + int key = 5; + int data = 42; + + // add 42 + hashmap__add(hm, &key, &data); + + ASSERT_EQ(hashmap__size(hm), 1); + + int * ptr = NULL; + void ** dp = (void **) &ptr; + + ASSERT(hashmap__find(hm, &key, dp)); + ASSERT_EQ(&data, *dp); + ASSERT_EQ(data, *ptr); + + // set 42 to 69 + int new_data = 69; + hashmap__set(hm, &key,&new_data, NULL, NULL); + + ASSERT(hashmap__find(hm, &key, dp)); + ASSERT_EQ(&new_data, *dp); + ASSERT_EQ(new_data, *ptr); + + // set (144,196) which doesn't exist yet + int extra_data = 196; + int extra_key = 144; + hashmap__set(hm, &extra_key,&extra_data, NULL, NULL); + + ASSERT(hashmap__find(hm, &extra_key, dp)); + ASSERT_EQ(&extra_data, *dp); + ASSERT_EQ(extra_data, *ptr); + + hashmap__free(hm); +}) + + +TEST_CREATE(test_update_hm, { + HashMap * hm = hashmap__new(int_hash_fn, int_compare_fn, fakeFree, fakeFree, NULL); + + int key = 5; + int data = 42; + + // add 42 + hashmap__add(hm, &key, &data); + + ASSERT_EQ(hashmap__size(hm), 1); + + int * ptr = NULL; + void ** dp = (void **) &ptr; + + ASSERT(hashmap__find(hm, &key, dp)); + ASSERT_EQ(&data, *dp); + ASSERT_EQ(data, *ptr); + + // set 42 to 69 + int new_data = 69; + hashmap__update(hm, &key,&new_data, NULL, NULL); + + ASSERT(hashmap__find(hm, &key, dp)); + ASSERT_EQ(&new_data, *dp); + ASSERT_EQ(new_data, *ptr); + + // set (144,196) which doesn't exist + int extra_data = 196; + int extra_key = 144; + ASSERT_EQ(hashmap__update(hm, &extra_key,&extra_data, NULL, NULL), -1); + + hashmap__free(hm); +}) + diff --git a/kernel/src/ds/test/vp_hash_map_test.c b/kernel/src/ds/test/vp_hash_map_test.c deleted file mode 100644 index e69de29b..00000000 diff --git a/kernel/src/memory/vm/test/test_vm.c b/kernel/src/memory/vm/test/test_vm.c index c80d9ae2..bb4af60f 100644 --- a/kernel/src/memory/vm/test/test_vm.c +++ b/kernel/src/memory/vm/test/test_vm.c @@ -41,7 +41,7 @@ TEST_CREATE(test_vm_1, { // Test allocating frames... #define P3_BASE 0x24000000 - int retval = vm_allocate_page(vas3, (void*) P3_BASE,VM_PERM_PRIVILEGED_RW); + int retval = vm_allocate_page(vas3, (void*) P3_BASE, VM_PERM_PRIVILEGED_RW); // vm_allocate_page fails ASSERT(!retval); @@ -90,11 +90,11 @@ TEST_CREATE(test_vm_1, { p -= BLOCK_SIZE; } - // FIXME: This part of the test crashes the os, we should capture that in some way. + // FIXME: This part of the test crashes the os, we should catch that in some way. // Test the data abort... -// WARN("You should see a data abort...\n"); -// int i = p[-1]; -// LOG("%d\n", i); + //WARN("You should see a data abort...\n"); + //int i = p[-1]; + //LOG("%d\n", i); // Free the page! LOG("Freeing page at %X\n", p); From 91add9fcb4d035b2b44309e9092aaa3973fd2f67 Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Fri, 28 Feb 2020 12:10:30 +0100 Subject: [PATCH 024/104] Added CI with Github actions. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Used semihosting to exit the vm appropriately at the end of a test. Co-authored-by: Jonathan Dönszelmann --- .editorconfig | 4 +++ .github/workflows/os_test.yml | 41 +++++++++++++++++++++++ .gitignore | 1 + Makefile | 4 +-- kernel/Makefile | 25 +++++++------- kernel/src/common/hw_handlers.c | 16 +++++++-- kernel/src/common/include/hw_handlers.h | 44 ++++++++++++++++++------- kernel/src/common/start.c | 6 ++-- kernel/src/test/generate_tests.sh | 2 ++ kernel/src/test/monitor_tests.sh | 23 ------------- kernel/tests.c | 42 ----------------------- 11 files changed, 113 insertions(+), 95 deletions(-) create mode 100644 .github/workflows/os_test.yml delete mode 100755 kernel/src/test/monitor_tests.sh delete mode 100644 kernel/tests.c diff --git a/.editorconfig b/.editorconfig index a882442c..8f5ed13c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,3 +5,7 @@ end_of_line = lf insert_final_newline = true indent_style = space indent_size = 4 +charset = utf-8 + +[*.yml] +indent_size = 2 diff --git a/.github/workflows/os_test.yml b/.github/workflows/os_test.yml new file mode 100644 index 00000000..9ada401a --- /dev/null +++ b/.github/workflows/os_test.yml @@ -0,0 +1,41 @@ +name: course_os test suite + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Cache Toolchain + id: cache-toolchain + uses: actions/cache@v1 + with: + path: toolchain + key: toolchain + + - name: Cache u-boot + id: cache-u-boot + uses: actions/cache@v1 + with: + path: u-boot + key: u-boot + + - name: Install Dependencies + run: | + sudo apt-get update && + sudo apt-get install build-essential qemu-system-arm python3 wget texinfo zlib1g-dev -y + + - name: Install Toolchain + if: steps.cache-toolchain.outputs.cache-hit != 'true' + run: make toolchain + + - name: Install u-boot + run: make u-boot + + - name: Compile + run: make build + + - name: Test + run: make test diff --git a/.gitignore b/.gitignore index ff3f8ad3..4085608c 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ Session.vim uboot-commands.ubt NOTES +/server.PID diff --git a/Makefile b/Makefile index 842a032a..24ea3560 100644 --- a/Makefile +++ b/Makefile @@ -26,11 +26,11 @@ clean: build: u-boot kernel .PHONY: build -run: build +run: u-boot @$(MAKE) -C ./kernel run .PHONY: run -test: build +test: u-boot @$(MAKE) -C ./kernel test docs: diff --git a/kernel/Makefile b/kernel/Makefile index 7a852bed..ecfe4bb1 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -15,6 +15,7 @@ SOURCEDIR = src BUILDDIR = build # every directory named `include` will have it's contents autoincluded INCLUDEDIR = include +TEST_MAIN_FILE = $(SOURCEDIR)/test/test.c # =================== End Configuration =================== @@ -27,7 +28,8 @@ MKIMAGE:=$(CURDIR)/../u-boot/u-boot-$(UBOOT_VERSION)/tools/mkimage GDB:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gdb DIRS = $(shell find $(SOURCEDIR)/ -type d -print) -C_SOURCE_FILES := $(foreach dir,$(DIRS),$(wildcard $(dir)/*.c)) +C_SOURCE_FILES := $(foreach dir,$(DIRS),$(wildcard $(dir)/*.c)) $(TEST_MAIN_FILE) +# Add test.c when we are compiling tests C_OBJECT_FILES := $(patsubst $(SOURCEDIR)/%.c, \ $(BUILDDIR)/%.o, $(C_SOURCE_FILES)) @@ -36,6 +38,8 @@ S_OBJECT_FILES := $(patsubst $(SOURCEDIR)/%.s, \ $(BUILDDIR)/%.o, $(S_SOURCE_FILES)) OBJECT_FILES := $(S_OBJECT_FILES) $(C_OBJECT_FILES) +#test: OBJECT_FILES += $(patsubst $(SOURCEDIR)/%.c, $(BUILDDIR)/%.o, $(TEST_MAIN_FILE)) + INCLUDEDIRS := $(sort $(foreach dir, $(foreach dir1, $(DIRS), $(shell dirname $(dir1))), $(wildcard $(dir)/$(INCLUDEDIR)))) CFLAGS += $(foreach dir, $(INCLUDEDIRS), -I./$(dir)) @@ -45,17 +49,14 @@ build: $(BUILDDIR)/card.sd $(BUILDDIR)/flash.bin | builddir build_pi: $(BUILDDIR)/kernelPi.img | builddir test: build | builddir - ${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -kernel build/flash.bin -append "-load 0x410000 0x14000" > test.log & echo $$! > server.PID; - # montior the output, save exit code, remove logfile, kill qemu, - # remove pid file used to kill qemu, exit with correct exit code - $(SOURCEDIR)/test/monitor_tests.sh;e=$$?; rm test.log; kill $$(cat server.PID); rm server.PID; exit $$e + ${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -semihosting -kernel build/flash.bin -append "-load 0x410000 0x14000" run: build | builddir # nographic to turn off the gui # monitor none to disable stdio monitoring so # serial stdio works - ${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -monitor none -serial stdio -kernel build/flash.bin -append "-load 0x410000 0x14000" + ${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -semihosting -monitor none -serial stdio -kernel build/flash.bin -append "-load 0x410000 0x14000" $(BUILDDIR)/flash.bin: $(BUILDDIR)/kernel.img $(BUILDDIR)/bootloader.img @@ -70,7 +71,9 @@ $(BUILDDIR)/card.sd: | builddir dd if=/dev/zero of=$@ conv=notrunc bs=4096 count=32768 $(BUILDDIR)/kernel.elf: $(OBJECT_FILES) | builddir - $(LD) -T linker/kernel.ld -nostartfiles -Wl,-Map,kernel.map $(OBJECT_FILES) -o $@ + @echo $< + @echo $^ + $(LD) -T linker/kernel.ld -nostartfiles -Wl,-Map,kernel.map $^ -o $@ $(BUILDDIR)/kernel.bin: $(BUILDDIR)/kernel.elf | builddir $(OBJCOPY) -O binary $< $@ @@ -102,11 +105,8 @@ $(BUILDDIR)/%.o: $(SOURCEDIR)/%.s | builddir @echo Assembling $< @$(AS) -mcpu=arm1176jzf-s -g $< -o $@ -$(BUILDDIR)/test/test.o: $(SOURCEDIR)/test/test.c dummy | builddir +$(TEST_MAIN_FILE): dummy @$(SOURCEDIR)/test/generate_tests.sh - @mkdir -p $(shell dirname $@) - @echo Compiling $< - @$(CC) $(CFLAGS) -c $< -o $@ # depend on dummy to always recompile. There aren't that many files atm anyway and @@ -119,6 +119,7 @@ $(BUILDDIR)/%.o: $(SOURCEDIR)/%.c dummy | builddir clean: rm -rf $(BUILDDIR) + rm -rf $(SOURCEDIR)/test/test.c # use to force rebuild of certain recipes -dummy:; \ No newline at end of file +dummy:; diff --git a/kernel/src/common/hw_handlers.c b/kernel/src/common/hw_handlers.c index 422b294c..3412ac65 100644 --- a/kernel/src/common/hw_handlers.c +++ b/kernel/src/common/hw_handlers.c @@ -11,8 +11,6 @@ #include #include #include -// TODO: fs is removed -//#include "fs/file.h" /* copy vector table from wherever QEMU loads the kernel to 0x00 */ void init_vector_table(void) @@ -318,3 +316,17 @@ void __attribute__((interrupt("FIQ"))) fiq_handler(void) restore_proc_status(cpsr); } + +void SemihostingCall(enum SemihostingSWI mode) { + + int a = mode; + + asm volatile ( + "MOV r0, #0x18\n" + "LDR r1, %[in0]\n" + "svc 0x00123456\n" + : + : [in0] "m" (a) + ); + +} diff --git a/kernel/src/common/include/hw_handlers.h b/kernel/src/common/include/hw_handlers.h index 7180b027..146c7368 100644 --- a/kernel/src/common/include/hw_handlers.h +++ b/kernel/src/common/include/hw_handlers.h @@ -32,10 +32,10 @@ */ #include "stdint.h" -#define BRANCH_INSTRUCTION 0xe59ff018 // ldr pc, pc+offset +#define BRANCH_INSTRUCTION 0xe59ff018 // ldr pc, pc+offset // System Call Types -#define SYSCALL_CREATE 0 +#define SYSCALL_CREATE 0 #define SYSCALL_SWITCH 1 #define SYSCALL_DELETE 2 #define SYSCALL_OPEN 3 @@ -46,8 +46,8 @@ #define SYSCALL_MEM_MAP 8 #define SYSCALL_SEEK 9 #define SYSCALL_MKDIR 10 -#define SYSCALL_COPY 11 -#define SYSCALL_LS 12 +#define SYSCALL_COPY 11 +#define SYSCALL_LS 12 #define SYSCALL_MALLOC 13 #define SYSCALL_ALIGNED_ALLOC 14 #define SYSCALL_FREE 15 @@ -57,18 +57,38 @@ #define SYSCALL_WRITEV 101 #define SYSCALL_PAUSE 102 -void init_vector_table(void); +void init_vector_table(void); // vector table handlers, should be loaded at 0x00 in this order! extern void _Reset(); + void reset_handler(void); -void __attribute__((interrupt("UNDEF"))) undef_instruction_handler(void); // 0x04 -long __attribute__((interrupt("SWI"))) software_interrupt_handler(void); // 0x08 -void __attribute__((interrupt("ABORT"))) prefetch_abort_handler(void); // 0x0c -void __attribute__((interrupt("ABORT"))) data_abort_handler(void); // 0x10 -void reserved_handler(void); // 0x14 -void __attribute__((interrupt("IRQ"))) irq_handler(void); // 0x18 -void __attribute__((interrupt("FIQ"))) fiq_handler(void); // 0x1c +void __attribute__((interrupt("UNDEF"))) undef_instruction_handler(void); // 0x04 +long __attribute__((interrupt("SWI"))) software_interrupt_handler(void); // 0x08 +void __attribute__((interrupt("ABORT"))) prefetch_abort_handler(void); // 0x0c +void __attribute__((interrupt("ABORT"))) data_abort_handler(void); // 0x10 +void reserved_handler(void); // 0x14 +void __attribute__((interrupt("IRQ"))) irq_handler(void); // 0x18 +void __attribute__((interrupt("FIQ"))) fiq_handler(void); // 0x1c + +/** + * Semihosting calls + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471g/CHDJHHDI.html + */ +enum SemihostingSWI { + BreakPoint = 0x20020, + WatchPoint = 0x20021, + StepComplete = 0x20022, + RunTimeErrorUnknown = 0x20023, + InternalError = 0x20024, + UserInterruption = 0x20025, + ApplicationExit = 0x20026, // Qemu exits with 0 + StackOverflow = 0x20027, + DivisionByZero = 0x20028, + OSSpecific = 0x20029, // Qemu exits with 1 +}; + +void SemihostingCall(enum SemihostingSWI mode); #endif diff --git a/kernel/src/common/start.c b/kernel/src/common/start.c index 4ad456af..57b48d91 100644 --- a/kernel/src/common/start.c +++ b/kernel/src/common/start.c @@ -106,15 +106,18 @@ void start2(uint32_t *p_bootargs) { process_init(); sched_init(); - // FIXME: temporary kprintf("Programming the timer interrupt\n"); start_timer_interrupts(0, 10); +// exit_test(); + #ifndef ENABLE_TESTS argparse_process(p_bootargs); #else test_main(); + // If we return, the tests failed. + SemihostingCall(OSSpecific); #endif print_uart0("done parsing atag list\n"); @@ -135,6 +138,5 @@ void start2(uint32_t *p_bootargs) { // * Load initramfs into tmpfs // * execute userland init program - SLEEP; } diff --git a/kernel/src/test/generate_tests.sh b/kernel/src/test/generate_tests.sh index b40b2969..09707b84 100755 --- a/kernel/src/test/generate_tests.sh +++ b/kernel/src/test/generate_tests.sh @@ -16,6 +16,7 @@ echo " #ifdef ENABLE_TESTS #include +#include " >> "$DIR/test.c" @@ -40,6 +41,7 @@ done # shellcheck disable=SC2028 echo " kprintf(\"TESTS COMPLETE. Passed %i tests\n\", "$len"); + SemihostingCall(ApplicationExit); } #endif " >> "$DIR/test.c" diff --git a/kernel/src/test/monitor_tests.sh b/kernel/src/test/monitor_tests.sh deleted file mode 100755 index ee1d2062..00000000 --- a/kernel/src/test/monitor_tests.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -tail -f -n +1 "$DIR/../../test.log" | while read line -do - if [[ $line == *"TESTS COMPLETE"* ]]; then - echo "$line" - exit 0 - elif [[ $line == *"MEMORY LEAK"* ]]; then - echo "FAILED (MEMORY: $line)" - exit 1 - elif [[ $line == *"FAILED"* ]]; then - echo "FAILED" - exit 2 - elif [[ $line == *"DATA ABORT HANDLER"* ]]; then - echo "FAILED (EXCEPTION: $line)" - exit 3 - else - echo "$line" - fi -done - diff --git a/kernel/tests.c b/kernel/tests.c deleted file mode 100644 index addc9729..00000000 --- a/kernel/tests.c +++ /dev/null @@ -1,42 +0,0 @@ -#include "global_defs.h" -#include "tests.h" -#include "klibc.h" -#include "mem_alloc.h" - -//This function executes and displays results of test set given to it. -void run_tests(Test *tests[], int num_tests) -{ - int i; - for (i = 0; i < num_tests; i++) - { - os_printf("Running test: %s", tests[i]->test_name); - os_printf(" ... \n"); - //evaluates test here, if it passes prints PASSES else FAILS - if (!(tests[i]->testptr)()) - { - os_printf(":-D\n\n"); - } - else - { - os_printf("=(\n\n"); - } - } -} - -Test* create_test(char *name, int (*test_function)(void*)) -{ - Test *test = (Test*) kmalloc(sizeof(Test)); - test->test_name = name; - test->testptr = test_function; - return test; -} - -int test1() -{ - return TRUE; -} - -int test2() -{ - return FALSE; -} From 6fcb1340713a26ba2ea93b9f4843c67e8ef4fa11 Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Fri, 28 Feb 2020 23:29:32 +0100 Subject: [PATCH 025/104] Updated cmakelist so that IntelliJ knows we are compiling ARM. --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d98ccf2..376df43d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,12 +8,17 @@ cmake_minimum_required(VERSION 3.6) project(course_os) +set(CMAKE_SYSTEM_NAME linux) +set(CMAKE_SYSTEM_PROCESSOR arm) +set(CMAKE_C_COMPILER ${CMAKE_CURRENT_SOURCE_DIR}/toolchain/arm-none-eabi/bin/arm-none-eabi-gcc) +set(CMAKE_C_LINK_EXECUTABLE ${CMAKE_CURRENT_SOURCE_DIR}/toolchain/arm-none-eabi/bin/arm-none-eabi-ld) + file(GLOB_RECURSE kernel_sources ./kernel/src/*.c ./kernel/src/**/*.c) file(GLOB_RECURSE kernel_include LIST_DIRECTORIES true ./kernel/src/**/include) set(SOURCE_FILES ${kernel_sources}) -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") add_compile_definitions(ENABLE_TESTS MEM_DEBUG) From d2081237682d6ac6106d3c4e2bea9a49290c010b Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Fri, 28 Feb 2020 23:41:59 +0100 Subject: [PATCH 026/104] Testing if we can upgrade the toolchain to some more modern tools. --- toolchain/build.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/toolchain/build.sh b/toolchain/build.sh index 7197d954..a75b2755 100755 --- a/toolchain/build.sh +++ b/toolchain/build.sh @@ -6,9 +6,9 @@ TARGET=$(pwd)/target URL=ftp://ftp.gnu.org/gnu # toolchain -GCC_VERSION=4.8.1 -BINUTILS_VERSION=2.24 -NEWLIB_VERSION=2.0.0 +GCC_VERSION=9.2.0 +BINUTILS_VERSION=2.34 +NEWLIB_VERSION=3.1.0 GDB_VERSION=9.1 GDB_EXT_VERSION=${GDB_VERSION} From 7fffa3703b6cd35bca95242bc8c06c606a546fc2 Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Sat, 29 Feb 2020 09:47:16 +0100 Subject: [PATCH 027/104] using armv6 instead of v5 for uboot --- u-boot/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/u-boot/Makefile b/u-boot/Makefile index 31a47725..065c21f4 100644 --- a/u-boot/Makefile +++ b/u-boot/Makefile @@ -13,16 +13,17 @@ run: $(UBOOT_DIR)/u-boot.bin $(UBOOT_DIR)/u-boot.bin: $(UBOOT_DIR) -cd $(UBOOT_DIR); patch --silent --forward -p1 < ../versatile.patch + sed -i 's/armv5/armv6/g' $(UBOOT_DIR)/arch/arm/cpu/arm1136/config.mk # It's actually armv6 and we don't need the compiler compat cd $(UBOOT_DIR); make versatileqemu_config ARCH=arm CPU=arm1136 CROSS_COMPILE=$(BARE_METAL_TUPLE)- cp -r $(UBOOT_DIR)/arch/arm/cpu/arm926ejs/versatile $(UBOOT_DIR)/arch/arm/cpu/arm1136 - cd $(UBOOT_DIR); make all ARCH=arm CPU=arm1136 CROSS_COMPILE=$(BARE_METAL_TUPLE)- + cd $(UBOOT_DIR); make all ARCH=arm CPU=arm1136 CROSS_COMPILE=$(BARE_METAL_TUPLE)- $(UBOOT_DIR): $(UBOOT_ARCHIVE) tar xvf $(UBOOT_ARCHIVE) $(UBOOT_ARCHIVE): wget $(UBOOT_URL) - + clean: rm -rf $(UBOOT_DIR) From bc7eee7d7374bcbe554463268997238cee386f0e Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Sat, 29 Feb 2020 14:39:54 +0100 Subject: [PATCH 028/104] removed uboot and improved uart interface Co-authored-by: Victor Roest --- .github/workflows/os_test.yml | 10 -- Makefile | 16 +- kernel/Makefile | 45 +---- kernel/linker/kernelPi.ld | 4 +- kernel/src/common/interrupt.c | 11 +- kernel/src/common/start.c | 36 ++-- kernel/src/common/startup.s | 6 + kernel/src/drivers/uart/include/uart.h | 41 ++++- kernel/src/drivers/uart/uart.c | 32 +++- kernel/src/drivers/uart/uart_qemu.c | 164 ++++++++---------- kernel/src/klibc/printf.c | 4 +- kernel/src/memory/mmap.c | 6 +- kernel/uboot_configuration/generate.sh | 8 - kernel/uboot_configuration/uboot-commands.ubt | 4 - 14 files changed, 183 insertions(+), 204 deletions(-) delete mode 100755 kernel/uboot_configuration/generate.sh delete mode 100644 kernel/uboot_configuration/uboot-commands.ubt diff --git a/.github/workflows/os_test.yml b/.github/workflows/os_test.yml index 9ada401a..45463dcc 100644 --- a/.github/workflows/os_test.yml +++ b/.github/workflows/os_test.yml @@ -15,13 +15,6 @@ jobs: path: toolchain key: toolchain - - name: Cache u-boot - id: cache-u-boot - uses: actions/cache@v1 - with: - path: u-boot - key: u-boot - - name: Install Dependencies run: | sudo apt-get update && @@ -31,9 +24,6 @@ jobs: if: steps.cache-toolchain.outputs.cache-hit != 'true' run: make toolchain - - name: Install u-boot - run: make u-boot - - name: Compile run: make build diff --git a/Makefile b/Makefile index 24ea3560..486eb04e 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,9 @@ -all: toolchain u-boot kernel +all: toolchain kernel toolchain: cd ./toolchain && ./build.sh .PHONY: toolchain -u-boot: - $(MAKE) -C u-boot -.PHONY: u-boot - libc: $(MAKE) -C user/libc @@ -17,20 +13,18 @@ kernel: libc .PHONY: kernel clean: - $(MAKE) -C u-boot clean $(MAKE) -C kernel clean $(MAKE) -C user/libc clean $(MAKE) -C user/hello clean .PHONY: clean -build: u-boot kernel -.PHONY: build +build: + @$(MAKE) -C ./kernel build -run: u-boot +run: @$(MAKE) -C ./kernel run -.PHONY: run -test: u-boot +test: @$(MAKE) -C ./kernel test docs: diff --git a/kernel/Makefile b/kernel/Makefile index ecfe4bb1..09c91450 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -3,8 +3,8 @@ include $(CURDIR)/../config.mk # ===================== Configuration ===================== # Flags to give to the c compiler -CFLAGS += -pipe -std=gnu99 -ffreestanding -nostdinc -Wall -Werror -g -O2 -PI_CFLAGS = -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -nostartfiles +CFLAGS += -pipe -std=gnu99 -ffreestanding -nostdinc -Wall -Werror -g -O2 -mcpu=arm1176jzf-s -march=armv6zk -mfpu=vfp +#PI_CFLAGS = -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -nostartfiles # variables to define in the preprocessor. MEMORY = 128M @@ -29,7 +29,6 @@ GDB:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gdb DIRS = $(shell find $(SOURCEDIR)/ -type d -print) C_SOURCE_FILES := $(foreach dir,$(DIRS),$(wildcard $(dir)/*.c)) $(TEST_MAIN_FILE) -# Add test.c when we are compiling tests C_OBJECT_FILES := $(patsubst $(SOURCEDIR)/%.c, \ $(BUILDDIR)/%.o, $(C_SOURCE_FILES)) @@ -38,57 +37,28 @@ S_OBJECT_FILES := $(patsubst $(SOURCEDIR)/%.s, \ $(BUILDDIR)/%.o, $(S_SOURCE_FILES)) OBJECT_FILES := $(S_OBJECT_FILES) $(C_OBJECT_FILES) -#test: OBJECT_FILES += $(patsubst $(SOURCEDIR)/%.c, $(BUILDDIR)/%.o, $(TEST_MAIN_FILE)) - INCLUDEDIRS := $(sort $(foreach dir, $(foreach dir1, $(DIRS), $(shell dirname $(dir1))), $(wildcard $(dir)/$(INCLUDEDIR)))) CFLAGS += $(foreach dir, $(INCLUDEDIRS), -I./$(dir)) CFLAGS += $(foreach def, $(DEFINITIONS), -D$(def)) -build: $(BUILDDIR)/card.sd $(BUILDDIR)/flash.bin | builddir +build: $(BUILDDIR)/kernel.elf | builddir build_pi: $(BUILDDIR)/kernelPi.img | builddir test: build | builddir - ${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -semihosting -kernel build/flash.bin -append "-load 0x410000 0x14000" - + #${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -semihosting -kernel build/flash.bin -append "-load 0x410000 0x14000" + ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M versatilepb -cpu arm1176 -nographic -append "-load 0x410000 0x14000" -semihosting run: build | builddir # nographic to turn off the gui # monitor none to disable stdio monitoring so # serial stdio works - ${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -semihosting -monitor none -serial stdio -kernel build/flash.bin -append "-load 0x410000 0x14000" - - -$(BUILDDIR)/flash.bin: $(BUILDDIR)/kernel.img $(BUILDDIR)/bootloader.img - dd if=/dev/zero of=$@ bs=4k count=1536 - dd if=../u-boot/u-boot-$(UBOOT_VERSION)/u-boot.bin of=$@ conv=notrunc bs=4k - # kernel - dd if=$(BUILDDIR)/kernel.img of=$@ conv=notrunc bs=4k seek=512 - # bootloader - dd if=$(BUILDDIR)/bootloader.img of=$@ conv=notrunc bs=4k seek=575 - -$(BUILDDIR)/card.sd: | builddir - dd if=/dev/zero of=$@ conv=notrunc bs=4096 count=32768 + #${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -semihosting -monitor none -serial stdio -kernel build/flash.bin -append "-load 0x410000 0x14000" + ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M versatilepb -cpu arm1176 -nographic -append "-load 0x410000 0x14000" -semihosting $(BUILDDIR)/kernel.elf: $(OBJECT_FILES) | builddir - @echo $< - @echo $^ $(LD) -T linker/kernel.ld -nostartfiles -Wl,-Map,kernel.map $^ -o $@ -$(BUILDDIR)/kernel.bin: $(BUILDDIR)/kernel.elf | builddir - $(OBJCOPY) -O binary $< $@ - -$(BUILDDIR)/kernel.img: $(BUILDDIR)/kernel.bin | builddir - $(MKIMAGE) -A arm -C none -O linux -T kernel -d $< -a 0x00010000 -e 0x00010000 $@ - -# Begin bootloader Make -uboot_configuration/uboot-commands.ubt: $(and $(KERNEL_PARAMS),dummy) - uboot_configuration/generate.sh $(KERNEL_PARAMS) - -$(BUILDDIR)/bootloader.img: uboot_configuration/uboot-commands.ubt | builddir - $(MKIMAGE) -A arm -C none -T script -d $< -a 0x10000 -e 0x10000 $@ -# End bootloader make - # Begin Pi Make $(BUILDDIR)/kernelPi.elf: $(C_OBJECT_FILES) | builddir $(CC) -T kernelPi.ld -O2 $(PI_CFLAGS) $(C_OBJECT_FILES) -o $@ @@ -108,7 +78,6 @@ $(BUILDDIR)/%.o: $(SOURCEDIR)/%.s | builddir $(TEST_MAIN_FILE): dummy @$(SOURCEDIR)/test/generate_tests.sh - # depend on dummy to always recompile. There aren't that many files atm anyway and # when the definitions change, we have to recompile. TODO: move definitions to some kind of file # so make knows that when it changed it should recompile. diff --git a/kernel/linker/kernelPi.ld b/kernel/linker/kernelPi.ld index 0f8a6d3b..d2a979d7 100644 --- a/kernel/linker/kernelPi.ld +++ b/kernel/linker/kernelPi.ld @@ -2,11 +2,11 @@ ENTRY(_Reset) SECTIONS { . = 0x8000; - .startup . : { build//common/startup.o(.text) } + .startup . : { build/common/startup.o(.text) } .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss COMMON) } . = ALIGN(8); . = . + 0x1000; stack_top = .; -} \ No newline at end of file +} diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index 8715061c..c7ccae79 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -104,11 +104,11 @@ void handle_irq_interrupt(enum InterruptID interrupt_vector) { // go to handler routine kprintf("Jumping to %X...\n", handlers[interrupt_vector]->handler); handlers[interrupt_vector]->handler((void *) interrupt_vector); - } /* enable IRQ and/or FIQ */ void enable_interrupt(interrupt_t mask) { + kprintf("Enabling interrupts with mask %i\n", mask); get_proc_status(); // enable interrupt on the core @@ -129,7 +129,9 @@ void enable_interrupt(interrupt_t mask) { /* disable IRQ and/or FIQ */ void disable_interrupt(interrupt_t mask) { - // disable interrupts on the core + kprintf("Disabling interrupts with mask %i\n", mask); + + // disable interrupts on the core switch (mask) { case IRQ_MASK: @@ -147,7 +149,10 @@ void disable_interrupt(interrupt_t mask) /* disable IRQ and/or FIQ, but also return a copy of the CPSR */ int disable_interrupt_save(interrupt_t mask) { - /* get a copy of the current process status register */ + + kprintf("Disabling interrupts (save) with mask %i\n", mask); + + /* get a copy of the current process status register */ int cpsr; asm volatile("mrs %0, cpsr" : "=r"(cpsr)); // disable interrupts on the core diff --git a/kernel/src/common/start.c b/kernel/src/common/start.c index 57b48d91..66cf2def 100644 --- a/kernel/src/common/start.c +++ b/kernel/src/common/start.c @@ -30,36 +30,20 @@ #include #include -// The file system has currently been *disabled* due to bugs -//#include "fs/open_table.h" //to initialize fs opentable -//#include "tests.h" - - -// Tests -//#include "../../tests/test_klibc.h" -//#include "tests/test_hash_map.h" -//#include "tests/test_mem_alloc.h" -//#include "tests/test_vm.h" -//#include "tests/test_priority_queue.h" - -#define UART0_IMSC (*((volatile uint32_t *)(UART0_ADDRESS + 0x038))) - -void uart_handler(void *null) { - print_uart0("uart0!\n"); -} // This start is what u-boot calls. It's just a wrapper around setting up the // virtual memory for the kernel. void start(uint32_t *p_bootargs) { // Initialize the virtual memory - print_uart0("Enabling MMU...\n"); + uart_early_init(); + + kprintf("Enabling MMU...\n"); vm_init(); kprintf("Initialized VM datastructures.\n"); mmap(p_bootargs); } - // This start is what starts the kernel. Note that virtual memory is enabled // at this point (And running, also, in the kernel's VAS). void start2(uint32_t *p_bootargs) { @@ -69,8 +53,6 @@ void start2(uint32_t *p_bootargs) { // Setup kmalloc... init_heap(); - //print_uart0("\nCourseOS!\n"); - splash(); // Test stuff... @@ -100,6 +82,8 @@ void start2(uint32_t *p_bootargs) { // enable interrupt handling enable_interrupts(); + uart_late_init(); + // initialize the timers initialize_timers(); @@ -112,15 +96,18 @@ void start2(uint32_t *p_bootargs) { // exit_test(); + kprintf("0x%x\n", p_bootargs); + #ifndef ENABLE_TESTS - argparse_process(p_bootargs); +// argparse_process(p_bootargs); +// +// TODO: Start init process #else test_main(); // If we return, the tests failed. SemihostingCall(OSSpecific); #endif - - print_uart0("done parsing atag list\n"); + kprintf("done parsing atag list\n"); //init_kheap(31 * 0x100000); //init_uheap(0x100000); @@ -137,6 +124,5 @@ void start2(uint32_t *p_bootargs) { // * Mount vfs // * Load initramfs into tmpfs // * execute userland init program - SLEEP; } diff --git a/kernel/src/common/startup.s b/kernel/src/common/startup.s index d0d05445..a54f55a4 100644 --- a/kernel/src/common/startup.s +++ b/kernel/src/common/startup.s @@ -1,6 +1,12 @@ .global _Reset _Reset: + // Disable other cores + //mrc p15, 0, r5, c0, c0, 5 + //and r5, r5, #3 + //cmp r5, #0 + //bne loop + LDR sp, =stack_top MOV R0, R2 BL start diff --git a/kernel/src/drivers/uart/include/uart.h b/kernel/src/drivers/uart/include/uart.h index 27dc456d..c327c0f2 100644 --- a/kernel/src/drivers/uart/include/uart.h +++ b/kernel/src/drivers/uart/include/uart.h @@ -3,8 +3,6 @@ #include -void print_uart0(const char *); - // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0183f/DDI0183.pdf // Section 3.2: Summary of registers @@ -38,10 +36,47 @@ void uart_write_int(volatile UartInterface * interface, volatile uint32_t value) uint8_t uart_read_byte(volatile UartInterface * interface); void uart_write_byte(volatile UartInterface * interface, volatile uint8_t value); +void uart0_puts(const char * s); +void uart0_putc(char c); +char uart0_getc(); + void UART0_INTERRUPT_HANDLER(); void UART1_INTERRUPT_HANDLER(); void UART2_INTERRUPT_HANDLER(); -void uart_init(); +// Called when the processor first boots +void uart_early_init(); + +// Called when interrupts have been enabled. Can be used to enable UART interrupts +void uart_late_init(); + +// http://infocenter.arm.com/help/topic/com.arm.doc.ddi0183f/DDI0183.pdf +// uart flag register masks +// (FR) +#define RI (1<<8) // Ring Indicator +#define TXFE (1<<7) // Transmit fifo empty +#define RXFF (1<<6) // Receive fifo full +#define TXFF (1<<5) // Transmit fifo full +#define RXFE (1<<4) // Receive fifo empty +#define BUSY (1<<3) // UART busy, set while uart is sending something +#define DCD (1<<2) // Data carrier detect +#define DSR (1<<1) // Data set ready +#define CTS (1<<0) // Clear to send + +// Uart interrupt masks. When a mask is set, this action causes an interrupt +// (IMSC) +#define OEIM (1<<10) // Overrun error +#define BEIM (1<<9) // Break error +#define PEIM (1<<8) // Parity error +#define FEIM (1<<7) // Framing error +#define RTIM (1<<6) // Receive timeout +#define TXIM (1<<5) // Transmit +#define RXIM (1<<4) // Receive +#define DSRMIM (1<<3) // nUARTDSR Modem +#define DCDMIM (1<<2) // nUARTDCD Modem +#define CTCMIM (1<<1) // nUARTCTS Modem +#define RIMIM (1<<0) // nUARTRI Modem +// (CR) +//#define CTSEn () // CTS Hardware Control Enable #endif // ifndef UART_H diff --git a/kernel/src/drivers/uart/uart.c b/kernel/src/drivers/uart/uart.c index ee6906ef..5607f26b 100644 --- a/kernel/src/drivers/uart/uart.c +++ b/kernel/src/drivers/uart/uart.c @@ -1,9 +1,5 @@ #include - -volatile UartInterface * const UART0_ADDRESS = (volatile UartInterface *)0x101f1000; -volatile UartInterface * const UART1_ADDRESS = (volatile UartInterface *)0x101f2000; -volatile UartInterface * const UART2_ADDRESS = (volatile UartInterface *)0x101f3000; - +#include void UART0_INTERRUPT_HANDLER() { // UART_ClearITPendingBit(UART0, UART_IT_Receive); @@ -23,9 +19,31 @@ void uart_write_int(volatile UartInterface * interface, volatile uint32_t value) } uint8_t uart_read_byte(volatile UartInterface * interface) { - return 0; + // Wait for UART to have received something. + while ( interface->FR & RXFE ) { + asm volatile ("nop"); + } + return interface->DR; } void uart_write_byte(volatile UartInterface * interface, volatile uint8_t value) { + while (interface->FR & TXFF ) { + asm volatile ("nop"); + } interface->DR = (uint32_t)value; -} \ No newline at end of file +} + +char uart0_getc() { + return uart_read_byte(UART0_ADDRESS); +} + +void uart0_puts(const char *s) { + while (*s != '\0') { + uart0_putc(*s); + s++; + } +} + +void uart0_putc(char c) { + uart_write_byte(UART0_ADDRESS, c); +} diff --git a/kernel/src/drivers/uart/uart_qemu.c b/kernel/src/drivers/uart/uart_qemu.c index 805ba09c..b8a7a42e 100644 --- a/kernel/src/drivers/uart/uart_qemu.c +++ b/kernel/src/drivers/uart/uart_qemu.c @@ -4,103 +4,91 @@ #include #include #include +#include -void uart_init() { - // Register the uart interrupt handler. -// register_interrupt_handler(UART0_IRQ, UART0_INTERRUPT_HANDLER) -} +// 0x3F200000 + 0x1000 -void print_uart0(const char *s) { - while (*s != '\0') { - uart_write_byte(UART0_ADDRESS, *s); - s++; - } -} +/* +// raspberry pi 2 + 3 +volatile UartInterface * const UART0_ADDRESS = (volatile UartInterface *)0x3f201000; +volatile UartInterface * const UART1_ADDRESS = (volatile UartInterface *)0x3f202000; +volatile UartInterface * const UART2_ADDRESS = (volatile UartInterface *)0x3f203000; -void print_char_uart0(char c) { - uart_write_byte(UART0_ADDRESS, c); -} +// raspberry pi zero, 1, b+ etc +volatile UartInterface * const UART0_ADDRESS = (volatile UartInterface *)0x20201000; +volatile UartInterface * const UART1_ADDRESS = (volatile UartInterface *)0x20202000; +volatile UartInterface * const UART2_ADDRESS = (volatile UartInterface *)0x20203000; + +// raspberry pi 4: +volatile UartInterface * const UART0_ADDRESS = (volatile UartInterface *)0xfe201000; +volatile UartInterface * const UART1_ADDRESS = (volatile UartInterface *)0xfe202000; +volatile UartInterface * const UART2_ADDRESS = (volatile UartInterface *)0xfe203000; + */ +// VersatilePB +volatile UartInterface * const UART0_ADDRESS = (volatile UartInterface *)0x101f1000; +volatile UartInterface * const UART1_ADDRESS = (volatile UartInterface *)0x101f2000; +volatile UartInterface * const UART2_ADDRESS = (volatile UartInterface *)0x101f3000; -/* print the full 32 bits of a word at the given address */ -/* trailing newline... */ -void print_word_bits(uint32_t * c) { - int i; - for (i = 31; i >= 0; i--) - *c & (1 << i) ? print_uart0("1") : print_uart0("0"); - print_uart0("\n"); + + +static inline void delay(int32_t count) +{ + asm volatile("__delay_%=: subs %[count], %[count], #1; bne __delay_%=\n" + : "=r"(count): [count]"0"(count) : "cc"); } -/* print the full 8-digit hex code of a word at the given address */ -/* no '0x' prefix, NO trailing newline */ -void print_word_hex(uint32_t * c) { - int i; - uint32_t a; - for (i = 0x7; i >= 0x0; i--) - { - a = *c & (0xf << (i * 0x4)); - a >>= (i * 0x4); - - if (a <= 9) - uart_write_byte(UART0_ADDRESS, (uint32_t )(a + (uint32_t )'0')); - else if (a <= 0xf) - uart_write_byte(UART0_ADDRESS, (uint32_t )((a - 0xa) + (uint32_t )'a')); - else - uart_write_byte(UART0_ADDRESS, (uint32_t )('?')); - } +void set_baud_rate(volatile UartInterface * interface, uint32_t baud_rate) { + const int UART_CLOCK_SPEED = 4000000; + float divider = UART_CLOCK_SPEED / (16.0f * baud_rate); + uint16_t integer_divider = (uint16_t)divider; + uint8_t fractional_divider = ((divider - integer_divider) * 64) + 0.5; + + interface->IBRD = integer_divider; // Integer baud rate divider + interface->FBRD = fractional_divider; // Fractional baud rate divider +}; + +void uart_early_init() { + //Disable UART + UART0_ADDRESS->CR = 0x00000000; + + #define GPPUD (GPIO_ADDRESS_PI + 0x94) //Controls pull up/down on GPIO pins + #define GPPUDCLK0 (GPIO_ADDRESS_PI + 0x98) //GPIO Clo + + mmio_write(GPPUD, 0x00000000); + delay(150); + + mmio_write(GPPUDCLK0, (1<<14) | (1<<15)); + delay(150); + + mmio_write(GPPUDCLK0,0x00000000); + + UART0_ADDRESS->ICR = 0x7ff; + //Enable DMA memory reads & writes with UART + //mmio_write(UARTDMACR, (1<<0) | (1<<1)); + + //Enable FIFO and set word length to 8 + UART0_ADDRESS->LCR_H = (1<<4) | (1<<5) | (1<<6); + + set_baud_rate(UART0_ADDRESS, 115200); + + //Enable interrupts + UART0_ADDRESS->IMSC = CTCMIM | RXIM | TXIM | RTIM | FEIM | PEIM | BEIM | OEIM; + //Enable UART and UART transfer + UART0_ADDRESS->CR = (1<<0) | (1<<8) | (1 << 9); + + + kprintf("Baud rate: %i:%i\n", UART0_ADDRESS->IBRD, UART0_ADDRESS->FBRD); } -/* display memory at given address */ -/* format is: "[address]: word1 word2 word3\n", etc. */ -/* displays 30 words (10 lines) */ -void md(uint32_t * start) { - int i, j; - uint32_t *addr = start; - for (i = 0; i < 10; i++) { - print_uart0("0x"); - print_word_hex((uint32_t *) &addr); - print_uart0(": "); - for (j = 0; j < 3; j++) { - print_word_hex(addr); - print_uart0(" "); - addr++; - } - print_uart0("\n"); - } +void uart_late_init() { + // Register the uart interrupt handler. + // register_interrupt_handler(UART0_IRQ, UART0_INTERRUPT_HANDLER) + + // kprintf("uart: 0x%x\n", UART0_ADDRESS->IMSC); + // UART0_ADDRESS->IMSC = RXIM; + // kprintf("uart: 0x%x\n", UART0_ADDRESS->IMSC); } -/*void print_uart0(const char *s) {*/ -/*while (uart->dd->uart0_inter_val == 0) {}*/ -/*if(uart.UARTCR & RXE > 0) */ -/*{*/ -/*while(*s != '\0') */ -/*{*/ -/**UART0 = (uint32_t)(*s);*/ -/*s++;*/ -/*}*/ -/*}*/ -/*}*/ - -/* We need to implement a lock here. klibc will be implementing the buffer - * we just need to ensure the FIFO isn't read out of order. - */ -/*char *read_uart0() */ -/*{*/ -/*uint32_t buffer[STD_IN_BUFFER_SIZE] = {0};*/ -/*while (uart->dd->uart0_inter_val == 0) {}*/ -/*uint32_t *iterator = buffer;*/ -/*do */ -/*{*/ -/*if(uart.UARTCR & TXE > 0) */ -/*{*/ -/*break;*/ -/*} */ -/*else */ -/*{*/ -/**iterator = uart.UARTDR;*/ -/*iterator++;*/ -/*}*/ -/*} while (*iterator != '\0');*/ -/*return buffer;*/ -/*}*/ + #endif // RASPBERRY_PI diff --git a/kernel/src/klibc/printf.c b/kernel/src/klibc/printf.c index c90b0fcc..de3d227e 100644 --- a/kernel/src/klibc/printf.c +++ b/kernel/src/klibc/printf.c @@ -173,6 +173,6 @@ int kprintf(const char *str_buf, ...) { char buf[256]; int n = os_vsnprintf(buf, 255, str_buf, args); va_end(args); - print_uart0(buf); + uart0_puts(buf); return n; -} \ No newline at end of file +} diff --git a/kernel/src/memory/mmap.c b/kernel/src/memory/mmap.c index 83224574..d59b66ca 100644 --- a/kernel/src/memory/mmap.c +++ b/kernel/src/memory/mmap.c @@ -33,7 +33,7 @@ void mmap(void *p_bootargs) { //stash register state on the stack asm volatile("push {r0-r11}"); - kprintf("%X\n", p_bootargs); + kprintf("Boot arguments location: %X\n", p_bootargs); /* int pte; @@ -146,10 +146,10 @@ void mmap(void *p_bootargs) { //Read contents into control asm volatile("mrc p15, 0, %[control], c1, c0, 0" : [control] "=r" (control)); //Set bit 0,1,2,12,13 - //control |= 0x3007; //0b11000000000111 + // control |= 0x3007; //0b11000000000111 control |= 0x1007; //0b01000000000111 (No high vectors) control |= 1 << 23; // Enable ARMv6 - //control |= 1<<29; // Enable ForceAP + // control |= 1<<29; // Enable ForceAPs kprintf("control reg: 0x%x\n", control); //Write back value into the register asm volatile("mcr p15, 0, %[control], c1, c0, 0" : : [control] "r" (control)); diff --git a/kernel/uboot_configuration/generate.sh b/kernel/uboot_configuration/generate.sh deleted file mode 100755 index ab0fc227..00000000 --- a/kernel/uboot_configuration/generate.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -echo " -setenv bootargs $*@ -bootm 0x210000 -" > "$DIR/uboot-commands.ubt" diff --git a/kernel/uboot_configuration/uboot-commands.ubt b/kernel/uboot_configuration/uboot-commands.ubt deleted file mode 100644 index 15f90ee9..00000000 --- a/kernel/uboot_configuration/uboot-commands.ubt +++ /dev/null @@ -1,4 +0,0 @@ - -setenv bootargs root=/dev/ram mem=128M@ -bootm 0x210000 - From 9ef1147397ce6a940a1a3307862913094e6eb745 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Sat, 29 Feb 2020 14:44:49 +0100 Subject: [PATCH 029/104] removed uboot dir --- u-boot/Makefile | 28 ---------------------------- u-boot/versatile.patch | 15 --------------- 2 files changed, 43 deletions(-) delete mode 100644 u-boot/Makefile delete mode 100644 u-boot/versatile.patch diff --git a/u-boot/Makefile b/u-boot/Makefile deleted file mode 100644 index 31a47725..00000000 --- a/u-boot/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -include $(CURDIR)/../config.mk - -UBOOT_DIR:=u-boot-$(UBOOT_VERSION) -UBOOT_ARCHIVE:=$(UBOOT_DIR).tar.bz2 -UBOOT_URL:=ftp://ftp.denx.de/pub/u-boot/$(UBOOT_ARCHIVE) - -export PATH:=$(CURDIR)/../$(TOOLCHAIN_DIR)/$(BARE_METAL_TARGET)/bin:$(PATH) - -all: $(UBOOT_DIR)/u-boot.bin - -run: $(UBOOT_DIR)/u-boot.bin - ${QEMU} -M versatilepb -cpu arm1176 -m 128M -nographic -kernel $(UBOOT_DIR)/u-boot.bin - -$(UBOOT_DIR)/u-boot.bin: $(UBOOT_DIR) - -cd $(UBOOT_DIR); patch --silent --forward -p1 < ../versatile.patch - cd $(UBOOT_DIR); make versatileqemu_config ARCH=arm CPU=arm1136 CROSS_COMPILE=$(BARE_METAL_TUPLE)- - cp -r $(UBOOT_DIR)/arch/arm/cpu/arm926ejs/versatile $(UBOOT_DIR)/arch/arm/cpu/arm1136 - cd $(UBOOT_DIR); make all ARCH=arm CPU=arm1136 CROSS_COMPILE=$(BARE_METAL_TUPLE)- - -$(UBOOT_DIR): $(UBOOT_ARCHIVE) - tar xvf $(UBOOT_ARCHIVE) - -$(UBOOT_ARCHIVE): - wget $(UBOOT_URL) - -clean: - rm -rf $(UBOOT_DIR) - diff --git a/u-boot/versatile.patch b/u-boot/versatile.patch deleted file mode 100644 index 0acabcdf..00000000 --- a/u-boot/versatile.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- new/include/configs/versatile.h 2014-10-14 03:47:15.000000000 -0500 -+++ u-boot-2014.10/include/configs/versatile.h 2014-12-22 15:07:12.090798194 -0600 -@@ -100,9 +100,9 @@ - #define CONFIG_BOOTP_SUBNETMASK - - #define CONFIG_BOOTDELAY 2 --#define CONFIG_BOOTARGS "root=/dev/nfs mem=128M ip=dhcp "\ -- "netdev=25,0,0xf1010000,0xf1010010,eth0 "\ -- "console=ttyAMA0,38400n1" -+#define CONFIG_BOOTARGS "" -+#define CONFIG_CMD_SOURCE -+#define CONFIG_BOOTCOMMAND "source 24f000" - - /* - * Static configuration when assigning fixed address From 3004a40533526c820e14f3bb6a04e1c4d3d11ee0 Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Sat, 29 Feb 2020 16:09:35 +0100 Subject: [PATCH 030/104] Fixed virtual memory. Hint: after enabling vm actually use the correctly translated addresses. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jonathan Dönszelmann --- kernel/Makefile | 2 +- kernel/old/tests/test_vm.c | 160 ---- kernel/src/common/hw_handlers.c | 39 +- kernel/src/ds/test/priority_queue_test.c | 17 + kernel/src/memory/mmap.c | 53 +- kernel/src/memory/vm/include/vm.h | 407 +++++----- kernel/src/memory/vm/vm.c | 918 +++++++++++------------ u-boot/Makefile | 29 - u-boot/versatile.patch | 15 - 9 files changed, 737 insertions(+), 903 deletions(-) delete mode 100644 kernel/old/tests/test_vm.c create mode 100644 kernel/src/ds/test/priority_queue_test.c delete mode 100644 u-boot/Makefile delete mode 100644 u-boot/versatile.patch diff --git a/kernel/Makefile b/kernel/Makefile index 09c91450..06ccf1da 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -3,7 +3,7 @@ include $(CURDIR)/../config.mk # ===================== Configuration ===================== # Flags to give to the c compiler -CFLAGS += -pipe -std=gnu99 -ffreestanding -nostdinc -Wall -Werror -g -O2 -mcpu=arm1176jzf-s -march=armv6zk -mfpu=vfp +CFLAGS += -pipe -std=gnu99 -ffreestanding -nostdinc -Wall -Werror -g -O3 -mcpu=arm1176jzf-s -march=armv6zk -mfpu=vfp #PI_CFLAGS = -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -nostartfiles # variables to define in the preprocessor. diff --git a/kernel/old/tests/test_vm.c b/kernel/old/tests/test_vm.c deleted file mode 100644 index 6bec6944..00000000 --- a/kernel/old/tests/test_vm.c +++ /dev/null @@ -1,160 +0,0 @@ -#include "tests.h" -#include "klibc.h" -#include "memory.h" -#include "vm.h" - -#define NUM_TESTS 1 - -int test_vm_1() { - os_printf("asdf\n"); - - struct vas *vas1 = vm_new_vas(); - LOG("Got new vas at 0x%X\n", vas1); - - // We're part of the kernel, which is already mapped into vas1. - // But our stack isn't, so let's add that mapping. - unsigned int mystack = (unsigned int) &vas1; - mystack &= 0xFFF00000; // Round down to nearest MB - LOG("Stack addr: 0x%X\n", mystack); - LOG("Created page table w/ 0xFFF00000's entry = 0x%X\n", - vas1->l1_pagetable[V_KDSBASE>>20]); - - vm_enable_vas(vas1); - - // Can we still print? - INFO("Hey, I'm printing!\n"); - - // Do we still have the stack? - // FIXME Update constant as necessary -#define STACK_ADDR 0xF020000C - if (((int) vas1) != STACK_ADDR) { - ERROR("Invalid stack"); - return TEST_FAIL; - } - - struct vas *vas2 = (struct vas*) V_L1PTBASE; - INFO("%X (%X)\n", vas2, &vas2); - INFO("%X\n", *((unsigned int* ) vas2)); - INFO("%X\n", vas2->l1_pagetable); - INFO("Entry: %x\n", - vas1->l1_pagetable[(unsigned int ) vas2->l1_pagetable >> 20]); - INFO("%X\n", vas2->l1_pagetable[0]); - INFO("(deref: entry at 0x200000: 0x%X)\n", - vas2->l1_pagetable[0x200000 >> 20]); - - // Test making a thing in this thing - struct vas *vas3 = vm_new_vas(); - vm_enable_vas(vas3); - INFO("%X and %X and %X\n", vas1, vas2, vas3); - - // Test allocating frames... -#define P3_BASE 0x24000000 - int retval = vm_allocate_page(vas3, (void*) P3_BASE, - VM_PERM_PRIVILEGED_RW); - - if (retval) { - ERROR("ERROR: vm_allocate_page returned %x\n", retval); - return TEST_FAIL; - } - - int *p = (int*) 0xFFFFFFF0; - p[0] = 1; - - if (p[0] != 1) { - ERROR("0x%x == 1?\n", p[0]); - return TEST_FAIL; - } - - // Oh man! We should be able to write to there! - p = (int*) P3_BASE; - p[0] = 1; - - LOG("%x %x\n", &p, p); - - if (p[0] != 1) { - ERROR("0x%x == 1?\n", p[0]); - return TEST_FAIL; - } - - // Test shared memory... - LOG("Testing shared memory...\n"); - int *p_3 = (int*) P3_BASE;//0x24000000; - int *p_1 = (int*) 0x31000000; - retval = vm_map_shared_memory(vas1, p_1, vas3, p_3, VM_PERM_PRIVILEGED_RW); - LOG("map_shared_memory returned %d\n", retval); - - p_3[0] = 321; - vm_enable_vas(vas1); - if (p_1[0] != 321) { - ERROR("0x%x == 321?", p_1[0]); - return TEST_FAIL; - } - p_1[1] = 456; - - vm_enable_vas(vas3); - if (p_3[1] != 456) { - ERROR("0x%x == 456?", p_3[1]); - return TEST_FAIL; - } - - // Test allocating many frames... - /*p += BLOCK_SIZE; - while (!vm_allocate_page(vas3, (void*) p, 0)) { - //LOG("Allocated memory...\n"); - p += BLOCK_SIZE; - } - - p -= BLOCK_SIZE; - LOG("Highest frame allocated: 0x%X\n", p); - - while ((unsigned int) p > P3_BASE) { - //LOG("Freed memory...\n"); - vm_free_page(vas3, p); - p -= BLOCK_SIZE; - }*/ - - // Test the data abort... - WARN("You should see a data abort...\n"); - int i = p[-1]; - LOG("%d\n", i); - - // Free the page! - LOG("Freeing page at %X\n", p); - vm_free_page(vas3, p); - - // Clean up & switch back to the kernel's VAS before we return. - vm_enable_vas((struct vas*) KERNEL_VAS); - - return TEST_OK; -} - -void vm_test_early() { - os_printf("Test code for VM (early).\n"); - -#if 0 - // Test 4KB pages - os_printf("0x%X\n", ((unsigned int *)(V_L1PTBASE + PAGE_TABLE_SIZE))[(PMAPBASE+0x100000)>>20]); - os_printf("entry at the address: 0x%X\n", ((unsigned int *)(V_L1PTBASE + PAGE_TABLE_SIZE))[(PMAPBASE+0x100000)>>20]); - unsigned int *p2 = (unsigned int*)(PMAPBASE+0x100000); - os_printf("0x%X\n",p2); - p2[1]++; - p2[1023]++; - os_printf("Should not have seen a page fault, should see one now.\n"); - p2[1024]++; - - // Hey, let's check the access bit now. - p2 = ((unsigned int *)(V_L1PTBASE + PAGE_TABLE_SIZE)); - os_printf("Entry is the address: 0x%X\n", ((unsigned int *)(V_L1PTBASE + PAGE_TABLE_SIZE))[(PMAPBASE+0x100000)>>20]); -#endif - - os_printf("Leaving early test code for VM.\n"); - //while (1); -} - -void run_vm_tests() { - Test *tests[NUM_TESTS]; - tests[0] = create_test("test_vm_1", &test_vm_1); - run_tests(tests, NUM_TESTS); - // Just in case it returned in error... - //vm_enable_vas((struct vas*) KERNEL_VAS); -} diff --git a/kernel/src/common/hw_handlers.c b/kernel/src/common/hw_handlers.c index 3412ac65..da0c161b 100644 --- a/kernel/src/common/hw_handlers.c +++ b/kernel/src/common/hw_handlers.c @@ -25,26 +25,27 @@ void init_vector_table(void) *dst++ = *src++; */ - /* Primary Vector Table */ - mmio_write(0x00, BRANCH_INSTRUCTION); - mmio_write(0x04, BRANCH_INSTRUCTION); - mmio_write(0x08, BRANCH_INSTRUCTION); - mmio_write(0x0C, BRANCH_INSTRUCTION); - mmio_write(0x10, BRANCH_INSTRUCTION); - mmio_write(0x14, BRANCH_INSTRUCTION); - mmio_write(0x18, BRANCH_INSTRUCTION); - mmio_write(0x1C, BRANCH_INSTRUCTION); - - /* Secondary Vector Table */ - mmio_write(0x20, &reset_handler); - mmio_write(0x24, &undef_instruction_handler); - mmio_write(0x28, &software_interrupt_handler); - mmio_write(0x2C, &prefetch_abort_handler); - mmio_write(0x30, &data_abort_handler); - mmio_write(0x34, &reserved_handler); - mmio_write(0x38, &irq_handler); - mmio_write(0x3C, &fiq_handler); + uint32_t * start = vm_vtop(KERNEL_VAS, 0x00); + /* Primary Vector Table */ + mmio_write(start, BRANCH_INSTRUCTION); + mmio_write(start + 0x04, BRANCH_INSTRUCTION); + mmio_write(start + 0x08, BRANCH_INSTRUCTION); + mmio_write(start + 0x0C, BRANCH_INSTRUCTION); + mmio_write(start + 0x10, BRANCH_INSTRUCTION); + mmio_write(start + 0x14, BRANCH_INSTRUCTION); + mmio_write(start + 0x18, BRANCH_INSTRUCTION); + mmio_write(start + 0x1C, BRANCH_INSTRUCTION); + + /* Secondary Vector Table */ + mmio_write(start + 0x20, &reset_handler); + mmio_write(start + 0x24, &undef_instruction_handler); + mmio_write(start + 0x28, &software_interrupt_handler); + mmio_write(start + 0x2C, &prefetch_abort_handler); + mmio_write(start + 0x30, &data_abort_handler); + mmio_write(start + 0x34, &reserved_handler); + mmio_write(start + 0x38, &irq_handler); + mmio_write(start + 0x3C, &fiq_handler); } /* handlers */ diff --git a/kernel/src/ds/test/priority_queue_test.c b/kernel/src/ds/test/priority_queue_test.c new file mode 100644 index 00000000..0509f5c1 --- /dev/null +++ b/kernel/src/ds/test/priority_queue_test.c @@ -0,0 +1,17 @@ +#include +#include +#include + +#define DEFAULT_COUNT 10 +#define MIN_PRIORITY 20 +#define MAX_PRIORITY -20 + +TEST_CREATE(test_pq_1, { + prq_handle *queue = prq_create(); + ASSERT_NOT_NULL(queue); + + + prq_free(queue); +}) + +// TODO: Port all tests diff --git a/kernel/src/memory/mmap.c b/kernel/src/memory/mmap.c index d59b66ca..3ae3cad8 100644 --- a/kernel/src/memory/mmap.c +++ b/kernel/src/memory/mmap.c @@ -124,14 +124,14 @@ void mmap(void *p_bootargs) { kprintf("0x%X\n", first_level_pt[(PMAPBASE + 0x100000) >> 20]); //TTBR0 - asm volatile("mcr p15, 0, %[addr], c2, c0, 0" : : [addr] "r" (pt_addr)); - // Translation table 1 - //asm volatile("mcr p15, 0, %[addr], c2, c0, 1" : : [addr] "r" (pt_addr)); - //asm volatile("mcr p15, 0, %[n], c2, c0, 2" : : [n] "r" (0)); - - //Set Domain Access Control to enforce out permissions - //b01 = Client. Accesses are checked against the access permission bits in the TLB entry. - asm volatile("mcr p15, 0, %[r], c3, c0, 0" : : [r] "r" (0x1)); +// asm volatile("mcr p15, 0, %[addr], c2, c0, 0" : : [addr] "r" (pt_addr)); +// // Translation table 1 +//// asm volatile("mcr p15, 0, %[addr], c2, c0, 1" : : [addr] "r" (pt_addr)); +//// asm volatile("mcr p15, 0, %[n], c2, c0, 2" : : [n] "r" (0)); +// +// //Set Domain Access Control to enforce out permissions +// //b01 = Client. Accesses are checked against the access permission bits in the TLB entry. +// asm volatile("mcr p15, 0, %[r], c3, c0, 0" : : [r] "r" (0x1)); /*CONTROL REGISTER * Enable MMU by setting 0 @@ -141,18 +141,35 @@ void mmap(void *p_bootargs) { * V bit 13 (1=high vectors 0xffff0000) * We disable high vectors, since low vectors work just fine. */ - unsigned int control; +// volatile unsigned int control; //Read contents into control - asm volatile("mrc p15, 0, %[control], c1, c0, 0" : [control] "=r" (control)); - //Set bit 0,1,2,12,13 - // control |= 0x3007; //0b11000000000111 - control |= 0x1007; //0b01000000000111 (No high vectors) - control |= 1 << 23; // Enable ARMv6 - // control |= 1<<29; // Enable ForceAPs - kprintf("control reg: 0x%x\n", control); - //Write back value into the register - asm volatile("mcr p15, 0, %[control], c1, c0, 0" : : [control] "r" (control)); +// asm volatile("mrc p15, 0, %[control], c1, c0, 0" : [control] "=r" (control)); +// //Set bit 0,1,2,12,13 +// // control |= 0x3007; //0b11000000000111 +// control |= 0x1007; //0b01000000000111 (No high vectors) +// control |= 1 << 23; // Enable ARMv6 +// // control |= 1<<29; // Enable ForceAPs +// kprintf("control reg: 0x%x\n", control); +// //Write back value into the register +// asm volatile("mcr p15, 0, %[control], c1, c0, 0" : : [control] "r" (control)); + + asm volatile ( + "mcr p15, 0, %[addr], c2, c0, 0\n" + + "mov r3, #0x1\n" + "mcr p15, 0, r3, c3, c0, 0\n" + + "mrc p15, 0, r3, c1, c0, 0\n" + "mov r4, #0x1000 \n" + "add r4, #0x7 \n" + "orr r3, r4 \n" + "orr r3, #0x800000 \n" + // "orr r0, r0, #0x01\n" + "mcr p15, 0, r3, c1, c0, 0 \n" + : + : [addr] "r" (pt_addr) + ); // Build the free frame list vm_build_free_frame_list((void*) PMAPBASE + 0x100000, (void*) PMAPTOP); //(void*)PMAPBASE+(unsigned int)((PMAPTOP)-(PMAPBASE))); diff --git a/kernel/src/memory/vm/include/vm.h b/kernel/src/memory/vm/include/vm.h index a7f05e3c..e3111c97 100644 --- a/kernel/src/memory/vm/include/vm.h +++ b/kernel/src/memory/vm/include/vm.h @@ -1,202 +1,205 @@ -#ifndef __VM_H -#define __VM_H - -#include -#include -#include -#include - -//#define BLOCK_SIZE (1<<20) -#define BLOCK_SIZE ((uint32_t)(1<<12)) - -#define PAGE_TABLE_SIZE (1<<14) -#define L2_PAGE_TABLE_SIZE (1<<12) - -struct vas { - // A pointer to the first level of the pagetable. - volatile unsigned int *l1_pagetable; - volatile unsigned int *l1_pagetable_phys; // The physical address to it - - // A pointer to the next VAS (it's a linked list) - struct vas *next; -}; - -#define VM_ERR_BADV -1 -#define VM_ERR_BADP -2 -#define VM_ERR_MAPPED -3 -#define VM_ERR_BADPERM -4 -#define VM_ERR_UNKNOWN -5 -#define VM_ERR_NOT_MAPPED -6 - -#define KERNEL_VAS ((struct vas*)V_L1PTBASE) - - -#define VM_L1_GET_ENTRY(table,vptr) table[((unsigned int)vptr)>>20] -#define VM_L1_SET_ENTRY(table,vptr,ent) (table[((unsigned int)vptr)>>20]=ent) -#define VM_ENTRY_GET_FRAME(x) ((x)&~((PAGE_TABLE_SIZE<<1) - 1)) -#define VM_ENTRY_GET_L2(x) ((x)&~0x1FF) -#define VM_L2_ENTRY(l2pt,vptr) ((uint32_t*)l2pt)[((unsigned int)vptr&0x000FF000)>>12] -#define VM_L2ENTRY_GET_FRAME(x) ((x)&0xFFFFF000) - -/** - * These permissions dictate who can access what pages. Note that you - * cannot combine these arbitrarily. For example: - * VM_PERM_PRIVILEGED_RO|VM_PERM_PRIVILEGED_RW - * makes no sense. If the user mode is granted a given permission, then the - * privileged mode is granted that permission as well, unless there is a - * confliction. Some examples: - * VM_PERM_USER_RO - * grants RO status to both user and privileged modes. - * - * VM_PERM_USER_RO|VM_PERM_PRIVILEGED_RW - * grants RO to the user, and RW to privileged modes. - * - * VM_PERM_USER_RW|VM_PERM_PRIVILEGED_RO - * doesn't make sense. USER_RW grants RW to both user and privileged, but - * PRIVILEGED_RO contradicts the USER_RW's implied grant. - * - * VM_ERR_BADPERM is returned if a bad permission is passed. Note that 0 - * is a valid permission, indicating that nobody may have access. - * - * (RO stands for Read-Only, RW for Read-Write) - */ -#define VM_PERM_PRIVILEGED_RO 1 -#define VM_PERM_USER_RO 2 -#define VM_PERM_PRIVILEGED_RW 4 -#define VM_PERM_USER_RW 8 - -void vm_init(); - -/** - * vm_allocate_page and vm_free_page allocate and free pages, and allow the - * VAS to access them at the given virtual address (vptr). - * Note that you cannot call free_page on a virtual address that was - * mapped using set_mapping. - * Return values: - * 0 - success - * VM_ERR_BADV - vptr was not a multiple of BLOCK_SIZE. - * VM_ERR_MAPPED - vptr is already mapped in this VAS. - * VM_ERR_BADPERM - permission is not valid (see above). - * - * free_page return values: - * 0 - success - * VM_ERR_BADV - vptr was not a multiple of BLOCK_SIZE. - * VM_ERR_MAPPED - vptr was mapped using set_mapping, not allocate_page. - * VM_ERR_NOT_MAPPED - vptr is not mapped in this VAS. - */ -int vm_allocate_page(struct vas *vas, void *vptr, int permission); -void *vm_allocate_pages(struct vas *vas, void *vptr, uint32_t nbytes, int permission); -int vm_free_page(struct vas *vas, void *vptr); - -/** - * vm_pin and vm_unpin currently do nothing. However, in the future, they will - * prevent pages from being swapped out of physical memory. - * Return values: - * 0 - Success. - */ -int vm_pin(struct vas *vas, void *vptr); -int vm_unpin(struct vas *vas, void *vptr); - -/** - * vm_set_mapping maps the given vptr to the given pptr. - * Return values: - * 0 - success - * VM_ERR_BADV - vptr was not a multiple of BLOCK_SIZE. - * VM_ERR_BADP - pptr was not a multiple of BLOCK_SIZE. - * VM_ERR_MAPPED - vptr is already mapped in this VAS. - * VM_ERR_BADPERM - permission is not valid. - * - * vm_free_mapping unmaps the vptr. Note that you may not call free_mapping - * on a virtual address that was allocated using allocate_page. - * Return values: - * 0 - success - * VM_ERR_BADV - vptr was not a multiple of BLOCK_SIZE. - * VM_ERR_NOT_MAPPED - vptr was not mapped using set_mapping. - */ -int vm_set_mapping(struct vas *vas, void *vptr, void *pptr, int permission); -int vm_free_mapping(struct vas *vas, void *vptr); - - -/* vm_swap_free_mapping is the spapping frameworks flavor on vm's vm_free_mapping - * It takes in an extra paramter that will be set to the L2 page entry (instead of 0) - * - Noel Negusse - * - * Returns: Same as vm_free_mapping - */ -int vm_swap_free_mapping(struct vas*, void*, uint32_t*); - - -/** - * Will make the memory that accessible to other_vas at other_ptr - * accessible to vas at this_ptr. - * It can then be unmapped from either using a typical vm_free_mapping - * or vm_free_page. The behavior of vm_free_mapping and vm_free_page - * will be made equivalent. - * For both, the behavior will be to free the frame if a frame was - * allocated (via vm_allocate_page) and the page is not shared. If the - * page is shared, then both will behave like vm_free_mapping. - * - * It is an error for other_ptr to point to an area not mapped in other_vas. - * - * For example, given vas1 and vas2: - * - * vm_allocate_page(vas2,0x10) - * vm_map_shared_memory(vas1, 0x20, vas2, 0x10) - * // Now vas1's 0x20 points to the same memory as vas2's 0x10 - * vm_free_page(vas2, 0x10) - * // Now vas1 is the sole owner of the memory at vas1's 0x20 - * vm_free_mapping(vas1, 0x20) - * // Now that frame has been freed - * - * All the pointers have to be a multiple of BLOCK_SIZE. - * - * Return values: - * 0 - success - * VM_ERR_BADV - this_ptr was not a multiple of BLOCK_SIZE. - * VM_ERR_BADP - other_ptr was not a multiple of BLOCK_SIZE. - * VM_ERR_NOT_MAPPED - other_ptr is not mapped in other_vas. - * VM_ERR_MAPPED - this_ptr is already mapped in vas. - * VM_ERR_BADPERM - permission is bad. - */ -int vm_map_shared_memory(struct vas *vas, void *this_ptr, struct vas *other_vas, void *other_ptr, int permission); - -/** - * This enabled the given VAS. - */ -void vm_enable_vas(struct vas *vas); - -/** - * Allocates a new VAS. - * - * Note that there is a limit of 4096 VASs in the system, including the - * kernel's VAS. - */ -struct vas *vm_new_vas(); -int vm_free_vas(struct vas *vas); - -/** - * Retrieves a reference to the currently running VAS. - */ -struct vas *vm_get_current_vas(); - -/** - * Switches to the kernel's VAS. - */ -void vm_use_kernel_vas(); - -static inline void ensure_kernel_vas() -{ - assert (vm_get_current_vas() == KERNEL_VAS && "Must run in kernel VAS!"); -} - -void vm_test(); - -static inline void vm_invalidate_tlb(void) -{ - // Invalidate the TLB - asm volatile("mcr p15, 0, %[r], c8, c5, 0" : : [r] "r" (0x0)); - asm volatile("mcr p15, 0, %[r], c8, c6, 0" : : [r] "r" (0x0)); - asm volatile("mcr p15, 0, %[r], c8, c7, 0" : : [r] "r" (0x0)); -} - -#endif +#ifndef __VM_H +#define __VM_H + +#include +#include +#include +#include + +//#define BLOCK_SIZE (1<<20) +#define BLOCK_SIZE ((uint32_t)(1<<12)) + +#define PAGE_TABLE_SIZE (1<<14) +#define L2_PAGE_TABLE_SIZE (1<<12) + +struct vas { + // A pointer to the first level of the pagetable. + volatile unsigned int *l1_pagetable; + volatile unsigned int *l1_pagetable_phys; // The physical address to it + + // A pointer to the next VAS (it's a linked list) + struct vas *next; +}; + +#define VM_ERR_BADV -1 +#define VM_ERR_BADP -2 +#define VM_ERR_MAPPED -3 +#define VM_ERR_BADPERM -4 +#define VM_ERR_UNKNOWN -5 +#define VM_ERR_NOT_MAPPED -6 + +#define KERNEL_VAS ((struct vas*)V_L1PTBASE) + + +#define VM_L1_GET_ENTRY(table,vptr) table[((unsigned int)vptr)>>20] +#define VM_L1_SET_ENTRY(table,vptr,ent) (table[((unsigned int)vptr)>>20]=ent) +#define VM_ENTRY_GET_FRAME(x) ((x)&~((PAGE_TABLE_SIZE<<1) - 1)) +#define VM_ENTRY_GET_L2(x) ((x)&~0x1FF) +#define VM_L2_ENTRY(l2pt,vptr) ((uint32_t*)l2pt)[((unsigned int)vptr&0x000FF000)>>12] +#define VM_L2ENTRY_GET_FRAME(x) ((x)&0xFFFFF000) + +/** + * These permissions dictate who can access what pages. Note that you + * cannot combine these arbitrarily. For example: + * VM_PERM_PRIVILEGED_RO|VM_PERM_PRIVILEGED_RW + * makes no sense. If the user mode is granted a given permission, then the + * privileged mode is granted that permission as well, unless there is a + * confliction. Some examples: + * VM_PERM_USER_RO + * grants RO status to both user and privileged modes. + * + * VM_PERM_USER_RO|VM_PERM_PRIVILEGED_RW + * grants RO to the user, and RW to privileged modes. + * + * VM_PERM_USER_RW|VM_PERM_PRIVILEGED_RO + * doesn't make sense. USER_RW grants RW to both user and privileged, but + * PRIVILEGED_RO contradicts the USER_RW's implied grant. + * + * VM_ERR_BADPERM is returned if a bad permission is passed. Note that 0 + * is a valid permission, indicating that nobody may have access. + * + * (RO stands for Read-Only, RW for Read-Write) + */ +#define VM_PERM_PRIVILEGED_RO 1 +#define VM_PERM_USER_RO 2 +#define VM_PERM_PRIVILEGED_RW 4 +#define VM_PERM_USER_RW 8 + +void vm_init(); + +/** + * vm_allocate_page and vm_free_page allocate and free pages, and allow the + * VAS to access them at the given virtual address (vptr). + * Note that you cannot call free_page on a virtual address that was + * mapped using set_mapping. + * Return values: + * 0 - success + * VM_ERR_BADV - vptr was not a multiple of BLOCK_SIZE. + * VM_ERR_MAPPED - vptr is already mapped in this VAS. + * VM_ERR_BADPERM - permission is not valid (see above). + * + * free_page return values: + * 0 - success + * VM_ERR_BADV - vptr was not a multiple of BLOCK_SIZE. + * VM_ERR_MAPPED - vptr was mapped using set_mapping, not allocate_page. + * VM_ERR_NOT_MAPPED - vptr is not mapped in this VAS. + */ +int vm_allocate_page(struct vas *vas, void *vptr, int permission); +void *vm_allocate_pages(struct vas *vas, void *vptr, uint32_t nbytes, int permission); +int vm_free_page(struct vas *vas, void *vptr); + +/** + * vm_pin and vm_unpin currently do nothing. However, in the future, they will + * prevent pages from being swapped out of physical memory. + * Return values: + * 0 - Success. + */ +int vm_pin(struct vas *vas, void *vptr); +int vm_unpin(struct vas *vas, void *vptr); + +/** + * vm_set_mapping maps the given vptr to the given pptr. + * Return values: + * 0 - success + * VM_ERR_BADV - vptr was not a multiple of BLOCK_SIZE. + * VM_ERR_BADP - pptr was not a multiple of BLOCK_SIZE. + * VM_ERR_MAPPED - vptr is already mapped in this VAS. + * VM_ERR_BADPERM - permission is not valid. + * + * vm_free_mapping unmaps the vptr. Note that you may not call free_mapping + * on a virtual address that was allocated using allocate_page. + * Return values: + * 0 - success + * VM_ERR_BADV - vptr was not a multiple of BLOCK_SIZE. + * VM_ERR_NOT_MAPPED - vptr was not mapped using set_mapping. + */ +int vm_set_mapping(struct vas *vas, void *vptr, void *pptr, int permission); +int vm_free_mapping(struct vas *vas, void *vptr); + + +/* vm_swap_free_mapping is the spapping frameworks flavor on vm's vm_free_mapping + * It takes in an extra paramter that will be set to the L2 page entry (instead of 0) + * - Noel Negusse + * + * Returns: Same as vm_free_mapping + */ +int vm_swap_free_mapping(struct vas*, void*, uint32_t*); + + +/** + * Will make the memory that accessible to other_vas at other_ptr + * accessible to vas at this_ptr. + * It can then be unmapped from either using a typical vm_free_mapping + * or vm_free_page. The behavior of vm_free_mapping and vm_free_page + * will be made equivalent. + * For both, the behavior will be to free the frame if a frame was + * allocated (via vm_allocate_page) and the page is not shared. If the + * page is shared, then both will behave like vm_free_mapping. + * + * It is an error for other_ptr to point to an area not mapped in other_vas. + * + * For example, given vas1 and vas2: + * + * vm_allocate_page(vas2,0x10) + * vm_map_shared_memory(vas1, 0x20, vas2, 0x10) + * // Now vas1's 0x20 points to the same memory as vas2's 0x10 + * vm_free_page(vas2, 0x10) + * // Now vas1 is the sole owner of the memory at vas1's 0x20 + * vm_free_mapping(vas1, 0x20) + * // Now that frame has been freed + * + * All the pointers have to be a multiple of BLOCK_SIZE. + * + * Return values: + * 0 - success + * VM_ERR_BADV - this_ptr was not a multiple of BLOCK_SIZE. + * VM_ERR_BADP - other_ptr was not a multiple of BLOCK_SIZE. + * VM_ERR_NOT_MAPPED - other_ptr is not mapped in other_vas. + * VM_ERR_MAPPED - this_ptr is already mapped in vas. + * VM_ERR_BADPERM - permission is bad. + */ +int vm_map_shared_memory(struct vas *vas, void *this_ptr, struct vas *other_vas, void *other_ptr, int permission); + +/** + * This enabled the given VAS. + */ +void vm_enable_vas(struct vas *vas); + +/** + * Allocates a new VAS. + * + * Note that there is a limit of 4096 VASs in the system, including the + * kernel's VAS. + */ +struct vas *vm_new_vas(); +int vm_free_vas(struct vas *vas); + +/** + * Retrieves a reference to the currently running VAS. + */ +struct vas *vm_get_current_vas(); + +/** + * Switches to the kernel's VAS. + */ +void vm_use_kernel_vas(); + +static inline void ensure_kernel_vas() +{ + assert (vm_get_current_vas() == KERNEL_VAS && "Must run in kernel VAS!"); +} + +void vm_test(); + +static inline void vm_invalidate_tlb(void) +{ + // Invalidate the TLB + asm volatile("mcr p15, 0, %[r], c8, c5, 0" : : [r] "r" (0x0)); + asm volatile("mcr p15, 0, %[r], c8, c6, 0" : : [r] "r" (0x0)); + asm volatile("mcr p15, 0, %[r], c8, c7, 0" : : [r] "r" (0x0)); +} + +uint32_t *vm_vtop(struct vas *vas, uint32_t *vptr); +uint32_t *vm_ptov(struct vas *vas, uint32_t *vptr); + +#endif diff --git a/kernel/src/memory/vm/vm.c b/kernel/src/memory/vm/vm.c index c26ecdbc..ea718571 100644 --- a/kernel/src/memory/vm/vm.c +++ b/kernel/src/memory/vm/vm.c @@ -1,459 +1,459 @@ -#include -#include -#include -#include - -#define CHECK_VPTR if ((unsigned int)vptr & (BLOCK_SIZE-1)) return VM_ERR_BADV; -#define CHECK_PPTR if ((unsigned int)pptr & (BLOCK_SIZE-1)) return VM_ERR_BADP; - -static const int perm_mapping[16] = { - 0, // 0000 Nothing - 5, // 0001 Privileged RO, nothing otherwise - 6, // 0010 User RO, privileged RO. - 6, // 0011 User RO, privileged RO. - 1, // 0100 Privileged RW, nothing otherwise - -1, // 0101 ??? - 2, // 0110 Privileged RW, user RO - -1, // 0111 ??? - 3, // 1000 User RW, privileged RW - -1, // 1001 ??? - -1, // 1010 ??? - -1, // 1011 ??? - 3, // 1100 User RW, privileged RW - -1, // 1101 ??? - -1, // 1110 ??? - -1, // 1111 ??? - }; - -static struct vas *vm_current_vas = (struct vas*) V_L1PTBASE; - -struct vm_free_list -{ - struct vm_free_list *next; -}; - -struct vm_free_list *vm_vas_free_list = 0x0; -struct vm_free_list *vm_l1pt_free_list = 0x0; -struct vm_free_list *vm_l2pt_free_list = 0x0; - -void vm_init() -{ - // Initialize the VAS structures. We allocate enough for 4096 VASs. - struct vm_free_list *free_vas = (struct vm_free_list*) P_L1PTBASE; - //vm_vas_free_list = free_vas; - vm_vas_free_list = (struct vm_free_list*) ((void*) free_vas + V_L1PTBASE - - P_L1PTBASE); - struct vm_free_list *last = 0x0; - while ((uint32_t) free_vas < P_L1PTBASE + sizeof(struct vas) * 4096) - { - free_vas->next = 0x0; - if (last) - { - last->next = (struct vm_free_list*) ((void*) free_vas + V_L1PTBASE - - P_L1PTBASE); - } - last = free_vas; - free_vas = - (struct vm_free_list*) ((void*) free_vas + sizeof(struct vas)); - } - - // Initialize the L1 page tables - struct vm_free_list *free_l1pt = (struct vm_free_list*) (P_L1PTBASE - + sizeof(struct vas) * 4096); - vm_l1pt_free_list = (struct vm_free_list*) ((void*) free_l1pt + V_L1PTBASE - - P_L1PTBASE); - last = 0x0; - while ((uint32_t) free_l1pt < P_L1PTBASE + (1 << 20) - ((1 << 20) >> 2)) - { - free_l1pt->next = 0x0; - if (last) - { - last->next = (struct vm_free_list*) ((void*) free_l1pt + V_L1PTBASE - - P_L1PTBASE); - } - last = free_l1pt; - free_l1pt = - (struct vm_free_list*) ((void*) free_l1pt + PAGE_TABLE_SIZE); - } - - // Initialize the L2 coarse page tables - struct vm_free_list *free_l2pt = (struct vm_free_list*) (P_L1PTBASE - + (1 << 19)); - vm_l2pt_free_list = (struct vm_free_list*) ((void*) free_l2pt + V_L1PTBASE - - P_L1PTBASE); - last = 0x0; - while ((uint32_t) free_l2pt < P_L1PTBASE + (1 << 20)) - { - free_l2pt->next = 0x0; - if (last) - { - last->next = (struct vm_free_list*) ((void*) free_l2pt + V_L1PTBASE - - P_L1PTBASE); - } - last = free_l2pt; - free_l2pt = (struct vm_free_list*) ((void*) free_l2pt - + L2_PAGE_TABLE_SIZE); - } -} - -uint32_t *vm_alloc_coarse_page_table() -{ - // TODO: What if we run out? - uint32_t *vptr = (uint32_t*) vm_l2pt_free_list; - if (vptr == 0x0) - { - LOG( - "Could not allocate a coarse page table, bad things will happen soon.\n"); - return NULL; - } - vm_l2pt_free_list = ((struct vm_free_list*) vptr)->next; - memset((void*) vptr, 0, L2_PAGE_TABLE_SIZE); - return vptr; -} - -uint32_t *vm_vtop(struct vas *vas, uint32_t *vptr) -{ - // Hack. Assume it's all linearly mapped, and vas == KERNEL_VAS - if (vas != KERNEL_VAS) - { - kprintf("vas is not KERNEL_VAS in vm_vtop. :-(\n"); - while (1) - ; - } - return (uint32_t*) ((void*) vptr - V_L1PTBASE + P_L1PTBASE); -} - -uint32_t *vm_ptov(struct vas *vas, uint32_t *vptr) -{ - // Hack. Assume it's all linearly mapped, and vas == KERNEL_VAS - if (vas != KERNEL_VAS) - { - kprintf("vas is not KERNEL_VAS in vm_vtop. :-(\n"); - while (1) - ; - } - return (uint32_t*) ((void*) vptr + V_L1PTBASE - P_L1PTBASE); -} - -struct vas *vm_get_current_vas() -{ - return vm_current_vas; -} - -void vm_use_kernel_vas() -{ - vm_enable_vas((struct vas*) V_L1PTBASE); -} - -int vm_allocate_page(struct vas *vas, void *vptr, int permission) { - CHECK_VPTR; - - // We have to save the current VAS and switch to the kernel VAS - struct vas *prev_vas = vm_current_vas; - vm_use_kernel_vas(); - - // TODO: Check if the vas already has a mapping there. - void *pptr = vm_get_free_frame(); - if (pptr == 0x0) - { - // We need to swap! (or something...) - vm_enable_vas(prev_vas); - return VM_ERR_UNKNOWN; // For now, just fail - } - - kprintf("mapping VA %x to PA %x\n", vptr, pptr); - - //LOG("Free frame is at: %X\n", pptr); - int retval = vm_set_mapping(vas, vptr, pptr, permission); - if (retval) - { - // Release the frame to prevent a memory leak - kprintf("vm_set_mapping returned %d for 0x%X\n", retval, vptr); - vm_release_frame(pptr); - vm_enable_vas(prev_vas); - return retval; - } - - vm_enable_vas(prev_vas); - return 0; -} - -void *vm_allocate_pages(struct vas *vas, void *vptr, uint32_t nbytes, int permission) { - int rc; - unsigned char *p = (unsigned char*) vptr; - while (p - (unsigned char*) vptr < nbytes) { - rc = vm_allocate_page(vas, p, permission); - if(rc != STATUS_OK) { - kprintf("Allocate page failed with code %i\n", rc); - kprintf("vptr: 0x%x", (uint32_t) p); - - panic(); - } - - p += BLOCK_SIZE; - } - return p; -} - - -int vm_free_page(struct vas *vas, void *vptr) { - CHECK_VPTR; - - // We have to save the current VAS - struct vas *prev_vas = vm_current_vas; - vm_use_kernel_vas(); - - // TODO: Check if it was actually allocated - uint32_t entry = VM_L1_GET_ENTRY(vas->l1_pagetable, vptr); - - // Okay, it's a 4KB page. We need to walk the l2 page table. - uint32_t *l2pt = vm_ptov(KERNEL_VAS, (uint32_t*) VM_ENTRY_GET_L2(entry)); - entry = VM_L2_ENTRY(l2pt, vptr); - vm_release_frame((void*) VM_L2ENTRY_GET_FRAME(entry)); - //LOG("Releasing frame %X, l2pt=%X\n", VM_L2ENTRY_GET_FRAME(entry), l2pt); - VM_L2_ENTRY(l2pt,vptr)= 0; - //vas->l1_pagetable[(unsigned int)vptr>>20] = 0; - - vm_enable_vas(prev_vas); - return 0; -} - -int vm_pin(struct vas *vas, void *vptr) -{ - // FIXME: unimplemented - return 0; -} - -int vm_unpin(struct vas *vas, void *vptr) -{ - // FIXME: unimplemented - return 0; -} - -int vm_set_mapping(struct vas *vas, void *vptr, void *pptr, int permission) -{ - CHECK_VPTR; - CHECK_PPTR; - int perm = perm_mapping[permission]; - if (perm == -1) - return VM_ERR_BADPERM; - - uint32_t cur_entry = vas->l1_pagetable[(unsigned int) vptr >> 20]; - if ((cur_entry & 3) == 2) - { - return VM_ERR_MAPPED; - } - if ((cur_entry & 3) == 0) - { - // We need to allocate a coarse page table - uint32_t *vptr_coarse_pt = vm_alloc_coarse_page_table(); - vas->l1_pagetable[(unsigned int) vptr >> 20] = (uint32_t) vm_vtop( - KERNEL_VAS, vptr_coarse_pt) | 1; - cur_entry = vas->l1_pagetable[(unsigned int) vptr >> 20]; - } - - uint32_t *l2_pagetable = vm_ptov(KERNEL_VAS, - (uint32_t*) VM_ENTRY_GET_L2(cur_entry)); - int l2_idx = ((unsigned int) vptr & 0x000FF000) >> 12; - if (l2_pagetable[l2_idx]) - { - return VM_ERR_MAPPED; - } - - //perm &= ~(1<<10); // Clear AP[0] so we get an access exception. - //vas->l1_pagetable[(unsigned int)vptr>>20] = (unsigned int)pptr | (perm<<10) | 2; - // TODO: Permissions! - int lvl2_perm = perm; //perm_mapping[perm]; - int apx_bit = (lvl2_perm & 4) >> 2; - int ap_bits = lvl2_perm & 3; - l2_pagetable[l2_idx] = (unsigned int) pptr | (apx_bit << 9) | (ap_bits << 4) - | 2; - //os_printf("pptr: %X, idx=%d, l2pt=%X\n", pptr, l2_idx, l2_pagetable); - //os_printf("permission=%d lvl2_perm=%X apx=%X ap=%X\n", permission, lvl2_perm, apx_bit, ap_bits); - //l2_pagetable[l2_idx] = (unsigned int)pptr | (1<<4) | 2; - return 0; -} - -int vm_swap_free_mapping(struct vas *vas, void *vptr, uint32_t *ID) -{ - CHECK_VPTR; - // TODO: If this is a paged frame, then we need to throw an error - if ((vas->l1_pagetable[(unsigned int) vptr >> 20] & 3) == 2) - { - vas->l1_pagetable[(unsigned int) vptr >> 20] = 0; - } - else if ((vas->l1_pagetable[(unsigned int) vptr >> 20] & 3) == 1) - { - // We have to free the mapping in the L2 page table - uint32_t *l2pt = vm_ptov(KERNEL_VAS, - (uint32_t*) VM_ENTRY_GET_L2( - vas->l1_pagetable[(unsigned int )vptr >> 20])); - VM_L2_ENTRY(l2pt, vptr)= (uint32_t) ID; - } - return 0; -} - -int vm_free_mapping(struct vas *vas, void *vptr) -{ - CHECK_VPTR; - // TODO: If this is a paged frame, then we need to throw an error - if ((vas->l1_pagetable[(unsigned int) vptr >> 20] & 3) == 2) - { - vas->l1_pagetable[(unsigned int) vptr >> 20] = 0; - } - else if ((vas->l1_pagetable[(unsigned int) vptr >> 20] & 3) == 1) - { - // We have to free the mapping in the L2 page table - uint32_t *l2pt = vm_ptov(KERNEL_VAS, - (uint32_t*) VM_ENTRY_GET_L2( - vas->l1_pagetable[(unsigned int )vptr >> 20])); - VM_L2_ENTRY(l2pt, vptr)= 0; - } - return 0; -} - -// We're going to have to switch to the kernel's VAS, then copy it over. -int vm_map_shared_memory(struct vas *vas, void *this_ptr, struct vas *other_vas, - void *other_ptr, int permission) -{ - if ((unsigned int) this_ptr & (BLOCK_SIZE - 1)) - return VM_ERR_BADV; - if ((unsigned int) other_ptr & (BLOCK_SIZE - 1)) - return VM_ERR_BADP; - - struct vas *prev_vas = vm_current_vas; - vm_enable_vas(KERNEL_VAS); - - if ((vas->l1_pagetable[(unsigned int) this_ptr >> 20] & 3) == 2) - { - return VM_ERR_MAPPED; - } - if (!other_vas->l1_pagetable[(unsigned int) other_ptr >> 20]) - { - return VM_ERR_NOT_MAPPED; - } - if (!vas->l1_pagetable[(unsigned int) this_ptr >> 20]) - { - // We need to allocate a coarse page table... - uint32_t *vptr_coarse_pt = vm_alloc_coarse_page_table(); - vas->l1_pagetable[(unsigned int) this_ptr >> 20] = (uint32_t) vm_vtop( - KERNEL_VAS, vptr_coarse_pt) | 1; - //LOG("Allocated coarse page table.\n"); - //LOG("Should be zero: %X (%X)\n", vptr_coarse_pt[0], vptr_coarse_pt); - } - uint32_t *this_l2pt = vm_ptov(KERNEL_VAS, - (uint32_t*) VM_ENTRY_GET_L2( - vas->l1_pagetable[(unsigned int )this_ptr >> 20])); - if (VM_L2_ENTRY(this_l2pt, this_ptr)) - { - //LOG("Should be zero: %X (this_l2pt=%X, idx=%d)\n", VM_L2_ENTRY(this_l2pt, this_ptr), this_l2pt, ((unsigned int)this_ptr&0x000FF000)>>12); - return VM_ERR_MAPPED; - } - uint32_t *other_l2pt = vm_ptov(KERNEL_VAS, - (uint32_t*) VM_ENTRY_GET_L2( - other_vas->l1_pagetable[(unsigned int )other_ptr >> 20])); - if (!VM_L2_ENTRY(other_l2pt, other_ptr)) - { - return VM_ERR_NOT_MAPPED; - } - - int perm = perm_mapping[permission]; - if (perm == -1) - return VM_ERR_BADPERM; - - // Well, this was remarkably easy. - //unsigned int pptr = VM_ENTRY_GET_FRAME(other_vas->l1_pagetable[(unsigned int)other_ptr>>20]); - unsigned int pptr = VM_L2ENTRY_GET_FRAME( - VM_L2_ENTRY(other_l2pt, other_ptr)); - //os_printf("pptr: %X\n",pptr); - //perm &= ~(1<<10); // Clear AP[0] so we get an access exception. - //vas->l1_pagetable[(unsigned int)this_ptr>>20] = pptr | (perm<<10) | 2; - VM_L2_ENTRY(this_l2pt, this_ptr)= pptr | (1<<4) | 2; - LOG("%X\n", VM_L2_ENTRY(this_l2pt, this_ptr)); - - vm_enable_vas(prev_vas); - return 0; -} - -void vm_enable_vas(struct vas *vas) -{ - vm_current_vas = vas; - - // Clear the BTAC - // Performed by cleaning the caches, below - // asm volatile("mcr p15, 0, %[r], c7, c5, 6" : : [r] "r" (0x0)); - - // Flush the write caches - asm volatile("MCR p15, 0, %[r], c7, c10, 4" : : [r] "r" (0x0)); - // sync barrier - asm volatile("MCR p15, 0, %[r], c7, c10, 5" : : [r] "r" (0x0)); - // memory barrier - - //TTBR0 - asm volatile("mcr p15, 0, %[addr], c2, c0, 0" : : [addr] "r" (vas->l1_pagetable_phys)); - // Translation table 1 is currently ignored - - // Clean the caches (data & instruction) - asm volatile("mcr p15, 0, %[r], c7, c14, 0" : : [r] "r" (0x0)); -} - -struct vas *vm_new_vas() -{ - if (!vm_vas_free_list) - { - return 0x0; - } - if (!vm_l1pt_free_list) - { - return 0x0; - } - struct vas *p = (struct vas*) vm_vas_free_list; - vm_vas_free_list = vm_vas_free_list->next; - - kprintf("vm_l1pt_free_list=%X\n", vm_l1pt_free_list); - p->l1_pagetable = (uint32_t*) vm_l1pt_free_list; - vm_l1pt_free_list = vm_l1pt_free_list->next; - - p->l1_pagetable_phys = (unsigned int*) ((unsigned int) p->l1_pagetable - - (V_L1PTBASE - P_L1PTBASE)); - - // Zero out the page table - memset((unsigned int *)p->l1_pagetable, 0, PAGE_TABLE_SIZE); - - // Setup the static mappings... - // The kernel (high & low addresses) - //should be less than a MB - p->l1_pagetable[P_KERNBASE >> 20] = 0 << 20 | 0x0400 | 2; - - //also map it to high memory at 0xf0000000 - p->l1_pagetable[V_KERNBASE >> 20] = 0 << 20 | 0x0400 | 2; - p->l1_pagetable[(V_KERNBASE + 0x100000) >> 20] = 0x100000 | 0x0400 | 2; - - // Kernel datastructures - //temporarily map where it is until we copy it in VAS - p->l1_pagetable[P_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; - - //1MB for static kernel data structures (stacks and l1 pt) - p->l1_pagetable[V_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; - - // Our 1MB page to store VAS datastructures - p->l1_pagetable[V_L1PTBASE >> 20] = P_L1PTBASE | 0x0400 | 2; - - // 2MB of peripheral registers (so we get the serial port et. al.) - p->l1_pagetable[PERIPHBASE >> 20] = PERIPHBASE | 0x0400 | 2; - p->l1_pagetable[(PERIPHBASE + 0x100000) >> 20] = (PERIPHBASE + 0x100000) - | 0x0400 | 2; - return p; -} - -int vm_free_vas(struct vas *vas) -{ - struct vm_free_list *n = (struct vm_free_list*) vas->l1_pagetable; - n->next = vm_l1pt_free_list; - vm_l1pt_free_list = n; - - n = (struct vm_free_list*) vas; - n->next = vm_vas_free_list; - vm_vas_free_list = n; - return 0; -} +#include +#include +#include +#include + +#define CHECK_VPTR if ((unsigned int)vptr & (BLOCK_SIZE-1)) return VM_ERR_BADV; +#define CHECK_PPTR if ((unsigned int)pptr & (BLOCK_SIZE-1)) return VM_ERR_BADP; + +static const int perm_mapping[16] = { + 0, // 0000 Nothing + 5, // 0001 Privileged RO, nothing otherwise + 6, // 0010 User RO, privileged RO. + 6, // 0011 User RO, privileged RO. + 1, // 0100 Privileged RW, nothing otherwise + -1, // 0101 ??? + 2, // 0110 Privileged RW, user RO + -1, // 0111 ??? + 3, // 1000 User RW, privileged RW + -1, // 1001 ??? + -1, // 1010 ??? + -1, // 1011 ??? + 3, // 1100 User RW, privileged RW + -1, // 1101 ??? + -1, // 1110 ??? + -1, // 1111 ??? + }; + +static struct vas *vm_current_vas = (struct vas*) V_L1PTBASE; + +struct vm_free_list +{ + struct vm_free_list *next; +}; + +struct vm_free_list *vm_vas_free_list = 0x0; +struct vm_free_list *vm_l1pt_free_list = 0x0; +struct vm_free_list *vm_l2pt_free_list = 0x0; + +void vm_init() +{ + // Initialize the VAS structures. We allocate enough for 4096 VASs. + struct vm_free_list *free_vas = (struct vm_free_list*) P_L1PTBASE; + //vm_vas_free_list = free_vas; + vm_vas_free_list = (struct vm_free_list*) ((void*) free_vas + V_L1PTBASE + - P_L1PTBASE); + struct vm_free_list *last = 0x0; + while ((uint32_t) free_vas < P_L1PTBASE + sizeof(struct vas) * 4096) + { + free_vas->next = 0x0; + if (last) + { + last->next = (struct vm_free_list*) ((void*) free_vas + V_L1PTBASE + - P_L1PTBASE); + } + last = free_vas; + free_vas = + (struct vm_free_list*) ((void*) free_vas + sizeof(struct vas)); + } + + // Initialize the L1 page tables + struct vm_free_list *free_l1pt = (struct vm_free_list*) (P_L1PTBASE + + sizeof(struct vas) * 4096); + vm_l1pt_free_list = (struct vm_free_list*) ((void*) free_l1pt + V_L1PTBASE + - P_L1PTBASE); + last = 0x0; + while ((uint32_t) free_l1pt < P_L1PTBASE + (1 << 20) - ((1 << 20) >> 2)) + { + free_l1pt->next = 0x0; + if (last) + { + last->next = (struct vm_free_list*) ((void*) free_l1pt + V_L1PTBASE + - P_L1PTBASE); + } + last = free_l1pt; + free_l1pt = + (struct vm_free_list*) ((void*) free_l1pt + PAGE_TABLE_SIZE); + } + + // Initialize the L2 coarse page tables + struct vm_free_list *free_l2pt = (struct vm_free_list*) (P_L1PTBASE + + (1 << 19)); + vm_l2pt_free_list = (struct vm_free_list*) ((void*) free_l2pt + V_L1PTBASE + - P_L1PTBASE); + last = 0x0; + while ((uint32_t) free_l2pt < P_L1PTBASE + (1 << 20)) + { + free_l2pt->next = 0x0; + if (last) + { + last->next = (struct vm_free_list*) ((void*) free_l2pt + V_L1PTBASE + - P_L1PTBASE); + } + last = free_l2pt; + free_l2pt = (struct vm_free_list*) ((void*) free_l2pt + + L2_PAGE_TABLE_SIZE); + } +} + +uint32_t *vm_alloc_coarse_page_table() +{ + // TODO: What if we run out? + uint32_t *vptr = (uint32_t*) vm_l2pt_free_list; + if (vptr == 0x0) + { + LOG( + "Could not allocate a coarse page table, bad things will happen soon.\n"); + return NULL; + } + vm_l2pt_free_list = ((struct vm_free_list*) vptr)->next; + memset((void*) vptr, 0, L2_PAGE_TABLE_SIZE); + return vptr; +} + +uint32_t *vm_vtop(struct vas *vas, uint32_t *vptr) +{ + // Hack. Assume it's all linearly mapped, and vas == KERNEL_VAS + if (vas != KERNEL_VAS) + { + kprintf("vas is not KERNEL_VAS in vm_vtop. :-(\n"); + while (1) + ; + } + return (uint32_t*) ((void*) vptr - V_L1PTBASE + P_L1PTBASE); +} + +uint32_t *vm_ptov(struct vas *vas, uint32_t *vptr) +{ + // Hack. Assume it's all linearly mapped, and vas == KERNEL_VAS + if (vas != KERNEL_VAS) + { + kprintf("vas is not KERNEL_VAS in vm_vtop. :-(\n"); + while (1) + ; + } + return (uint32_t*) ((void*) vptr + V_L1PTBASE - P_L1PTBASE); +} + +struct vas *vm_get_current_vas() +{ + return vm_current_vas; +} + +void vm_use_kernel_vas() +{ + vm_enable_vas((struct vas*) V_L1PTBASE); +} + +int vm_allocate_page(struct vas *vas, void *vptr, int permission) { + CHECK_VPTR; + + // We have to save the current VAS and switch to the kernel VAS + struct vas *prev_vas = vm_current_vas; + vm_use_kernel_vas(); + + // TODO: Check if the vas already has a mapping there. + void *pptr = vm_get_free_frame(); + if (pptr == 0x0) + { + // We need to swap! (or something...) + vm_enable_vas(prev_vas); + return VM_ERR_UNKNOWN; // For now, just fail + } + + kprintf("mapping VA %x to PA %x\n", vptr, pptr); + + //LOG("Free frame is at: %X\n", pptr); + int retval = vm_set_mapping(vas, vptr, pptr, permission); + if (retval) + { + // Release the frame to prevent a memory leak + kprintf("vm_set_mapping returned %d for 0x%X\n", retval, vptr); + vm_release_frame(pptr); + vm_enable_vas(prev_vas); + return retval; + } + + vm_enable_vas(prev_vas); + return 0; +} + +void *vm_allocate_pages(struct vas *vas, void *vptr, uint32_t nbytes, int permission) { + int rc; + unsigned char *p = (unsigned char*) vptr; + while (p - (unsigned char*) vptr < nbytes) { + rc = vm_allocate_page(vas, p, permission); + if(rc != STATUS_OK) { + kprintf("Allocate page failed with code %i\n", rc); + kprintf("vptr: 0x%x", (uint32_t) p); + + panic(); + } + + p += BLOCK_SIZE; + } + return p; +} + + +int vm_free_page(struct vas *vas, void *vptr) { + CHECK_VPTR; + + // We have to save the current VAS + struct vas *prev_vas = vm_current_vas; + vm_use_kernel_vas(); + + // TODO: Check if it was actually allocated + uint32_t entry = VM_L1_GET_ENTRY(vas->l1_pagetable, vptr); + + // Okay, it's a 4KB page. We need to walk the l2 page table. + uint32_t *l2pt = vm_ptov(KERNEL_VAS, (uint32_t*) VM_ENTRY_GET_L2(entry)); + entry = VM_L2_ENTRY(l2pt, vptr); + vm_release_frame((void*) VM_L2ENTRY_GET_FRAME(entry)); + //LOG("Releasing frame %X, l2pt=%X\n", VM_L2ENTRY_GET_FRAME(entry), l2pt); + VM_L2_ENTRY(l2pt,vptr)= 0; + //vas->l1_pagetable[(unsigned int)vptr>>20] = 0; + + vm_enable_vas(prev_vas); + return 0; +} + +int vm_pin(struct vas *vas, void *vptr) +{ + // FIXME: unimplemented + return 0; +} + +int vm_unpin(struct vas *vas, void *vptr) +{ + // FIXME: unimplemented + return 0; +} + +int vm_set_mapping(struct vas *vas, void *vptr, void *pptr, int permission) +{ + CHECK_VPTR; + CHECK_PPTR; + int perm = perm_mapping[permission]; + if (perm == -1) + return VM_ERR_BADPERM; + + uint32_t cur_entry = vas->l1_pagetable[(unsigned int) vptr >> 20]; + if ((cur_entry & 3) == 2) + { + return VM_ERR_MAPPED; + } + if ((cur_entry & 3) == 0) + { + // We need to allocate a coarse page table + uint32_t *vptr_coarse_pt = vm_alloc_coarse_page_table(); + vas->l1_pagetable[(unsigned int) vptr >> 20] = (uint32_t) vm_vtop( + KERNEL_VAS, vptr_coarse_pt) | 1; + cur_entry = vas->l1_pagetable[(unsigned int) vptr >> 20]; + } + + uint32_t *l2_pagetable = vm_ptov(KERNEL_VAS, + (uint32_t*) VM_ENTRY_GET_L2(cur_entry)); + int l2_idx = ((unsigned int) vptr & 0x000FF000) >> 12; + if (l2_pagetable[l2_idx]) + { + return VM_ERR_MAPPED; + } + + //perm &= ~(1<<10); // Clear AP[0] so we get an access exception. + //vas->l1_pagetable[(unsigned int)vptr>>20] = (unsigned int)pptr | (perm<<10) | 2; + // TODO: Permissions! + int lvl2_perm = perm; //perm_mapping[perm]; + int apx_bit = (lvl2_perm & 4) >> 2; + int ap_bits = lvl2_perm & 3; + l2_pagetable[l2_idx] = (unsigned int) pptr | (apx_bit << 9) | (ap_bits << 4) + | 2; + //os_printf("pptr: %X, idx=%d, l2pt=%X\n", pptr, l2_idx, l2_pagetable); + //os_printf("permission=%d lvl2_perm=%X apx=%X ap=%X\n", permission, lvl2_perm, apx_bit, ap_bits); + //l2_pagetable[l2_idx] = (unsigned int)pptr | (1<<4) | 2; + return 0; +} + +int vm_swap_free_mapping(struct vas *vas, void *vptr, uint32_t *ID) +{ + CHECK_VPTR; + // TODO: If this is a paged frame, then we need to throw an error + if ((vas->l1_pagetable[(unsigned int) vptr >> 20] & 3) == 2) + { + vas->l1_pagetable[(unsigned int) vptr >> 20] = 0; + } + else if ((vas->l1_pagetable[(unsigned int) vptr >> 20] & 3) == 1) + { + // We have to free the mapping in the L2 page table + uint32_t *l2pt = vm_ptov(KERNEL_VAS, + (uint32_t*) VM_ENTRY_GET_L2( + vas->l1_pagetable[(unsigned int )vptr >> 20])); + VM_L2_ENTRY(l2pt, vptr)= (uint32_t) ID; + } + return 0; +} + +int vm_free_mapping(struct vas *vas, void *vptr) +{ + CHECK_VPTR; + // TODO: If this is a paged frame, then we need to throw an error + if ((vas->l1_pagetable[(unsigned int) vptr >> 20] & 3) == 2) + { + vas->l1_pagetable[(unsigned int) vptr >> 20] = 0; + } + else if ((vas->l1_pagetable[(unsigned int) vptr >> 20] & 3) == 1) + { + // We have to free the mapping in the L2 page table + uint32_t *l2pt = vm_ptov(KERNEL_VAS, + (uint32_t*) VM_ENTRY_GET_L2( + vas->l1_pagetable[(unsigned int )vptr >> 20])); + VM_L2_ENTRY(l2pt, vptr)= 0; + } + return 0; +} + +// We're going to have to switch to the kernel's VAS, then copy it over. +int vm_map_shared_memory(struct vas *vas, void *this_ptr, struct vas *other_vas, + void *other_ptr, int permission) +{ + if ((unsigned int) this_ptr & (BLOCK_SIZE - 1)) + return VM_ERR_BADV; + if ((unsigned int) other_ptr & (BLOCK_SIZE - 1)) + return VM_ERR_BADP; + + struct vas *prev_vas = vm_current_vas; + vm_enable_vas(KERNEL_VAS); + + if ((vas->l1_pagetable[(unsigned int) this_ptr >> 20] & 3) == 2) + { + return VM_ERR_MAPPED; + } + if (!other_vas->l1_pagetable[(unsigned int) other_ptr >> 20]) + { + return VM_ERR_NOT_MAPPED; + } + if (!vas->l1_pagetable[(unsigned int) this_ptr >> 20]) + { + // We need to allocate a coarse page table... + uint32_t *vptr_coarse_pt = vm_alloc_coarse_page_table(); + vas->l1_pagetable[(unsigned int) this_ptr >> 20] = (uint32_t) vm_vtop( + KERNEL_VAS, vptr_coarse_pt) | 1; + //LOG("Allocated coarse page table.\n"); + //LOG("Should be zero: %X (%X)\n", vptr_coarse_pt[0], vptr_coarse_pt); + } + uint32_t *this_l2pt = vm_ptov(KERNEL_VAS, + (uint32_t*) VM_ENTRY_GET_L2( + vas->l1_pagetable[(unsigned int )this_ptr >> 20])); + if (VM_L2_ENTRY(this_l2pt, this_ptr)) + { + //LOG("Should be zero: %X (this_l2pt=%X, idx=%d)\n", VM_L2_ENTRY(this_l2pt, this_ptr), this_l2pt, ((unsigned int)this_ptr&0x000FF000)>>12); + return VM_ERR_MAPPED; + } + uint32_t *other_l2pt = vm_ptov(KERNEL_VAS, + (uint32_t*) VM_ENTRY_GET_L2( + other_vas->l1_pagetable[(unsigned int )other_ptr >> 20])); + if (!VM_L2_ENTRY(other_l2pt, other_ptr)) + { + return VM_ERR_NOT_MAPPED; + } + + int perm = perm_mapping[permission]; + if (perm == -1) + return VM_ERR_BADPERM; + + // Well, this was remarkably easy. + //unsigned int pptr = VM_ENTRY_GET_FRAME(other_vas->l1_pagetable[(unsigned int)other_ptr>>20]); + unsigned int pptr = VM_L2ENTRY_GET_FRAME( + VM_L2_ENTRY(other_l2pt, other_ptr)); + //os_printf("pptr: %X\n",pptr); + //perm &= ~(1<<10); // Clear AP[0] so we get an access exception. + //vas->l1_pagetable[(unsigned int)this_ptr>>20] = pptr | (perm<<10) | 2; + VM_L2_ENTRY(this_l2pt, this_ptr)= pptr | (1<<4) | 2; + LOG("%X\n", VM_L2_ENTRY(this_l2pt, this_ptr)); + + vm_enable_vas(prev_vas); + return 0; +} + +void vm_enable_vas(struct vas *vas) +{ + vm_current_vas = vas; + + // Clear the BTAC + // Performed by cleaning the caches, below + // asm volatile("mcr p15, 0, %[r], c7, c5, 6" : : [r] "r" (0x0)); + + // Flush the write caches + asm volatile("MCR p15, 0, %[r], c7, c10, 4" : : [r] "r" (0x0)); + // sync barrier + asm volatile("MCR p15, 0, %[r], c7, c10, 5" : : [r] "r" (0x0)); + // memory barrier + + //TTBR0 + asm volatile("mcr p15, 0, %[addr], c2, c0, 0" : : [addr] "r" (vas->l1_pagetable_phys)); + // Translation table 1 is currently ignored + + // Clean the caches (data & instruction) + asm volatile("mcr p15, 0, %[r], c7, c14, 0" : : [r] "r" (0x0)); +} + +struct vas *vm_new_vas() +{ + if (!vm_vas_free_list) + { + return 0x0; + } + if (!vm_l1pt_free_list) + { + return 0x0; + } + struct vas *p = (struct vas*) vm_vas_free_list; + vm_vas_free_list = vm_vas_free_list->next; + + kprintf("vm_l1pt_free_list=%X\n", vm_l1pt_free_list); + p->l1_pagetable = (uint32_t*) vm_l1pt_free_list; + vm_l1pt_free_list = vm_l1pt_free_list->next; + + p->l1_pagetable_phys = (unsigned int*) ((unsigned int) p->l1_pagetable + - (V_L1PTBASE - P_L1PTBASE)); + + // Zero out the page table + memset((unsigned int *)p->l1_pagetable, 0, PAGE_TABLE_SIZE); + + // Setup the static mappings... + // The kernel (high & low addresses) + //should be less than a MB + p->l1_pagetable[P_KERNBASE >> 20] = 0 << 20 | 0x0400 | 2; + + //also map it to high memory at 0xf0000000 + p->l1_pagetable[V_KERNBASE >> 20] = 0 << 20 | 0x0400 | 2; + p->l1_pagetable[(V_KERNBASE + 0x100000) >> 20] = 0x100000 | 0x0400 | 2; + + // Kernel datastructures + //temporarily map where it is until we copy it in VAS + p->l1_pagetable[P_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; + + //1MB for static kernel data structures (stacks and l1 pt) + p->l1_pagetable[V_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; + + // Our 1MB page to store VAS datastructures + p->l1_pagetable[V_L1PTBASE >> 20] = P_L1PTBASE | 0x0400 | 2; + + // 2MB of peripheral registers (so we get the serial port et. al.) + p->l1_pagetable[PERIPHBASE >> 20] = PERIPHBASE | 0x0400 | 2; + p->l1_pagetable[(PERIPHBASE + 0x100000) >> 20] = (PERIPHBASE + 0x100000) + | 0x0400 | 2; + return p; +} + +int vm_free_vas(struct vas *vas) +{ + struct vm_free_list *n = (struct vm_free_list*) vas->l1_pagetable; + n->next = vm_l1pt_free_list; + vm_l1pt_free_list = n; + + n = (struct vm_free_list*) vas; + n->next = vm_vas_free_list; + vm_vas_free_list = n; + return 0; +} diff --git a/u-boot/Makefile b/u-boot/Makefile deleted file mode 100644 index 065c21f4..00000000 --- a/u-boot/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -include $(CURDIR)/../config.mk - -UBOOT_DIR:=u-boot-$(UBOOT_VERSION) -UBOOT_ARCHIVE:=$(UBOOT_DIR).tar.bz2 -UBOOT_URL:=ftp://ftp.denx.de/pub/u-boot/$(UBOOT_ARCHIVE) - -export PATH:=$(CURDIR)/../$(TOOLCHAIN_DIR)/$(BARE_METAL_TARGET)/bin:$(PATH) - -all: $(UBOOT_DIR)/u-boot.bin - -run: $(UBOOT_DIR)/u-boot.bin - ${QEMU} -M versatilepb -cpu arm1176 -m 128M -nographic -kernel $(UBOOT_DIR)/u-boot.bin - -$(UBOOT_DIR)/u-boot.bin: $(UBOOT_DIR) - -cd $(UBOOT_DIR); patch --silent --forward -p1 < ../versatile.patch - sed -i 's/armv5/armv6/g' $(UBOOT_DIR)/arch/arm/cpu/arm1136/config.mk # It's actually armv6 and we don't need the compiler compat - cd $(UBOOT_DIR); make versatileqemu_config ARCH=arm CPU=arm1136 CROSS_COMPILE=$(BARE_METAL_TUPLE)- - cp -r $(UBOOT_DIR)/arch/arm/cpu/arm926ejs/versatile $(UBOOT_DIR)/arch/arm/cpu/arm1136 - cd $(UBOOT_DIR); make all ARCH=arm CPU=arm1136 CROSS_COMPILE=$(BARE_METAL_TUPLE)- - -$(UBOOT_DIR): $(UBOOT_ARCHIVE) - tar xvf $(UBOOT_ARCHIVE) - -$(UBOOT_ARCHIVE): - wget $(UBOOT_URL) - -clean: - rm -rf $(UBOOT_DIR) - diff --git a/u-boot/versatile.patch b/u-boot/versatile.patch deleted file mode 100644 index 0acabcdf..00000000 --- a/u-boot/versatile.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- new/include/configs/versatile.h 2014-10-14 03:47:15.000000000 -0500 -+++ u-boot-2014.10/include/configs/versatile.h 2014-12-22 15:07:12.090798194 -0600 -@@ -100,9 +100,9 @@ - #define CONFIG_BOOTP_SUBNETMASK - - #define CONFIG_BOOTDELAY 2 --#define CONFIG_BOOTARGS "root=/dev/nfs mem=128M ip=dhcp "\ -- "netdev=25,0,0xf1010000,0xf1010010,eth0 "\ -- "console=ttyAMA0,38400n1" -+#define CONFIG_BOOTARGS "" -+#define CONFIG_CMD_SOURCE -+#define CONFIG_BOOTCOMMAND "source 24f000" - - /* - * Static configuration when assigning fixed address From 7af56fb1496abd51852040299d4eebe5365afd86 Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Sat, 29 Feb 2020 18:32:15 +0100 Subject: [PATCH 031/104] rebuild toolchain cache --- .github/workflows/os_test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/os_test.yml b/.github/workflows/os_test.yml index 45463dcc..f38de978 100644 --- a/.github/workflows/os_test.yml +++ b/.github/workflows/os_test.yml @@ -21,8 +21,8 @@ jobs: sudo apt-get install build-essential qemu-system-arm python3 wget texinfo zlib1g-dev -y - name: Install Toolchain - if: steps.cache-toolchain.outputs.cache-hit != 'true' - run: make toolchain + #if: steps.cache-toolchain.outputs.cache-hit != 'true' + run: rm -rf toolchain/arm-none-eabi/ && make toolchain - name: Compile run: make build From d1522c4ead8dca606e969e39d2765040c27848a6 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Mon, 2 Mar 2020 19:46:46 +0100 Subject: [PATCH 032/104] timer interrupts work (though currently disabled). --- a.s | 1 + kernel/Makefile | 7 +- kernel/linker/kernel.ld | 4 +- kernel/old/legacy/pm.c | 2 +- kernel/src/common/hardwareinfo.c | 55 ++ kernel/src/common/hw_handlers.c | 333 ------------- kernel/src/common/include/hardwareinfo.h | 28 ++ kernel/src/common/include/hw_handlers.h | 94 ---- kernel/src/common/include/interrupt.h | 225 ++++----- kernel/src/common/include/interruptold.h | 113 +++++ kernel/src/common/interrupt.c | 468 ++++++++++++------ kernel/src/common/interruptold.c | 121 +++++ kernel/src/common/start.c | 77 ++- kernel/src/common/startup.s | 8 +- kernel/src/drivers/chipset/bcm2835/bcm2835.c | 1 + .../drivers/chipset/bcm2835/include/bcm2835.h | 4 + kernel/src/drivers/chipset/bcm2836/bcm2836.c | 62 +++ .../drivers/chipset/bcm2836/include/bcm2836.h | 114 +++++ kernel/src/drivers/chipset/bcm2836/timer.c | 74 +++ kernel/src/drivers/chipset/bcm2836/uart.c | 113 +++++ kernel/src/drivers/chipset/chipset.c | 32 ++ kernel/src/drivers/chipset/include/chipset.h | 51 ++ kernel/src/drivers/time/include/timer.h | 3 +- kernel/src/drivers/time/include/timer.h.old | 36 ++ kernel/src/drivers/time/timer.c | 307 ++---------- kernel/src/drivers/time/timer.c.old | 303 ++++++++++++ kernel/src/drivers/uart/include/uart.h | 82 --- kernel/src/drivers/uart/uart.c | 49 -- kernel/src/drivers/uart/uart_pi.c | 156 ------ kernel/src/drivers/uart/uart_qemu.c | 94 ---- kernel/src/klibc/klibc.c | 25 +- kernel/src/klibc/printf.c | 11 +- kernel/src/memory/include/memory.h | 26 +- kernel/src/memory/include/mmap.h | 23 +- kernel/src/memory/mmap.c | 179 +++---- kernel/src/memory/vm/test/test_vm.c | 6 +- kernel/src/memory/vm/vm.c | 172 +++---- kernel/src/process/scheduler.c | 2 +- kernel/src/test/generate_tests.sh | 2 +- 39 files changed, 1870 insertions(+), 1593 deletions(-) create mode 100644 a.s create mode 100644 kernel/src/common/hardwareinfo.c delete mode 100644 kernel/src/common/hw_handlers.c create mode 100644 kernel/src/common/include/hardwareinfo.h delete mode 100644 kernel/src/common/include/hw_handlers.h create mode 100644 kernel/src/common/include/interruptold.h create mode 100644 kernel/src/common/interruptold.c create mode 100644 kernel/src/drivers/chipset/bcm2835/bcm2835.c create mode 100644 kernel/src/drivers/chipset/bcm2835/include/bcm2835.h create mode 100644 kernel/src/drivers/chipset/bcm2836/bcm2836.c create mode 100644 kernel/src/drivers/chipset/bcm2836/include/bcm2836.h create mode 100644 kernel/src/drivers/chipset/bcm2836/timer.c create mode 100644 kernel/src/drivers/chipset/bcm2836/uart.c create mode 100644 kernel/src/drivers/chipset/chipset.c create mode 100644 kernel/src/drivers/chipset/include/chipset.h create mode 100644 kernel/src/drivers/time/include/timer.h.old create mode 100644 kernel/src/drivers/time/timer.c.old delete mode 100644 kernel/src/drivers/uart/include/uart.h delete mode 100644 kernel/src/drivers/uart/uart.c delete mode 100644 kernel/src/drivers/uart/uart_pi.c delete mode 100644 kernel/src/drivers/uart/uart_qemu.c diff --git a/a.s b/a.s new file mode 100644 index 00000000..612027f7 --- /dev/null +++ b/a.s @@ -0,0 +1 @@ +ldr pc, [pc, #0x20] diff --git a/kernel/Makefile b/kernel/Makefile index 06ccf1da..997ceb9c 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -2,8 +2,9 @@ include $(CURDIR)/../config.mk # ===================== Configuration ===================== +# TODO should we have "-nostdinc"? # Flags to give to the c compiler -CFLAGS += -pipe -std=gnu99 -ffreestanding -nostdinc -Wall -Werror -g -O3 -mcpu=arm1176jzf-s -march=armv6zk -mfpu=vfp +CFLAGS += -pipe -std=gnu99 -ffreestanding -Wall -Werror -g -O0 -mcpu=arm1176jzf-s -march=armv6zk -mfpu=vfp -fpic #PI_CFLAGS = -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -nostartfiles # variables to define in the preprocessor. @@ -47,14 +48,14 @@ build_pi: $(BUILDDIR)/kernelPi.img | builddir test: build | builddir #${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -semihosting -kernel build/flash.bin -append "-load 0x410000 0x14000" - ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M versatilepb -cpu arm1176 -nographic -append "-load 0x410000 0x14000" -semihosting + ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M raspi2 -cpu arm1176 -nographic -append "-load 0x410000 0x14000" -semihosting run: build | builddir # nographic to turn off the gui # monitor none to disable stdio monitoring so # serial stdio works #${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -semihosting -monitor none -serial stdio -kernel build/flash.bin -append "-load 0x410000 0x14000" - ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M versatilepb -cpu arm1176 -nographic -append "-load 0x410000 0x14000" -semihosting + ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M raspi2 -cpu arm1176 -nographic -append "-load 0x410000 0x14000" -semihosting $(BUILDDIR)/kernel.elf: $(OBJECT_FILES) | builddir $(LD) -T linker/kernel.ld -nostartfiles -Wl,-Map,kernel.map $^ -o $@ diff --git a/kernel/linker/kernel.ld b/kernel/linker/kernel.ld index db096f68..b0419f97 100644 --- a/kernel/linker/kernel.ld +++ b/kernel/linker/kernel.ld @@ -1,11 +1,13 @@ ENTRY(_Reset) SECTIONS { - . = 0x10000; + . = 0x8000; + P_KERNBASE = .; .startup . : { build/common/startup.o(.text) } .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss COMMON) } + P_KERNTOP = .; . = ALIGN(8); . = . + 0x1000; stack_top = .; diff --git a/kernel/old/legacy/pm.c b/kernel/old/legacy/pm.c index b93509ba..7d0a2328 100644 --- a/kernel/old/legacy/pm.c +++ b/kernel/old/legacy/pm.c @@ -1,7 +1,7 @@ #include "pm.h" #include "../../src/klibc//include/stdint.h" #include "../../src/klibc//include/stdarg.h" -#include "../../src/common/include/interrupt.h" +#include "interruptold.h" #include "klibc.h" #include "stack.h" diff --git a/kernel/src/common/hardwareinfo.c b/kernel/src/common/hardwareinfo.c new file mode 100644 index 00000000..2587f170 --- /dev/null +++ b/kernel/src/common/hardwareinfo.c @@ -0,0 +1,55 @@ +#include +#include + +static HardwareInfo hardware_info; + +BoardType detect_boardtype() { + uint32_t reg; + + // read system register + asm volatile ("mrc p15,0,r0,c0,c0,0" : "=r" (reg)); + + uint32_t type = (reg >> 4) & 0xFFF; + switch (type) { + case 0xB76: + return RaspberryPiZero; // bcm2835 + case 0xC07: + return RaspBerryPiTwo; // bcm2836 + default: + panic(); + } +} + +// TODO: detect hardware info. +void init_hardwareinfo() { + hardware_info = (HardwareInfo){ + .cpuType = ARM1176, + .boardType = RaspBerryPiTwo, + }; +} + +HardwareInfo * get_hardwareinfo() { + return &hardware_info; +} + +void print_hardwareinfo() { + kprintf("==============================================\n"); + kprintf("Hardware info detected:\n"); + switch (hardware_info.cpuType) { + case ARM1176: + kprintf("CPU type: %s\n", "ARM 1176"); break; + case CortexA7: + kprintf("CPU type: %s\n", "Cortex A7"); break; + } + + switch (hardware_info.boardType) { + case RaspberryPiZero: + kprintf("Board type: %s\n", "Raspberry Pi zero or 1b+"); break; + case RaspBerryPiTwo: + kprintf("Board type: %s\n", "Raspberry Pi two"); break; + case VersatilePB: + kprintf("Board type: %s\n", "Versatile PB"); break; + } + + kprintf("==============================================\n"); +} diff --git a/kernel/src/common/hw_handlers.c b/kernel/src/common/hw_handlers.c deleted file mode 100644 index da0c161b..00000000 --- a/kernel/src/common/hw_handlers.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * - * Harware Handler Interface - * - */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* copy vector table from wherever QEMU loads the kernel to 0x00 */ -void init_vector_table(void) -{ - /* This doesn't seem to work well with virtual memory; reverting - * to old method. - extern uint32_t vector_table_start, vector_table_end; - uint32_t *src = &vector_table_start; - uint32_t *dst = (uint32_t *) HIVECTABLE; - - while(src < &vector_table_end) - *dst++ = *src++; - */ - - uint32_t * start = vm_vtop(KERNEL_VAS, 0x00); - - /* Primary Vector Table */ - mmio_write(start, BRANCH_INSTRUCTION); - mmio_write(start + 0x04, BRANCH_INSTRUCTION); - mmio_write(start + 0x08, BRANCH_INSTRUCTION); - mmio_write(start + 0x0C, BRANCH_INSTRUCTION); - mmio_write(start + 0x10, BRANCH_INSTRUCTION); - mmio_write(start + 0x14, BRANCH_INSTRUCTION); - mmio_write(start + 0x18, BRANCH_INSTRUCTION); - mmio_write(start + 0x1C, BRANCH_INSTRUCTION); - - /* Secondary Vector Table */ - mmio_write(start + 0x20, &reset_handler); - mmio_write(start + 0x24, &undef_instruction_handler); - mmio_write(start + 0x28, &software_interrupt_handler); - mmio_write(start + 0x2C, &prefetch_abort_handler); - mmio_write(start + 0x30, &data_abort_handler); - mmio_write(start + 0x34, &reserved_handler); - mmio_write(start + 0x38, &irq_handler); - mmio_write(start + 0x3C, &fiq_handler); -} - -/* handlers */ -void reset_handler(void) -{ - kprintf("RESET HANDLER\n"); - _Reset(); -} - -void __attribute__((interrupt("UNDEF"))) undef_instruction_handler(void) -{ - int spsr, lr; - - asm volatile("mrs %0, spsr" : "=r"(spsr)); - asm volatile("mov %0, lr" : "=r" (lr)); - - int thumb = spsr & 0x20; - int pc = thumb ? lr - 0x2 : lr - 0x4; - - if ((*(size_t *) pc) == UNDEFINED_INSTRUCTION_BYTES){ - kprintf("FATAL ERROR\n"); - panic(); - } - - kprintf("UNDEFINED INSTRUCTION HANDLER\n"); - - int copro = (*(int*)pc & 0xf00000) >> 24; - - if (spsr & 0x20) { - kprintf("THUMB mode\n"); - } else { - kprintf("ARM mode\n"); - } - if (spsr & 0x1000000) { - kprintf("JAZELLE enabled\n"); - } - - kprintf("COPRO: %x\n", copro); - kprintf("violating instruction (at %x): %x\n", pc, *((int *) pc)); - if (pc >= V_KERNBASE && pc < V_KERNTOP) - { - kprintf("(instruction is in kernel address range)\n"); - } - - panic(); -} - -long __attribute__((interrupt("SWI"))) software_interrupt_handler(void) -{ - int callNumber = 0, r0 = 0, r1 = 0, r2 = 0, r3 = 0; - - asm volatile ("MOV %0, r7":"=r"(callNumber)::); - asm volatile ("MOV %0, r0":"=r"(r0)::); - asm volatile ("MOV %0, r1":"=r"(r1)::); - asm volatile ("MOV %0, r2":"=r"(r2)::); - asm volatile ("MOV %0, r3":"=r"(r3)::); - - kprintf("SOFTWARE INTERRUPT HANDLER\n"); - - // Print out syscall # for debug purposes - kprintf("Syscall #: "); - kprintf("%d\n", callNumber); - kprintf("arg0=%d\n", r0); - kprintf("arg1=%d\n", r1); - kprintf("arg2=%d\n", r2); - kprintf("arg3=%d\n", r3); - kprintf("\n"); - - // System Call Handler - switch (callNumber) - { - case SYSCALL_EXIT: - // TODO: remove current process from scheduler - for (;;); - break; - case SYSCALL_DUMMY: - return 0L; - - break; - - // NOTE: All FS syscalls have been *DISABLED* until the filesystem works again. - case SYSCALL_CREATE: - kprintf("Create system call called!\n"); - return -1; - -// return (long) kcreate((char*) r0, r1, 0); - case SYSCALL_DELETE: - kprintf("Delete system call called!\n"); - return -1; - -// return (long) kdelete((char*) r0, 1); - case SYSCALL_OPEN: - kprintf("Open system call called!\n"); - return -1; - -// return (long) kopen((char*) r0, r1); - case SYSCALL_MKDIR: - kprintf("Mkdir system call called!\n"); - return -1; - -// return (long) kcreate((char*) r0, 'w', 1); - case SYSCALL_READ: - kprintf("Read system call called!\n"); - return -1; - -// return (long) kread(r0, (void*) r1, r2); - case SYSCALL_WRITE: - kprintf("Write system call called!\n"); - return -1; - -// return (long) kwrite(r0, (void*) r1, r2); - case SYSCALL_CLOSE: - kprintf("Close system call called!\n"); - return -1; - -// return (long) kclose(r0); - case SYSCALL_SEEK: - kprintf("Seek system call called!\n"); - return -1; - -// return (long) kseek(r0, r1); - case SYSCALL_COPY: - kprintf("Copy system call called!\n"); - return -1; - -// return (long) kcopy((char*) r0, (char*) r1, r2); - case SYSCALL_LS: - kprintf("Ls system call called!\n"); - return -1; -// return (long) kls((char*) r0); - case SYSCALL_SET_PERM: - kprintf("Set permission system call called!\n"); - kprintf("Yet to be implemented\n"); - return -1; - case SYSCALL_MEM_MAP: - kprintf("Memory map system call called!\n"); - kprintf("Yet to be implemented\n"); - return -1; - - case SYSCALL_MALLOC: - kprintf("malloc system call called!\n"); - - void *ptr = umalloc(r0); - - kprintf("malloc is about to return %x\n", ptr); - - return (long) ptr; - case SYSCALL_ALIGNED_ALLOC: - kprintf("aligned_alloc system call called!\n"); - void *ptr2 = ualigned_alloc(r0, r1); - - kprintf("ualigned_alloc is about to return %x\n", ptr2); - - return (long) ptr2; - case SYSCALL_FREE: - kprintf("Free system call called!\n"); - - ufree((void*) r0); - return 0L; - case SYSCALL_PRINTF: - kprintf("Printf system call called!\n"); - - kprintf((const char *) r0); - return 0L; - default: - kprintf("That wasn't a syscall you knob!\n"); - return -1L; - } -} - -void __attribute__((interrupt("ABORT"))) prefetch_abort_handler(void) -{ - int lr; - - asm volatile("mov %0, lr" : "=r" (lr)); - - kprintf("PREFETCH ABORT HANDLER, violating address: %x\n", (lr - 4)); - - panic(); -} - -void __attribute__((interrupt("ABORT"))) data_abort_handler(void) -{ - int lr; - asm volatile("mov %0, lr" : "=r" (lr)); - int pc = lr - 8; - - int far; - asm volatile("mrc p15, 0, %0, c6, c0, 0" : "=r" (far)); - - kprintf("DATA ABORT HANDLER (Page Fault)\n"); - kprintf("faulting address: 0x%x\n", far); - if (far >= V_KDSBASE) - { - kprintf("(address is in kernel address range)\n"); - } - kprintf("violating instruction (at 0x%x): %x\n", pc, *((int *) pc)); - - // Get the DSFR - int dsfr; - asm volatile("MRC p15, 0, %0, c5, c0, 0" : "=r" (dsfr)); - //os_printf("DSFR: 0x%X\n", dsfr); - - switch (dsfr) - { - case 6: // Access bit. - // Set it to 1 so we don't get notified again. - // TODO: The eviction policy will listen to this. - *((unsigned int*) (V_L1PTBASE + 2 * PAGE_TABLE_SIZE)) |= (1 << 4); - break; - default: - break; - }; -} - -void reserved_handler(void) -{ - kprintf("RESERVED HANDLER\n"); -} - -// the attribute automatically saves and restores state -void __attribute__((interrupt("IRQ"))) irq_handler(void) -{ - - kprintf("IRQ HANDLER\n"); - int cpsr = disable_interrupt_save(IRQ); -// os_printf("disabled CSPR:%X\n",cpsr); - // Discover source of interrupt - int i = 0; - // do a straight run through the VIC_INT_STATUS to determine - // which interrupt lines need to be tended to - for (i = 0; i < MAX_NUM_INTERRUPTS; i++) - { - // is the line active? - if ((1 << i) & mmio_read(VIC_IRQ_STATUS)) - { - // activate that specific handler - handle_irq_interrupt(i); - } - } - // we've gone through the VIC and handled all active interrupts - restore_proc_status(cpsr); - - enable_interrupt(IRQ_MASK); - -} - -void __attribute__((interrupt("FIQ"))) fiq_handler(void) -{ - kprintf("FIQ HANDLER\n"); - - int cpsr = disable_interrupt_save(FIQ); - - int i = 0; - // do a straight run through the VIC_INT_STATUS to determine - // which interrupt lines need to be tended to - for (i = 0; i < MAX_NUM_INTERRUPTS; i++) - { - // is the line active? - if ((1 << i) & mmio_read(VIC_FIQ_STATUS)) - { - // activate that specific handler - handle_irq_interrupt(i); - } - } - -// FIQ handler returns from the interrupt by executing: -// SUBS PC, R14_fiq, #4 - - restore_proc_status(cpsr); -} - -void SemihostingCall(enum SemihostingSWI mode) { - - int a = mode; - - asm volatile ( - "MOV r0, #0x18\n" - "LDR r1, %[in0]\n" - "svc 0x00123456\n" - : - : [in0] "m" (a) - ); - -} diff --git a/kernel/src/common/include/hardwareinfo.h b/kernel/src/common/include/hardwareinfo.h new file mode 100644 index 00000000..2e11ea29 --- /dev/null +++ b/kernel/src/common/include/hardwareinfo.h @@ -0,0 +1,28 @@ +#ifndef HARDWAREINFO_H +#define HARDWAREINFO_H + +typedef enum CpuType { + ARM1176, + CortexA7 +} CpuType; + +typedef enum BoardType { + VersatilePB, + RaspberryPiZero, + RaspBerryPiTwo +} BoardType; + + +// TODO: memory size? +typedef struct HardwareInfo { + CpuType cpuType; + BoardType boardType; +} HardwareInfo; + +void init_hardwareinfo(); + +// Get a pointer to the hardwareinfo struct. +HardwareInfo * get_hardwareinfo(); +void print_hardwareinfo(); + +#endif diff --git a/kernel/src/common/include/hw_handlers.h b/kernel/src/common/include/hw_handlers.h deleted file mode 100644 index 146c7368..00000000 --- a/kernel/src/common/include/hw_handlers.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef __HW_HANDLERS_H__ -#define __HW_HANDLERS_H__ - -/* - * - * Hardware Handler Interface for course_os - * - * - * A bit of background: - * - The ARM architecture has 7 modes of operation: - * + USR - user mode - * + FIQ - processing "fast" interrupts - * + IRQ - processing "normal" interrupts - * + SVC - proctected mode for OS - * + UND - processing an undefined instruction exception - * + SYS - also protecteed mode for OS --if anyone wants to clarify, feel free-- - * These modes can be entered or exited by modifying the CPSR (status register) - * - * exceptions (e.g. software interrupts, system calls, etc.), Interrupts (IRQ, FIQ) - * trigger the core to switch to an appropriate mode and the pc to jump to a - * preset address (somewhere in the vector table) for a branch instruction to the - * proper handler. - * - * When this happens the state of the machine must be preserved. The HW handler interface - * centralizes the 'top half' exception/interrupt handling code and takes care of the dirty low-level - * work so that the software handling interfaces for interrupts, system calls, and exceptions - * can be written more clearly elsewhere. - * - * tl;dr - write your handlers as a separate module and call them from one - * of the prototypes below. - * - */ -#include "stdint.h" - -#define BRANCH_INSTRUCTION 0xe59ff018 // ldr pc, pc+offset - -// System Call Types -#define SYSCALL_CREATE 0 -#define SYSCALL_SWITCH 1 -#define SYSCALL_DELETE 2 -#define SYSCALL_OPEN 3 -#define SYSCALL_READ 4 -#define SYSCALL_WRITE 5 -#define SYSCALL_CLOSE 6 -#define SYSCALL_SET_PERM 7 -#define SYSCALL_MEM_MAP 8 -#define SYSCALL_SEEK 9 -#define SYSCALL_MKDIR 10 -#define SYSCALL_COPY 11 -#define SYSCALL_LS 12 -#define SYSCALL_MALLOC 13 -#define SYSCALL_ALIGNED_ALLOC 14 -#define SYSCALL_FREE 15 -#define SYSCALL_PRINTF 16 -#define SYSCALL_DUMMY 99 -#define SYSCALL_EXIT 100 -#define SYSCALL_WRITEV 101 -#define SYSCALL_PAUSE 102 - -void init_vector_table(void); - -// vector table handlers, should be loaded at 0x00 in this order! -extern void _Reset(); - -void reset_handler(void); - -void __attribute__((interrupt("UNDEF"))) undef_instruction_handler(void); // 0x04 -long __attribute__((interrupt("SWI"))) software_interrupt_handler(void); // 0x08 -void __attribute__((interrupt("ABORT"))) prefetch_abort_handler(void); // 0x0c -void __attribute__((interrupt("ABORT"))) data_abort_handler(void); // 0x10 -void reserved_handler(void); // 0x14 -void __attribute__((interrupt("IRQ"))) irq_handler(void); // 0x18 -void __attribute__((interrupt("FIQ"))) fiq_handler(void); // 0x1c - -/** - * Semihosting calls - * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471g/CHDJHHDI.html - */ -enum SemihostingSWI { - BreakPoint = 0x20020, - WatchPoint = 0x20021, - StepComplete = 0x20022, - RunTimeErrorUnknown = 0x20023, - InternalError = 0x20024, - UserInterruption = 0x20025, - ApplicationExit = 0x20026, // Qemu exits with 0 - StackOverflow = 0x20027, - DivisionByZero = 0x20028, - OSSpecific = 0x20029, // Qemu exits with 1 -}; - -void SemihostingCall(enum SemihostingSWI mode); - -#endif diff --git a/kernel/src/common/include/interrupt.h b/kernel/src/common/include/interrupt.h index b2b83684..107dd277 100644 --- a/kernel/src/common/include/interrupt.h +++ b/kernel/src/common/include/interrupt.h @@ -1,142 +1,105 @@ -#ifndef __INTERRUPT_H__ -#define __INTERRUPT_H__ +#ifndef __HW_HANDLERS_H__ +#define __HW_HANDLERS_H__ + /* * - * Interrupt handler for course_os + * Hardware Handler Interface for course_os + * + * + * A bit of background: + * - The ARM architecture has 7 modes of operation: + * + USR - user mode + * + FIQ - processing "fast" interrupts + * + IRQ - processing "normal" interrupts + * + SVC - proctected mode for OS + * + UND - processing an undefined instruction exception + * + SYS - also protecteed mode for OS --if anyone wants to clarify, feel free-- + * These modes can be entered or exited by modifying the CPSR (status register) * + * exceptions (e.g. software interrupts, system calls, etc.), Interrupts (IRQ, FIQ) + * trigger the core to switch to an appropriate mode and the pc to jump to a + * preset address (somewhere in the vector table) for a branch instruction to the + * proper handler. * - * - ARM has two interrupt lines to the core: FIQ (fast interrupt), IRQ (normal interrupt) - * - Our VIC multiplexes intterupts and feeds them to the processor as either FIQ or IRQ - * Basic interrupt control flow (no vectored interrupts, no nested interrupts) is as follows: - * Interrupt Occurs -> Core branches to FIQ or IRQ vector -> vector branches to hanlder \ - * handler interfaces with VIC to determine source of interrupt -> branch to service routine \ + * When this happens the state of the machine must be preserved. The HW handler interface + * centralizes the 'top half' exception/interrupt handling code and takes care of the dirty low-level + * work so that the software handling interfaces for interrupts, system calls, and exceptions + * can be written more clearly elsewhere. + * + * tl;dr - write your handlers as a separate module and call them from one + * of the prototypes below. * */ - -#include -#include - -volatile uint32_t * const PIC_ADDRESS; - -// general syscall function -extern int syscall(int number); - -// the VIC has 32 bits to indicate a type of interrupt -// currently we just pull a bit off the VIC and jump to that number handler -// in the handler array -// this may need to be expanded if we use the secondary controller -#define MAX_NUM_INTERRUPTS 32 - -typedef enum -{ - IRQ_MASK, // (this is bit 0x8 on the CPSR) - FIQ_MASK, // (this is bit 0x4 on the CPSR) - ALL_INTERRUPT_MASK -} interrupt_t; - -extern interrupt_t IRQ; -extern interrupt_t FIQ; -extern interrupt_t ALL; - -// this will tell if an interrupt mapping is an FIQ -// HIGH bits are FIQs -// extern char check_if_fiq[MAX_NUM_INTERRUPTS]; - -typedef struct interrupt_handler_t -{ - void (*handler)(void *args); -// more may need to be added -} interrupt_handler_t; - -/* these are what you should use to effect an - interrupt status change! */ - -#define enable_irq() \ - enable_interrupt(IRQ) -#define enable_fiq() \ - enable_interrupt(FIQ) -#define enable_interrupts() \ - enable_interrupt(ALL) -#define disable_irq() \ - disable_interrupt(IRQ) -#define disable_fiq() \ - disable_interrupt(FIQ) -#define disable_irq_save() \ - disable_interrupt_save(IRQ) -#define disable_fiq_save() \ - disable_interrupt_save(FIQ) -#define disable_interrupts() \ - disable_interrupt(ALL); -#define disable_interrupts_save() \ - disable_interrupt_save(ALL); - - - -/* VIC Interrupt Mappings */ -#define VIC_IRQ_STATUS PIC_ADDRESS // status of pending irqs after masking (R) -#define VIC_FIQ_STATUS (((volatile uint32_t *)(PIC_ADDRESS+0x004))) // status of pending fiqs after masking (R) -#define VIC_RAW_STATUS (((volatile uint32_t *)(PIC_ADDRESS+0x008))) // pending irqs before masking by enable register (R) -#define VIC_INT_SELECT (((volatile uint32_t *)(PIC_ADDRESS+0x00C))) // select whether source generates an IRQ or FIQ (R/W) -#define VIC_INT_ENABLE (((volatile uint32_t *)(PIC_ADDRESS+0x010))) // actually enable interrupt lines (1 = YES) (R/W) -#define VIC_INT_ENCLEAR (((volatile uint32_t *)(PIC_ADDRESS+0x014))) // clear enabled lines in VICINTENABLE (1=clear) -//#define VIC_VECT_ADDR (*((volatile uint32_t *)(PIC_ADDRESS=0x030))) // the ISR of the currently active interrupt - -// these should be used in conjunction with the bit shift mappings below -#define hw_interrupt_enable(n) mmio_write(VIC_INT_ENABLE, mmio_read(VIC_INT_ENABLE) | (1 << n)) -#define hw_interrupt_disable(n) mmio_write(VIC_INT_ENCLEAR, (1 << n)); -#define vic_select_fiq(n) mmio_write(VIC_INT_SELECT, (1 << n)); - -enum InterruptID { - WATCHDOG_IRQ = 0, /* watchdog controller */ - SWI_IRQ = 1, /* software interrupt */ - COMMS_RX_IRQ = 2, /* debug comms receive intercept */ - COMMS_TX_IRQ = 3, /* debug comms transmit intercept */ - TIMER_A_IRQ = 4, /* timer 0 or 1 */ - TIMER_B_IRQ = 5, /* timer 2 or 3 */ - GPIO_A_IRQ = 6, /* GPIO 0 */ - GPIO_B_IRQ = 7, /* GPIO 1 */ - GPIO_C_IRQ = 8, /* GPIO 2 */ - GPIO_D_IRQ = 9, /* GPIO 3 */ - RTC_IRQ = 10, /* Real Time Clock (RTC) */ - SSP_IRQ = 11, /* synchronous serial port */ - UART0_IRQ = 12, /* UART 0 */ - UART1_IRQ = 13, /* UART 1 */ - UART2_IRQ = 14, /* UART 2 */ - SCIO_IRQ = 15, /* smart card interface */ - CLCD_IRQ = 16, /* CLCD controller */ - DMA_IRQ = 17, /* DMA controller */ - PWRFAIL_IRQ = 18, /* power failure from FPGA */ - MBX_IRQ = 19, /* graphics processor */ - // IRQ 20 is reserved by the architecture - VICINTSOURCE_21 = 21, /* external interrupt signal from DiskOnChip flash device */ - VICINTSOURCE_22 = 22, /* external interrupt signal from MCIO A */ - // IRQ 23 is reserved by the architecture - VICINTSOURCE_24 = 24, /* external interrupt signal from AACI */ - VICINTSOURCE_25 = 25, /* Ethernet */ - VICINTSOURCE_26 = 26, /* USB */ - VICINTSOURCE_27 = 27, /* external interrupt signal from expansion connector */ - VICINTSOURCE_28 = 28, /* external interrupt signal from expansion connector */ - // IRQ 29 is reserved by the architecture - // IRQ 30 is reserved by the architecture - VICINTSOURCE_31 = 31, /* secondary interrupt controller (SIC) */ +#include "stdint.h" + +#define BRANCH_INSTRUCTION 0xe59ff018 // ldr pc, pc+offset + +// System Call Types +#define SYSCALL_CREATE 0 +#define SYSCALL_SWITCH 1 +#define SYSCALL_DELETE 2 +#define SYSCALL_OPEN 3 +#define SYSCALL_READ 4 +#define SYSCALL_WRITE 5 +#define SYSCALL_CLOSE 6 +#define SYSCALL_SET_PERM 7 +#define SYSCALL_MEM_MAP 8 +#define SYSCALL_SEEK 9 +#define SYSCALL_MKDIR 10 +#define SYSCALL_COPY 11 +#define SYSCALL_LS 12 +#define SYSCALL_MALLOC 13 +#define SYSCALL_ALIGNED_ALLOC 14 +#define SYSCALL_FREE 15 +#define SYSCALL_PRINTF 16 +#define SYSCALL_DUMMY 99 +#define SYSCALL_EXIT 100 +#define SYSCALL_WRITEV 101 +#define SYSCALL_PAUSE 102 + +void init_vector_table(void); + +// vector table handlers, should be loaded at 0x00 in this order! +extern void _Reset(); + +void reset_handler(void); + +void __attribute__((interrupt("UNDEF"))) undef_instruction_handler(); // 0x04 +long __attribute__((interrupt("SWI"))) software_interrupt_handler(); // 0x08 +void __attribute__((interrupt("ABORT"))) prefetch_abort_handler(); // 0x0c +void __attribute__((interrupt("ABORT"))) data_abort_handler(); // 0x10 +void reserved_handler(); // 0x14 +void __attribute__((interrupt("IRQ"))) irq_handler(); // 0x18 +void __attribute__((interrupt("FIQ"))) fiq_handler(); // 0x1c + +/** + * Semihosting calls + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471g/CHDJHHDI.html + */ +enum SemihostingSWI { + BreakPoint = 0x20020, + WatchPoint = 0x20021, + StepComplete = 0x20022, + RunTimeErrorUnknown = 0x20023, + InternalError = 0x20024, + UserInterruption = 0x20025, + ApplicationExit = 0x20026, // Qemu exits with 0 + StackOverflow = 0x20027, + DivisionByZero = 0x20028, + OSSpecific = 0x20029, // Qemu exits with 1 }; -// Primary Interrupt Controller (PIC) - - -/* functions (e.g. passing a bad parameter), so we'll - refer to the macros above for adjusting specific interrupt status */ -void enable_interrupt(interrupt_t); -int enable_interrupt_save(interrupt_t); - -void disable_interrupt(interrupt_t); -int disable_interrupt_save(interrupt_t); - -int get_proc_status(void); -void restore_proc_status(int); +void SemihostingCall(enum SemihostingSWI mode); -int register_interrupt_handler(enum InterruptID, interrupt_handler_t *); -void handle_irq_interrupt(enum InterruptID); +typedef enum { + IRQ, // (this is bit 0x8 on the CPSR) + FIQ, // (this is bit 0x4 on the CPSR) + BOTH +} InterruptType; +void enable_interrupt(InterruptType); +int enable_interrupt_save(InterruptType); +void disable_interrupt(InterruptType); +int disable_interrupt_save(InterruptType); -#endif //__INTERRUPT_H__ +#endif diff --git a/kernel/src/common/include/interruptold.h b/kernel/src/common/include/interruptold.h new file mode 100644 index 00000000..ced19d37 --- /dev/null +++ b/kernel/src/common/include/interruptold.h @@ -0,0 +1,113 @@ +#ifndef __INTERRUPT_H__ +#define __INTERRUPT_H__ +/* + * + * Interrupt handler for course_os + * + * + * - ARM has two interrupt lines to the core: FIQ (fast interrupt), IRQ (normal interrupt) + * - Our VIC multiplexes intterupts and feeds them to the processor as either FIQ or IRQ + * Basic interrupt control flow (no vectored interrupts, no nested interrupts) is as follows: + * Interrupt Occurs -> Core branches to FIQ or IRQ vector -> vector branches to hanlder \ + * handler interfaces with VIC to determine source of interrupt -> branch to service routine \ + * + */ + +#include +#include + +volatile uint32_t * const PIC_ADDRESS; + +// general syscall function +extern int syscall(int number); + +// the VIC has 32 bits to indicate a type of interrupt +// currently we just pull a bit off the VIC and jump to that number handler +// in the handler array +// this may need to be expanded if we use the secondary controller +#define MAX_NUM_INTERRUPTS 32 + + + + +// this will tell if an interrupt mapping is an FIQ +// HIGH bits are FIQs +// extern char check_if_fiq[MAX_NUM_INTERRUPTS]; + +typedef struct interrupt_handler_t { + void (*handler)(void *args); + // more may need to be added +} interrupt_handler_t; + +// https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf +// Page ~ 117 +struct IRQ_registers { + uint32_t irq_basic_pending; + uint32_t irq_gpu1_pending; + uint32_t irq_gpu2_pending; + uint32_t fiq_control; + uint32_t irq_gpu1_enable; // Interrupt enable register 1 (GPU) + uint32_t irq_gpu2_enable; // Interrupt enable register 2 (GPU) + uint32_t irq_basic_enable; // Base enable register (ARM/CPU) + uint32_t irq_gpu1_disable; + uint32_t irq_gpu2_disable; + uint32_t irq_basic_disable; +}; + +// these should be used in conjunction with the bit shift mappings below +#define hw_interrupt_enable(n) mmio_write(VIC_INT_ENABLE, mmio_read(VIC_INT_ENABLE) | (1 << n)) +#define hw_interrupt_disable(n) mmio_write(VIC_INT_ENCLEAR, (1 << n)); +#define vic_select_fiq(n) mmio_write(VIC_INT_SELECT, (1 << n)); + +enum InterruptID { + WATCHDOG_IRQ = 0, /* watchdog controller */ + SWI_IRQ = 1, /* software interrupt */ + COMMS_RX_IRQ = 2, /* debug comms receive intercept */ + COMMS_TX_IRQ = 3, /* debug comms transmit intercept */ + TIMER_A_IRQ = 4, /* timer 0 or 1 */ + TIMER_B_IRQ = 5, /* timer 2 or 3 */ + GPIO_A_IRQ = 6, /* GPIO 0 */ + GPIO_B_IRQ = 7, /* GPIO 1 */ + GPIO_C_IRQ = 8, /* GPIO 2 */ + GPIO_D_IRQ = 9, /* GPIO 3 */ + RTC_IRQ = 10, /* Real Time Clock (RTC) */ + SSP_IRQ = 11, /* synchronous serial port */ + UART0_IRQ = 12, /* UART 0 */ + UART1_IRQ = 13, /* UART 1 */ + UART2_IRQ = 14, /* UART 2 */ + SCIO_IRQ = 15, /* smart card interface */ + CLCD_IRQ = 16, /* CLCD controller */ + DMA_IRQ = 17, /* DMA controller */ + PWRFAIL_IRQ = 18, /* power failure from FPGA */ + MBX_IRQ = 19, /* graphics processor */ + // IRQ 20 is reserved by the architecture + VICINTSOURCE_21 = 21, /* external interrupt signal from DiskOnChip flash device */ + VICINTSOURCE_22 = 22, /* external interrupt signal from MCIO A */ + // IRQ 23 is reserved by the architecture + VICINTSOURCE_24 = 24, /* external interrupt signal from AACI */ + VICINTSOURCE_25 = 25, /* Ethernet */ + VICINTSOURCE_26 = 26, /* USB */ + VICINTSOURCE_27 = 27, /* external interrupt signal from expansion connector */ + VICINTSOURCE_28 = 28, /* external interrupt signal from expansion connector */ + // IRQ 29 is reserved by the architecture + // IRQ 30 is reserved by the architecture + VICINTSOURCE_31 = 31, /* secondary interrupt controller (SIC) */ +}; + +// Primary Interrupt Controller (PIC) + +volatile struct IRQ_registers * interrupt_registers; + +/* functions (e.g. passing a bad parameter), so we'll + refer to the macros above for adjusting specific interrupt status */ +void init_chipsetold(); + + +int get_proc_status(void); +void restore_proc_status(int); + +int register_interrupt_handler(enum InterruptID, interrupt_handler_t *); +void handle_irq_interrupt(enum InterruptID); + + +#endif //__INTERRUPT_H__ diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index c7ccae79..4c48560d 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -1,189 +1,381 @@ -/* - * - * Interrupts - * - */ +#include +#include +#include #include #include +#include +#include +#include -volatile uint32_t * const PIC_ADDRESS = (volatile uint32_t *)0x10140000; +/* copy vector table from wherever QEMU loads the kernel to 0x00 */ +void init_vector_table() { + /* This doesn't seem to work well with virtual memory; reverting + * to old method. + extern uint32_t vector_table_start, vector_table_end; + uint32_t *src = &vector_table_start; + uint32_t *dst = (uint32_t *) HIVECTABLE; -// there are 32 kinds of interrupts on the VIC -// this structure may need to be expanded if the secondary controller is incorporated -static interrupt_handler_t *handlers[MAX_NUM_INTERRUPTS]; + while(src < &vector_table_end) + *dst++ = *src++; + */ -static int initialized; + /* Primary Vector Table */ + mmio_write(0x0, BRANCH_INSTRUCTION); + mmio_write(0x04, BRANCH_INSTRUCTION); + mmio_write(0x08, BRANCH_INSTRUCTION); + mmio_write(0x0C, BRANCH_INSTRUCTION); + mmio_write(0x10, BRANCH_INSTRUCTION); + mmio_write(0x14, BRANCH_INSTRUCTION); + mmio_write(0x18, BRANCH_INSTRUCTION); + mmio_write(0x1C, BRANCH_INSTRUCTION); -// holds defined fiq interrupts -static int check_if_fiq[MAX_NUM_INTERRUPTS]; + /* Secondary Vector Table */ + mmio_write(0x20, &reset_handler); + mmio_write(0x24, &undef_instruction_handler); + mmio_write(0x28, &software_interrupt_handler); + mmio_write(0x2C, &prefetch_abort_handler); + mmio_write(0x30, &data_abort_handler); + mmio_write(0x34, &reserved_handler); + mmio_write(0x38, &irq_handler); + mmio_write(0x3C, &fiq_handler); -// define interrupt types -interrupt_t IRQ = IRQ_MASK; -interrupt_t FIQ = FIQ_MASK; -interrupt_t ALL = ALL_INTERRUPT_MASK; +} -// In a system with an interrupt controller, software is required to: -// determine from the interrupt controller which interrupt source is requesting service -// determine where the service routine for that interrupt source is loaded -// mask or clear that interrupt source, before re-enabling processor interrupts to permit another interrupt to be taken. +/* handlers */ +void reset_handler(void) +{ + kprintf("RESET HANDLER\n"); + _Reset(); +} -// Interrupts must be enabled in three places: -// (1) the core (CPSR) -// (2) the VIC (interrupt controller) -// (3) (sometimes) in the device (this should be done in the device driver) +void __attribute__((interrupt("UNDEF"))) undef_instruction_handler(void) +{ + int spsr, lr; -// CLear Interrupts -// Do not disable the VIC and the CSPR is disable in the hw_hanlders -// you have to clear the interrupt from the register handler -// Look At timer.c it has a great example of it. -// Here's the Website to the VIC we are using http://infocenter.arm.com/help/topic/com.arm.doc.ddi0181e/DDI0181.pdf + asm volatile("mrs %0, spsr" : "=r"(spsr)); + asm volatile("mov %0, lr" : "=r" (lr)); -//They are three handlers you must use First is the (IRQ)interrupt handler its in hw_handlers.c (with attribute Irq) -// second is the ISR routine handler which is the one in interrupt.c -// third is the specific handler you created a great example is in the timer.c it is called timer_interrupt_handler. -// If youre having an error it must be in the third handler not the first two. + int thumb = spsr & 0x20; + int pc = thumb ? lr - 0x2 : lr - 0x4; -// Setup FIQ interrupts -void init_fiqs() -{ - check_if_fiq[11] = 1; // synchronous serial port - check_if_fiq[17] = 1; // DMA controller + if ((*(size_t *) pc) == UNDEFINED_INSTRUCTION_BYTES){ + kprintf("FATAL ERROR\n"); + panic(); + } + + kprintf("UNDEFINED INSTRUCTION HANDLER\n"); + + int copro = (*(int*)pc & 0xf00000) >> 24; + + if (spsr & 0x20) { + kprintf("THUMB mode\n"); + } else { + kprintf("ARM mode\n"); + } + if (spsr & 0x1000000) { + kprintf("JAZELLE enabled\n"); + } + + kprintf("COPRO: %x\n", copro); + kprintf("violating instruction (at %x): %x\n", pc, *((int *) pc)); + if (pc >= V_KERNBASE && pc < V_KERNTOP) + { + kprintf("(instruction is in kernel address range)\n"); + } + + panic(); } -// when you register an interrupt handler it's line will be enabled in the VIC -// telling the device itself to fire interrupts should be done in the driver -// -// TODO: We do now ------------------------------V -// also, since we don't really have a working malloc, the handler structure will -// have to be built in the driver and passed to register_ -int register_interrupt_handler(enum InterruptID num, interrupt_handler_t *handler) { - // lazy initialization - if (initialized != -1) { - kprintf("INITIALIZING THE INTERRUPT SYSTEM\n"); +long __attribute__((interrupt("SWI"))) software_interrupt_handler(void) +{ + int callNumber = 0, r0 = 0, r1 = 0, r2 = 0, r3 = 0; - for (int i = 0; i < MAX_NUM_INTERRUPTS; i++) { - handlers[i] = 0; - } + asm volatile ("MOV %0, r7":"=r"(callNumber)::); + asm volatile ("MOV %0, r0":"=r"(r0)::); + asm volatile ("MOV %0, r1":"=r"(r1)::); + asm volatile ("MOV %0, r2":"=r"(r2)::); + asm volatile ("MOV %0, r3":"=r"(r3)::); - kprintf("INITIALIZED THE INTERRUPT SYSTEM\n"); + kprintf("SOFTWARE INTERRUPT HANDLER\n"); - initialized = -1; - } + // Print out syscall # for debug purposes + kprintf("Syscall #: "); + kprintf("%d\n", callNumber); + kprintf("arg0=%d\n", r0); + kprintf("arg1=%d\n", r1); + kprintf("arg2=%d\n", r2); + kprintf("arg3=%d\n", r3); + kprintf("\n"); - if (num < 0 || num > MAX_NUM_INTERRUPTS) { - kprintf("Register a handler between 0 and %i\n", MAX_NUM_INTERRUPTS); - panic(); - } else if (handlers[num] != NULL) { - kprintf("Tried to re-register interrupt handler %i\n", num); - panic(); - } else if (handler == NULL) { - kprintf("The interrupt handler can't be NULL\n"); - panic(); - } + // System Call Handler + switch (callNumber) + { + case SYSCALL_EXIT: + // TODO: remove current process from scheduler + for (;;); + break; + case SYSCALL_DUMMY: + return 0L; + break; - // put the handler in the array - handlers[num] = handler; + // NOTE: All FS syscalls have been *DISABLED* until the filesystem works again. + case SYSCALL_CREATE: + kprintf("Create system call called!\n"); + return -1; - // enable the specific interrupt in hardware on the VIC - hw_interrupt_enable(num); +// return (long) kcreate((char*) r0, r1, 0); + case SYSCALL_DELETE: + kprintf("Delete system call called!\n"); + return -1; - // check to see if this is an FIQ - if (check_if_fiq[num]){ - // update the "select" register on the VIC - vic_select_fiq(num); - } +// return (long) kdelete((char*) r0, 1); + case SYSCALL_OPEN: + kprintf("Open system call called!\n"); + return -1; + +// return (long) kopen((char*) r0, r1); + case SYSCALL_MKDIR: + kprintf("Mkdir system call called!\n"); + return -1; + +// return (long) kcreate((char*) r0, 'w', 1); + case SYSCALL_READ: + kprintf("Read system call called!\n"); + return -1; + +// return (long) kread(r0, (void*) r1, r2); + case SYSCALL_WRITE: + kprintf("Write system call called!\n"); + return -1; + +// return (long) kwrite(r0, (void*) r1, r2); + case SYSCALL_CLOSE: + kprintf("Close system call called!\n"); + return -1; + +// return (long) kclose(r0); + case SYSCALL_SEEK: + kprintf("Seek system call called!\n"); + return -1; + +// return (long) kseek(r0, r1); + case SYSCALL_COPY: + kprintf("Copy system call called!\n"); + return -1; + +// return (long) kcopy((char*) r0, (char*) r1, r2); + case SYSCALL_LS: + kprintf("Ls system call called!\n"); + return -1; +// return (long) kls((char*) r0); + case SYSCALL_SET_PERM: + kprintf("Set permission system call called!\n"); + kprintf("Yet to be implemented\n"); + return -1; + case SYSCALL_MEM_MAP: + kprintf("Memory map system call called!\n"); + kprintf("Yet to be implemented\n"); + return -1; + + case SYSCALL_MALLOC: + kprintf("malloc system call called!\n"); + + void *ptr = umalloc(r0); + + kprintf("malloc is about to return %x\n", ptr); - // return a success value - return 0; + return (long) ptr; + case SYSCALL_ALIGNED_ALLOC: + kprintf("aligned_alloc system call called!\n"); + void *ptr2 = ualigned_alloc(r0, r1); + + kprintf("ualigned_alloc is about to return %x\n", ptr2); + + return (long) ptr2; + case SYSCALL_FREE: + kprintf("Free system call called!\n"); + + ufree((void*) r0); + return 0L; + case SYSCALL_PRINTF: + kprintf("Printf system call called!\n"); + + kprintf((const char *) r0); + return 0L; + default: + kprintf("That wasn't a syscall you knob!\n"); + return -1L; + } } -// handle_interrupt takes a number (the interrupt from the VIC), looks into -// the table of registered handlers, and calls the appropriate handler -void handle_irq_interrupt(enum InterruptID interrupt_vector) { - kprintf("handling interrupt %d\n", interrupt_vector); - // go to handler routine - kprintf("Jumping to %X...\n", handlers[interrupt_vector]->handler); - handlers[interrupt_vector]->handler((void *) interrupt_vector); +void __attribute__((interrupt("ABORT"))) prefetch_abort_handler(void) +{ + int lr; + + asm volatile("mov %0, lr" : "=r" (lr)); + + kprintf("PREFETCH ABORT HANDLER, violating address: %x\n", (lr - 4)); + + panic(); } -/* enable IRQ and/or FIQ */ -void enable_interrupt(interrupt_t mask) { - kprintf("Enabling interrupts with mask %i\n", mask); - get_proc_status(); +void __attribute__((interrupt("ABORT"))) data_abort_handler(void) +{ + int lr; + asm volatile("mov %0, lr" : "=r" (lr)); + int pc = lr - 8; - // enable interrupt on the core - switch (mask) + int far; + asm volatile("mrc p15, 0, %0, c6, c0, 0" : "=r" (far)); + + kprintf("DATA ABORT HANDLER (Page Fault)\n"); + kprintf("faulting address: 0x%x\n", far); + if (far >= V_KDSBASE) { - case IRQ_MASK: - asm volatile("cpsie i"); - break; - case FIQ_MASK: - asm volatile("cpsie f"); + kprintf("(address is in kernel address range)\n"); + } + kprintf("violating instruction (at 0x%x): %x\n", pc, *((int *) pc)); + + // Get the DSFR + int dsfr; + asm volatile("MRC p15, 0, %0, c5, c0, 0" : "=r" (dsfr)); + //os_printf("DSFR: 0x%X\n", dsfr); + + switch (dsfr) + { + case 6: // Access bit. + // Set it to 1 so we don't get notified again. + // TODO: The eviction policy will listen to this. + *((unsigned int*) (V_L1PTBASE + 2 * PAGE_TABLE_SIZE)) |= (1 << 4); break; - case ALL_INTERRUPT_MASK: - asm volatile("cpsie if"); + default: break; - } + }; } -/* disable IRQ and/or FIQ */ -void disable_interrupt(interrupt_t mask) +void reserved_handler(void) { + kprintf("RESERVED HANDLER\n"); +} + +// the attribute automatically saves and restores state +void __attribute__((interrupt("IRQ"))) irq_handler(void) { + kprintf("IRQ HANDLER\n"); + return chipset.handle_irq(); + +// int * pendingregister = (int *) 0x40000060; +// int cpsr = disable_interrupt_save(IRQ); + + //os_printf("disabled CSPR:%X\n",cpsr); + // Discover source of interrupt + // do a straight run through the VIC_INT_STATUS to determine + // which interrupt lines need to be tended to +// for (int i = 0; i < MAX_NUM_INTERRUPTS; i++) { +// // is the line active? +// if ((1 << i) & mmio_read(&interrupt_registers->irq_basic_pending)) { +// // activate that specific handler +// handle_irq_interrupt(i); +// } +// } + // we've gone through the VIC and handled all active interrupts + // restore_proc_status(cpsr); + + // enable_interrupt(IRQ_MASK); + +} + +void __attribute__((interrupt("FIQ"))) fiq_handler(void) { + kprintf("FIQ HANDLER\n"); + return chipset.handle_fiq(); + +// handle_irq_interrupt(interrupt_registers->fiq_control & 0x7f); + + +// FIQ handler returns from the interrupt by executing: +// SUBS PC, R14_fiq, #4 +} + +void SemihostingCall(enum SemihostingSWI mode) { + + int a = mode; + asm volatile ( + "MOV r0, #0x18\n" + "LDR r1, %[in0]\n" + "svc 0x00123456\n" + : + : [in0] "m" (a) + ); +} + +/* enable IRQ and/or FIQ */ +void enable_interrupt(InterruptType mask) { + kprintf("Enabling interrupts with mask %i\n", mask); + + // enable interrupt on the core + switch (mask) { + case IRQ: + asm volatile("cpsie i"); + break; + case FIQ: + asm volatile("cpsie f"); + break; + case BOTH: + asm volatile("cpsie if"); + break; + } +} + +/* disable IRQ and/or FIQ */ +void disable_interrupt(InterruptType mask) { kprintf("Disabling interrupts with mask %i\n", mask); // disable interrupts on the core - switch (mask) - { - case IRQ_MASK: - asm volatile("cpsid i"); - break; - case FIQ_MASK: - asm volatile("cpsid f"); - break; - case ALL_INTERRUPT_MASK: - asm volatile("cpsid if"); - break; - } + switch (mask) { + case IRQ: + asm volatile("cpsid i"); + break; + case FIQ: + asm volatile("cpsid f"); + break; + case BOTH: + asm volatile("cpsid if"); + break; + } } /* disable IRQ and/or FIQ, but also return a copy of the CPSR */ -int disable_interrupt_save(interrupt_t mask) -{ +int disable_interrupt_save(InterruptType mask) { kprintf("Disabling interrupts (save) with mask %i\n", mask); /* get a copy of the current process status register */ - int cpsr; - asm volatile("mrs %0, cpsr" : "=r"(cpsr)); - // disable interrupts on the core - switch (mask) - { - case IRQ_MASK: - asm volatile("cpsid i"); - break; - case FIQ_MASK: - asm volatile("cpsid f"); - break; - case ALL_INTERRUPT_MASK: - asm volatile("cpsid if"); - break; - } - return cpsr; + int cpsr; + asm volatile("mrs %0, cpsr" : "=r"(cpsr)); + // disable interrupts on the core + switch (mask) { + case IRQ: + asm volatile("cpsid i"); + break; + case FIQ: + asm volatile("cpsid f"); + break; + case BOTH: + asm volatile("cpsid if"); + break; + } + return cpsr; } /* return a full 32-bit copy of the current process status register */ -int get_proc_status(void) -{ - int cpsr; - asm volatile("mrs %0, cpsr" : "=r"(cpsr)); - return cpsr; +int get_proc_status() { + int cpsr; + asm volatile("mrs %0, cpsr" : "=r"(cpsr)); + return cpsr; } /* restore control status (interrupt, mode bits) of the cpsr */ -/* (e.g. when we return from a handler, restore value from +/* (e.g. when we return from a handler, restore value from disable_interrupt_save */ -void restore_proc_status(int cpsr) -{ - asm volatile("msr cpsr_c, %0" : : "r"(cpsr)); +void restore_proc_status(int cpsr) { + asm volatile("msr cpsr_c, %0" : : "r"(cpsr)); } - diff --git a/kernel/src/common/interruptold.c b/kernel/src/common/interruptold.c new file mode 100644 index 00000000..1373cd29 --- /dev/null +++ b/kernel/src/common/interruptold.c @@ -0,0 +1,121 @@ +/* + * + * Interrupts + * + */ +#include +#include +#include +#include + +// TODO: make consistent (old val: 0x10140000) +volatile uint32_t * const PIC_ADDRESS = (volatile uint32_t *)(0x2000b200); + +// there are 32 kinds of interrupts on the VIC +// this structure may need to be expanded if the secondary controller is incorporated +static interrupt_handler_t *handlers[MAX_NUM_INTERRUPTS]; + +static int initialized; + +// holds defined fiq interrupts +static int check_if_fiq[MAX_NUM_INTERRUPTS]; + + +// In a system with an interrupt controller, software is required to: +// determine from the interrupt controller which interrupt source is requesting service +// determine where the service routine for that interrupt source is loaded +// mask or clear that interrupt source, before re-enabling processor interrupts to permit another interrupt to be taken. + +// Interrupts must be enabled in three places: +// (1) the core (CPSR) +// (2) the VIC (interrupt controller) +// (3) (sometimes) in the device (this should be done in the device driver) + +// CLear Interrupts +// Do not disable the VIC and the CSPR is disable in the hw_hanlders +// you have to clear the interrupt from the register handler +// Look At timer.c it has a great example of it. +// Here's the Website to the VIC we are using http://infocenter.arm.com/help/topic/com.arm.doc.ddi0181e/DDI0181.pdf + +//They are three handlers you must use First is the (IRQ)interrupt handler its in hw_handlers.c (with attribute Irq) +// second is the ISR routine handler which is the one in interrupt.c +// third is the specific handler you created a great example is in the timer.c it is called timer_interrupt_handler. +// If youre having an error it must be in the third handler not the first two. + +// Setup FIQ interrupts +void init_fiqs() +{ + check_if_fiq[11] = 1; // synchronous serial port + check_if_fiq[17] = 1; // DMA controller +} + +void init_chipsetold() { + init_fiqs(); + interrupt_registers = (volatile struct IRQ_registers *)PIC_ADDRESS; + + enable_interrupt(BOTH); + + interrupt_registers->irq_basic_enable = 0; + interrupt_registers->irq_gpu1_enable = 0; + interrupt_registers->irq_gpu2_enable = 0; +} + +// when you register an interrupt handler it's line will be enabled in the VIC +// telling the device itself to fire interrupts should be done in the driver +// +// TODO: We do now ------------------------------V +// also, since we don't really have a working malloc, the handler structure will +// have to be built in the driver and passed to register_ +int register_interrupt_handler(enum InterruptID num, interrupt_handler_t *handler) { + // lazy initialization + if (initialized != -1) { + kprintf("INITIALIZING THE INTERRUPT SYSTEM\n"); + + for (int i = 0; i < MAX_NUM_INTERRUPTS; i++) { + handlers[i] = 0; + } + + kprintf("INITIALIZED THE INTERRUPT SYSTEM\n"); + + initialized = -1; + } + + if (num < 0 || num > MAX_NUM_INTERRUPTS) { + kprintf("Register a handler between 0 and %i\n", MAX_NUM_INTERRUPTS); + panic(); + } else if (handlers[num] != NULL) { + kprintf("Tried to re-register interrupt handler %i\n", num); + panic(); + } else if (handler == NULL) { + kprintf("The interrupt handler can't be NULL\n"); + panic(); + } + + // put the handler in the array + handlers[num] = handler; + + kprintf("Enabling interrupt 0x%x\n", num); + // enable the specific interrupt in hardware on the VIC + interrupt_registers->irq_basic_enable |= (1 << num); + + // check to see if this is an FIQ +// if (check_if_fiq[num]){ +// // update the "select" register on the VIC +// vic_select_fiq(num); +// } + + // return a success value + return 0; +} + +// handle_interrupt takes a number (the interrupt from the VIC), looks into +// the table of registered handlers, and calls the appropriate handler +void handle_irq_interrupt(enum InterruptID interrupt_vector) { + kprintf("handling interrupt %d\n", interrupt_vector); + // go to handler routine + kprintf("Jumping to %X...\n", handlers[interrupt_vector]->handler); + handlers[interrupt_vector]->handler((void *) interrupt_vector); +} + + + diff --git a/kernel/src/common/start.c b/kernel/src/common/start.c index 66cf2def..283e781f 100644 --- a/kernel/src/common/start.c +++ b/kernel/src/common/start.c @@ -17,86 +17,69 @@ */ #include -#include -#include #include +#include #include #include -#include #include #include -#include #include #include #include - +#include +#include +#include +#include // This start is what u-boot calls. It's just a wrapper around setting up the // virtual memory for the kernel. void start(uint32_t *p_bootargs) { - // Initialize the virtual memory - uart_early_init(); + prepare_pagetable(); + + + // Before this point, all code has to be hardware independent. + // After this point, code can request the hardware info struct to find out what + // Code should be ran. + init_hardwareinfo(); + + // Initialize the chipset and enable uart + init_chipset(); + + print_hardwareinfo(); kprintf("Enabling MMU...\n"); vm_init(); kprintf("Initialized VM datastructures.\n"); + + // Paging and virtual memory is initialized. This code jumps us to start2. mmap(p_bootargs); } - // This start is what starts the kernel. Note that virtual memory is enabled // at this point (And running, also, in the kernel's VAS). void start2(uint32_t *p_bootargs) { - // Setup all of the exception handlers... (hrm, interaction with VM?) + + // Set up the exception handlers. init_vector_table(); - // Setup kmalloc... + // After this point kmalloc and kfree can be used for dynamic memory management. init_heap(); splash(); - // Test stuff... - /*int *p = (int*)0xFFFFFFF0; - p[0] = 1; - os_printf("0x%x == 1?\n", p[0]);*/ - //run_vm_tests(); - //INFO("There are %d free frames.\n", vm_count_free_frames()); - //run_mem_alloc_tests(); - //INFO("There are %d free frames.\n", vm_count_free_frames()); - //run_prq_tests(); - //run_hmap_tests(); + // Turn on interrupts + enable_interrupt(BOTH); - // The file system has currently been *disabled* due to bugs - // kfs_init(0, 0, 0); - - - /* - 4-15-15: #Prakash: What happens if we let the program load here? - Let's make argparse_process() do its thing - - Note: As of 4-15-15 this fails horribly with hello.o not being - recognized as an ELF file and DATA ABORT HANDLER being syscalled - */ - - // enable interrupt handling - enable_interrupts(); - - uart_late_init(); - - // initialize the timers - initialize_timers(); + // Call the chipset again to do post-interrupt-enable initialization + chipset.late_init(); process_init(); - sched_init(); // FIXME: temporary - kprintf("Programming the timer interrupt\n"); - start_timer_interrupts(0, 10); - -// exit_test(); + sched_init(); - kprintf("0x%x\n", p_bootargs); + kprintf("bootargs: 0x%x\n", p_bootargs); #ifndef ENABLE_TESTS // argparse_process(p_bootargs); @@ -124,5 +107,9 @@ void start2(uint32_t *p_bootargs) { // * Mount vfs // * Load initramfs into tmpfs // * execute userland init program + + asm volatile("cpsie i"); + + kprintf("End of start method.\n"); SLEEP; } diff --git a/kernel/src/common/startup.s b/kernel/src/common/startup.s index a54f55a4..bf7e76a6 100644 --- a/kernel/src/common/startup.s +++ b/kernel/src/common/startup.s @@ -2,10 +2,10 @@ _Reset: // Disable other cores - //mrc p15, 0, r5, c0, c0, 5 - //and r5, r5, #3 - //cmp r5, #0 - //bne loop + mrc p15, #0, r1, c0, c0, #5 + and r1, r1, #3 + cmp r1, #0 + bne loop LDR sp, =stack_top MOV R0, R2 diff --git a/kernel/src/drivers/chipset/bcm2835/bcm2835.c b/kernel/src/drivers/chipset/bcm2835/bcm2835.c new file mode 100644 index 00000000..0c353e4f --- /dev/null +++ b/kernel/src/drivers/chipset/bcm2835/bcm2835.c @@ -0,0 +1 @@ +#include diff --git a/kernel/src/drivers/chipset/bcm2835/include/bcm2835.h b/kernel/src/drivers/chipset/bcm2835/include/bcm2835.h new file mode 100644 index 00000000..fd40910d --- /dev/null +++ b/kernel/src/drivers/chipset/bcm2835/include/bcm2835.h @@ -0,0 +1,4 @@ + + + + diff --git a/kernel/src/drivers/chipset/bcm2836/bcm2836.c b/kernel/src/drivers/chipset/bcm2836/bcm2836.c new file mode 100644 index 00000000..c92a8273 --- /dev/null +++ b/kernel/src/drivers/chipset/bcm2836/bcm2836.c @@ -0,0 +1,62 @@ +// https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf +#include +#include +#include +#include +#include + +volatile struct BCM2836Registers * bcm2836_registers_base = (struct BCM2836Registers *) 0x40000000; +const size_t BCM2836_peripheral_base = 0x3F000000; + +//static TimerHandle handleindex; + +// uart.c +void bcm2836_uart_init(); +void bcm2836_uart_putc(char c, int uartchannel); +void bcm2836_uart_on_message(UartCallback callback, int uartchannel); + +// timer.c +void bcm2836_timer_init(); +TimerHandle bcm2836_schedule_timer_periodic(TimerCallback callback, uint32_t ms); +TimerHandle bcm2836_schedule_timer_once(TimerCallback callback, uint32_t ms); +void bcm2836_deschedule_timer(TimerHandle handle); + +void bcm2836_on_interrupt(InterruptCallback callback) { + +} + + +void bcm2836_late_init() { + bcm2836_timer_init(); + +} + +void bcm2836_irq_handler() { + volatile uint32_t pending = bcm2836_registers_base->Core0IRQSource; + + + kprintf("interrupt: 0x%x", pending); +} + +void bcm2836_fiq_handler() { + +} + +void bcm2836_init() { + bcm2836_uart_init(); + chipset.schedule_timer_periodic = &bcm2836_schedule_timer_periodic; + chipset.schedule_timer_once = &bcm2836_schedule_timer_once; + chipset.deschedule_timer = &bcm2836_deschedule_timer; + chipset.uart_putc = &bcm2836_uart_putc; + chipset.uart_on_message = &bcm2836_uart_on_message; + chipset.on_interrupt = &bcm2836_on_interrupt; + chipset.handle_irq = &bcm2836_irq_handler; + chipset.handle_fiq = &bcm2836_fiq_handler; + chipset.late_init = &bcm2836_late_init; + + // Mapping memory used by bcm2836 peripherals + request_identity_mapped_section(BCM2836_peripheral_base, 4); + + // Map control registers + request_identity_mapped_section((size_t)bcm2836_registers_base, 1); +} diff --git a/kernel/src/drivers/chipset/bcm2836/include/bcm2836.h b/kernel/src/drivers/chipset/bcm2836/include/bcm2836.h new file mode 100644 index 00000000..16efc651 --- /dev/null +++ b/kernel/src/drivers/chipset/bcm2836/include/bcm2836.h @@ -0,0 +1,114 @@ +// Data sheet: https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf +#ifndef BCM2836_H +#define BCM2836_H + +#include + +// Starts at memory address 0x4000_0000 +struct BCM2836Registers { + uint32_t ControlRegister; + uint32_t __unused1; + uint32_t CoreTimerPrescaler; + uint32_t GPUInterruptsRouting; + uint32_t PerformanceMonitorRoutingSet; + uint32_t PerformanceMonitorRoutingClear; + uint32_t __unused2; + uint32_t CoreTimerAccessLS32Bits; + uint32_t CoreTimerAccessMS32Bits; + uint32_t LocalInterupts0Routing; + uint32_t __LocalInterupts8Routing __attribute__ ((deprecated)); // Deprecated + uint32_t AxiOutstandingCounters; + uint32_t AxiOutstandingIRQ; + uint32_t LocalTimerControlAndStatus; + uint32_t LocalTimerWriteFlags; + uint32_t __unused3; + uint32_t Core0TimersInterruptControl; + uint32_t Core1TimersInterruptControl; + uint32_t Core2TimersInterruptControl; + uint32_t Core3TimersInterruptControl; + uint32_t Core0MailboxInterruptControl; + uint32_t Core1MailboxInterruptControl; + uint32_t Core2MailboxInterruptControl; + uint32_t Core3MailboxInterruptControl; + uint32_t Core0IRQSource; + uint32_t Core1IRQSource; + uint32_t Core2IRQSource; + uint32_t Core3IRQSource; + uint32_t Core0FIQSource; + uint32_t Core1FIQSource; + uint32_t Core2FIQSource; + uint32_t Core3FIQSource; + uint32_t Core0Mailbox0WriteSet; + uint32_t Core0Mailbox1WriteSet; + uint32_t Core0Mailbox2WriteSet; + uint32_t Core0Mailbox3WriteSet; + uint32_t Core1Mailbox0WriteSet; + uint32_t Core1Mailbox1WriteSet; + uint32_t Core1Mailbox2WriteSet; + uint32_t Core1Mailbox3WriteSet; + uint32_t Core2Mailbox0WriteSet; + uint32_t Core2Mailbox1WriteSet; + uint32_t Core2Mailbox2WriteSet; + uint32_t Core2Mailbox3WriteSet; + uint32_t Core3Mailbox0WriteSet; + uint32_t Core3Mailbox1WriteSet; + uint32_t Core3Mailbox2WriteSet; + uint32_t Core3Mailbox3WriteSet; + uint32_t Core0Mailbox0ReadClear; + uint32_t Core0Mailbox1ReadClear; + uint32_t Core0Mailbox2ReadClear; + uint32_t Core0Mailbox3ReadClear; + uint32_t Core1Mailbox0ReadClear; + uint32_t Core1Mailbox1ReadClear; + uint32_t Core1Mailbox2ReadClear; + uint32_t Core1Mailbox3ReadClear; + uint32_t Core2Mailbox0ReadClear; + uint32_t Core2Mailbox1ReadClear; + uint32_t Core2Mailbox2ReadClear; + uint32_t Core2Mailbox3ReadClear; + uint32_t Core3Mailbox0ReadClear; + uint32_t Core3Mailbox1ReadClear; + uint32_t Core3Mailbox2ReadClear; + uint32_t Core3Mailbox3ReadClear; +}; + + + + + + + + +enum InterruptSource { + // nCNTPSIRQ : Secure physical timer event + PHYSICAL_SECURE_TIMER = (1 << 0), + + // nCNTPNSIRQ : Non-secure physical timer event + PHYSICAL_NONSECURE_TIMER = (1 << 1), + + // nCNTHPIRQ: Physical Timer for use in Hypervisor mode. + PHYSICAL_HYPERVISOR_TIMER = (1 << 2), + + // nCNTVIRQ: Virtual Timer for use in Non-secure PL1 modes. + VIRTUAL_NONSECURE_TIMER = (1 << 3), + + MAILBOX_0 = (1 << 4), + MAILBOX_1 = (1 << 5), + MAILBOX_2 = (1 << 6), + MAILBOX_3 = (1 << 7), + + GPU = (1 << 8), + PMU = (1 << 9), + + AXI = (1 << 10), + LOCAL_TIMER = (1 << 11), +}; + +volatile struct BCM2836Registers * bcm2836_registers_base; + +void bcm2836_init(); + + +extern const size_t BCM2836_peripheral_base; + +#endif diff --git a/kernel/src/drivers/chipset/bcm2836/timer.c b/kernel/src/drivers/chipset/bcm2836/timer.c new file mode 100644 index 00000000..06af7c4e --- /dev/null +++ b/kernel/src/drivers/chipset/bcm2836/timer.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include + +inline static uint32_t get_frequency() { + uint32_t val; + asm volatile ("mrc p15, 0, %0, c14, c0, 0" : "=r"(val) ); + return val; +} + +void write_interrupt_count_value(uint32_t val) { + asm volatile ("mcr p15, 0, %0, c14, c3, 0" :: "r"(val) ); +} + +uint32_t read_interrupt_count_value() { + uint32_t val; + asm volatile ("mrc p15, 0, %0, c14, c3, 0" : "=r"(val) ); + return val; +} + + + +// https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf +// Page ~ 117 +struct IRQ_registers { + uint32_t irq_basic_pending; + uint32_t irq_gpu1_pending; + uint32_t irq_gpu2_pending; + uint32_t fiq_control; + uint32_t irq_gpu1_enable; // Interrupt enable register 1 (GPU) + uint32_t irq_gpu2_enable; // Interrupt enable register 2 (GPU) + uint32_t irq_basic_enable; // Base enable register (ARM/CPU) + uint32_t irq_gpu1_disable; + uint32_t irq_gpu2_disable; + uint32_t irq_basic_disable; +}; + + +void bcm2836_timer_init() { + + uint32_t freq = get_frequency(); + + kprintf("control frequency: %i\n", freq); + // 1 (milli)second timer + write_interrupt_count_value(freq); + + kprintf("value: %i\n", read_interrupt_count_value()); + kprintf("value: %i\n", read_interrupt_count_value()); + + // when the register reaches the count value set above, interrupt. +// mmio_write(&bcm2836_registers_base->Core0TimersInterruptControl, VIRTUAL_NONSECURE_TIMER); + + // Enable timer interrupts. + uint32_t cntv_ctl = 1; + asm volatile ("mcr p15, 0, %0, c14, c3, 1" :: "r"(cntv_ctl) ); + + bcm2836_registers_base->PerformanceMonitorRoutingSet = 0xf; + +} + +TimerHandle bcm2836_schedule_timer_periodic(TimerCallback callback, uint32_t ms) { + + + return 0; +} + +TimerHandle bcm2836_schedule_timer_once(TimerCallback callback, uint32_t ms) { + return 0; +} + +void bcm2836_deschedule_timer(TimerHandle handle) { + +} diff --git a/kernel/src/drivers/chipset/bcm2836/uart.c b/kernel/src/drivers/chipset/bcm2836/uart.c new file mode 100644 index 00000000..38dffbf0 --- /dev/null +++ b/kernel/src/drivers/chipset/bcm2836/uart.c @@ -0,0 +1,113 @@ +#include +#include +#include +#include + +/* +// raspberry pi zero, 1, b+ etc +volatile UartInterface * const UART0_ADDRESS = (volatile UartInterface *)0x20201000; +volatile UartInterface * const UART1_ADDRESS = (volatile UartInterface *)0x20202000; +volatile UartInterface * const UART2_ADDRESS = (volatile UartInterface *)0x20203000; + +// raspberry pi 4: +volatile UartInterface * const UART0_ADDRESS = (volatile UartInterface *)0xfe201000; +volatile UartInterface * const UART1_ADDRESS = (volatile UartInterface *)0xfe202000; +volatile UartInterface * const UART2_ADDRESS = (volatile UartInterface *)0xfe203000; + VersatilePB +volatile UartInterface * const UART0_ADDRESS = (volatile UartInterface *)0x101f1000; +volatile UartInterface * const UART1_ADDRESS = (volatile UartInterface *)0x101f2000; +volatile UartInterface * const UART2_ADDRESS = (volatile UartInterface *)0x101f3000; +*/ + + +// http://infocenter.arm.com/help/topic/com.arm.doc.ddi0183f/DDI0183.pdf +// uart flag register masks +// (FR) +#define RI (1<<8) // Ring Indicator +#define TXFE (1<<7) // Transmit fifo empty +#define RXFF (1<<6) // Receive fifo full +#define TXFF (1<<5) // Transmit fifo full +#define RXFE (1<<4) // Receive fifo empty +#define BUSY (1<<3) // UART busy, set while uart is sending something +#define DCD (1<<2) // Data carrier detect +#define DSR (1<<1) // Data set ready +#define CTS (1<<0) // Clear to send + +// Uart interrupt masks. When a mask is set, this action causes an interrupt +// (IMSC) +#define OEIM (1<<10) // Overrun error +#define BEIM (1<<9) // Break error +#define PEIM (1<<8) // Parity error +#define FEIM (1<<7) // Framing error +#define RTIM (1<<6) // Receive timeout +#define TXIM (1<<5) // Transmit +#define RXIM (1<<4) // Receive +#define DSRMIM (1<<3) // nUARTDSR Modem +#define DCDMIM (1<<2) // nUARTDCD Modem +#define CTCMIM (1<<1) // nUARTCTS Modem +#define RIMIM (1<<0) // nUARTRI Modem + +// (CR) +//#define CTSEn () // CTS Hardware Control Enable + + +// http://infocenter.arm.com/help/topic/com.arm.doc.ddi0183f/DDI0183.pdf +// Section 3.2: Summary of registers +// https://balau82.wordpress.com/2010/11/30/emulating-arm-pl011-serial-ports/ +// This struct is memory mappend. I call them registers but they all live in memory. +typedef volatile struct BCM2836UartInterface { + uint32_t DR; // Data Register + uint32_t RSR_ECR; // Receive Status Register / Error Clear Register + uint8_t reserved1[0x10]; // Reserved + const uint32_t FR; // Flag Register + uint8_t reserved2[0x4]; // Reserved + uint32_t LPR; // IrDA low power counter Register + uint32_t IBRD; // Integer Baud Rate Register + uint32_t FBRD; // Fractional Baud Rate Register + uint32_t LCR_H; // Line Control Register + uint32_t CR; // Control Register + uint32_t IFLS; // Interrupt FIFO Level Select Register + uint32_t IMSC; // Interrupt Mask Set/Clear Register + const uint32_t RIS; // Raw Interrupt Status Register + const uint32_t MIS; // Masked Interrupt Status Register + uint32_t ICR; // Interrupt Clear Register + uint32_t DMACR; // DMA Control Register +} BCM2836UartInterface; + +volatile BCM2836UartInterface * BCM2836_UART0_ADDRESS; +volatile BCM2836UartInterface * BCM2836_UART1_ADDRESS; +volatile BCM2836UartInterface * BCM2836_UART2_ADDRESS; +volatile BCM2836UartInterface * BCM2836_UART3_ADDRESS; + +void bcm2836_uart_init() { + BCM2836_UART0_ADDRESS = (volatile BCM2836UartInterface *)(BCM2836_peripheral_base + 0x201000); + BCM2836_UART1_ADDRESS = (volatile BCM2836UartInterface *)(BCM2836_peripheral_base + 0x202000); + BCM2836_UART2_ADDRESS = (volatile BCM2836UartInterface *)(BCM2836_peripheral_base + 0x203000); + BCM2836_UART3_ADDRESS = (volatile BCM2836UartInterface *)(BCM2836_peripheral_base + 0x204000); +} + +void uart_write_byte(volatile BCM2836UartInterface * interface, volatile uint8_t value) { +// while (interface->FR & TXFF ) { +// asm volatile ("nop"); +// } + interface->DR = (uint32_t)value; +} + +void bcm2836_uart_putc(char c, int uartchannel) { + + if (uartchannel >= 4) { + uartchannel = 0; + } + + switch (uartchannel) { + case 0: return uart_write_byte(BCM2836_UART0_ADDRESS, c); + case 1: return uart_write_byte(BCM2836_UART1_ADDRESS, c); + case 2: return uart_write_byte(BCM2836_UART2_ADDRESS, c); + case 3: return uart_write_byte(BCM2836_UART3_ADDRESS, c); + default: __unreachable(); + } + +} + +void bcm2836_uart_on_message(UartCallback callback, int uartchannel) { +} diff --git a/kernel/src/drivers/chipset/chipset.c b/kernel/src/drivers/chipset/chipset.c new file mode 100644 index 00000000..61691948 --- /dev/null +++ b/kernel/src/drivers/chipset/chipset.c @@ -0,0 +1,32 @@ + +#include +#include +#include +#include +#include + +ChipsetInterface chipset; + +void init_chipset() { + HardwareInfo * info = get_hardwareinfo(); + + memset(&chipset, 0, sizeof(ChipsetInterface)); + + switch (info->boardType) { + case RaspBerryPiTwo: + bcm2836_init(); + break; + default: { + kprintf("Board type not supported for interrupts \n"); + panic(); + } + } + + for (size_t i = 0; i < sizeof(ChipsetInterface) / sizeof(uint32_t); i++) { + if (((uint32_t **) &chipset)[i] == NULL) { + kprintf("Chipset did not satisfy the required interface. Missing field %i\n", i); + panic(); + } + } + +} diff --git a/kernel/src/drivers/chipset/include/chipset.h b/kernel/src/drivers/chipset/include/chipset.h new file mode 100644 index 00000000..9febce36 --- /dev/null +++ b/kernel/src/drivers/chipset/include/chipset.h @@ -0,0 +1,51 @@ +#ifndef INTERRUPT_H +#define INTERRUPT_H + +#include + +void init_chipset(); + +// A timer handle is an identifier for a timer so it can be descheduled later. +// These handles must be unique. +typedef size_t TimerHandle; +typedef void (*TimerCallback)(); +typedef void (*UartCallback)(char c); +typedef void (*InterruptCallback)(); + +typedef struct ChipsetInterface { + /// Timer Functions + //TODO: time/duration struct of some sort. + TimerHandle (*schedule_timer_periodic)(TimerCallback callback, uint32_t ms); + TimerHandle (*schedule_timer_once)(TimerCallback callback, uint32_t ms); + + void (*deschedule_timer)(TimerHandle handle); + + /// UART Functions + // Prints a character to a uart channel. + // The definition of a channel is pretty open to interpretation + // but what must be guaranteed is that channel 0 is the default channel + // and in normal operation should always just work. Other channels might not exist. + // If a user requests to print on a non existent channel, the output must be printed on + // channel 0. + void (*uart_putc)(char c, int uartchannel); + + // The callback given to this function is called any time a uart message + // is received on the channel. The same rules apply as for puts. When a channel + // is requested that does not exist, input from channel zero shall be given to this callback. + void (*uart_on_message)(UartCallback callback, int uartchannel); + + // Interrupt numbers are not guaranteed to work from one boardtype/version to another. + // Only use this function after checking hardwareinfo. + void (*on_interrupt)(InterruptCallback callback); + + void (*handle_irq)(); + void (*handle_fiq)(); + + // Called for every chipset after interrupts and dynamic memory has been enabled + // So the chipset can do some more initialization. + void (*late_init)(); +} ChipsetInterface; + +ChipsetInterface chipset; + +#endif diff --git a/kernel/src/drivers/time/include/timer.h b/kernel/src/drivers/time/include/timer.h index 2778faaf..c8220523 100644 --- a/kernel/src/drivers/time/include/timer.h +++ b/kernel/src/drivers/time/include/timer.h @@ -1,7 +1,7 @@ #ifndef TIMER_H #define TIMER_H -#include "../../../src/klibc//include/stdint.h" +#include typedef struct { uint32_t timer_load_value; // read/write @@ -13,7 +13,6 @@ typedef struct { uint32_t background_timer_load_value; // read/write } rasp_pi_timer; -_Static_assert (sizeof (rasp_pi_timer) == 28, "rasp_pi_timer check"); void initialize_timers(); int set_load_value(int timer_index, int value); diff --git a/kernel/src/drivers/time/include/timer.h.old b/kernel/src/drivers/time/include/timer.h.old new file mode 100644 index 00000000..2778faaf --- /dev/null +++ b/kernel/src/drivers/time/include/timer.h.old @@ -0,0 +1,36 @@ +#ifndef TIMER_H +#define TIMER_H + +#include "../../../src/klibc//include/stdint.h" + +typedef struct { + uint32_t timer_load_value; // read/write + uint32_t timer_actual_value; // read only + uint32_t control; // read/write + uint32_t interrupt_clear; // write only + uint32_t interrupt_status; // read only + uint32_t masked_interrupt_status; // read only + uint32_t background_timer_load_value; // read/write +} rasp_pi_timer; + +_Static_assert (sizeof (rasp_pi_timer) == 28, "rasp_pi_timer check"); + +void initialize_timers(); +int set_load_value(int timer_index, int value); +int set_background_load_value(int timer_index, int value); +int clear_interupt(int timer_index); +int set_32_bit_mode(int timer_index); +int get_current_timer_value(int timer_index); +int set_periodic_mode(int timer_index); +int set_free_running_mode(int timer_index); +int start_timer(int timer_index); +int set_prescale(int timer_index, int mode); +int start_timer_interrupts( int timer_index, int star_val); +int conversion(int timer_index, int milliseconds); +int enable_timer_interrupt(int timer_index); +int disable_timer(int timer_index); +int register_handler(int timer_index, void (*handler)(void *args)); +int unregister_handler(int timer_index); + + +#endif diff --git a/kernel/src/drivers/time/timer.c b/kernel/src/drivers/time/timer.c index b51dfb97..9cdb46d9 100644 --- a/kernel/src/drivers/time/timer.c +++ b/kernel/src/drivers/time/timer.c @@ -1,295 +1,90 @@ -/* Device Driver for ARM Dual-Timer Module (SP804) - Reference Manual can be found here : http://infocenter.arm.com/help/topic/com.arm.doc.ddi0271d/DDI0271.pdf*/ -#include -#include -#include -#include -#include - -rasp_pi_timer *timer_pointers[4]; - -void timer_irq_handler(void* args); -void (*handlers[4])(void *args); - -/* initializes timers as an array. Call this before - * using any of the timer functions */ -void initialize_timers() -{ - kprintf("initializing timers\n"); - volatile rasp_pi_timer *TIMER_0 = (rasp_pi_timer *) 0x101e2000; - volatile rasp_pi_timer *TIMER_1 = (rasp_pi_timer *) 0x101e2020; - volatile rasp_pi_timer *TIMER_2 = (rasp_pi_timer *) 0x101e3000; - volatile rasp_pi_timer *TIMER_3 = (rasp_pi_timer *) 0x101e3020; - timer_pointers[0] = (rasp_pi_timer*) TIMER_0; - timer_pointers[1] = (rasp_pi_timer*) TIMER_1; - timer_pointers[2] = (rasp_pi_timer*) TIMER_2; - timer_pointers[3] = (rasp_pi_timer*) TIMER_3; - - handlers[0] = NULL; - handlers[1] = NULL; - handlers[2] = NULL; - handlers[3] = NULL; - - interrupt_handler_t *tmr_handler = kmalloc(sizeof(interrupt_handler_t)); - tmr_handler->handler = timer_irq_handler; - register_interrupt_handler(TIMER_A_IRQ, tmr_handler); -} - -#define CHECK_TIMER_INDEX(index) { if (index < 0 || index > 4) return -1; } - -/* This function sets the value that the timer will begin at. - * This operation also resets the timer to this new value. - * if you want to keep the timer running with its current state - * use set background load. */ -int set_load_value(int timer_index, int value) -{ - CHECK_TIMER_INDEX(timer_index); - - timer_pointers[timer_index]->timer_load_value = value; - return 0; -} - -//returns the current control register value (configuration of timer) -int get_timer_control_value(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - - return timer_pointers[timer_index]->control; -} - -/* Sets the value for the timer to load the next time it reaches - * 0 and loads the reset value. Does not affect current timer. */ -int set_background_load_value(int timer_index, int value) -{ - CHECK_TIMER_INDEX(timer_index); - - timer_pointers[timer_index]->background_timer_load_value = value; - return 0; -} - -/* Clear any interrupt data for the timer. - * note: writing to the clear timer register clears - * the interrupt status completely. */ -int clear_interrupt(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - timer_pointers[timer_index]->interrupt_clear = 0x1; +#include +#include +#include +#include - return 0; +inline static uint32_t get_frequency() { + uint32_t val; + asm volatile ("mrc p15, 0, %0, c14, c0, 0" : "=r"(val) ); + return val; } -//enable 32 bit mode in the specified timer index -int set_32_bit_mode(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - - disable_timer(timer_index); - timer_pointers[timer_index]->control |= 0x2; - return 0; +void write_cntv_tval(uint32_t val) { + asm volatile ("mcr p15, 0, %0, c14, c3, 0" :: "r"(val) ); + return; } -int get_current_timer_value(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - - return timer_pointers[timer_index]->timer_actual_value; +uint32_t read_cntv_tval() { + uint32_t val; + asm volatile ("mrc p15, 0, %0, c14, c3, 0" : "=r"(val) ); + return val; } -//enable periodic mode of specified timer index -int set_periodic_mode(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - - disable_timer(timer_index); - timer_pointers[timer_index]->control &= 0xFFFFFFBE; +// https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf +#define CORE0_TIMER_IRQCNTL BCM2836BASE +#define CORE1_TIMER_IRQCNTL BCM2836BASE + 0x04 +#define CORE2_TIMER_IRQCNTL BCM2836BASE + 0x08 +#define CORE3_TIMER_IRQCNTL BCM2836BASE + 0x0c - return 0; -} +#define CORE0_IRQ_SOURCE BCM2836BASE + 0x20 +#define CORE1_IRQ_SOURCE BCM2836BASE + 0x24 +#define CORE2_IRQ_SOURCE BCM2836BASE + 0x28 +#define CORE3_IRQ_SOURCE BCM2836BASE + 0x2c -//converts ms into ticks -//assumes modes are valid, if not, should return 0 -int conversion(int timer_index, int milliseconds) -{ - int mode = (timer_pointers[timer_index]->control & 0xC) >> 2; +#define CORE0_FIQ_SOURCE BCM2836BASE + 0x30 +#define CORE1_FIQ_SOURCE BCM2836BASE + 0x34 +#define CORE2_FIQ_SOURCE BCM2836BASE + 0x38 +#define CORE3_FIQ_SOURCE BCM2836BASE + 0x3c - int ticks = 0; - if (mode == 0) - { - ticks = 32; - } - else if (mode == 1) - { - ticks = 256; - } - else if (mode == 2) - { - ticks = 1000; - } - return milliseconds * ticks; -} -//function to set timer to different timer clock rates... 0 -> 1 (default), 1 -> 16, 2 -> 256... -//any other modes are invalid and will do nothing -int set_prescale(int timer_index, int mode) -{ - CHECK_TIMER_INDEX(timer_index); +void timer_handler_func(void * args) { - disable_timer(timer_index); - if (mode == 0) - timer_pointers[timer_index]->control &= 0xFFFFFFF3; - else if (mode == 1) - { - timer_pointers[timer_index]->control |= 0x4; - timer_pointers[timer_index]->control &= 0xFFFFFFF7; - } - else if (mode == 2) - { - timer_pointers[timer_index]->control |= 0x8; - timer_pointers[timer_index]->control &= 0xFFFFFFFB; - } - return 0; } -//enables timer interrupt of the given timer index -int enable_timer_interrupt(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); +//struct interrupt_handler_t timer_irq_handler = { +// .handler = timer_handler_func +//}; - timer_pointers[timer_index]->control |= (1 << 5); - return 0; -} -//disables timer interrupt of the given timer index -int disable_timer_interrupt(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - timer_pointers[timer_index]->control &= 0xFFFFFFDF; - return 0; -} +void initialize_timers() { +// return; -int set_free_running_mode(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); + uint32_t freq = get_frequency(); - disable_timer(timer_index); - timer_pointers[timer_index]->control |= 0x1; - return 0; -} + kprintf("control frequency: %i\n", freq); + // 1 second timer + write_cntv_tval(freq); -//starts the timer, countdown from load value -int enable_timer(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); + kprintf("value: %i\n", read_cntv_tval()); - timer_pointers[timer_index]->control |= (1 << 7); - return 0; -} + mmio_write(CORE0_TIMER_IRQCNTL, 0x08); -//pauses the timer -int disable_timer(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); + uint32_t cntv_ctl = 1; + asm volatile ("mcr p15, 0, %0, c14, c3, 1" :: "r"(cntv_ctl) ); // write CNTV_CTL - timer_pointers[timer_index]->control &= 0xFFFFFF7F; - return 0; -} +// register_handler(, timer_handler) +// register_interrupt_handler(4, &timer_irq_handler); +// register_interrupt_handler(3, &timer_irq_handler); -//prints the configuration of the control byte -int print_control_status(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - kprintf("control byte:%x", timer_pointers[timer_index]->control); - return 0; } -/*starts interrupts every start_val ticks */ -//You give it a vallut and the specific timer you want to star. -// YOu have four timers just start with timer zero -// The speed of counter or number ticks depends on qemu hertz speed -// we don't know he start of it but it should be around 10 milliseconds -// per proccess. -// ex: start_timer_interrupts(0,10) which means start timer(0) -// and interrupt every 10 clicks. -int start_timer_interrupts(int timer_index, int milliseconds) -{ -// conversion(timer_index, milliseconds); - CHECK_TIMER_INDEX(timer_index); - int clicks = conversion(timer_index, milliseconds); - kprintf("CLICKS ARE %d\n", clicks); - set_background_load_value(timer_index, clicks); - set_periodic_mode(timer_index); - enable_timer_interrupt(timer_index); - enable_timer(timer_index); - return 0; -} -int register_handler(int timer_index, void (*handler)(void *args)) -{ - CHECK_TIMER_INDEX(timer_index); - handlers[timer_index] = handler; - return 0; +int start_timer_interrupts( int timer_index, int star_val) { + return 0; } -int unregister_handler(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - handlers[timer_index] = NULL; - return 0; +int register_handler(int timer_index, void (*handler)(void *args)) { + return 0; } -void timer_irq_handler(void* args) { - clear_interrupt(0); - - kprintf("@@@@@@ RECEIVED TIMER INTERRUPT\n"); - - // TODO: find out which timer fired. For the moment, hard-code to 0 - if (handlers[0] != NULL) - { - handlers[0](args); - } +int unregister_handler(int timer_index) { + return 0; } -void timer_test() -{ -// enable_interrupt(ALL_INTERRUPT_MASK); - - /*interrupt_handler_t *tmr_handler = kmalloc(sizeof(interrupt_handler_t)); - tmr_handler->handler = simple_timer_handler; - os_printf("fn ptr: %X\n", simple_timer_handler); - register_interrupt_handler(4, tmr_handler);*/ - - kprintf("FIQ status: %X\n", mmio_read(VIC_FIQ_STATUS)); - initialize_timers(); - start_timer_interrupts(0, 10); - //print_control_status(1); - - // Wait forever... - /* os_printf("\n"); - int cnt = 0; - os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); - os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); - os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); - while (!(timer_pointers[0]->masked_interrupt_status&1)) { - cnt++; - //os_printf("%X\n", timer_pointers[1]->timer_actual_value); - int i; - for (i=0; i<1000; i++); - } - os_printf("%d\n", cnt); - os_printf("%X\n", mmio_read(PIC_ADDRESS+0x8)); - os_printf("%X\n", mmio_read(VIC_IRQ_STATUS)); - os_printf("%X\n", mmio_read(VIC_FIQ_STATUS)); - os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); - os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); - os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); - while(1); - */ - return; -} diff --git a/kernel/src/drivers/time/timer.c.old b/kernel/src/drivers/time/timer.c.old new file mode 100644 index 00000000..90119b69 --- /dev/null +++ b/kernel/src/drivers/time/timer.c.old @@ -0,0 +1,303 @@ +/* Device Driver for ARM Dual-Timer Module (SP804) + Reference Manual can be found here : http://infocenter.arm.com/help/topic/com.arm.doc.ddi0271d/DDI0271.pdf*/ +#include +#include +#include +#include +#include +#include + +rasp_pi_timer *timer_pointers[4]; + +void timer_irq_handler(void* args); +void (*handlers[4])(void *args); + +/* initializes timers as an array. Call this before + * using any of the timer functions */ +void initialize_timers() +{ +// TODO: make consistent + kprintf("initializing timers\n"); +// volatile rasp_pi_timer *TIMER_0 = (rasp_pi_timer *) 0x101e2000; +// volatile rasp_pi_timer *TIMER_1 = (rasp_pi_timer *) 0x101e2020; +// volatile rasp_pi_timer *TIMER_2 = (rasp_pi_timer *) 0x101e3000; +// volatile rasp_pi_timer *TIMER_3 = (rasp_pi_timer *) 0x101e3020; + volatile rasp_pi_timer *TIMER_0 = (rasp_pi_timer *) PERIPHBASE + 0x300c; + volatile rasp_pi_timer *TIMER_1 = (rasp_pi_timer *) PERIPHBASE + 0x3010; + volatile rasp_pi_timer *TIMER_2 = (rasp_pi_timer *) PERIPHBASE + 0x3014; + volatile rasp_pi_timer *TIMER_3 = (rasp_pi_timer *) PERIPHBASE + 0x3018; +// 0x3f201000 + + timer_pointers[0] = (rasp_pi_timer*) TIMER_0; + timer_pointers[1] = (rasp_pi_timer*) TIMER_1; + timer_pointers[2] = (rasp_pi_timer*) TIMER_2; + timer_pointers[3] = (rasp_pi_timer*) TIMER_3; + + handlers[0] = NULL; + handlers[1] = NULL; + handlers[2] = NULL; + handlers[3] = NULL; + + interrupt_handler_t *tmr_handler = kmalloc(sizeof(interrupt_handler_t)); + tmr_handler->handler = timer_irq_handler; + register_interrupt_handler(TIMER_A_IRQ, tmr_handler); +} + +#define CHECK_TIMER_INDEX(index) { if (index < 0 || index > 4) return -1; } + +/* This function sets the value that the timer will begin at. + * This operation also resets the timer to this new value. + * if you want to keep the timer running with its current state + * use set background load. */ +int set_load_value(int timer_index, int value) +{ + CHECK_TIMER_INDEX(timer_index); + + timer_pointers[timer_index]->timer_load_value = value; + return 0; +} + +//returns the current control register value (configuration of timer) +int get_timer_control_value(int timer_index) +{ + CHECK_TIMER_INDEX(timer_index); + + return timer_pointers[timer_index]->control; +} + +/* Sets the value for the timer to load the next time it reaches + * 0 and loads the reset value. Does not affect current timer. */ +int set_background_load_value(int timer_index, int value) +{ + CHECK_TIMER_INDEX(timer_index); + + timer_pointers[timer_index]->background_timer_load_value = value; + return 0; +} + +/* Clear any interrupt data for the timer. + * note: writing to the clear timer register clears + * the interrupt status completely. */ +int clear_interrupt(int timer_index) +{ + CHECK_TIMER_INDEX(timer_index); + + timer_pointers[timer_index]->interrupt_clear = 0x1; + + return 0; +} + +//enable 32 bit mode in the specified timer index +int set_32_bit_mode(int timer_index) +{ + CHECK_TIMER_INDEX(timer_index); + + disable_timer(timer_index); + timer_pointers[timer_index]->control |= 0x2; + return 0; +} + +int get_current_timer_value(int timer_index) +{ + CHECK_TIMER_INDEX(timer_index); + + return timer_pointers[timer_index]->timer_actual_value; +} + +//enable periodic mode of specified timer index +int set_periodic_mode(int timer_index) +{ + CHECK_TIMER_INDEX(timer_index); + + disable_timer(timer_index); + timer_pointers[timer_index]->control &= 0xFFFFFFBE; + + return 0; +} + +//converts ms into ticks +//assumes modes are valid, if not, should return 0 +int conversion(int timer_index, int milliseconds) +{ + int mode = (timer_pointers[timer_index]->control & 0xC) >> 2; + + int ticks = 0; + if (mode == 0) + { + ticks = 32; + } + else if (mode == 1) + { + ticks = 256; + } + else if (mode == 2) + { + ticks = 1000; + } + return milliseconds * ticks; +} + +//function to set timer to different timer clock rates... 0 -> 1 (default), 1 -> 16, 2 -> 256... +//any other modes are invalid and will do nothing +int set_prescale(int timer_index, int mode) +{ + CHECK_TIMER_INDEX(timer_index); + + disable_timer(timer_index); + if (mode == 0) + timer_pointers[timer_index]->control &= 0xFFFFFFF3; + else if (mode == 1) + { + timer_pointers[timer_index]->control |= 0x4; + timer_pointers[timer_index]->control &= 0xFFFFFFF7; + } + else if (mode == 2) + { + timer_pointers[timer_index]->control |= 0x8; + timer_pointers[timer_index]->control &= 0xFFFFFFFB; + } + return 0; +} + +//enables timer interrupt of the given timer index +int enable_timer_interrupt(int timer_index) +{ + CHECK_TIMER_INDEX(timer_index); + + timer_pointers[timer_index]->control |= (1 << 5); + return 0; +} + +//disables timer interrupt of the given timer index +int disable_timer_interrupt(int timer_index) +{ + CHECK_TIMER_INDEX(timer_index); + + timer_pointers[timer_index]->control &= 0xFFFFFFDF; + return 0; +} + +int set_free_running_mode(int timer_index) +{ + CHECK_TIMER_INDEX(timer_index); + + disable_timer(timer_index); + timer_pointers[timer_index]->control |= 0x1; + return 0; +} + +//starts the timer, countdown from load value +int enable_timer(int timer_index) +{ + CHECK_TIMER_INDEX(timer_index); + + timer_pointers[timer_index]->control |= (1 << 7); + return 0; +} + +//pauses the timer +int disable_timer(int timer_index) +{ + CHECK_TIMER_INDEX(timer_index); + + timer_pointers[timer_index]->control &= 0xFFFFFF7F; + return 0; +} + +//prints the configuration of the control byte +int print_control_status(int timer_index) +{ + CHECK_TIMER_INDEX(timer_index); + + kprintf("control byte:%x", timer_pointers[timer_index]->control); + return 0; +} + +/*starts interrupts every start_val ticks */ +//You give it a vallut and the specific timer you want to star. +// YOu have four timers just start with timer zero +// The speed of counter or number ticks depends on qemu hertz speed +// we don't know he start of it but it should be around 10 milliseconds +// per proccess. +// ex: start_timer_interrupts(0,10) which means start timer(0) +// and interrupt every 10 clicks. +int start_timer_interrupts(int timer_index, int milliseconds) +{ +// conversion(timer_index, milliseconds); + CHECK_TIMER_INDEX(timer_index); + + int clicks = conversion(timer_index, milliseconds); + + kprintf("CLICKS ARE %d\n", clicks); + + set_background_load_value(timer_index, clicks); + set_periodic_mode(timer_index); + enable_timer_interrupt(timer_index); + enable_timer(timer_index); + return 0; +} + +int register_handler(int timer_index, void (*handler)(void *args)) +{ + CHECK_TIMER_INDEX(timer_index); + handlers[timer_index] = handler; + return 0; +} + +int unregister_handler(int timer_index) +{ + CHECK_TIMER_INDEX(timer_index); + handlers[timer_index] = NULL; + return 0; +} + +void timer_irq_handler(void* args) { + clear_interrupt(0); + + kprintf("@@@@@@ RECEIVED TIMER INTERRUPT\n"); + + // TODO: find out which timer fired. For the moment, hard-code to 0 + if (handlers[0] != NULL) + { + handlers[0](args); + } +} + +void timer_test() +{ + +// enable_interrupt(ALL_INTERRUPT_MASK); + + /*interrupt_handler_t *tmr_handler = kmalloc(sizeof(interrupt_handler_t)); + tmr_handler->handler = simple_timer_handler; + os_printf("fn ptr: %X\n", simple_timer_handler); + register_interrupt_handler(4, tmr_handler);*/ + + kprintf("FIQ status: %X\n", mmio_read(VIC_FIQ_STATUS)); + initialize_timers(); + start_timer_interrupts(0, 10); + //print_control_status(1); + + // Wait forever... + /* os_printf("\n"); + int cnt = 0; + os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); + os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); + os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); + while (!(timer_pointers[0]->masked_interrupt_status&1)) { + cnt++; + //os_printf("%X\n", timer_pointers[1]->timer_actual_value); + int i; + for (i=0; i<1000; i++); + } + os_printf("%d\n", cnt); + os_printf("%X\n", mmio_read(PIC_ADDRESS+0x8)); + os_printf("%X\n", mmio_read(VIC_IRQ_STATUS)); + os_printf("%X\n", mmio_read(VIC_FIQ_STATUS)); + os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); + os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); + os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); + while(1); + */ + return; +} diff --git a/kernel/src/drivers/uart/include/uart.h b/kernel/src/drivers/uart/include/uart.h deleted file mode 100644 index c327c0f2..00000000 --- a/kernel/src/drivers/uart/include/uart.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef UART_H -#define UART_H - -#include - - -// http://infocenter.arm.com/help/topic/com.arm.doc.ddi0183f/DDI0183.pdf -// Section 3.2: Summary of registers -// https://balau82.wordpress.com/2010/11/30/emulating-arm-pl011-serial-ports/ -// This struct is memory mappend. I call them registers but they all live in memory. -typedef volatile struct UartInterface { - uint32_t DR; // Data Register - uint32_t RSR_ECR; // Receive Status Register / Error Clear Register - uint8_t reserved1[0x10]; // Reserved - const uint32_t FR; // Flag Register - uint8_t reserved2[0x4]; // Reserved - uint32_t LPR; // IrDA low power counter Register - uint32_t IBRD; // Integer Baud Rate Register - uint32_t FBRD; // Fractional Baud Rate Register - uint32_t LCR_H; // Line Control Register - uint32_t CR; // Control Register - uint32_t IFLS; // Interrupt FIFO Level Select Register - uint32_t IMSC; // Interrupt Mask Set/Clear Register - const uint32_t RIS; // Raw Interrupt Status Register - const uint32_t MIS; // Masked Interrupt Status Register - uint32_t ICR; // Interrupt Clear Register - uint32_t DMACR; // DMA Control Register -} UartInterface; - -volatile UartInterface * const UART0_ADDRESS; -volatile UartInterface * const UART1_ADDRESS; -volatile UartInterface * const UART2_ADDRESS; - -uint32_t uart_read_int(volatile UartInterface * interface); -void uart_write_int(volatile UartInterface * interface, volatile uint32_t value); -uint8_t uart_read_byte(volatile UartInterface * interface); -void uart_write_byte(volatile UartInterface * interface, volatile uint8_t value); - -void uart0_puts(const char * s); -void uart0_putc(char c); -char uart0_getc(); - -void UART0_INTERRUPT_HANDLER(); -void UART1_INTERRUPT_HANDLER(); -void UART2_INTERRUPT_HANDLER(); - -// Called when the processor first boots -void uart_early_init(); - -// Called when interrupts have been enabled. Can be used to enable UART interrupts -void uart_late_init(); - -// http://infocenter.arm.com/help/topic/com.arm.doc.ddi0183f/DDI0183.pdf -// uart flag register masks -// (FR) -#define RI (1<<8) // Ring Indicator -#define TXFE (1<<7) // Transmit fifo empty -#define RXFF (1<<6) // Receive fifo full -#define TXFF (1<<5) // Transmit fifo full -#define RXFE (1<<4) // Receive fifo empty -#define BUSY (1<<3) // UART busy, set while uart is sending something -#define DCD (1<<2) // Data carrier detect -#define DSR (1<<1) // Data set ready -#define CTS (1<<0) // Clear to send - -// Uart interrupt masks. When a mask is set, this action causes an interrupt -// (IMSC) -#define OEIM (1<<10) // Overrun error -#define BEIM (1<<9) // Break error -#define PEIM (1<<8) // Parity error -#define FEIM (1<<7) // Framing error -#define RTIM (1<<6) // Receive timeout -#define TXIM (1<<5) // Transmit -#define RXIM (1<<4) // Receive -#define DSRMIM (1<<3) // nUARTDSR Modem -#define DCDMIM (1<<2) // nUARTDCD Modem -#define CTCMIM (1<<1) // nUARTCTS Modem -#define RIMIM (1<<0) // nUARTRI Modem - -// (CR) -//#define CTSEn () // CTS Hardware Control Enable -#endif // ifndef UART_H diff --git a/kernel/src/drivers/uart/uart.c b/kernel/src/drivers/uart/uart.c deleted file mode 100644 index 5607f26b..00000000 --- a/kernel/src/drivers/uart/uart.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include - -void UART0_INTERRUPT_HANDLER() { -// UART_ClearITPendingBit(UART0, UART_IT_Receive); -// UART_ClearITPendingBit(UART0, UART_IT_Transmit); -// while(UART_GetFlagStatus(UART0, UART_FLAG_TxFIFOFull) != RESET); -// UART_SendData(UART0, UART_ReceiveData(UART0)); -// VIC1->VAR=0xFF; - -} - -uint32_t uart_read_int(volatile UartInterface * interface) { - return 0; -} - -void uart_write_int(volatile UartInterface * interface, volatile uint32_t value) { - interface->DR = value; -} - -uint8_t uart_read_byte(volatile UartInterface * interface) { - // Wait for UART to have received something. - while ( interface->FR & RXFE ) { - asm volatile ("nop"); - } - return interface->DR; -} - -void uart_write_byte(volatile UartInterface * interface, volatile uint8_t value) { - while (interface->FR & TXFF ) { - asm volatile ("nop"); - } - interface->DR = (uint32_t)value; -} - -char uart0_getc() { - return uart_read_byte(UART0_ADDRESS); -} - -void uart0_puts(const char *s) { - while (*s != '\0') { - uart0_putc(*s); - s++; - } -} - -void uart0_putc(char c) { - uart_write_byte(UART0_ADDRESS, c); -} diff --git a/kernel/src/drivers/uart/uart_pi.c b/kernel/src/drivers/uart/uart_pi.c deleted file mode 100644 index 27abe916..00000000 --- a/kernel/src/drivers/uart/uart_pi.c +++ /dev/null @@ -1,156 +0,0 @@ - -// Only compile this file when compiling for a raspberry pi -#ifdef RASPBERRY_PI - -#include "stdint.h" -#include "drivers/uart.h" -#include "mmap.h" - -#define UARTDR (UART0_ADDRESS_PI+0x00) // Data Register -#define UARTRSR (UART0_ADDRESS_PI+0x04) //Recieve status register -#define UARTFR (UART0_ADDRESS_PI+0x18) // Flag Register -#define UARTILPR (UART0_ADDRESS_PI+0x20) //IrDA low power counter register -#define UARTIBRD (UART0_ADDRESS_PI+0x24) // Integer baud rate -#define UARTFBRD (UART0_ADDRESS_PI+0x28) //Fractional baud rate register -#define UARTLCR_H (UART0_ADDRESS_PI+0x2C) // Line control register -#define UARTCR (UART0_ADDRESS_PI+0x30) //Control Register -#define UARTIFLS (UART0_ADDRESS_PI+0x34) // Interrupt FIFO level select register -#define UARTIMSC (UART0_ADDRESS_PI+0x38) //Interrupt mask set/clear register -#define UARTRIS (UART0_ADDRESS_PI+0x3C) //Raw interrupt status register -#define UARTMIS (UART0_ADDRESS_PI+0x40) //masked interrupt status register -#define UARTICR (UART0_ADDRESS_PI+0x44) // Interrupt clear register -#define UARTDMACR (UART0_ADDRESS_PI+0x48) // DMA controlled register -#define GPPUD (GPIO_ADDRESS_PI + 0x94) //Controls pull up/down on GPIO pins -#define GPPUDCLK0 (GPIO_ADDRESS_PI + 0x98) //GPIO Clock - - -void init_uart() -{ - //Disable UART - mmio_write(UARTCR, 0x00000000); - - mmio_write(GPPUD, 0x00000000); - for(int i = 0;i<150;i++){ - asm volatile ("nop"); - } - - mmio_write(GPPUDCLK0, (1<<14) | (1<<15)); - for(int i = 0;i<150;i++){ - asm volatile ("nop"); - } - - mmio_write(GPPUDCLK0,0x00000000); - - mmio_write(UARTICR, 0x7FF); - //Enable DMA memory reads & writes with UART - //mmio_write(UARTDMACR, (1<<0) | (1<<1)); - - //Enable FIFO and set word length to 8 - mmio_write(UARTLCR_H, (1<<4) | (1<<5) | (1<<6)); - //Set the baud transfer rate at 115200 - mmio_write(UARTIBRD, 1); - mmio_write(UARTFBRD, 40); - - //Enable interrupts - mmio_write(UARTIMSC, (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10)); - //Enable UART and UART transfer - mmio_write(UARTCR, (1<<0) | (1<<8)); -} - -void print_char_uart0(char c) { - //Wait for room in the FIFO queue - while(mmio_read(UARTFR) & (1<<5)) {} - mmio_write(UART0_ADDRESS_PI, c); //Changed -} - -void print_uart0(const char *s) { - while(*s != '\0') { - while(mmio_read(UARTFR) & (1<<5)) {} - - print_char_uart0(*s); //Altering for testing purposes, don't kill me! - s++; - } -} - - - -/* print the full 32 bits of a word at the given address */ -/* trailing newline... */ -void print_word_bits(uint32_t * c) { - int i; - for(i = 31; i >= 0; i--) - *c & (1 << i) ? print_uart0("1") : print_uart0("0"); - print_uart0("\n"); -} - -/* print the full 8-digit hex code of a word at the given address */ -/* no '0x' prefix, NO trailing newline */ -void print_word_hex(uint32_t * c){ - int i; - uint32_t a; - for(i = 0x7; i >= 0x0; i--){ - a = *c & (0xf << (i*0x4)); - a >>= (i*0x4); - while(mmio_read(UARTFR) & (1<<5)) {} - if(a <= 9) - mmio_write(UART0_ADDRESS_PI, (uint32_t)(a + (uint32_t )'0')); //Changed - else if(a <= 0xf) - mmio_write(UART0_ADDRESS_PI, (uint32_t)((a - 0xa) + (uint32_t )'a'));//Changed - else - mmio_write(UART0_ADDRESS_PI, (uint32_t)('?')); //Changed - } -} - -/* display memory at given address */ -/* format is: "[address]: word1 word2 word3\n", etc. */ -/* displays 30 words (10 lines) */ -void md(uint32_t * start){ - int i, j; - uint32_t *addr = start; - for(i = 0; i < 10; i++) { - print_uart0("0x"); print_word_hex((uint32_t *)&addr); print_uart0(": "); - for(j = 0; j < 3; j++) { - print_word_hex(addr); - print_uart0(" "); - addr++; - } - print_uart0("\n"); - } -} - -/*void print_uart0(const char *s) {*/ -/*while (uart->dd->uart0_inter_val == 0) {}*/ -/*if(uart.UARTCR & RXE > 0) */ -/*{*/ -/*while(*s != '\0') */ -/*{*/ -/**UART0 = (uint32_t)(*s);*/ -/*s++;*/ -/*}*/ -/*}*/ -/*}*/ - -/* We need to implement a lock here. klibc will be implementing the buffer - * we just need to ensure the FIFO isn't read out of order. - */ -/*char *read_uart0() */ -/*{*/ -/*uint32_t buffer[STD_IN_BUFFER_SIZE] = {0};*/ -/*while (uart->dd->uart0_inter_val == 0) {}*/ -/*uint32_t *iterator = buffer;*/ -/*do */ -/*{*/ -/*if(uart.UARTCR & TXE > 0) */ -/*{*/ -/*break;*/ -/*} */ -/*else */ -/*{*/ -/**iterator = uart.UARTDR;*/ -/*iterator++;*/ -/*}*/ -/*} while (*iterator != '\0');*/ -/*return buffer;*/ -/*}*/ - -#endif // RASPBERRY_PI diff --git a/kernel/src/drivers/uart/uart_qemu.c b/kernel/src/drivers/uart/uart_qemu.c deleted file mode 100644 index b8a7a42e..00000000 --- a/kernel/src/drivers/uart/uart_qemu.c +++ /dev/null @@ -1,94 +0,0 @@ -// Only compile this file when **not** compiling for a raspberry pi -#ifndef RASPBERRY_PI - -#include -#include -#include -#include - -// 0x3F200000 + 0x1000 - -/* -// raspberry pi 2 + 3 -volatile UartInterface * const UART0_ADDRESS = (volatile UartInterface *)0x3f201000; -volatile UartInterface * const UART1_ADDRESS = (volatile UartInterface *)0x3f202000; -volatile UartInterface * const UART2_ADDRESS = (volatile UartInterface *)0x3f203000; - -// raspberry pi zero, 1, b+ etc -volatile UartInterface * const UART0_ADDRESS = (volatile UartInterface *)0x20201000; -volatile UartInterface * const UART1_ADDRESS = (volatile UartInterface *)0x20202000; -volatile UartInterface * const UART2_ADDRESS = (volatile UartInterface *)0x20203000; - -// raspberry pi 4: -volatile UartInterface * const UART0_ADDRESS = (volatile UartInterface *)0xfe201000; -volatile UartInterface * const UART1_ADDRESS = (volatile UartInterface *)0xfe202000; -volatile UartInterface * const UART2_ADDRESS = (volatile UartInterface *)0xfe203000; - */ -// VersatilePB -volatile UartInterface * const UART0_ADDRESS = (volatile UartInterface *)0x101f1000; -volatile UartInterface * const UART1_ADDRESS = (volatile UartInterface *)0x101f2000; -volatile UartInterface * const UART2_ADDRESS = (volatile UartInterface *)0x101f3000; - - - -static inline void delay(int32_t count) -{ - asm volatile("__delay_%=: subs %[count], %[count], #1; bne __delay_%=\n" - : "=r"(count): [count]"0"(count) : "cc"); -} - -void set_baud_rate(volatile UartInterface * interface, uint32_t baud_rate) { - const int UART_CLOCK_SPEED = 4000000; - float divider = UART_CLOCK_SPEED / (16.0f * baud_rate); - uint16_t integer_divider = (uint16_t)divider; - uint8_t fractional_divider = ((divider - integer_divider) * 64) + 0.5; - - interface->IBRD = integer_divider; // Integer baud rate divider - interface->FBRD = fractional_divider; // Fractional baud rate divider -}; - -void uart_early_init() { - //Disable UART - UART0_ADDRESS->CR = 0x00000000; - - #define GPPUD (GPIO_ADDRESS_PI + 0x94) //Controls pull up/down on GPIO pins - #define GPPUDCLK0 (GPIO_ADDRESS_PI + 0x98) //GPIO Clo - - mmio_write(GPPUD, 0x00000000); - delay(150); - - mmio_write(GPPUDCLK0, (1<<14) | (1<<15)); - delay(150); - - mmio_write(GPPUDCLK0,0x00000000); - - UART0_ADDRESS->ICR = 0x7ff; - //Enable DMA memory reads & writes with UART - //mmio_write(UARTDMACR, (1<<0) | (1<<1)); - - //Enable FIFO and set word length to 8 - UART0_ADDRESS->LCR_H = (1<<4) | (1<<5) | (1<<6); - - set_baud_rate(UART0_ADDRESS, 115200); - - //Enable interrupts - UART0_ADDRESS->IMSC = CTCMIM | RXIM | TXIM | RTIM | FEIM | PEIM | BEIM | OEIM; - //Enable UART and UART transfer - UART0_ADDRESS->CR = (1<<0) | (1<<8) | (1 << 9); - - - kprintf("Baud rate: %i:%i\n", UART0_ADDRESS->IBRD, UART0_ADDRESS->FBRD); -} - -void uart_late_init() { - // Register the uart interrupt handler. - // register_interrupt_handler(UART0_IRQ, UART0_INTERRUPT_HANDLER) - - // kprintf("uart: 0x%x\n", UART0_ADDRESS->IMSC); - // UART0_ADDRESS->IMSC = RXIM; - // kprintf("uart: 0x%x\n", UART0_ADDRESS->IMSC); -} - - - -#endif // RASPBERRY_PI diff --git a/kernel/src/klibc/klibc.c b/kernel/src/klibc/klibc.c index 95cdea0c..72a38bcd 100644 --- a/kernel/src/klibc/klibc.c +++ b/kernel/src/klibc/klibc.c @@ -22,10 +22,9 @@ #include #include -#include //FIXME: decouple -#include +#include #define LOWER_CASE 0 #define UPPER_CASE 1 @@ -43,7 +42,7 @@ - Currrently states the panic and stalls the machine */ void panic() { - disable_interrupts(); + disable_interrupt(BOTH); kprintf("Kernel panic!\n"); kprintf("\n ) ( \n"); kprintf(" ( /( ( )\\ ) \n"); @@ -53,16 +52,26 @@ void panic() { kprintf("| |/ (_)) ((_)_(_/((_))| | | _ ((_)_ _(_/((_)((_) \n"); kprintf(" ' -#include +#include #include static char lower_case_digits[16] = "0123456789abcdef"; @@ -167,12 +167,19 @@ int os_snprintf(char *buf, int buflen, const char *fmt, ...) { return n; } +void puts(const char *s) { + while (*s != '\0') { + chipset.uart_putc(*s, 0); + s++; + } +} + int kprintf(const char *str_buf, ...) { va_list args; va_start(args, str_buf); char buf[256]; int n = os_vsnprintf(buf, 255, str_buf, args); va_end(args); - uart0_puts(buf); + puts(buf); return n; } diff --git a/kernel/src/memory/include/memory.h b/kernel/src/memory/include/memory.h index 55291475..8331abfe 100644 --- a/kernel/src/memory/include/memory.h +++ b/kernel/src/memory/include/memory.h @@ -1,6 +1,14 @@ -//Physical location of kernel -#define P_KERNBASE 0x00010000 + +#include + + + +#define P_KERNBASE 0x00008000 #define P_KERNTOP 0x00200000 +//Physical location of kernel. Defined in the linker script. +//const uint32_t P_KERNBASE; +//const uint32_t P_KERNTOP; + //Virtual location of kernel #define V_KERNBASE 0xf0000000 #define V_KERNTOP 0xf0200000 @@ -8,21 +16,25 @@ //All static kernel data structures //Total space=1MB, currently used=44kB #define P_KDSBASE 0x07f00000 -#define P_L1PTBASE P_KERNTOP +#define P_L1PTBASE P_KERNTOP #define V_KDSBASE 0xfff00000 -#define V_L1PTBASE V_KERNTOP +#define V_L1PTBASE V_KERNTOP -#define PERIPHBASE 0x10000000 +//#define PERIPHBASE 0x10000000 +#define PERIPHBASE 0x3F000000 #define PERIPHTOP 0x20000000 -#define PCIBASE 0x41000000 -#define PCITOP 0x70000000 +//#define PCIBASE 0x41000000 +//#define PCITOP 0x70000000 //remapped physical memory for direct access #define PMAPBASE 0xf0200000 #define PMAPTOP 0xf7f00000 +#define BCM2836BASE 0x40000000 +#define TIMERBASE BCM2836BASE + 0x40 + // Region where we use 4K pages. #define P_4K_BASE (P_L1PTBASE+0x200000) #define P_4K_TOP (PMAPTOP - 0xf0000000) diff --git a/kernel/src/memory/include/mmap.h b/kernel/src/memory/include/mmap.h index afb0ac16..a3e335bb 100644 --- a/kernel/src/memory/include/mmap.h +++ b/kernel/src/memory/include/mmap.h @@ -6,14 +6,25 @@ #define MMAP_H #include -#include - -#define mmio_read(address) (*((volatile uint32_t *)(address))) -#define mmio_write(address, value) (*((volatile uint32_t *)(address)) = (volatile uint32_t)(value)) - +#define mmio_read(address) (*((volatile uint32_t *)(address))) +#define mmio_write(address, value) mmio_write_internal((volatile uint32_t *)(address), (volatile uint32_t)(value)) + +// Do the mmio write in assembly to remove any chance of gcc optimizing the call away. *yes* even if it was marked volatile already. +// Hence the 4 hours it took us to make timer.c work...... +static inline void mmio_write_internal(volatile uint32_t * address, volatile uint32_t value ) { + asm volatile ( + "ldr r1, %1\n" + "str r1, %0\n" + :: + "m" (*address), + "m" (value) + ); +} + +void prepare_pagetable(); void mmap(void *p_bootargs); - +void request_identity_mapped_section(size_t start_address, size_t megabytes); #define CLOCK_ADDRESS (volatile uint32_t *const) 0x101e8000 /* RTC base address */ diff --git a/kernel/src/memory/mmap.c b/kernel/src/memory/mmap.c index 3ae3cad8..4feb18e4 100644 --- a/kernel/src/memory/mmap.c +++ b/kernel/src/memory/mmap.c @@ -2,6 +2,7 @@ #include #include #include +#include /* * APX AP Privileged Unprivileged @@ -12,54 +13,59 @@ * See http://infocenter.arm.com/help/topic/com.arm.doc.ddi0333h/Caceaije.html * Bits 0 and 1 identify the table entry type - * 0 = translation fault + * 0 = translation fault * 1 = course page table * 2 = section or supersection */ int vm_build_free_frame_list(void *start, void *end); -volatile unsigned int * first_level_pt = (unsigned int*) P_L1PTBASE; +volatile unsigned int * first_level_pt = (unsigned int *) (P_L1PTBASE + PAGE_TABLE_SIZE); extern struct vm_free_list *vm_vas_free_list; extern struct vm_free_list *vm_l1pt_free_list; extern struct vm_free_list *vm_l2pt_free_list; -void mmap(void *p_bootargs) { - //char *cmdline_args = read_cmdline_tag(p_bootargs); - //print_uart0(cmdline_args); - //print_uart0("\n"); - asm volatile("cpsid if"); +bool mmapped = false; + +// Must be called before mmap and after vm.c +void request_identity_mapped_section(size_t start_address, size_t megabytes) { + + if (mmapped) { + // TODO: Technically possible if we were to flush the cache + kprintf("Can only request identity mapping before mmap is called."); + panic(); + } + kprintf("Identity mapping %i megabyte(s) at 0x%x\n", megabytes, start_address); + + for (unsigned int i = 0; i < megabytes; i++) { + kprintf("i: %i\n", i * 0x100000); + first_level_pt[(start_address + (i * 0x100000)) >> 20] = ((start_address + (i *0x100000)) & 0xFFF00000) | 0x0400 | 2; + } +} - //stash register state on the stack - asm volatile("push {r0-r11}"); +void prepare_pagetable() { + memset((uint32_t *)first_level_pt,0, PAGE_TABLE_SIZE); +} - kprintf("Boot arguments location: %X\n", p_bootargs); +void mmap(void *p_bootargs) { - /* - int pte; - unsigned int mb_addr = 0; - for(pte = 0; pte < 4096; pte++){ + disable_interrupt(BOTH); + //stash register state on the stack + asm volatile("push {r0-r11}"); - //one-to-one mapping - first_level_pt[pte] = mb_addr | 0x0400 | 2; - mb_addr += (1024*1024); + kprintf("Boot arguments location: %X\n", p_bootargs); - } - */ - //TODO:. Collin LOOOK HERE - first_level_pt = (unsigned int *) (P_L1PTBASE + PAGE_TABLE_SIZE); - //first_level_pt = 0x00200000 + 0x4000 = 0x00204000 kprintf("first_level_pt=%X\n", first_level_pt); - for (int i = 0; i < PAGE_TABLE_SIZE >> 2; i++) { - first_level_pt[i] = 0; - } +// for (int i = 0; i < PAGE_TABLE_SIZE >> 2; i++) { +// first_level_pt[i] = 0; +// } //temporarily map where it is until we copy it in VAS first_level_pt[P_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; - //first_level_pt[0x07f00000>>20] = first_level_pt[7F] = 0x07f00000 = 0x07f04010 + //first_level_pt[0x07f00000>>20] = first_level_pt[7F] = 0x07ffirst_level_pt=400000000 = 0x07f04010 // 0x00004000 - // 0x00000010 + // 0x00000010 //1MB for static kernel data structures (stacks and l1 pt) first_level_pt[V_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; @@ -71,25 +77,31 @@ void mmap(void *p_bootargs) { //also map it to high memory at 0xf0000000 (vpn = 3840) first_level_pt[V_KERNBASE >> 20] = 0 << 20 | 0x0400 | 2; - first_level_pt[(V_KERNBASE + 0x100000) >> 20] = 0x100000 | 0x0400 | 2; + first_level_pt[(V_KERNBASE + 0x100000) >> 20] = 0x100000 | 0x0400 | 2; // 0xf...; //map ~2MB of peripheral registers one-to-one - first_level_pt[PERIPHBASE >> 20] = PERIPHBASE | 0x0400 | 2; - first_level_pt[(PERIPHBASE + 0x100000) >> 20] = (PERIPHBASE + 0x100000) - | 0x0400 | 2; - - //map 752MB of PCI interface one-to-one - unsigned int pci_bus_addr = PCIBASE; - for (int i = (PCIBASE >> 20); i < (PCITOP >> 20); i++) { - first_level_pt[i] = pci_bus_addr | 0x0400 | 2; - pci_bus_addr += 0x100000; - } +// first_level_pt[PERIPHBASE >> 20] = PERIPHBASE | 0x0400 | 2; // PERIPHBASE + 1 MiB +// first_level_pt[(PERIPHBASE + 0x100000) >> 20] = (PERIPHBASE + 0x100000) | 0x0400 | 2; +// first_level_pt[(PERIPHBASE + 0x200000) >> 20] = (PERIPHBASE + 0x200000) | 0x0400 | 2; + first_level_pt[(0x20000000) >> 20] = (0x20000000) | 0x0400 | 2; + + first_level_pt[BCM2836BASE >> 20] = (BCM2836BASE & 0xFFF00000) | 0x0400 | 2; // TIMERBASE + 1 MiB + first_level_pt[(PERIPHBASE) >> 20] = (PERIPHBASE + 0x300000) | 0x0400 | 2; + + + // TODO: re enable when we actually need it. 700mb seems a bit excessive though. + //map 752MB of PCI interface one-to-one + // unsigned int pci_bus_addr = PCIBASE; + // for (int i = (PCIBASE >> 20); i < (PCITOP >> 20); i++) { + // first_level_pt[i] = pci_bus_addr | 0x0400 | 2; + // pci_bus_addr += 0x100000; + // } // Quick coarse page table address //unsigned int coarse_page_table_address = P_L1PTBASE + 2*PAGE_TABLE_SIZE; //os_printf("coarse pt: 0x%X\n", coarse_page_table_address); - //remap 62MB of physical memory after the kernel + //remap 62MB of physical memory after the kernel // (KERNTOP to end of physical RAM (PMAPTOP)) // This is where we allocate frames from. Except for the first one. unsigned int phys_addr = P_KERNTOP; @@ -110,28 +122,13 @@ void mmap(void *p_bootargs) { // We have to empty out the first MB of that, so we can use it as an array of VASs // The first slot is actually the kernel's VAS - ((struct vas*) P_L1PTBASE)->l1_pagetable = (unsigned int*) (V_L1PTBASE - + PAGE_TABLE_SIZE); //first_level_pt; + ((struct vas*) P_L1PTBASE)->l1_pagetable = (unsigned int*) (V_L1PTBASE + PAGE_TABLE_SIZE); //first_level_pt; ((struct vas*) P_L1PTBASE)->l1_pagetable_phys = first_level_pt; ((struct vas*) P_L1PTBASE)->next = 0x0; - vm_vas_free_list = (struct vm_free_list*) ((void*) vm_vas_free_list - + sizeof(struct vas)); - vm_l1pt_free_list = (struct vm_free_list*) ((void*) vm_l1pt_free_list - + PAGE_TABLE_SIZE); - - unsigned int pt_addr = (unsigned int) first_level_pt; + vm_vas_free_list = (struct vm_free_list*) ((void*) vm_vas_free_list + sizeof(struct vas)); + vm_l1pt_free_list = (struct vm_free_list*) ((void*) vm_l1pt_free_list + PAGE_TABLE_SIZE); - kprintf("0x%X\n", first_level_pt[(PMAPBASE + 0x100000) >> 20]); - - //TTBR0 -// asm volatile("mcr p15, 0, %[addr], c2, c0, 0" : : [addr] "r" (pt_addr)); -// // Translation table 1 -//// asm volatile("mcr p15, 0, %[addr], c2, c0, 1" : : [addr] "r" (pt_addr)); -//// asm volatile("mcr p15, 0, %[n], c2, c0, 2" : : [n] "r" (0)); -// -// //Set Domain Access Control to enforce out permissions -// //b01 = Client. Accesses are checked against the access permission bits in the TLB entry. -// asm volatile("mcr p15, 0, %[r], c3, c0, 0" : : [r] "r" (0x1)); + unsigned int pt_addr = (unsigned int) first_level_pt; /*CONTROL REGISTER * Enable MMU by setting 0 @@ -141,36 +138,40 @@ void mmap(void *p_bootargs) { * V bit 13 (1=high vectors 0xffff0000) * We disable high vectors, since low vectors work just fine. */ -// volatile unsigned int control; - - //Read contents into control -// asm volatile("mrc p15, 0, %[control], c1, c0, 0" : [control] "=r" (control)); -// //Set bit 0,1,2,12,13 -// // control |= 0x3007; //0b11000000000111 -// control |= 0x1007; //0b01000000000111 (No high vectors) -// control |= 1 << 23; // Enable ARMv6 -// // control |= 1<<29; // Enable ForceAPs -// kprintf("control reg: 0x%x\n", control); -// //Write back value into the register -// asm volatile("mcr p15, 0, %[control], c1, c0, 0" : : [control] "r" (control)); asm volatile ( - "mcr p15, 0, %[addr], c2, c0, 0\n" - - "mov r3, #0x1\n" - "mcr p15, 0, r3, c3, c0, 0\n" - - "mrc p15, 0, r3, c1, c0, 0\n" - "mov r4, #0x1000 \n" - "add r4, #0x7 \n" - "orr r3, r4 \n" - "orr r3, #0x800000 \n" - // "orr r0, r0, #0x01\n" - "mcr p15, 0, r3, c1, c0, 0 \n" + // invalidate caches + "mcr p15, 0, %[r], c7, c7, 0\n" + // invalidate tlb + "mcr p15, 0, %[r], c8, c7, 0\n" + // data sync barrier + "mcr p15, 0, %[r], c7,c10, 4\n" + + // set domains + "mov r2, #0x01\n" +// "ldr r2, =0x55555555\n" // [added] full r/w to everyone + "mcr p15, 0, r2, c3, c0, 0\n" + + "mcr p15, 0, %[addr], c2, c0, 0\n" // Give the pagetable addr to the MMU + "mcr p15, 0, %[addr], c2, c0, 1\n" + + "mrc p15, 0, r3, c1, c0, 0\n" // Read p15 +// "mov r4, #0x1000 \n" +// "add r4, #0x7 \n" +// "orr r3, r4 \n" + "orr r3, #0x800000\n" // Enable Armv6 bit +// "orr r3, #0x1000\n" + "orr r3, r3, #0x1\n" // Enable MMU bit + "mcr p15, 0, r3, c1, c0, 0 \n" // Set p15 : - : [addr] "r" (pt_addr) + : [addr] "r" (pt_addr), + [r] "r" (0x0) ); + mmapped = true; + +// SemihostingCall(OSSpecific); + // Build the free frame list vm_build_free_frame_list((void*) PMAPBASE + 0x100000, (void*) PMAPTOP); //(void*)PMAPBASE+(unsigned int)((PMAPTOP)-(PMAPBASE))); @@ -180,10 +181,16 @@ void mmap(void *p_bootargs) { // Except for r0, which is p_bootargs. stacks.s needs to know it. asm volatile("mov r0, %[args]" : : [args] "r" (p_bootargs)); - asm volatile("cpsie if"); + // asm volatile("cpsie if"); asm volatile (".include \"src/memory/stacks.s\""); - //branch to proper kernel at start - asm volatile("bl start2"); + void start2(uint32_t *p_bootargs); + kprintf("Location of start2: 0x%x\n", &start2); + //branch to proper kernel at start +// asm volatile("bl start2"); + + void * oldstart2 = start2; + void (*newstart2)(uint32_t *) = oldstart2 + V_KERNBASE; + newstart2(p_bootargs); } diff --git a/kernel/src/memory/vm/test/test_vm.c b/kernel/src/memory/vm/test/test_vm.c index bb4af60f..407dcc6b 100644 --- a/kernel/src/memory/vm/test/test_vm.c +++ b/kernel/src/memory/vm/test/test_vm.c @@ -92,9 +92,9 @@ TEST_CREATE(test_vm_1, { // FIXME: This part of the test crashes the os, we should catch that in some way. // Test the data abort... - //WARN("You should see a data abort...\n"); - //int i = p[-1]; - //LOG("%d\n", i); +// WARN("You should see a data abort...\n"); +// int i = p[-1]; +// LOG("%d\n", i); // Free the page! LOG("Freeing page at %X\n", p); diff --git a/kernel/src/memory/vm/vm.c b/kernel/src/memory/vm/vm.c index ea718571..bd64c2e4 100644 --- a/kernel/src/memory/vm/vm.c +++ b/kernel/src/memory/vm/vm.c @@ -38,110 +38,111 @@ struct vm_free_list *vm_l2pt_free_list = 0x0; void vm_init() { - // Initialize the VAS structures. We allocate enough for 4096 VASs. - struct vm_free_list *free_vas = (struct vm_free_list*) P_L1PTBASE; - //vm_vas_free_list = free_vas; - vm_vas_free_list = (struct vm_free_list*) ((void*) free_vas + V_L1PTBASE - - P_L1PTBASE); + const int num_vas = 1024; + + // Initialize the VAS structures. We allocate enough for num_vas VASs. + struct vm_free_list * free_vas = (struct vm_free_list*) P_L1PTBASE; + kprintf("free_vas start location 0x%x\n", free_vas); + +// vm_vas_free_list = free_vas; + vm_vas_free_list = (struct vm_free_list*) ((void*) free_vas + V_L1PTBASE - P_L1PTBASE); struct vm_free_list *last = 0x0; - while ((uint32_t) free_vas < P_L1PTBASE + sizeof(struct vas) * 4096) + while ((uint32_t) free_vas < P_L1PTBASE + sizeof(struct vas) * num_vas) { free_vas->next = 0x0; if (last) { - last->next = (struct vm_free_list*) ((void*) free_vas + V_L1PTBASE - - P_L1PTBASE); + last->next = (struct vm_free_list*) ((void*) free_vas + V_L1PTBASE - P_L1PTBASE); } last = free_vas; - free_vas = - (struct vm_free_list*) ((void*) free_vas + sizeof(struct vas)); + free_vas = (struct vm_free_list*) ((void*) free_vas + sizeof(struct vas)); } + // FIXME: doesn't this overlap with the l1pt? + kprintf("free_vas end location 0x%x\n", free_vas); // Initialize the L1 page tables - struct vm_free_list *free_l1pt = (struct vm_free_list*) (P_L1PTBASE - + sizeof(struct vas) * 4096); - vm_l1pt_free_list = (struct vm_free_list*) ((void*) free_l1pt + V_L1PTBASE - - P_L1PTBASE); - last = 0x0; + struct vm_free_list * free_l1pt = (struct vm_free_list*) (P_L1PTBASE + sizeof(struct vas) * num_vas); + + kprintf("free_l1pt start location 0x%x\n", free_l1pt); + + vm_l1pt_free_list = (struct vm_free_list*) ((void*) free_l1pt + V_L1PTBASE - P_L1PTBASE); + + + last = 0x0; while ((uint32_t) free_l1pt < P_L1PTBASE + (1 << 20) - ((1 << 20) >> 2)) { free_l1pt->next = 0x0; if (last) { - last->next = (struct vm_free_list*) ((void*) free_l1pt + V_L1PTBASE - - P_L1PTBASE); + last->next = (struct vm_free_list*) ((void*) free_l1pt + V_L1PTBASE - P_L1PTBASE); } last = free_l1pt; - free_l1pt = - (struct vm_free_list*) ((void*) free_l1pt + PAGE_TABLE_SIZE); + free_l1pt = (struct vm_free_list*) ((void*) free_l1pt + PAGE_TABLE_SIZE); } + kprintf("free_l1pt end location 0x%x\n", free_l1pt); // Initialize the L2 coarse page tables - struct vm_free_list *free_l2pt = (struct vm_free_list*) (P_L1PTBASE - + (1 << 19)); - vm_l2pt_free_list = (struct vm_free_list*) ((void*) free_l2pt + V_L1PTBASE - - P_L1PTBASE); + struct vm_free_list * free_l2pt = (struct vm_free_list*) (P_L1PTBASE + (1 << 19)); + + kprintf("free_l2pt location 0x%x\n", free_l2pt); + + + vm_l2pt_free_list = (struct vm_free_list*) ((void*) free_l2pt + V_L1PTBASE - P_L1PTBASE); last = 0x0; while ((uint32_t) free_l2pt < P_L1PTBASE + (1 << 20)) { free_l2pt->next = 0x0; if (last) { - last->next = (struct vm_free_list*) ((void*) free_l2pt + V_L1PTBASE - - P_L1PTBASE); + last->next = (struct vm_free_list*) ((void*) free_l2pt + V_L1PTBASE - P_L1PTBASE); } last = free_l2pt; - free_l2pt = (struct vm_free_list*) ((void*) free_l2pt - + L2_PAGE_TABLE_SIZE); + free_l2pt = (struct vm_free_list*) ((void*) free_l2pt + L2_PAGE_TABLE_SIZE); } + + kprintf("free_l2pt end location 0x%x\n", free_l2pt); + } uint32_t *vm_alloc_coarse_page_table() { // TODO: What if we run out? uint32_t *vptr = (uint32_t*) vm_l2pt_free_list; + kprintf("Allocating l2 pagetable at 0x%x\n", vptr); if (vptr == 0x0) { - LOG( - "Could not allocate a coarse page table, bad things will happen soon.\n"); + LOG("Could not allocate a coarse page table, bad things will happen soon.\n"); return NULL; } vm_l2pt_free_list = ((struct vm_free_list*) vptr)->next; memset((void*) vptr, 0, L2_PAGE_TABLE_SIZE); return vptr; + } -uint32_t *vm_vtop(struct vas *vas, uint32_t *vptr) -{ +uint32_t *vm_vtop(struct vas *vas, uint32_t *vptr) { // Hack. Assume it's all linearly mapped, and vas == KERNEL_VAS - if (vas != KERNEL_VAS) - { + if (vas != KERNEL_VAS) { kprintf("vas is not KERNEL_VAS in vm_vtop. :-(\n"); - while (1) - ; - } + panic(); + } return (uint32_t*) ((void*) vptr - V_L1PTBASE + P_L1PTBASE); } -uint32_t *vm_ptov(struct vas *vas, uint32_t *vptr) -{ +uint32_t *vm_ptov(struct vas *vas, uint32_t *vptr) { // Hack. Assume it's all linearly mapped, and vas == KERNEL_VAS - if (vas != KERNEL_VAS) - { + if (vas != KERNEL_VAS) { kprintf("vas is not KERNEL_VAS in vm_vtop. :-(\n"); - while (1) - ; + panic(); } return (uint32_t*) ((void*) vptr + V_L1PTBASE - P_L1PTBASE); } -struct vas *vm_get_current_vas() -{ +struct vas *vm_get_current_vas() { return vm_current_vas; } -void vm_use_kernel_vas() -{ +void vm_use_kernel_vas() { vm_enable_vas((struct vas*) V_L1PTBASE); } @@ -218,20 +219,17 @@ int vm_free_page(struct vas *vas, void *vptr) { return 0; } -int vm_pin(struct vas *vas, void *vptr) -{ +int vm_pin(struct vas *vas, void *vptr) { // FIXME: unimplemented return 0; } -int vm_unpin(struct vas *vas, void *vptr) -{ +int vm_unpin(struct vas *vas, void *vptr) { // FIXME: unimplemented return 0; } -int vm_set_mapping(struct vas *vas, void *vptr, void *pptr, int permission) -{ +int vm_set_mapping(struct vas *vas, void *vptr, void *pptr, int permission) { CHECK_VPTR; CHECK_PPTR; int perm = perm_mapping[permission]; @@ -239,12 +237,10 @@ int vm_set_mapping(struct vas *vas, void *vptr, void *pptr, int permission) return VM_ERR_BADPERM; uint32_t cur_entry = vas->l1_pagetable[(unsigned int) vptr >> 20]; - if ((cur_entry & 3) == 2) - { + if ((cur_entry & 3) == 2) { return VM_ERR_MAPPED; } - if ((cur_entry & 3) == 0) - { + if ((cur_entry & 3) == 0) { // We need to allocate a coarse page table uint32_t *vptr_coarse_pt = vm_alloc_coarse_page_table(); vas->l1_pagetable[(unsigned int) vptr >> 20] = (uint32_t) vm_vtop( @@ -255,8 +251,7 @@ int vm_set_mapping(struct vas *vas, void *vptr, void *pptr, int permission) uint32_t *l2_pagetable = vm_ptov(KERNEL_VAS, (uint32_t*) VM_ENTRY_GET_L2(cur_entry)); int l2_idx = ((unsigned int) vptr & 0x000FF000) >> 12; - if (l2_pagetable[l2_idx]) - { + if (l2_pagetable[l2_idx]) { return VM_ERR_MAPPED; } @@ -399,12 +394,10 @@ void vm_enable_vas(struct vas *vas) struct vas *vm_new_vas() { - if (!vm_vas_free_list) - { + if (!vm_vas_free_list) { return 0x0; } - if (!vm_l1pt_free_list) - { + if (!vm_l1pt_free_list) { return 0x0; } struct vas *p = (struct vas*) vm_vas_free_list; @@ -414,35 +407,34 @@ struct vas *vm_new_vas() p->l1_pagetable = (uint32_t*) vm_l1pt_free_list; vm_l1pt_free_list = vm_l1pt_free_list->next; - p->l1_pagetable_phys = (unsigned int*) ((unsigned int) p->l1_pagetable - - (V_L1PTBASE - P_L1PTBASE)); - - // Zero out the page table - memset((unsigned int *)p->l1_pagetable, 0, PAGE_TABLE_SIZE); - - // Setup the static mappings... - // The kernel (high & low addresses) - //should be less than a MB - p->l1_pagetable[P_KERNBASE >> 20] = 0 << 20 | 0x0400 | 2; - - //also map it to high memory at 0xf0000000 - p->l1_pagetable[V_KERNBASE >> 20] = 0 << 20 | 0x0400 | 2; - p->l1_pagetable[(V_KERNBASE + 0x100000) >> 20] = 0x100000 | 0x0400 | 2; - - // Kernel datastructures - //temporarily map where it is until we copy it in VAS - p->l1_pagetable[P_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; - - //1MB for static kernel data structures (stacks and l1 pt) - p->l1_pagetable[V_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; - - // Our 1MB page to store VAS datastructures - p->l1_pagetable[V_L1PTBASE >> 20] = P_L1PTBASE | 0x0400 | 2; + p->l1_pagetable_phys = (unsigned int*) ((unsigned int) p->l1_pagetable - (V_L1PTBASE - P_L1PTBASE)); + + // Zero out the page table +// memset((unsigned int *)p->l1_pagetable, 0, PAGE_TABLE_SIZE); +// +// // Setup the static mappings... +// // The kernel (high & low addresses) +// //should be less than a MB +// p->l1_pagetable[P_KERNBASE >> 20] = 0 << 20 | 0x0400 | 2; +// +// //also map it to high memory at 0xf0000000 +// p->l1_pagetable[V_KERNBASE >> 20] = 0 << 20 | 0x0400 | 2; +// p->l1_pagetable[(V_KERNBASE + 0x100000) >> 20] = 0x100000 | 0x0400 | 2; +// +// // Kernel datastructures +// //temporarily map where it is until we copy it in VAS +// p->l1_pagetable[P_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; +// +// //1MB for static kernel data structures (stacks and l1 pt) +// p->l1_pagetable[V_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; +// +// // Our 1MB page to store VAS datastructures +// p->l1_pagetable[V_L1PTBASE >> 20] = P_L1PTBASE | 0x0400 | 2; +// +// // 2MB of peripheral registers (so we get the serial port et. al.) +// p->l1_pagetable[PERIPHBASE >> 20] = PERIPHBASE | 0x0400 | 2; +// p->l1_pagetable[(PERIPHBASE + 0x100000) >> 20] = (PERIPHBASE + 0x100000) | 0x0400 | 2; - // 2MB of peripheral registers (so we get the serial port et. al.) - p->l1_pagetable[PERIPHBASE >> 20] = PERIPHBASE | 0x0400 | 2; - p->l1_pagetable[(PERIPHBASE + 0x100000) >> 20] = (PERIPHBASE + 0x100000) - | 0x0400 | 2; return p; } diff --git a/kernel/src/process/scheduler.c b/kernel/src/process/scheduler.c index c2776ecd..ed986e54 100644 --- a/kernel/src/process/scheduler.c +++ b/kernel/src/process/scheduler.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #define MAX_TASKS 100 // in the future, cap will be removed diff --git a/kernel/src/test/generate_tests.sh b/kernel/src/test/generate_tests.sh index 09707b84..333698bc 100755 --- a/kernel/src/test/generate_tests.sh +++ b/kernel/src/test/generate_tests.sh @@ -16,7 +16,7 @@ echo " #ifdef ENABLE_TESTS #include -#include +#include " >> "$DIR/test.c" From da8d5ee4263e8fe1926feea46a1f35df125a4e65 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Tue, 3 Mar 2020 11:36:45 +0100 Subject: [PATCH 033/104] made sure printf works even before uart is initialized --- kernel/src/common/include/interruptold.h | 113 ------- kernel/src/common/interrupt.c | 3 +- kernel/src/common/interruptold.c | 121 -------- kernel/src/common/start.c | 10 +- kernel/src/drivers/chipset/bcm2836/bcm2836.c | 1 - kernel/src/drivers/chipset/chipset.c | 9 +- kernel/src/drivers/chipset/include/chipset.h | 10 +- kernel/src/drivers/time/include/timer.h | 35 --- kernel/src/drivers/time/include/timer.h.old | 36 --- kernel/src/drivers/time/timer.c | 90 ------ kernel/src/drivers/time/timer.c.old | 303 ------------------- kernel/src/ds/array_list.c.old | 119 -------- kernel/src/ds/bin_tree.c.old | 287 ------------------ kernel/src/memory/mmap.c | 2 +- kernel/src/memory/stacks.s | 2 +- kernel/src/memory/vm/include/vm2.h | 272 +++++++++++++++++ kernel/src/memory/vm/test/test_vm.c | 210 ++++++------- kernel/src/memory/vm/test/test_vm2.c | 7 + kernel/src/memory/vm/vm2.c | 64 ++++ kernel/src/process/scheduler.c | 5 +- 20 files changed, 474 insertions(+), 1225 deletions(-) delete mode 100644 kernel/src/common/include/interruptold.h delete mode 100644 kernel/src/common/interruptold.c delete mode 100644 kernel/src/drivers/time/include/timer.h delete mode 100644 kernel/src/drivers/time/include/timer.h.old delete mode 100644 kernel/src/drivers/time/timer.c delete mode 100644 kernel/src/drivers/time/timer.c.old delete mode 100644 kernel/src/ds/array_list.c.old delete mode 100644 kernel/src/ds/bin_tree.c.old create mode 100644 kernel/src/memory/vm/include/vm2.h create mode 100644 kernel/src/memory/vm/test/test_vm2.c create mode 100644 kernel/src/memory/vm/vm2.c diff --git a/kernel/src/common/include/interruptold.h b/kernel/src/common/include/interruptold.h deleted file mode 100644 index ced19d37..00000000 --- a/kernel/src/common/include/interruptold.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef __INTERRUPT_H__ -#define __INTERRUPT_H__ -/* - * - * Interrupt handler for course_os - * - * - * - ARM has two interrupt lines to the core: FIQ (fast interrupt), IRQ (normal interrupt) - * - Our VIC multiplexes intterupts and feeds them to the processor as either FIQ or IRQ - * Basic interrupt control flow (no vectored interrupts, no nested interrupts) is as follows: - * Interrupt Occurs -> Core branches to FIQ or IRQ vector -> vector branches to hanlder \ - * handler interfaces with VIC to determine source of interrupt -> branch to service routine \ - * - */ - -#include -#include - -volatile uint32_t * const PIC_ADDRESS; - -// general syscall function -extern int syscall(int number); - -// the VIC has 32 bits to indicate a type of interrupt -// currently we just pull a bit off the VIC and jump to that number handler -// in the handler array -// this may need to be expanded if we use the secondary controller -#define MAX_NUM_INTERRUPTS 32 - - - - -// this will tell if an interrupt mapping is an FIQ -// HIGH bits are FIQs -// extern char check_if_fiq[MAX_NUM_INTERRUPTS]; - -typedef struct interrupt_handler_t { - void (*handler)(void *args); - // more may need to be added -} interrupt_handler_t; - -// https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf -// Page ~ 117 -struct IRQ_registers { - uint32_t irq_basic_pending; - uint32_t irq_gpu1_pending; - uint32_t irq_gpu2_pending; - uint32_t fiq_control; - uint32_t irq_gpu1_enable; // Interrupt enable register 1 (GPU) - uint32_t irq_gpu2_enable; // Interrupt enable register 2 (GPU) - uint32_t irq_basic_enable; // Base enable register (ARM/CPU) - uint32_t irq_gpu1_disable; - uint32_t irq_gpu2_disable; - uint32_t irq_basic_disable; -}; - -// these should be used in conjunction with the bit shift mappings below -#define hw_interrupt_enable(n) mmio_write(VIC_INT_ENABLE, mmio_read(VIC_INT_ENABLE) | (1 << n)) -#define hw_interrupt_disable(n) mmio_write(VIC_INT_ENCLEAR, (1 << n)); -#define vic_select_fiq(n) mmio_write(VIC_INT_SELECT, (1 << n)); - -enum InterruptID { - WATCHDOG_IRQ = 0, /* watchdog controller */ - SWI_IRQ = 1, /* software interrupt */ - COMMS_RX_IRQ = 2, /* debug comms receive intercept */ - COMMS_TX_IRQ = 3, /* debug comms transmit intercept */ - TIMER_A_IRQ = 4, /* timer 0 or 1 */ - TIMER_B_IRQ = 5, /* timer 2 or 3 */ - GPIO_A_IRQ = 6, /* GPIO 0 */ - GPIO_B_IRQ = 7, /* GPIO 1 */ - GPIO_C_IRQ = 8, /* GPIO 2 */ - GPIO_D_IRQ = 9, /* GPIO 3 */ - RTC_IRQ = 10, /* Real Time Clock (RTC) */ - SSP_IRQ = 11, /* synchronous serial port */ - UART0_IRQ = 12, /* UART 0 */ - UART1_IRQ = 13, /* UART 1 */ - UART2_IRQ = 14, /* UART 2 */ - SCIO_IRQ = 15, /* smart card interface */ - CLCD_IRQ = 16, /* CLCD controller */ - DMA_IRQ = 17, /* DMA controller */ - PWRFAIL_IRQ = 18, /* power failure from FPGA */ - MBX_IRQ = 19, /* graphics processor */ - // IRQ 20 is reserved by the architecture - VICINTSOURCE_21 = 21, /* external interrupt signal from DiskOnChip flash device */ - VICINTSOURCE_22 = 22, /* external interrupt signal from MCIO A */ - // IRQ 23 is reserved by the architecture - VICINTSOURCE_24 = 24, /* external interrupt signal from AACI */ - VICINTSOURCE_25 = 25, /* Ethernet */ - VICINTSOURCE_26 = 26, /* USB */ - VICINTSOURCE_27 = 27, /* external interrupt signal from expansion connector */ - VICINTSOURCE_28 = 28, /* external interrupt signal from expansion connector */ - // IRQ 29 is reserved by the architecture - // IRQ 30 is reserved by the architecture - VICINTSOURCE_31 = 31, /* secondary interrupt controller (SIC) */ -}; - -// Primary Interrupt Controller (PIC) - -volatile struct IRQ_registers * interrupt_registers; - -/* functions (e.g. passing a bad parameter), so we'll - refer to the macros above for adjusting specific interrupt status */ -void init_chipsetold(); - - -int get_proc_status(void); -void restore_proc_status(int); - -int register_interrupt_handler(enum InterruptID, interrupt_handler_t *); -void handle_irq_interrupt(enum InterruptID); - - -#endif //__INTERRUPT_H__ diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index 4c48560d..5f8bc03d 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -230,8 +230,7 @@ void __attribute__((interrupt("ABORT"))) data_abort_handler(void) kprintf("DATA ABORT HANDLER (Page Fault)\n"); kprintf("faulting address: 0x%x\n", far); - if (far >= V_KDSBASE) - { + if (far >= V_KDSBASE) { kprintf("(address is in kernel address range)\n"); } kprintf("violating instruction (at 0x%x): %x\n", pc, *((int *) pc)); diff --git a/kernel/src/common/interruptold.c b/kernel/src/common/interruptold.c deleted file mode 100644 index 1373cd29..00000000 --- a/kernel/src/common/interruptold.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * - * Interrupts - * - */ -#include -#include -#include -#include - -// TODO: make consistent (old val: 0x10140000) -volatile uint32_t * const PIC_ADDRESS = (volatile uint32_t *)(0x2000b200); - -// there are 32 kinds of interrupts on the VIC -// this structure may need to be expanded if the secondary controller is incorporated -static interrupt_handler_t *handlers[MAX_NUM_INTERRUPTS]; - -static int initialized; - -// holds defined fiq interrupts -static int check_if_fiq[MAX_NUM_INTERRUPTS]; - - -// In a system with an interrupt controller, software is required to: -// determine from the interrupt controller which interrupt source is requesting service -// determine where the service routine for that interrupt source is loaded -// mask or clear that interrupt source, before re-enabling processor interrupts to permit another interrupt to be taken. - -// Interrupts must be enabled in three places: -// (1) the core (CPSR) -// (2) the VIC (interrupt controller) -// (3) (sometimes) in the device (this should be done in the device driver) - -// CLear Interrupts -// Do not disable the VIC and the CSPR is disable in the hw_hanlders -// you have to clear the interrupt from the register handler -// Look At timer.c it has a great example of it. -// Here's the Website to the VIC we are using http://infocenter.arm.com/help/topic/com.arm.doc.ddi0181e/DDI0181.pdf - -//They are three handlers you must use First is the (IRQ)interrupt handler its in hw_handlers.c (with attribute Irq) -// second is the ISR routine handler which is the one in interrupt.c -// third is the specific handler you created a great example is in the timer.c it is called timer_interrupt_handler. -// If youre having an error it must be in the third handler not the first two. - -// Setup FIQ interrupts -void init_fiqs() -{ - check_if_fiq[11] = 1; // synchronous serial port - check_if_fiq[17] = 1; // DMA controller -} - -void init_chipsetold() { - init_fiqs(); - interrupt_registers = (volatile struct IRQ_registers *)PIC_ADDRESS; - - enable_interrupt(BOTH); - - interrupt_registers->irq_basic_enable = 0; - interrupt_registers->irq_gpu1_enable = 0; - interrupt_registers->irq_gpu2_enable = 0; -} - -// when you register an interrupt handler it's line will be enabled in the VIC -// telling the device itself to fire interrupts should be done in the driver -// -// TODO: We do now ------------------------------V -// also, since we don't really have a working malloc, the handler structure will -// have to be built in the driver and passed to register_ -int register_interrupt_handler(enum InterruptID num, interrupt_handler_t *handler) { - // lazy initialization - if (initialized != -1) { - kprintf("INITIALIZING THE INTERRUPT SYSTEM\n"); - - for (int i = 0; i < MAX_NUM_INTERRUPTS; i++) { - handlers[i] = 0; - } - - kprintf("INITIALIZED THE INTERRUPT SYSTEM\n"); - - initialized = -1; - } - - if (num < 0 || num > MAX_NUM_INTERRUPTS) { - kprintf("Register a handler between 0 and %i\n", MAX_NUM_INTERRUPTS); - panic(); - } else if (handlers[num] != NULL) { - kprintf("Tried to re-register interrupt handler %i\n", num); - panic(); - } else if (handler == NULL) { - kprintf("The interrupt handler can't be NULL\n"); - panic(); - } - - // put the handler in the array - handlers[num] = handler; - - kprintf("Enabling interrupt 0x%x\n", num); - // enable the specific interrupt in hardware on the VIC - interrupt_registers->irq_basic_enable |= (1 << num); - - // check to see if this is an FIQ -// if (check_if_fiq[num]){ -// // update the "select" register on the VIC -// vic_select_fiq(num); -// } - - // return a success value - return 0; -} - -// handle_interrupt takes a number (the interrupt from the VIC), looks into -// the table of registered handlers, and calls the appropriate handler -void handle_irq_interrupt(enum InterruptID interrupt_vector) { - kprintf("handling interrupt %d\n", interrupt_vector); - // go to handler routine - kprintf("Jumping to %X...\n", handlers[interrupt_vector]->handler); - handlers[interrupt_vector]->handler((void *) interrupt_vector); -} - - - diff --git a/kernel/src/common/start.c b/kernel/src/common/start.c index 283e781f..b6e16c86 100644 --- a/kernel/src/common/start.c +++ b/kernel/src/common/start.c @@ -18,8 +18,6 @@ #include #include -#include -#include #include #include #include @@ -28,14 +26,14 @@ #include #include #include -#include -#include +#include +#include // This start is what u-boot calls. It's just a wrapper around setting up the // virtual memory for the kernel. void start(uint32_t *p_bootargs) { prepare_pagetable(); - + vm2_prepare(); // Before this point, all code has to be hardware independent. // After this point, code can request the hardware info struct to find out what @@ -51,6 +49,8 @@ void start(uint32_t *p_bootargs) { vm_init(); kprintf("Initialized VM datastructures.\n"); + vm2_start(); + // Paging and virtual memory is initialized. This code jumps us to start2. mmap(p_bootargs); } diff --git a/kernel/src/drivers/chipset/bcm2836/bcm2836.c b/kernel/src/drivers/chipset/bcm2836/bcm2836.c index c92a8273..e8c9b4ae 100644 --- a/kernel/src/drivers/chipset/bcm2836/bcm2836.c +++ b/kernel/src/drivers/chipset/bcm2836/bcm2836.c @@ -28,7 +28,6 @@ void bcm2836_on_interrupt(InterruptCallback callback) { void bcm2836_late_init() { bcm2836_timer_init(); - } void bcm2836_irq_handler() { diff --git a/kernel/src/drivers/chipset/chipset.c b/kernel/src/drivers/chipset/chipset.c index 61691948..0125852d 100644 --- a/kernel/src/drivers/chipset/chipset.c +++ b/kernel/src/drivers/chipset/chipset.c @@ -5,7 +5,13 @@ #include #include -ChipsetInterface chipset; +// We use putc (and printf) before the chipset is initialized already. +// This stub makes sure that nothing crashes if you do that. +void uart_putc_stub(char c __attribute__((unused)), int channel __attribute__((unused))) { } + +ChipsetInterface chipset = { + .uart_putc = uart_putc_stub // Stub putc +}; void init_chipset() { HardwareInfo * info = get_hardwareinfo(); @@ -28,5 +34,4 @@ void init_chipset() { panic(); } } - } diff --git a/kernel/src/drivers/chipset/include/chipset.h b/kernel/src/drivers/chipset/include/chipset.h index 9febce36..35542cd0 100644 --- a/kernel/src/drivers/chipset/include/chipset.h +++ b/kernel/src/drivers/chipset/include/chipset.h @@ -2,8 +2,10 @@ #define INTERRUPT_H #include +#include void init_chipset(); +void uart_putc(char c, int channel); // A timer handle is an identifier for a timer so it can be descheduled later. // These handles must be unique. @@ -12,9 +14,15 @@ typedef void (*TimerCallback)(); typedef void (*UartCallback)(char c); typedef void (*InterruptCallback)(); +enum ChipsetState { + UNINITIALIZED = 0, + INITIALIZED = 1, + LATE_INITIALIZED = 2, +}; + typedef struct ChipsetInterface { /// Timer Functions - //TODO: time/duration struct of some sort. + //TODO: time/duration struct of some sort (Go-like). TimerHandle (*schedule_timer_periodic)(TimerCallback callback, uint32_t ms); TimerHandle (*schedule_timer_once)(TimerCallback callback, uint32_t ms); diff --git a/kernel/src/drivers/time/include/timer.h b/kernel/src/drivers/time/include/timer.h deleted file mode 100644 index c8220523..00000000 --- a/kernel/src/drivers/time/include/timer.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef TIMER_H -#define TIMER_H - -#include - -typedef struct { - uint32_t timer_load_value; // read/write - uint32_t timer_actual_value; // read only - uint32_t control; // read/write - uint32_t interrupt_clear; // write only - uint32_t interrupt_status; // read only - uint32_t masked_interrupt_status; // read only - uint32_t background_timer_load_value; // read/write -} rasp_pi_timer; - - -void initialize_timers(); -int set_load_value(int timer_index, int value); -int set_background_load_value(int timer_index, int value); -int clear_interupt(int timer_index); -int set_32_bit_mode(int timer_index); -int get_current_timer_value(int timer_index); -int set_periodic_mode(int timer_index); -int set_free_running_mode(int timer_index); -int start_timer(int timer_index); -int set_prescale(int timer_index, int mode); -int start_timer_interrupts( int timer_index, int star_val); -int conversion(int timer_index, int milliseconds); -int enable_timer_interrupt(int timer_index); -int disable_timer(int timer_index); -int register_handler(int timer_index, void (*handler)(void *args)); -int unregister_handler(int timer_index); - - -#endif diff --git a/kernel/src/drivers/time/include/timer.h.old b/kernel/src/drivers/time/include/timer.h.old deleted file mode 100644 index 2778faaf..00000000 --- a/kernel/src/drivers/time/include/timer.h.old +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef TIMER_H -#define TIMER_H - -#include "../../../src/klibc//include/stdint.h" - -typedef struct { - uint32_t timer_load_value; // read/write - uint32_t timer_actual_value; // read only - uint32_t control; // read/write - uint32_t interrupt_clear; // write only - uint32_t interrupt_status; // read only - uint32_t masked_interrupt_status; // read only - uint32_t background_timer_load_value; // read/write -} rasp_pi_timer; - -_Static_assert (sizeof (rasp_pi_timer) == 28, "rasp_pi_timer check"); - -void initialize_timers(); -int set_load_value(int timer_index, int value); -int set_background_load_value(int timer_index, int value); -int clear_interupt(int timer_index); -int set_32_bit_mode(int timer_index); -int get_current_timer_value(int timer_index); -int set_periodic_mode(int timer_index); -int set_free_running_mode(int timer_index); -int start_timer(int timer_index); -int set_prescale(int timer_index, int mode); -int start_timer_interrupts( int timer_index, int star_val); -int conversion(int timer_index, int milliseconds); -int enable_timer_interrupt(int timer_index); -int disable_timer(int timer_index); -int register_handler(int timer_index, void (*handler)(void *args)); -int unregister_handler(int timer_index); - - -#endif diff --git a/kernel/src/drivers/time/timer.c b/kernel/src/drivers/time/timer.c deleted file mode 100644 index 9cdb46d9..00000000 --- a/kernel/src/drivers/time/timer.c +++ /dev/null @@ -1,90 +0,0 @@ - -#include -#include -#include -#include - -inline static uint32_t get_frequency() { - uint32_t val; - asm volatile ("mrc p15, 0, %0, c14, c0, 0" : "=r"(val) ); - return val; -} - -void write_cntv_tval(uint32_t val) { - asm volatile ("mcr p15, 0, %0, c14, c3, 0" :: "r"(val) ); - return; -} - -uint32_t read_cntv_tval() { - uint32_t val; - asm volatile ("mrc p15, 0, %0, c14, c3, 0" : "=r"(val) ); - return val; -} - -// https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf -#define CORE0_TIMER_IRQCNTL BCM2836BASE -#define CORE1_TIMER_IRQCNTL BCM2836BASE + 0x04 -#define CORE2_TIMER_IRQCNTL BCM2836BASE + 0x08 -#define CORE3_TIMER_IRQCNTL BCM2836BASE + 0x0c - -#define CORE0_IRQ_SOURCE BCM2836BASE + 0x20 -#define CORE1_IRQ_SOURCE BCM2836BASE + 0x24 -#define CORE2_IRQ_SOURCE BCM2836BASE + 0x28 -#define CORE3_IRQ_SOURCE BCM2836BASE + 0x2c - -#define CORE0_FIQ_SOURCE BCM2836BASE + 0x30 -#define CORE1_FIQ_SOURCE BCM2836BASE + 0x34 -#define CORE2_FIQ_SOURCE BCM2836BASE + 0x38 -#define CORE3_FIQ_SOURCE BCM2836BASE + 0x3c - - -void timer_handler_func(void * args) { - -} - -//struct interrupt_handler_t timer_irq_handler = { -// .handler = timer_handler_func -//}; - - - -void initialize_timers() { -// return; - - uint32_t freq = get_frequency(); - - kprintf("control frequency: %i\n", freq); - // 1 second timer - write_cntv_tval(freq); - - kprintf("value: %i\n", read_cntv_tval()); - - mmio_write(CORE0_TIMER_IRQCNTL, 0x08); - - uint32_t cntv_ctl = 1; - asm volatile ("mcr p15, 0, %0, c14, c3, 1" :: "r"(cntv_ctl) ); // write CNTV_CTL - -// register_handler(, timer_handler) -// register_interrupt_handler(4, &timer_irq_handler); -// register_interrupt_handler(3, &timer_irq_handler); - - -} - - - - - -int start_timer_interrupts( int timer_index, int star_val) { - return 0; -} - -int register_handler(int timer_index, void (*handler)(void *args)) { - return 0; -} - -int unregister_handler(int timer_index) { - return 0; -} - - diff --git a/kernel/src/drivers/time/timer.c.old b/kernel/src/drivers/time/timer.c.old deleted file mode 100644 index 90119b69..00000000 --- a/kernel/src/drivers/time/timer.c.old +++ /dev/null @@ -1,303 +0,0 @@ -/* Device Driver for ARM Dual-Timer Module (SP804) - Reference Manual can be found here : http://infocenter.arm.com/help/topic/com.arm.doc.ddi0271d/DDI0271.pdf*/ -#include -#include -#include -#include -#include -#include - -rasp_pi_timer *timer_pointers[4]; - -void timer_irq_handler(void* args); -void (*handlers[4])(void *args); - -/* initializes timers as an array. Call this before - * using any of the timer functions */ -void initialize_timers() -{ -// TODO: make consistent - kprintf("initializing timers\n"); -// volatile rasp_pi_timer *TIMER_0 = (rasp_pi_timer *) 0x101e2000; -// volatile rasp_pi_timer *TIMER_1 = (rasp_pi_timer *) 0x101e2020; -// volatile rasp_pi_timer *TIMER_2 = (rasp_pi_timer *) 0x101e3000; -// volatile rasp_pi_timer *TIMER_3 = (rasp_pi_timer *) 0x101e3020; - volatile rasp_pi_timer *TIMER_0 = (rasp_pi_timer *) PERIPHBASE + 0x300c; - volatile rasp_pi_timer *TIMER_1 = (rasp_pi_timer *) PERIPHBASE + 0x3010; - volatile rasp_pi_timer *TIMER_2 = (rasp_pi_timer *) PERIPHBASE + 0x3014; - volatile rasp_pi_timer *TIMER_3 = (rasp_pi_timer *) PERIPHBASE + 0x3018; -// 0x3f201000 - - timer_pointers[0] = (rasp_pi_timer*) TIMER_0; - timer_pointers[1] = (rasp_pi_timer*) TIMER_1; - timer_pointers[2] = (rasp_pi_timer*) TIMER_2; - timer_pointers[3] = (rasp_pi_timer*) TIMER_3; - - handlers[0] = NULL; - handlers[1] = NULL; - handlers[2] = NULL; - handlers[3] = NULL; - - interrupt_handler_t *tmr_handler = kmalloc(sizeof(interrupt_handler_t)); - tmr_handler->handler = timer_irq_handler; - register_interrupt_handler(TIMER_A_IRQ, tmr_handler); -} - -#define CHECK_TIMER_INDEX(index) { if (index < 0 || index > 4) return -1; } - -/* This function sets the value that the timer will begin at. - * This operation also resets the timer to this new value. - * if you want to keep the timer running with its current state - * use set background load. */ -int set_load_value(int timer_index, int value) -{ - CHECK_TIMER_INDEX(timer_index); - - timer_pointers[timer_index]->timer_load_value = value; - return 0; -} - -//returns the current control register value (configuration of timer) -int get_timer_control_value(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - - return timer_pointers[timer_index]->control; -} - -/* Sets the value for the timer to load the next time it reaches - * 0 and loads the reset value. Does not affect current timer. */ -int set_background_load_value(int timer_index, int value) -{ - CHECK_TIMER_INDEX(timer_index); - - timer_pointers[timer_index]->background_timer_load_value = value; - return 0; -} - -/* Clear any interrupt data for the timer. - * note: writing to the clear timer register clears - * the interrupt status completely. */ -int clear_interrupt(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - - timer_pointers[timer_index]->interrupt_clear = 0x1; - - return 0; -} - -//enable 32 bit mode in the specified timer index -int set_32_bit_mode(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - - disable_timer(timer_index); - timer_pointers[timer_index]->control |= 0x2; - return 0; -} - -int get_current_timer_value(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - - return timer_pointers[timer_index]->timer_actual_value; -} - -//enable periodic mode of specified timer index -int set_periodic_mode(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - - disable_timer(timer_index); - timer_pointers[timer_index]->control &= 0xFFFFFFBE; - - return 0; -} - -//converts ms into ticks -//assumes modes are valid, if not, should return 0 -int conversion(int timer_index, int milliseconds) -{ - int mode = (timer_pointers[timer_index]->control & 0xC) >> 2; - - int ticks = 0; - if (mode == 0) - { - ticks = 32; - } - else if (mode == 1) - { - ticks = 256; - } - else if (mode == 2) - { - ticks = 1000; - } - return milliseconds * ticks; -} - -//function to set timer to different timer clock rates... 0 -> 1 (default), 1 -> 16, 2 -> 256... -//any other modes are invalid and will do nothing -int set_prescale(int timer_index, int mode) -{ - CHECK_TIMER_INDEX(timer_index); - - disable_timer(timer_index); - if (mode == 0) - timer_pointers[timer_index]->control &= 0xFFFFFFF3; - else if (mode == 1) - { - timer_pointers[timer_index]->control |= 0x4; - timer_pointers[timer_index]->control &= 0xFFFFFFF7; - } - else if (mode == 2) - { - timer_pointers[timer_index]->control |= 0x8; - timer_pointers[timer_index]->control &= 0xFFFFFFFB; - } - return 0; -} - -//enables timer interrupt of the given timer index -int enable_timer_interrupt(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - - timer_pointers[timer_index]->control |= (1 << 5); - return 0; -} - -//disables timer interrupt of the given timer index -int disable_timer_interrupt(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - - timer_pointers[timer_index]->control &= 0xFFFFFFDF; - return 0; -} - -int set_free_running_mode(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - - disable_timer(timer_index); - timer_pointers[timer_index]->control |= 0x1; - return 0; -} - -//starts the timer, countdown from load value -int enable_timer(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - - timer_pointers[timer_index]->control |= (1 << 7); - return 0; -} - -//pauses the timer -int disable_timer(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - - timer_pointers[timer_index]->control &= 0xFFFFFF7F; - return 0; -} - -//prints the configuration of the control byte -int print_control_status(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - - kprintf("control byte:%x", timer_pointers[timer_index]->control); - return 0; -} - -/*starts interrupts every start_val ticks */ -//You give it a vallut and the specific timer you want to star. -// YOu have four timers just start with timer zero -// The speed of counter or number ticks depends on qemu hertz speed -// we don't know he start of it but it should be around 10 milliseconds -// per proccess. -// ex: start_timer_interrupts(0,10) which means start timer(0) -// and interrupt every 10 clicks. -int start_timer_interrupts(int timer_index, int milliseconds) -{ -// conversion(timer_index, milliseconds); - CHECK_TIMER_INDEX(timer_index); - - int clicks = conversion(timer_index, milliseconds); - - kprintf("CLICKS ARE %d\n", clicks); - - set_background_load_value(timer_index, clicks); - set_periodic_mode(timer_index); - enable_timer_interrupt(timer_index); - enable_timer(timer_index); - return 0; -} - -int register_handler(int timer_index, void (*handler)(void *args)) -{ - CHECK_TIMER_INDEX(timer_index); - handlers[timer_index] = handler; - return 0; -} - -int unregister_handler(int timer_index) -{ - CHECK_TIMER_INDEX(timer_index); - handlers[timer_index] = NULL; - return 0; -} - -void timer_irq_handler(void* args) { - clear_interrupt(0); - - kprintf("@@@@@@ RECEIVED TIMER INTERRUPT\n"); - - // TODO: find out which timer fired. For the moment, hard-code to 0 - if (handlers[0] != NULL) - { - handlers[0](args); - } -} - -void timer_test() -{ - -// enable_interrupt(ALL_INTERRUPT_MASK); - - /*interrupt_handler_t *tmr_handler = kmalloc(sizeof(interrupt_handler_t)); - tmr_handler->handler = simple_timer_handler; - os_printf("fn ptr: %X\n", simple_timer_handler); - register_interrupt_handler(4, tmr_handler);*/ - - kprintf("FIQ status: %X\n", mmio_read(VIC_FIQ_STATUS)); - initialize_timers(); - start_timer_interrupts(0, 10); - //print_control_status(1); - - // Wait forever... - /* os_printf("\n"); - int cnt = 0; - os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); - os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); - os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); - while (!(timer_pointers[0]->masked_interrupt_status&1)) { - cnt++; - //os_printf("%X\n", timer_pointers[1]->timer_actual_value); - int i; - for (i=0; i<1000; i++); - } - os_printf("%d\n", cnt); - os_printf("%X\n", mmio_read(PIC_ADDRESS+0x8)); - os_printf("%X\n", mmio_read(VIC_IRQ_STATUS)); - os_printf("%X\n", mmio_read(VIC_FIQ_STATUS)); - os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); - os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); - os_printf("Timer: %d\n", timer_pointers[0]->timer_actual_value); - while(1); - */ - return; -} diff --git a/kernel/src/ds/array_list.c.old b/kernel/src/ds/array_list.c.old deleted file mode 100644 index b60105e8..00000000 --- a/kernel/src/ds/array_list.c.old +++ /dev/null @@ -1,119 +0,0 @@ -/* - * array_list.c - * - * Created on: Apr 21, 2015 - * Author: kittenRainbow - */ - -#include -#include -#include - -arrl_handle* arrl_create() { - return arrl_create_fixed(DEFAULT_BUCKET_SIZE); -} - -arrl_handle* arrl_create_fixed(uint32_t bucket_size) { - arrl_handle* result = (arrl_handle *) kmalloc(sizeof(arrl_handle)); - void** bucket = kmalloc(bucket_size * sizeof(void*)); - llist_handle * l = llist_create(bucket); - result->linked_list = l; - result->size = 0; - result->capacity = bucket_size; - return result; -} - -void arrl_append(arrl_handle* arrl, void* elem) { - llist_node * curr_bucket; - uint32_t list_size; - uint32_t last_bucket_size; - - if (arrl->capacity == arrl->size) { - void* data = kmalloc(arrl->bucket_size * sizeof(void*)); - llist_enqueue(arrl->linked_list, data); - arrl->capacity += arrl->bucket_size; - } - - curr_bucket = arrl->linked_list->head; - list_size = arrl->size / arrl->bucket_size; - last_bucket_size = arrl->size % arrl->bucket_size; - - for(uint32_t i=0; i < list_size; ++i) { - curr_bucket= curr_bucket->next; - } - *(((int**)curr_bucket->data) + last_bucket_size) = (int*)elem; -} - -void arrl_remove(arrl_handle* arrl, void* elem) { - uint32_t bucket_size; - uint32_t list_size; - uint32_t bucket_index; - uint32_t list_index; - llist_node* curr_bucket; - llist_node* tail; - - bucket_size = arrl->bucket_size; - list_size = arrl->linked_list->count; - curr_bucket = arrl->linked_list->head; - tail = arrl->linked_list->tail; - - for (list_index = 0; list_index < list_size; ++list_index) { - for (bucket_index = 0; bucket_index < bucket_size; ++bucket_index) { - //if (elem == curr_bucket->data[bucket_index]) { - kfree(elem); - goto out; - //} - } - curr_bucket = curr_bucket->next; - } - - // Except the last bucket, shift each bucket up by one and copy first element of the next bucket to the last cell of the current bucket - out: while (curr_bucket != tail) { - os_memcpy(*(((uint32_t**)curr_bucket->data) + bucket_index + 1), - *(((uint32_t**)curr_bucket->data) + bucket_index + 0), - bucket_size - bucket_index - 1); - bucket_index = 0; - *(((int**)curr_bucket->data) + bucket_size - 1) = *((int**)curr_bucket->next->data); - curr_bucket = curr_bucket->next; - } - - --arrl->size; -} - -uint32_t arrl_contains(arrl_handle* arrl, void* elem) { - uint32_t bucket_size = arrl->bucket_size; - uint32_t list_size = arrl->linked_list->count; - llist_node* bucket = arrl->linked_list->head; - - for (uint32_t list_index = 0; list_index < list_size; ++list_index) { - for (uint32_t bucket_index = 0; bucket_index < bucket_size; - ++bucket_index) { - //if (elem == bucket->data[bucket_index]) { - return 1; - //} - } - bucket = bucket->next; - } - return 0; -} - -uint32_t arrl_index_of(arrl_handle* arrl, void* elem) { - int bucket_size = arrl->bucket_size; - int list_size = arrl->linked_list->count; - llist_node* bucket = arrl->linked_list->head; - - for (int list_index = 0; list_index < list_size; ++list_index) { - for (int bucket_index = 0; bucket_index < bucket_size; ++bucket_index) { -// if (elem == bucket->data[bucket_index]) { - return list_index * DEFAULT_BUCKET_SIZE + bucket_index; -// } - } - bucket = bucket->next; - } - return -1; -} - -uint32_t arrl_count(arrl_handle* arrl) { - return arrl->size; -} - diff --git a/kernel/src/ds/bin_tree.c.old b/kernel/src/ds/bin_tree.c.old deleted file mode 100644 index 3baa5095..00000000 --- a/kernel/src/ds/bin_tree.c.old +++ /dev/null @@ -1,287 +0,0 @@ -/******************************************************************** - * bin_tree.c - * - * Authors: Brandon Olivier, Collin Massey // any collaborators, please add name - * - * Created: 19 April 2014 - * - * Last edit: 27 November 2015 - * - * Purpose: Implement unbalanced binary trees for addresses - * - ********************************************************************/ -//#include "klibc.h" -//#include "ds/bin_tree.h" -#include -#include - - -typedef struct node { - struct node *parent; - struct node *left; - struct node *right; - void *data; -} node; - -typedef struct tree { - struct node *root; - int size; -} tree; - - -struct tree *new_tree(node *root) -{ - struct tree *t = (tree *)kmalloc(sizeof(struct tree)); // TODO: Needs to be fixed - t->root = root; - t->size = 0; - return t; -} - -struct tree *init_tree() -{ - return new_tree(NULL); -} - -// Compare 2 values -int comparison(void *a, void *b) -{ - int x = *(int *)a; - int y = *(int *)b; - if (x < y) - return -1; - if (x > y) - return 1; - return 0; // x = y (a = b) -} - -// Insert a node into the tree if not already present -// Returns 1 if inserted, 0 otherwise -int insert(tree *t, void *val) -{ - if (contains_node(t, val)) { - return 0; - } - - struct node *new_node = (node *)kmalloc(sizeof(struct node)); // TODO: Needs to be fixed - new_node->left = new_node->right = NULL; - new_node->parent = NULL; - new_node->data = val; - - if (t->root == NULL) { // Empty tree - t->root = new_node; - t->size += 1; - return 1; - } - - node *parent = NULL; // Will be parent of new node - node *temp = t->root; // Temporary node - int comp = 0; // Comparison value, used in final step - - // Traverse tree - while(temp) { - parent = temp; - switch (comparison(temp->data, val)) { - case 1: - comp = 1; - temp = temp->left; - break; - case -1: - comp = -1; - temp = temp->right; - break; - case 0: // This should never hit, but just in case - return 0; - default: - return 0; // Undefined behavior - } - } - - // Add node to tree - if (comp == 1) { - parent->left = new_node; - } else { // comp = -1 - parent->right = new_node; - } - - new_node->parent = parent; // Each node know its parent - t->size += 1; - return 1; -} - -// Returns the node that has data = val if present, NULL otherwise -node *find_node(tree *t, void *val) -{ - node *current_node = t->root; - - while (current_node) { - switch (comparison(¤t_node->data, val)) { - case -1: - current_node = current_node->right; - break; - case 1: - current_node = current_node->left; - break; - case 0: - return current_node; - default: - return NULL; // Undefined behavior - } - } - - // val not found - return NULL; -} - -// Returns 1 if the tree contains a node with data = val, 0 otherwise -int contains_node(tree *t, void *val) -{ - return find_node(t, val) != NULL ? 1 : 0; -} - -// Returns the node with the minimum value in the tree provided -// If tree is empty, returns NULL -node *min_node(tree *t) -{ - node *temp = t->root; - - while (temp->left != NULL) { - temp = temp->left; - } - - return temp; -} - -// Returns the minimum value in the tree, or 0 if not present -int min_val(tree *t) -{ - node *n = min_node(t); - return n != NULL ? *((int *)n->data) : 0; -} - -// Returns the node with the maximum value in the tree provided -// If tree is empty, returns NULL -node *max_node(tree *t) -{ - node *temp = t->root; - - while (temp->right != NULL) { - temp = temp->right; - } - - return temp; -} - -// Returns the maximum value in the tree, or 0 if not present -int max_val(tree *t) -{ - node *n = max_node(t); - return n != NULL ? *((int *)n->data) : 0; -} - -// Remove node with data = val from tree if present -// Returns 1 if removed, 0 if node not present -int remove_node(tree *t, void *val) -{ - node *n = find_node(t, val); - if (n == NULL) // node not present - return 0; - - node *parent = n->parent; - int children = 0; // # of children n has - - if (n->left != NULL) - children += 1; - if (n->right != NULL) - children += 1; - - if (children == 0) { // Most simple - if (parent->left == n) { - parent->left = NULL; - } else { - parent->right = NULL; - } - - kfree(n); - t->size -= 1; - return 1; - } else if (children == 1) { // Less simple - if (parent->left == n) { - if (n->left != NULL) { - parent->left = n->left; - } else { - parent->left = n->right; - } - } else { - if (n->left != NULL) { - parent->right = n->left; - } else { - parent->right = n->right; - } - } - - kfree(n); - t->size -= 1; - return 1; - } else { // children = 2, least simple - // Need to replace n's data with the smallest value in its right subtree - tree *right_subtree = new_tree(n->right); - node *min = min_node(right_subtree); - node *min_parent = min->parent; // Parent of min node - - n->data = min->data; // Move min node to where n was - - // Erase duplicate - if (min_parent->left == min) { - min_parent->left = NULL; - } else { - min_parent->right = min->right; - } - - kfree(min); - t->size -= 1; - return 1; - } -} - -// Support method for delete_tree -void delete(node *n) -{ - if (n != NULL) { - delete(n->left); - delete(n->right); - kfree(n); - } -} - -// Remove all node pointers and the tree pointer -void delete_tree(tree *t) -{ - if (t->root != NULL) - delete(t->root); - - kfree(t); -} - -// Returns 1 if the tree is empty, 0 otherwise -int is_empty(tree *t) -{ - return t->root == NULL ? 1 : 0; -} - -// Support method for print_tree -void print_nodes(node *n) -{ - printf("%d\n", *((int *)n->data)); - if (n->left != NULL) - print_nodes(n->left); - if (n->right != NULL) - print_nodes(n->right); -} - -// Print an in-order traversal of the tree -void print_tree(tree *t) -{ - node *root = t->root; - if (root != NULL) - print_nodes(root); -} diff --git a/kernel/src/memory/mmap.c b/kernel/src/memory/mmap.c index 4feb18e4..83274df0 100644 --- a/kernel/src/memory/mmap.c +++ b/kernel/src/memory/mmap.c @@ -62,7 +62,7 @@ void mmap(void *p_bootargs) { // } //temporarily map where it is until we copy it in VAS - first_level_pt[P_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; +// first_level_pt[P_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; //first_level_pt[0x07f00000>>20] = first_level_pt[7F] = 0x07ffirst_level_pt=400000000 = 0x07f04010 // 0x00004000 // 0x00000010 diff --git a/kernel/src/memory/stacks.s b/kernel/src/memory/stacks.s index e0768994..4bc9e933 100644 --- a/kernel/src/memory/stacks.s +++ b/kernel/src/memory/stacks.s @@ -49,4 +49,4 @@ EOR R0, R0 ADD R0, lr, #0xf0000000 MOV lr, R0 - MOV R0, R1 + MOV R0, R1 diff --git a/kernel/src/memory/vm/include/vm2.h b/kernel/src/memory/vm/include/vm2.h new file mode 100644 index 00000000..821d962d --- /dev/null +++ b/kernel/src/memory/vm/include/vm2.h @@ -0,0 +1,272 @@ +#ifndef VM_H +#define VM_H + +#include + +/// The L1 pagetable starts at 0x4000 and is itself 0x4000 bytes long. (0x1000 entries of 4 bytes). +/// The kernel starts at 0x8000 which is exactly at the end of the pagetable. (What a coincidence *gasp*) +#define L1PagetableLocation 0x4000 + +/// A L1PagetableEntry is an entry in the top level pagetable. +/// There is only one L1 pagetable and it is always located at address 0x4000. +/// Relevant manual section: http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf +/// * 6.1 +/// * 6.5 (memory access control) +/// * 6.11.1 (entry layout) +/// * 6.13 (control registers) +/// * 6.10 (page faults and aborts) +typedef union L1PagetableEntry{ + uint32_t entry; + struct { + /// This 2 bit field gives what type of entry this is. + /// 00 for invalid pages (pagefault) + /// 01 for coarse pages (64kb). + /// 10 for sections and supersections. (see bit 18) + /// 11 for invalid pages (pagefault) + /// Note that for supersections you have to repeat this entry 16x to fill up all 1mb entries that would lie within it, + /// and the first of these 16 entries must be on a 16-word boundary + uint32_t type: 2; + + /// Should be zero + uint32_t sbz1: 1; + + /// Non-secure bit. This is used by the security extensions (TrustZone). + uint32_t nonSecure: 1; + + /// Should be zero + uint32_t sbz2: 1; + + /// Domain. This is used by the security extensions (TrustZone). + uint32_t domain: 4; + + /// (P) ECC bit (some processors support this but the ARM1176 does *NOT*) + uint32_t ECC: 1; + + /// Top 22 bits of the base address. Points to a L2 pagetable. + /// formula: + /// base_address = (address >> 10) << 10; + uint32_t base_address: 22; + + } coarse; + + struct { + /// This 2 bit field gives what type of entry this is. + /// 00 for invalid pages (pagefault) + /// 01 for coarse pages (64kb). + /// 10 for sections and supersections. (see bit 18) + /// 11 for invalid pages (pagefault) + /// Note that for supersections you have to repeat this entry 16x to fill up all 1mb entries that would lie within it, + /// and the first of these 16 entries must be on a 16-word boundary + uint32_t type: 2; + + /// If set, this page is bufferable + uint32_t bufferable: 1; + + /// If set, this page is cachable + uint32_t cachable: 1; + + /// Should be zero + uint32_t sbz2: 1; + + /// Domain. This is used by the security extensions (TrustZone). + uint32_t domain: 4; + + /// (P) ECC bit (some processors support this but the ARM1176 does *NOT*) + uint32_t ECC: 1; + + /// Access permissions + /// accessExtended = 0: + /// Kernel: User: + /// 00 No access No access (Recommended) + /// 01 Read/Write No access + /// 10 Read/Write Read only + /// 11 Read/Write Read/Write + /// accessExtended = 1: + /// 00 Reserved Reserved + /// 01 Read only No access + /// 10 Read only Read only + /// 11 Read only Read only + uint32_t accessPermissions: 2; + + /// Type Extension + /// TEX C B Description Memory type Sharable + /// 000 0 0 Strongly ordered Strongly ordered yes + /// 000 0 1 Shared device Device yes + /// 000 1 0 Outer and Inner Write-Through,No Allocate on Write Normal Page sharable if S bit is set + /// 000 1 1 Outer and Inner Write-Back,No Allocate on Write Normal Page sharable if S bit is set + /// 001 0 0 Outer and Inner Noncacheable Normal Page sharable if S bit is set + /// 001 0 1 Reserved + /// 001 1 0 Reserved + /// 001 1 1 Outer and Inner Write-Back, Allocate on Write Normal Page sharable if S bit is set + /// 010 0 0 Non shared device Device no + /// 010 0 1 Reserved + /// 010 1 X Reserved + /// 011 X X Reserved + /// 1BB A A Cached Memory Normal Page sharable if S bit is set + /// BB = Outer policy + /// AA = Inner policy + /// + /// BB *or* AA bits: + /// 00 Non-cachable + /// 01 Write-back cached, write allocate + /// 10 Write-through cached, no allocate on write + /// 11 Write-back cached, no allocate on write + /// + /// For more info (and there is a lot more!), see table 6-4 in the ARM1176jzf-s + /// [reference manual](http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf) + uint32_t TEX: 3; + + /// Access extended bit. See `accessPermissions` + uint32_t accessExtended: 1; + + /// Marks the page sharable (see TEX). Also named S-bit + uint32_t sharable: 1; + + /// Not Global (ng). Determines how this is marked in the TLB. + uint32_t notglobal: 1; + + /// Supersection identifier is '1' if this entry is a supersection, is '0' if this is a normal section + uint32_t supersection: 1; + + /// Non-secure bit. This is used by the security extensions (TrustZone). + uint32_t nonSecure: 1; + + /// Top 12 bits of the base address. Pointer to the first byte in a 1mb-large block. + /// If this entry refers to a supersection, the lower 4 bits Should Be Zero. + /// The top 8 bits now refer to a 16mb-large block + /// + /// formulae: + /// section_base_address = (address >> 20) << 20; + /// supersection_base_address = (address >> 24) << 24; + uint32_t base_address: 12; + } section; +} L1PagetableEntry; + +/// +typedef union { + uint32_t entry; + struct { + /// This 2 bit field gives what type of entry this is. + /// 00 for invalid pages (pagefault) + /// 01 for large pages (64kb). + /// 10 for extended small pages (4kb) + /// 11 for extended *non-executable* small pages. (4kb) + /// Note that for large pages you have to repeat this entry 16x to fill up all 4kb entries that would lie within it, + /// and the first of these 16 entries must be on a 16-word boundary + uint32_t type: 2; + + /// If set, this page is bufferable + uint32_t bufferable: 1; + + /// If set, this page is cachable + uint32_t cachable: 1; + + + /// Access permissions + /// accessExtended = 0: + /// Kernel: User: + /// 00 No access No access (Recommended) + /// 01 Read/Write No access + /// 10 Read/Write Read only + /// 11 Read/Write Read/Write + /// accessExtended = 1: + /// 00 Reserved Reserved + /// 01 Read only No access + /// 10 Read only Read only + /// 11 Read only Read only + uint32_t accessPermissions: 2; + + /// reserved (and Should Be Zero) + uint32_t shouldBeZero1: 3; + + /// Access extended bit. See `accessPermissions` + uint32_t accessExtended: 1; + + /// Marks the page sharable (see TEX). Also named S-bit + uint32_t sharable: 1; + + /// Not Global (ng). Determines how this is marked in the TLB. + uint32_t notglobal: 1; + + /// Type Extension + /// For explanation: see [L1PagetableEntry.section.TEX] + uint32_t TEX: 3; + + /// Mark this page as non executable. + uint32_t nonExecutable: 1; + + /// Top 16 bits of the base address. Pointer to the first byte in a 64kb-large block. + /// formula: + /// base_address = (address >> 16) << 16; + uint32_t base_address: 16; + + } __attribute__((packed)) largepage; + + struct { + /// This 2 bit field gives what type of entry this is. + /// 0 for invalid pages (pagefault) + /// 1 for large pages (64kb). + /// 2 for extended small pages (4kb) + /// 3 for exetended *non-executable* small pages. (4kb) + /// Note that for large pages you have to repeat this entry 16x to fill up all 4kb entries that would lie within it, + /// and the first of these 16 entries must be on a 16-word boundary + uint32_t type: 2; + + /// If set, this page is bufferable (B) + uint32_t bufferable: 1; + + /// If set, this page is cachable (S) + uint32_t cachable: 1; + + + /// Access permissions + /// accessExtended = 0: + /// Kernel: User: + /// 00 No access No access (Recommended) + /// 01 Read/Write No access + /// 10 Read/Write Read only + /// 11 Read/Write Read/Write + /// accessExtended = 1: + /// 00 Reserved Reserved + /// 01 Read only No access + /// 10 Read only Read only + /// 11 Read only Read only + uint32_t accessPermissions: 2; + + /// Type Extension + /// For explanation: see [L2PagetableEntry.largepage.TEX] + uint32_t TEX: 3; + + /// Access extended bit. See `accessPermissions` (APX) + uint32_t accessExtended: 1; + + /// Marks the page sharable (see TEX). Also named S-bit + uint32_t sharable: 1; + + /// Not Global (ng). Determines how this is marked in the TLB. + uint32_t notglobal: 1; + + /// Top 20 bits of the base address. Pointer to the first byte in a 4kb-large block. + /// formula: + /// base_address = (address >> 12) << 12; + uint32_t base_address: 20; + + } __attribute__((packed)) smallpage; +} L2PagetableEntry; + + +struct L1PageTable { + L1PagetableEntry entries[0x1000]; +} __attribute__((packed)); + +struct L2PageTable { + L2PagetableEntry entries[0x400]; +} __attribute__((packed)); + +void vm2_prepare(); +void vm2_start(); +void vm2_map_virtual_to_physical_l1(size_t virtual, size_t physical); +void vm2_map_nmegabytes_1to1(size_t address, size_t n); + + +#endif diff --git a/kernel/src/memory/vm/test/test_vm.c b/kernel/src/memory/vm/test/test_vm.c index 407dcc6b..2a0f8bbd 100644 --- a/kernel/src/memory/vm/test/test_vm.c +++ b/kernel/src/memory/vm/test/test_vm.c @@ -1,105 +1,105 @@ -#include -#include "klibc.h" -#include "memory.h" -#include "vm.h" - -// TODO: This test has many LOG calls, we should try and looking at improving the logging capabilities -TEST_CREATE(test_vm_1, { - struct vas *vas1 = vm_new_vas(); - LOG("Got new vas at 0x%X\n", vas1); - - // We're part of the kernel, which is already mapped into vas1. - // But our stack isn't, so let's add that mapping. - unsigned int mystack = (unsigned int) &vas1; - mystack &= 0xFFF00000; // Round down to nearest MB - LOG("Stack addr: 0x%X\n", mystack); - LOG("Created page table w/ 0xFFF00000's entry = 0x%X\n", - vas1->l1_pagetable[V_KDSBASE>>20]); - - vm_enable_vas(vas1); - - // Do we still have the stack? - // FIXME Update constant as necessary - #define STACK_ADDR 0xF020000C - // Invalid stack - ASSERT_EQ((unsigned int) vas1, STACK_ADDR); - - struct vas *vas2 = (struct vas*) V_L1PTBASE; - INFO("%X (%X)\n", vas2, &vas2); - INFO("%X\n", *((unsigned int* ) vas2)); - INFO("%X\n", vas2->l1_pagetable); - INFO("Entry: %x\n", - vas1->l1_pagetable[(unsigned int ) vas2->l1_pagetable >> 20]); - INFO("%X\n", vas2->l1_pagetable[0]); - INFO("(deref: entry at 0x200000: 0x%X)\n", - vas2->l1_pagetable[0x200000 >> 20]); - - // Test making a thing in this thing - struct vas *vas3 = vm_new_vas(); - vm_enable_vas(vas3); - INFO("%X and %X and %X\n", vas1, vas2, vas3); - - // Test allocating frames... - #define P3_BASE 0x24000000 - int retval = vm_allocate_page(vas3, (void*) P3_BASE, VM_PERM_PRIVILEGED_RW); - - // vm_allocate_page fails - ASSERT(!retval); - - int *p = (int*) 0xFFFFFFF0; - p[0] = 1; - - ASSERT_EQ(p[0], 1); - - // Oh man! We should be able to write to there! - p = (int*) P3_BASE; - p[0] = 1; - - LOG("%x %x\n", &p, p); - - ASSERT_EQ(p[0], 1); - - // Test shared memory... - LOG("Testing shared memory...\n"); - int *p_3 = (int*) P3_BASE;//0x24000000; - int *p_1 = (int*) 0x31000000; - retval = vm_map_shared_memory(vas1, p_1, vas3, p_3, VM_PERM_PRIVILEGED_RW); - LOG("map_shared_memory returned %d\n", retval); - - p_3[0] = 321; - vm_enable_vas(vas1); - ASSERT_EQ(p_1[0], 321); - p_1[1] = 456; - - vm_enable_vas(vas3); - ASSERT_EQ(p_3[1], 456); - - // Test allocating many frames... (this was commented but seems to work just fine) - *p += BLOCK_SIZE; - while (!vm_allocate_page(vas3, (void*) p, 0)) { - //LOG("Allocated memory...\n"); - p += BLOCK_SIZE; - } - - p -= BLOCK_SIZE; - kprintf("Highest frame allocated: 0x%X\n", p); - - while ((unsigned int) p > P3_BASE) { - //LOG("Freed memory...\n"); - vm_free_page(vas3, p); - p -= BLOCK_SIZE; - } - - // FIXME: This part of the test crashes the os, we should catch that in some way. - // Test the data abort... -// WARN("You should see a data abort...\n"); -// int i = p[-1]; -// LOG("%d\n", i); - - // Free the page! - LOG("Freeing page at %X\n", p); - vm_free_page(vas3, p); - - // Clean up & switch back to the kernel's VAS before we return. - vm_enable_vas((struct vas*) KERNEL_VAS); -}) +//#include +//#include "klibc.h" +//#include "memory.h" +//#include "vm.h" +// +//// TODO: This test has many LOG calls, we should try and looking at improving the logging capabilities +//TEST_CREATE(test_vm_1, { +// struct vas *vas1 = vm_new_vas(); +// LOG("Got new vas at 0x%X\n", vas1); +// +// // We're part of the kernel, which is already mapped into vas1. +// // But our stack isn't, so let's add that mapping. +// unsigned int mystack = (unsigned int) &vas1; +// mystack &= 0xFFF00000; // Round down to nearest MB +// LOG("Stack addr: 0x%X\n", mystack); +// LOG("Created page table w/ 0xFFF00000's entry = 0x%X\n", +// vas1->l1_pagetable[V_KDSBASE>>20]); +// +// vm_enable_vas(vas1); +// +// // Do we still have the stack? +// // FIXME Update constant as necessary +// #define STACK_ADDR 0xF020000C +// // Invalid stack +// ASSERT_EQ((unsigned int) vas1, STACK_ADDR); +// +// struct vas *vas2 = (struct vas*) V_L1PTBASE; +// INFO("%X (%X)\n", vas2, &vas2); +// INFO("%X\n", *((unsigned int* ) vas2)); +// INFO("%X\n", vas2->l1_pagetable); +// INFO("Entry: %x\n", +// vas1->l1_pagetable[(unsigned int ) vas2->l1_pagetable >> 20]); +// INFO("%X\n", vas2->l1_pagetable[0]); +// INFO("(deref: entry at 0x200000: 0x%X)\n", +// vas2->l1_pagetable[0x200000 >> 20]); +// +// // Test making a thing in this thing +// struct vas *vas3 = vm_new_vas(); +// vm_enable_vas(vas3); +// INFO("%X and %X and %X\n", vas1, vas2, vas3); +// +// // Test allocating frames... +// #define P3_BASE 0x24000000 +// int retval = vm_allocate_page(vas3, (void*) P3_BASE, VM_PERM_PRIVILEGED_RW); +// +// // vm_allocate_page fails +// ASSERT(!retval); +// +// int *p = (int*) 0xFFFFFFF0; +// p[0] = 1; +// +// ASSERT_EQ(p[0], 1); +// +// // Oh man! We should be able to write to there! +// p = (int*) P3_BASE; +// p[0] = 1; +// +// LOG("%x %x\n", &p, p); +// +// ASSERT_EQ(p[0], 1); +// +// // Test shared memory... +// LOG("Testing shared memory...\n"); +// int *p_3 = (int*) P3_BASE;//0x24000000; +// int *p_1 = (int*) 0x31000000; +// retval = vm_map_shared_memory(vas1, p_1, vas3, p_3, VM_PERM_PRIVILEGED_RW); +// LOG("map_shared_memory returned %d\n", retval); +// +// p_3[0] = 321; +// vm_enable_vas(vas1); +// ASSERT_EQ(p_1[0], 321); +// p_1[1] = 456; +// +// vm_enable_vas(vas3); +// ASSERT_EQ(p_3[1], 456); +// +// // Test allocating many frames... (this was commented but seems to work just fine) +// *p += BLOCK_SIZE; +// while (!vm_allocate_page(vas3, (void*) p, 0)) { +// //LOG("Allocated memory...\n"); +// p += BLOCK_SIZE; +// } +// +// p -= BLOCK_SIZE; +// kprintf("Highest frame allocated: 0x%X\n", p); +// +// while ((unsigned int) p > P3_BASE) { +// //LOG("Freed memory...\n"); +// vm_free_page(vas3, p); +// p -= BLOCK_SIZE; +// } +// +// // FIXME: This part of the test crashes the os, we should catch that in some way. +// // Test the data abort... +//// WARN("You should see a data abort...\n"); +//// int i = p[-1]; +//// LOG("%d\n", i); +// +// // Free the page! +// LOG("Freeing page at %X\n", p); +// vm_free_page(vas3, p); +// +// // Clean up & switch back to the kernel's VAS before we return. +// vm_enable_vas((struct vas*) KERNEL_VAS); +//}) diff --git a/kernel/src/memory/vm/test/test_vm2.c b/kernel/src/memory/vm/test/test_vm2.c new file mode 100644 index 00000000..3dad2fe2 --- /dev/null +++ b/kernel/src/memory/vm/test/test_vm2.c @@ -0,0 +1,7 @@ +#include +#include + +TEST_CREATE(test_size, { + ASSERT_EQ(sizeof(L2PagetableEntry), 4); + ASSERT_EQ(sizeof(L1PagetableEntry), 4); +}) diff --git a/kernel/src/memory/vm/vm2.c b/kernel/src/memory/vm/vm2.c new file mode 100644 index 00000000..9835539e --- /dev/null +++ b/kernel/src/memory/vm/vm2.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include + +struct L1PageTable * l1PageTable = (struct L1PageTable *) L1PagetableLocation; +bool mmu_started = false; + +static inline size_t l1pt_index(size_t address) { + return address >> 20u; +} + +void vm2_map_virtual_to_physical_l1(size_t virtual, size_t physical) { + if(mmu_started) { + // Outside users are not allowed to add entries to the pagetable + // after the mmu has been started. They can request a new frame with + // + panic(); + } + + if (l1PageTable->entries[l1pt_index(virtual)].entry != 0){ + // The entry is already mapped + kprintf("Request for already mapped address denied"); + panic(); + } + + L1PagetableEntry entry = { + .section.type = 2, // section + .section.bufferable = 0, + .section.cachable = 0, + .section.accessPermissions = 0b01, // Kernel r/w, user no access. + .section.TEX = 0, // Strongly ordered + .section.accessExtended = 0, // r/w access + .section.supersection = 0, + .section.nonSecure = 1, + .section.base_address = (physical >> 20u) << 20u, + }; + + l1PageTable->entries[l1pt_index(virtual)] = entry; +} + +void vm2_map_nmegabytes_1to1(size_t address, size_t n) { + // Iterate over the address in 1 MiB chunks. + for (; address < (address + 0x100000u * n) ; address += 0x100000u) { + kprintf("mapping address 0x%x 1:1\n", address); + vm2_map_virtual_to_physical_l1(address, address); + } +} + +// Prepares the pagetable and add +void vm2_prepare() { + // Clear the pagetable + memset(l1PageTable, 0, sizeof(struct L1PageTable)); + + + vm2_map_nmegabytes_1to1(0, 1); + +} + +// Starts the actual MMU after this function we live in Virtual Memory +void vm2_start() { + + mmu_started = true; +} diff --git a/kernel/src/process/scheduler.c b/kernel/src/process/scheduler.c index ed986e54..163d22f6 100644 --- a/kernel/src/process/scheduler.c +++ b/kernel/src/process/scheduler.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #define MAX_TASKS 100 // in the future, cap will be removed @@ -60,12 +59,12 @@ void timer_handler(void *args) void __sched_register_timer_irq(void) { - register_handler(SCHEDULER_TIMER, timer_handler); +// register_handler(SCHEDULER_TIMER, timer_handler); } void __sched_deregister_timer_irq() { - unregister_handler(SCHEDULER_TIMER); +// unregister_handler(SCHEDULER_TIMER); } void __sched_pause_timer_irq() From c947872d8245113b5197778030bb53cbd37d423a Mon Sep 17 00:00:00 2001 From: Reinout Meliesie Date: Tue, 3 Mar 2020 14:15:23 +0100 Subject: [PATCH 034/104] Kernel makefile fixes --- kernel/Makefile | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/kernel/Makefile b/kernel/Makefile index 997ceb9c..1592a7e0 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -14,9 +14,8 @@ test: DEFINITIONS += ENABLE_TESTS # if we execute the test: rule, enable tests b KERNEL_PARAMS = root=/dev/ram mem=$(MEMORY) SOURCEDIR = src BUILDDIR = build -# every directory named `include` will have it's contents autoincluded +# every directory named `include` will have its contents autoincluded INCLUDEDIR = include -TEST_MAIN_FILE = $(SOURCEDIR)/test/test.c # =================== End Configuration =================== @@ -29,7 +28,8 @@ MKIMAGE:=$(CURDIR)/../u-boot/u-boot-$(UBOOT_VERSION)/tools/mkimage GDB:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gdb DIRS = $(shell find $(SOURCEDIR)/ -type d -print) -C_SOURCE_FILES := $(foreach dir,$(DIRS),$(wildcard $(dir)/*.c)) $(TEST_MAIN_FILE) +C_GEN_SOURCE_FILES := $(SOURCEDIR)/test/test.c +C_SOURCE_FILES := $(foreach dir,$(DIRS),$(wildcard $(dir)/*.c)) $(C_GEN_SOURCE_FILES) C_OBJECT_FILES := $(patsubst $(SOURCEDIR)/%.c, \ $(BUILDDIR)/%.o, $(C_SOURCE_FILES)) @@ -39,7 +39,7 @@ S_OBJECT_FILES := $(patsubst $(SOURCEDIR)/%.s, \ OBJECT_FILES := $(S_OBJECT_FILES) $(C_OBJECT_FILES) -INCLUDEDIRS := $(sort $(foreach dir, $(foreach dir1, $(DIRS), $(shell dirname $(dir1))), $(wildcard $(dir)/$(INCLUDEDIR)))) +INCLUDEDIRS := $(sort $(foreach dir, $(foreach dir1, $(DIRS), $(shell dirname $(dir1))), $(wildcard $(dir)/$(INCLUDEDIR)))) CFLAGS += $(foreach dir, $(INCLUDEDIRS), -I./$(dir)) CFLAGS += $(foreach def, $(DEFINITIONS), -D$(def)) @@ -62,21 +62,22 @@ $(BUILDDIR)/kernel.elf: $(OBJECT_FILES) | builddir # Begin Pi Make $(BUILDDIR)/kernelPi.elf: $(C_OBJECT_FILES) | builddir - $(CC) -T kernelPi.ld -O2 $(PI_CFLAGS) $(C_OBJECT_FILES) -o $@ + $(CC) -T kernelPi.ld -O2 $(PI_CFLAGS) $^ -o $@ $(BUILDDIR)/kernelPi.img: $(BUILDDIR)/kernelPi.elf | builddir $(OBJCOPY) $< -O binary $@ # End Pi Make builddir: - mkdir -p $(BUILDDIR) + @mkdir -p $(BUILDDIR) $(BUILDDIR)/%.o: $(SOURCEDIR)/%.s | builddir @mkdir -p $(shell dirname $@) @echo Assembling $< @$(AS) -mcpu=arm1176jzf-s -g $< -o $@ -$(TEST_MAIN_FILE): dummy +$(SOURCEDIR)/test/test.c: dummy | builddir + @echo Generating tests @$(SOURCEDIR)/test/generate_tests.sh # depend on dummy to always recompile. There aren't that many files atm anyway and From 2a0f78bdacc020f548b4e0fce72796deb53765a4 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Thu, 5 Mar 2020 15:16:01 +0100 Subject: [PATCH 035/104] slice allocator works Co-authored-by: Victor Roest --- frameallocatortest/pagealloc2.c | 81 +++++ kernel/Makefile | 2 +- kernel/linker/kernel.ld | 13 +- kernel/src/common/include/interrupt.h | 2 +- kernel/src/common/interrupt.c | 4 + kernel/src/common/start.c | 3 +- kernel/src/common/startup.s | 78 ++++- kernel/src/drivers/chipset/bcm2836/bcm2836.c | 9 + kernel/src/ds/array_list.c | 1 + kernel/src/ds/include/array_list.h | 2 +- kernel/src/klibc/include/constants.h | 17 + kernel/src/memory/include/memory.h | 4 +- kernel/src/memory/mem_alloc.c | 24 +- kernel/src/memory/mmap.c | 17 +- kernel/src/memory/vm/frame.c | 3 +- kernel/src/memory/vm/include/pagealloc2.h | 144 +++++++++ kernel/src/memory/vm/include/vas2.h | 17 + kernel/src/memory/vm/include/vm2.h | 43 ++- kernel/src/memory/vm/pagealloc2.c | 324 +++++++++++++++++++ kernel/src/memory/vm/test/test_pagealloc2.c | 278 ++++++++++++++++ kernel/src/memory/vm/vas2.c | 4 + kernel/src/memory/vm/vm.c | 2 +- kernel/src/memory/vm/vm2.c | 53 ++- kernel/src/process/include/process.h | 8 +- kernel/src/process/process.c | 22 +- kernel/src/test/include/test.h | 1 + 26 files changed, 1082 insertions(+), 74 deletions(-) create mode 100644 frameallocatortest/pagealloc2.c create mode 100644 kernel/src/klibc/include/constants.h create mode 100644 kernel/src/memory/vm/include/pagealloc2.h create mode 100644 kernel/src/memory/vm/include/vas2.h create mode 100644 kernel/src/memory/vm/pagealloc2.c create mode 100644 kernel/src/memory/vm/test/test_pagealloc2.c create mode 100644 kernel/src/memory/vm/vas2.c diff --git a/frameallocatortest/pagealloc2.c b/frameallocatortest/pagealloc2.c new file mode 100644 index 00000000..ff28173b --- /dev/null +++ b/frameallocatortest/pagealloc2.c @@ -0,0 +1,81 @@ +#include +#include +#include + +struct PageAllocator allocator; + +void pagealloc_init(size_t start, size_t end) { + + // Create the first sliceinfo at the start address + struct MemorySliceInfo * firstinfo = (struct MemorySliceInfo *)start; + // This start address is itself a memory slice + union MemorySlice * firstslice = (union MemorySlice *)firstinfo; + + // Make the first sliceinfo describe this first slice. + firstinfo->next = NULL; + // It's type is sliceinfo + firstinfo->type = SliceInfo; + // It points to the first slice + firstinfo->slice = (union MemorySlice *)firstinfo; + // And there's one sliceinfo struct in it. This first one. + firstinfo->filled = 1; + + // Now make an allocator with one sliceinfo in the allocated array. + allocator = (struct PageAllocator){ + .start = start, + .end = end, + .l2ptPartialFree = NULL, + .pagePartialFree = NULL, + .allocated = firstinfo, + .unused = NULL, + }; + + // the infoindex is 1 since we just allocated the 0th one above^^^ + size_t infoindex = 1; + union MemorySlice * currentslice = firstslice; + + // Go through all memory and index it with sliceinfo structs. + for (size_t i = start; i < end; i += sizeof(union MemorySlice)) { + struct MemorySliceInfo * currentsliceinfo = ¤tslice->sliceinfo[infoindex]; + + // make this sliceinfo struct point to the right slice + currentsliceinfo->slice = (union MemorySlice *) i; + + // Add the sliceinfo to the unused list + currentsliceinfo->next = allocator.unused; + allocator.unused = currentsliceinfo; + + // continue to the next slicinfo + infoindex++; + + if (infoindex >= SLICEINFO_PER_SLICE) { + // We can now do this as we already made at least one new sliceinfo struct on the unused list + // Which we can use for this. + currentslice = allocate_new_sliceinfo_slice()->slice; + } + } +} + +struct MemorySliceInfo * allocate_new_sliceinfo_slice() { + // Take a slice from the unused list and the the next one to the top of unused. + struct MemorySliceInfo * sliceinfo = allocator.unused; + allocator.unused = sliceinfo->next; + + // Change it's type to typeinfo + sliceinfo->type = SliceInfo; + sliceinfo->filled = 0; + + // Add it to the allocated list + sliceinfo->next = allocator.allocated; + allocator.allocated = sliceinfo; + + return sliceinfo; +} + + +int main() { + size_t size = 128 * 1024 * 1024; + size_t start = (size_t) malloc(size); + + pagealloc_init(start, start + size); +} diff --git a/kernel/Makefile b/kernel/Makefile index 997ceb9c..099ecd23 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -8,7 +8,7 @@ CFLAGS += -pipe -std=gnu99 -ffreestanding -Wall -Werror -g -O0 -mcpu=arm1176jzf- #PI_CFLAGS = -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -nostartfiles # variables to define in the preprocessor. -MEMORY = 128M +MEMORY = 1G DEFINITIONS = MEM_DEBUG test: DEFINITIONS += ENABLE_TESTS # if we execute the test: rule, enable tests before recompiling KERNEL_PARAMS = root=/dev/ram mem=$(MEMORY) diff --git a/kernel/linker/kernel.ld b/kernel/linker/kernel.ld index b0419f97..71319cf4 100644 --- a/kernel/linker/kernel.ld +++ b/kernel/linker/kernel.ld @@ -2,14 +2,13 @@ ENTRY(_Reset) SECTIONS { . = 0x8000; - P_KERNBASE = .; + KERNEL_BASE = .; .startup . : { build/common/startup.o(.text) } .text : { *(.text) } .data : { *(.data) } - .bss : { *(.bss COMMON) } - P_KERNTOP = .; - . = ALIGN(8); - . = . + 0x1000; - stack_top = .; -} + .bss : { *(.bss COMMON)} + /*make kernel top megabyte aligned*/ + . = ALIGN(1024 * 1024); + KERNEL_TOP = .; +} diff --git a/kernel/src/common/include/interrupt.h b/kernel/src/common/include/interrupt.h index 107dd277..21f024ad 100644 --- a/kernel/src/common/include/interrupt.h +++ b/kernel/src/common/include/interrupt.h @@ -32,7 +32,7 @@ */ #include "stdint.h" -#define BRANCH_INSTRUCTION 0xe59ff018 // ldr pc, pc+offset +#define BRANCH_INSTRUCTION 0xe59ff018 // ldr pc, pc+offset (where offset is 0x20 bytes) // System Call Types #define SYSCALL_CREATE 0 diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index 5f8bc03d..6c6595c0 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -240,6 +240,10 @@ void __attribute__((interrupt("ABORT"))) data_abort_handler(void) asm volatile("MRC p15, 0, %0, c5, c0, 0" : "=r" (dsfr)); //os_printf("DSFR: 0x%X\n", dsfr); +#ifdef ENABLE_TESTS + panic(); +#endif + switch (dsfr) { case 6: // Access bit. diff --git a/kernel/src/common/start.c b/kernel/src/common/start.c index b6e16c86..70ff57e4 100644 --- a/kernel/src/common/start.c +++ b/kernel/src/common/start.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -27,7 +28,6 @@ #include #include #include -#include // This start is what u-boot calls. It's just a wrapper around setting up the // virtual memory for the kernel. @@ -81,6 +81,7 @@ void start2(uint32_t *p_bootargs) { kprintf("bootargs: 0x%x\n", p_bootargs); + #ifndef ENABLE_TESTS // argparse_process(p_bootargs); // diff --git a/kernel/src/common/startup.s b/kernel/src/common/startup.s index bf7e76a6..c0a496af 100644 --- a/kernel/src/common/startup.s +++ b/kernel/src/common/startup.s @@ -1,5 +1,16 @@ .global _Reset +// Codes for the various execution modes +// https://heyrick.eu/armwiki/Processor_modes +.equ Mode_USR, 0x10 // User +.equ Mode_FIQ, 0x11 // Fast interrupt +.equ Mode_IRQ, 0x12 // Normal iterrupt +.equ Mode_SVC, 0x13 // Supervisor mode, this is the privileged moded for the OS (/Kernel) +.equ Mode_MON, 0x16 // Monitor, more info: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.prd29-genc-009492c/CACJBHJA.html +.equ Mode_ABT, 0x17 // Abort, for virtual memory and memory protection +.equ Mode_UND, 0x1B // Undefined, +.equ Mode_SYS, 0x1F // System, a hybrid between SVC and + _Reset: // Disable other cores mrc p15, #0, r1, c0, c0, #5 @@ -7,9 +18,72 @@ _Reset: cmp r1, #0 bne loop - LDR sp, =stack_top - MOV R0, R2 + LDR sp, =KERNEL_STACK_TOP // Set the kernel/SVC stack + + // FIQ Stack + MSR CPSR_c, #Mode_FIQ // Switch to FIQ Mode + LDR sp, =FIQ_STACK_TOP // Set the FIQ stack pointer + + // IRQ Stack + MSR CPSR_c, #Mode_IRQ + LDR sp, =IRQ_STACK_TOP + + // MON Stack + MSR CPSR_c, #Mode_MON + LDR sp, =MON_STACK_TOP + + // ABT Stack + MSR CPSR_c, #Mode_ABT + LDR sp, =ABT_STACK_TOP + + // UND Stack + MSR CPSR_c, #Mode_UND + LDR sp, =UND_STACK_TOP + + // SYS Stack + MSR CPSR_c, #Mode_SYS + LDR sp, =SYS_STACK_TOP + + // Switch back SVC/Kernel + MSR CPSR_c, #Mode_SVC + ADD fp, sp, #0 // ??? + + MOV R0, R2 // boot args in R0 BL start loop: WFI B loop + +.section .bss +//.global KERNEL_STACK_TOP, KERNEL_STACK_BASE, FIQ_STACK_START, FIQ_STACK_TOP, IRQ_STACK_START, IRQ_STACK_TOP + +KERNEL_STACK_START: + .space 4096 // 4 KiB of stack should be enough +KERNEL_STACK_TOP: + +FIQ_STACK_START: + .space 1024 // 1 KiB of stack for the FIQ handlers +FIQ_STACK_TOP: + +IRQ_STACK_START: + .space 1024 // 1 KiB of stack for the FIQ handlers +IRQ_STACK_TOP: + +ABT_STACK_START: + .space 1024 // 1 KiB of stack for abort modes +ABT_STACK_TOP: + +// TODO: We are not quite sure what this processor mode is and why it needs a stack, +// TODO: but the previous people gave it as stack as well so it seems useful... +MON_STACK_START: + .space 1024 // 1 KiB of stack for monitor modes +MON_STACK_TOP: + +UND_STACK_START: + .space 1024 // 1 KiB of stack for undefined modes +UND_STACK_TOP: + +SYS_STACK_START: + .space 1024 // 1 KiB of stack for undefined modes +SYS_STACK_TOP: + diff --git a/kernel/src/drivers/chipset/bcm2836/bcm2836.c b/kernel/src/drivers/chipset/bcm2836/bcm2836.c index e8c9b4ae..c89c8b45 100644 --- a/kernel/src/drivers/chipset/bcm2836/bcm2836.c +++ b/kernel/src/drivers/chipset/bcm2836/bcm2836.c @@ -4,6 +4,7 @@ #include #include #include +#include volatile struct BCM2836Registers * bcm2836_registers_base = (struct BCM2836Registers *) 0x40000000; const size_t BCM2836_peripheral_base = 0x3F000000; @@ -54,8 +55,16 @@ void bcm2836_init() { chipset.late_init = &bcm2836_late_init; // Mapping memory used by bcm2836 peripherals + // TEMP (vm1): request_identity_mapped_section(BCM2836_peripheral_base, 4); + // TODO: remove vm1 code and leave only this vm2 call + vm2_map_nmegabytes_1to1(BCM2836_peripheral_base, 4); + // Map control registers + // TEMP (vm1): request_identity_mapped_section((size_t)bcm2836_registers_base, 1); + + // TODO: remove vm1 code and leave only this vm2 call + vm2_map_nmegabytes_1to1((size_t)bcm2836_registers_base, 1); } diff --git a/kernel/src/ds/array_list.c b/kernel/src/ds/array_list.c index 00760c83..02bb235a 100644 --- a/kernel/src/ds/array_list.c +++ b/kernel/src/ds/array_list.c @@ -4,6 +4,7 @@ * Created on: Apr 21, 2015 * Author: kittenRainbow */ +/// FIXME: All usages of this array list should be replaced with vp_array_list or even u8_array_list where applicable. #include #include diff --git a/kernel/src/ds/include/array_list.h b/kernel/src/ds/include/array_list.h index 2492180b..c99afb46 100644 --- a/kernel/src/ds/include/array_list.h +++ b/kernel/src/ds/include/array_list.h @@ -20,7 +20,7 @@ struct arrl_handle { int bucket_size; int size; int capacity; -}; +} __attribute__((deprecated)); // The implementation is faulty. arrl_handle* arrl_create(); arrl_handle* arrl_create_fixed(uint32_t bucket_size); diff --git a/kernel/src/klibc/include/constants.h b/kernel/src/klibc/include/constants.h new file mode 100644 index 00000000..59e8068a --- /dev/null +++ b/kernel/src/klibc/include/constants.h @@ -0,0 +1,17 @@ +#ifndef CONSTANTS_H +#define CONSTANTS_H + +#include + +/// SI Binary prefixes +#define Kibibyte ((size_t)(1024u)) +#define Mibibyte ((size_t)(Kibibyte * 1024u)) +#define Gibibyte ((size_t)(Mibibyte * 1024u)) +#define Tibibyte ((size_t)(Gibibyte * 1024u)) +#define Pebibyte ((size_t)(Tibibyte * 1024u)) +#define Exbibyte ((size_t)(Pebibyte * 1024u)) +#define Zebibyte ((size_t)(Exbibyte * 1024u)) +#define Yobibyte ((size_t)(Zebibyte * 1024u)) + + +#endif diff --git a/kernel/src/memory/include/memory.h b/kernel/src/memory/include/memory.h index 8331abfe..35c191a3 100644 --- a/kernel/src/memory/include/memory.h +++ b/kernel/src/memory/include/memory.h @@ -25,8 +25,8 @@ #define PERIPHBASE 0x3F000000 #define PERIPHTOP 0x20000000 -//#define PCIBASE 0x41000000 -//#define PCITOP 0x70000000 +#define PCIBASE 0x41000000 +#define PCITOP 0x70000000 //remapped physical memory for direct access #define PMAPBASE 0xf0200000 diff --git a/kernel/src/memory/mem_alloc.c b/kernel/src/memory/mem_alloc.c index 28f219e9..8e6ed633 100644 --- a/kernel/src/memory/mem_alloc.c +++ b/kernel/src/memory/mem_alloc.c @@ -1,5 +1,3 @@ - - #include "klibc.h" #include #include @@ -18,16 +16,16 @@ uint32_t __mem_extend_proc_heap(uint32_t amt); //bump pointer allocation void *mem_alloc(uint32_t size) { - uint32_t temp = size / 4; + uint32_t temp = size / 4; - if ((size % 4) > 0) - { - temp++; - } - uint32_t* allocBlock = nextBlock; - nextBlock = nextBlock + size; + if ((size % 4) > 0) + { + temp++; + } + uint32_t* allocBlock = nextBlock; + nextBlock = nextBlock + size; - return allocBlock; + return allocBlock; } /* @@ -52,7 +50,7 @@ uint32_t __mem_extend_heap(uint32_t amt) uint32_t amt_added = 0; while (amt_added < amt) { int retval = vm_allocate_page(KERNEL_VAS, - (void*) (MEM_START + buffer_size), VM_PERM_PRIVILEGED_RW); + (void*) (MEM_START + buffer_size), VM_PERM_PRIVILEGED_RW); if (retval) { kprintf("ERROR: vm_allocate_page(,%d,) returned %d\n", MEM_START + amt_added, retval); @@ -134,7 +132,7 @@ uint32_t init_process_heap(struct vas* vas) { } uint32_t __mem_extend_proc_heap(uint32_t amt) { - struct vas* pvas = vm_get_current_vas(); + struct vas* pvas = vm_get_current_vas(); uint32_t amt_added = 0; while (amt_added < amt) @@ -167,7 +165,7 @@ void proc_deallocate(void* ptr) } void *allocate(uint32_t size) { - return heap_alloc(allocator, size); + return heap_alloc(allocator, size); } void deallocate(void *ptr) { diff --git a/kernel/src/memory/mmap.c b/kernel/src/memory/mmap.c index 83274df0..95c40d95 100644 --- a/kernel/src/memory/mmap.c +++ b/kernel/src/memory/mmap.c @@ -3,6 +3,7 @@ #include #include #include +#include /* * APX AP Privileged Unprivileged @@ -38,7 +39,6 @@ void request_identity_mapped_section(size_t start_address, size_t megabytes) { kprintf("Identity mapping %i megabyte(s) at 0x%x\n", megabytes, start_address); for (unsigned int i = 0; i < megabytes; i++) { - kprintf("i: %i\n", i * 0x100000); first_level_pt[(start_address + (i * 0x100000)) >> 20] = ((start_address + (i *0x100000)) & 0xFFF00000) | 0x0400 | 2; } } @@ -47,6 +47,9 @@ void prepare_pagetable() { memset((uint32_t *)first_level_pt,0, PAGE_TABLE_SIZE); } +// 0x00000000 +// --- --- +// L1 off void mmap(void *p_bootargs) { disable_interrupt(BOTH); @@ -91,11 +94,12 @@ void mmap(void *p_bootargs) { // TODO: re enable when we actually need it. 700mb seems a bit excessive though. //map 752MB of PCI interface one-to-one - // unsigned int pci_bus_addr = PCIBASE; - // for (int i = (PCIBASE >> 20); i < (PCITOP >> 20); i++) { - // first_level_pt[i] = pci_bus_addr | 0x0400 | 2; - // pci_bus_addr += 0x100000; - // } +// unsigned int pci_bus_addr = PCIBASE; +// for (int i = (PCIBASE >> 20); i < (PCITOP >> 20); i++) { +// first_level_pt[i] = pci_bus_addr | 0x0400 | 2; +// pci_bus_addr += 0x100000; +// } + request_identity_mapped_section(Gibibyte - 25 * Mibibyte, 20); // Quick coarse page table address //unsigned int coarse_page_table_address = P_L1PTBASE + 2*PAGE_TABLE_SIZE; @@ -111,6 +115,7 @@ void mmap(void *p_bootargs) { phys_addr += 0x100000; } + // Fill in the coarse page table // (TODO: How do we handle 64kB pages? Do they take up 16 entries?) //os_memset((void*)coarse_page_table_address, 0, L2_PAGE_TABLE_SIZE); diff --git a/kernel/src/memory/vm/frame.c b/kernel/src/memory/vm/frame.c index d4cf962c..f1a5acf8 100644 --- a/kernel/src/memory/vm/frame.c +++ b/kernel/src/memory/vm/frame.c @@ -24,8 +24,7 @@ int vm_build_free_frame_list(void *start, void *end) return 0; } -void *vm_get_free_frame() -{ +void *vm_get_free_frame() { // Check if there are no frames if (vm_free_list == 0x0) { diff --git a/kernel/src/memory/vm/include/pagealloc2.h b/kernel/src/memory/vm/include/pagealloc2.h new file mode 100644 index 00000000..379a8f63 --- /dev/null +++ b/kernel/src/memory/vm/include/pagealloc2.h @@ -0,0 +1,144 @@ +/// This page allocator was completely designed and implemented by +/// Jonathan Donszelmann +/// Victor Roest +/// +/// ## Description +/// +/// It can allocate pages of sizes: +/// * 16kb (L1 pagetables) +/// * 1kb (L2 pagetables) +/// * 4kb (Normal data pages) +/// All pages are aligned to their own size (i.e. The 16kb pages are 16k algined) +/// +/// It stores all datastructures it uses in the same pages it allocates, +/// and can therefore be used without any existing allocator allocating it's space. +/// +/// This allocator has been made specifically for 32 bit ARM cpus. +/// This means it can *not* be used on x86 without adaptation. +/// It relies on addresses being 32 bits long and being aligned to boundaries to save (a lot) of space. +/// +/// ## Overhead +/// Since this allocator also has to store some datastructures in itself, it obviously has some overhead. +/// This overhead is 16kb for every 682 pages of size 16kb allocated. For 64 bit systems this ovehead would be larger. +/// +/// ## Time complexity +/// All operations performed on this allocator are O(1). They are in no way dependent on the size of memory. +/// With the exception of one method: The initialization of the allocator will loop once through all of physical memory +/// in increments of 16kb. +/// +/// ## Definitions +/// +/// In this code and the comments, we refer to the following things: +/// * (memory)slice A 16kb area of physical ram +/// * page A 4 kb area of physical ram (used for virtual user memory). +/// * sliceinfo A 12 byte element in the allocators datastructures, describing a single 16kb block +/// * bucket A piece of memory that can be referred to by a single 16kb page full of sliceinfo structs. +/// The size of a bucket is therefore 16kb * 682b which is just over 10.5 megabytes +/// * bucketinfo A slice containing an array of sliceinfo structs describing the contents of a bucket. +/// +/// The 1024 byte constant you might see popping up refers to the maximum number of 16 byte sliceinfo structs +/// can fit in a single 16kb slice. + + +#ifndef PAGE_ALLOC_H +#define PAGE_ALLOC_H + +#include +#include +#include "vm2.h" + +// TODO: detect memory size. +#define PAGEALLOC_TOP 0x8000000 // 128 MiB and less than all Peripheral bases + +#define SLICEINFO_PER_SLICE 1024 + +/// The type of a 16kib Slice +enum MemoryType { + L1PageTable, + L2PageTable, + Page, + BucketInfo, +}; + +struct Page { + uint8_t data[4096]; +}; + + +union MemorySlice; + +struct MemorySliceInfo { + union { + uint32_t entry; + struct { + enum MemoryType type: 2; + uint32_t filled: 16; + /// Filler bits + uint32_t unused: 14; + }; + }; + + struct MemorySliceInfo * next; + struct MemorySliceInfo * prev; + + union MemorySlice * slice; +}; + +/// A Memory slice of 16KB, that's also 16kb aligned. +/// A slice of 16kb can fit one of three things: +/// * 4 physical pages of 4kb +/// * 1 l1 pagetable of 16kb +/// * 16 l2 pagetabke of 1kb +/// * 682 (rounded down) MemorySliceInfo structs indexing other pages +union MemorySlice { + struct L1PageTable l1pt; + struct Page page[4]; + struct L2PageTable l2pt[16]; + // The sliceinfo array (bucketinfo) that contains the information of all Memoryslices in the next bucket. + struct MemorySliceInfo bucketinfo[SLICEINFO_PER_SLICE]; +}; + + +/// The page allocator allocates ***Physical*** pages. +struct PageAllocator { + /// Two linked lists of unused and allocated slices, referred to by their SliceInfos. + struct MemorySliceInfo * unused; + struct MemorySliceInfo * allocated; + + /// The partially allocated entries, these either exist or don't (NULL). + struct MemorySliceInfo * l2ptPartialFree; + struct MemorySliceInfo * pagePartialFree; + + /// The start address of the region we are allowed to allocate in. + size_t start; + /// The end address of the region we are allowed to allocate in. + size_t end; +}; + +struct PageAllocator pageallocator; + +// Allocator specific operations +void pagealloc_init(size_t start, size_t end); +struct MemorySliceInfo * allocate_new_sliceinfo_slice(); +struct MemorySliceInfo * pagealloc_get_sliceinfo_for_slice(union MemorySlice * slice); + + +// Element operations +struct L1PageTable * pagealloc_allocate_l1_pagetable(); +void pagealloc_free_l1_pagetable(struct L1PageTable * pt); +struct L2PageTable * pagealloc_allocate_l2_pagetable(); +void pagealloc_free_l2_pagetable(struct L2PageTable * pt); +struct Page * pagealloc_allocate_page(); +void pagealloc_free_page(struct Page * p); + +// Returns the index of the first zero from the LSB +size_t first_free(uint16_t); + +// MemorySliceInfo linked list helper functions. +void push_to_ll(struct MemorySliceInfo ** head, struct MemorySliceInfo * entry); +struct MemorySliceInfo * pop_from_ll(struct MemorySliceInfo ** head); +// It's important that for this function you give it the correct head. If it's not it may happen +// That the head you give it will be mixed up with the actual head of the list it was in. +void remove_element_ll(struct MemorySliceInfo ** head, struct MemorySliceInfo * entry); + +#endif diff --git a/kernel/src/memory/vm/include/vas2.h b/kernel/src/memory/vm/include/vas2.h new file mode 100644 index 00000000..ffe0be58 --- /dev/null +++ b/kernel/src/memory/vm/include/vas2.h @@ -0,0 +1,17 @@ +#ifndef VAS_2_H +#define VAS_2_H + +#include + +struct vas2 { + + struct L1PageTable * l1PageTable; + +}; + +struct L1PageTableAllocator { + +}; + + +#endif diff --git a/kernel/src/memory/vm/include/vm2.h b/kernel/src/memory/vm/include/vm2.h index 821d962d..7b945454 100644 --- a/kernel/src/memory/vm/include/vm2.h +++ b/kernel/src/memory/vm/include/vm2.h @@ -2,10 +2,7 @@ #define VM_H #include - -/// The L1 pagetable starts at 0x4000 and is itself 0x4000 bytes long. (0x1000 entries of 4 bytes). -/// The kernel starts at 0x8000 which is exactly at the end of the pagetable. (What a coincidence *gasp*) -#define L1PagetableLocation 0x4000 +#include /// A L1PagetableEntry is an entry in the top level pagetable. /// There is only one L1 pagetable and it is always located at address 0x4000. @@ -44,7 +41,7 @@ typedef union L1PagetableEntry{ /// Top 22 bits of the base address. Points to a L2 pagetable. /// formula: - /// base_address = (address >> 10) << 10; + /// base_address = (address >> 10); uint32_t base_address: 22; } coarse; @@ -136,8 +133,8 @@ typedef union L1PagetableEntry{ /// The top 8 bits now refer to a 16mb-large block /// /// formulae: - /// section_base_address = (address >> 20) << 20; - /// supersection_base_address = (address >> 24) << 24; + /// section_base_address = (address >> 20); + /// supersection_base_address = (address >> 24); uint32_t base_address: 12; } section; } L1PagetableEntry; @@ -197,7 +194,7 @@ typedef union { /// Top 16 bits of the base address. Pointer to the first byte in a 64kb-large block. /// formula: - /// base_address = (address >> 16) << 16; + /// base_address = (address >> 16); uint32_t base_address: 16; } __attribute__((packed)) largepage; @@ -248,7 +245,7 @@ typedef union { /// Top 20 bits of the base address. Pointer to the first byte in a 4kb-large block. /// formula: - /// base_address = (address >> 12) << 12; + /// base_address = (address >> 12); uint32_t base_address: 20; } __attribute__((packed)) smallpage; @@ -257,16 +254,38 @@ typedef union { struct L1PageTable { L1PagetableEntry entries[0x1000]; -} __attribute__((packed)); +}; struct L2PageTable { - L2PagetableEntry entries[0x400]; -} __attribute__((packed)); + L2PagetableEntry entries[0x100]; +}; + + void vm2_prepare(); void vm2_start(); void vm2_map_virtual_to_physical_l1(size_t virtual, size_t physical); void vm2_map_nmegabytes_1to1(size_t address, size_t n); +/// From the `kernel.ld` linker file. These are not arrays but this is how you refer to the pointers by the linker script. +extern const size_t KERNEL_BASE[]; // 0x8000 +extern const size_t KERNEL_TOP[]; +extern const size_t STACK_TOP[]; + +/// Above 3Gigs is the virtual kernel area, this also includes all Virtual Memory constructs, and the kernel stack. +#define KERNEL_VIRTUAL_OFFSET (3u * Gibibyte) + +/// Make the kernel start in virtual memory at 3GB +#define KERNEL_VIRTUAL_START (KERNEL_VIRTUAL_OFFSET + (size_t)KERNEL_BASE) +#define KERNEL_VIRTUAL_END (KERNEL_VIRTUAL_OFFSET + (size_t)KERNEL_TOP) + +/// The L1 pagetable starts at 0x4000 and is itself 0x4000 bytes long. (0x1000 entries of 4 bytes). +/// The kernel starts at 0x8000 which is exactly at the end of the pagetable. (What a coincidence *gasp*) +#define PhysicalL1PagetableLocation 0x4000 +#define VirtualL1PagetableLocation (KERNEL_VIRTUAL_OFFSET + PhysicalL1PagetableLocation) + +// The end of the kernel is guaranteed 1MiB aligned due to our linking script +#define VirtualL2PagetableLocation KERNEL_VIRTUAL_END +#define PhysicalL2PagetableLocation ((size_t)KERNEL_TOP) #endif diff --git a/kernel/src/memory/vm/pagealloc2.c b/kernel/src/memory/vm/pagealloc2.c new file mode 100644 index 00000000..bef46f43 --- /dev/null +++ b/kernel/src/memory/vm/pagealloc2.c @@ -0,0 +1,324 @@ +#include +#include +#include + + +void pagealloc_init(size_t start, size_t end) { + + // Create the first sliceinfo at the start address + struct MemorySliceInfo * firstinfo = (struct MemorySliceInfo *)start; + // This start address is itself a memory slice + union MemorySlice * firstslice = (union MemorySlice *)firstinfo; + + // Make the first sliceinfo describe this first slice. + firstinfo->next = NULL; + firstinfo->prev = NULL; + // It's type is sliceinfo + firstinfo->type = BucketInfo; + // It points to the first slice + firstinfo->slice = firstslice; + // And there's one sliceinfo struct in it. This first one. + firstinfo->filled = 1; + + // Now make an allocator with one sliceinfo in the allocated array. + pageallocator = (struct PageAllocator){ + .start = start, + .end = end, + .l2ptPartialFree = NULL, + .pagePartialFree = NULL, + .allocated = firstinfo, + .unused = NULL, + }; + + // the infoindex is 1 since we just allocated the 0th one above^^^ + size_t infoindex = 1; + union MemorySlice * currentslice = firstslice; + + + // Go through all memory and index it with sliceinfo structs. + // We start 1 Memoryslice after `start` because we already allocated the first one at the start of this function. + for (union MemorySlice* i = ((union MemorySlice *)start + 1); i < ((union MemorySlice *)end); i ++) { + + struct MemorySliceInfo * currentsliceinfo = ¤tslice->bucketinfo[infoindex]; + + // make this sliceinfo struct point to the right slice + currentsliceinfo->slice = i; + + // Add the sliceinfo to the unused list + push_to_ll(&pageallocator.unused, currentsliceinfo); + + // continue to the next sliceinfo + infoindex++; + + if (infoindex >= SLICEINFO_PER_SLICE) { + // We can now do this as we already made at least one new sliceinfo struct on the unused list + // Which we can use for this. + currentslice = allocate_new_sliceinfo_slice()->slice; + infoindex = 0; + } + } +} + +struct MemorySliceInfo * allocate_new_sliceinfo_slice() { + // Take a slice from the unused list and the the next one to the top of unused. + struct MemorySliceInfo * sliceinfo = pop_from_ll(&pageallocator.unused); + + // Change it's type to typeinfo + sliceinfo->type = BucketInfo; + sliceinfo->filled = 0; + + // Add it to the allocated list + push_to_ll(&pageallocator.allocated, sliceinfo); + + + return sliceinfo; +} + +struct MemorySliceInfo * pagealloc_get_sliceinfo_for_slice(union MemorySlice * slice) { + + // TODO: think about changing SLICEINFO_PER_SLICE to 512 instead of 682. This adds quite some memory overhead + // TODO: but makes the division and multiplication below a lot faster. (or even unnecessary as it can be replaced with a single logical AND) + const int bucketsize = (SLICEINFO_PER_SLICE * sizeof(union MemorySlice)); + + // Take the address of the slice and determine in which bucket it falls. + // each bucket is a sliceinfo struct describing a slice with sliceinfo structs in it. + // The buckets therefore describes (682 * 16K) blocks. + + size_t offset_from_allocator_start = (size_t)slice - pageallocator.start; + + // divide by blocksize + size_t bucketindex = (offset_from_allocator_start) / (bucketsize); + + // We need a small correction factor. Normally the bucketinfo + // slice for a bucket sits in the *last* slice of the previous bucket. + // However, for the first bucket, the bucketinfo slice is actually the + // *first* slice in the bucket + size_t correction; + if (bucketindex == 0) { + correction = 0; + } else { + correction = 1; + } + + // Multiply by blocksize again (NOTE: this is so we round down! The division and multiplication DO NOT CANCEL OUT) + // Subtract two as the bucket is actually the last page of the previous bucket. + union MemorySlice * bucketinfo = ((union MemorySlice *)(pageallocator.start + bucketindex * bucketsize)) - correction; + + // The first non-information slice in a bucket is always the slice after the information slice. + // Except for the first bucket. + size_t first_address_in_bucket = (size_t)(bucketinfo + correction); + + // now calculate how many times 16kb we are away from this. + // first_address_in_bucket - offset_from_allocator_start + size_t index = ((size_t)slice - first_address_in_bucket) / sizeof(union MemorySlice); + + struct MemorySliceInfo * info = &bucketinfo->bucketinfo[index]; + + return info; +} + +void pagealloc_free_l1_pagetable(struct L1PageTable * pt) { + + if (pt == NULL) { + return; + } + + struct MemorySliceInfo * sliceinfo = pagealloc_get_sliceinfo_for_slice((union MemorySlice *) pt); + + remove_element_ll(&pageallocator.allocated, sliceinfo); + + // now push it on the unused list. + push_to_ll(&pageallocator.unused, sliceinfo); + + // Since it's the first thing on the unused list, make prev null. + sliceinfo->prev = NULL; + +} + +struct L1PageTable * pagealloc_allocate_l1_pagetable() { + + if(pageallocator.unused == NULL) { + return NULL; + } + + // Take a slice from the unused list. + struct MemorySliceInfo * sliceinfo = pop_from_ll(&pageallocator.unused); + + // Change it's type to typeinfo + sliceinfo->type = L1PageTable; + + // Put it on the allocated stack + push_to_ll(&pageallocator.allocated, sliceinfo); + + return &sliceinfo->slice->l1pt; +} + +struct L2PageTable * pagealloc_allocate_l2_pagetable() { + // First test if there's a partial allocated l2 pagetable + if (pageallocator.l2ptPartialFree != NULL) { + + struct MemorySliceInfo * sliceinfo = pageallocator.l2ptPartialFree; + + uint32_t index = first_free(sliceinfo->filled); + + struct L2PageTable * newl2pt = &sliceinfo->slice->l2pt[index]; + + sliceinfo->filled |= (1u << index); + + // If it is filled + if(sliceinfo->filled == 0xffff) { + // Remove from the partial free list + // We can ignore the return value here as we already got it. + pop_from_ll(&pageallocator.l2ptPartialFree); + + // add to allocated list + push_to_ll(&pageallocator.allocated, sliceinfo); + } + + return newl2pt; + } else { + struct MemorySliceInfo * sliceinfo = pop_from_ll(&pageallocator.unused); + + // Change it's type to typeinfo + sliceinfo->type = L2PageTable; + sliceinfo->filled = 1; + + // Put it on the partially allocated list + push_to_ll(&pageallocator.l2ptPartialFree, sliceinfo); + + return &sliceinfo->slice->l2pt[0]; + } +} + +struct Page * pagealloc_allocate_page() { + // First test if there's a partial allocated page page + if (pageallocator.pagePartialFree != NULL) { + + struct MemorySliceInfo * sliceinfo = pageallocator.pagePartialFree; + + uint32_t index = first_free(sliceinfo->filled); + + + struct Page * newpage = &sliceinfo->slice->page[index]; + + sliceinfo->filled |= (1u << index); + + // If it is filled + if(sliceinfo->filled == 0xf) { + // Remove from the partial free list + // We can ignore the return value here as we already got it. + pop_from_ll(&pageallocator.pagePartialFree); + + // add to allocated list + push_to_ll(&pageallocator.allocated, sliceinfo); + } + + return newpage; + } else { + struct MemorySliceInfo * sliceinfo = pop_from_ll(&pageallocator.unused); + + // Change it's type to typeinfo + sliceinfo->type = Page; + sliceinfo->filled = 0b0001; + + // Put it on the partially allocated list + push_to_ll(&pageallocator.pagePartialFree, sliceinfo); + + return &sliceinfo->slice->page[0]; + } +} + +void pagealloc_free_page(struct Page * p) { + // works cuz rounding (we think, might just work because random luck) + struct MemorySliceInfo * info = pagealloc_get_sliceinfo_for_slice((union MemorySlice *) p); + + if (info->filled == 0xf) { + remove_element_ll(&pageallocator.allocated, info); + } else { + remove_element_ll(&pageallocator.pagePartialFree, info); + } + + // compute which subelement we are + size_t offset_from_slice_start = ((size_t)p - (size_t)info->slice); + size_t index_in_slice = offset_from_slice_start / sizeof(struct Page); + + // correctly clear the bit from filled + info->filled &= ~(1u << index_in_slice); + + // if there was only one l2pt in this slice, put it on unallocated + if(info->filled == 00) { + push_to_ll(&pageallocator.unused, info); + } else { + push_to_ll(&pageallocator.pagePartialFree, info); + } +} + +void pagealloc_free_l2_pagetable(struct L2PageTable * pt) { + // works cuz rounding (we think, might just work because random luck) + struct MemorySliceInfo * info = pagealloc_get_sliceinfo_for_slice((union MemorySlice *) pt); + + if (info->filled == 0xffff) { + remove_element_ll(&pageallocator.allocated, info); + } else { + remove_element_ll(&pageallocator.l2ptPartialFree, info); + } + + // compute which subelement we are + size_t offset_from_slice_start = ((size_t)pt - (size_t)info->slice); + size_t index_in_slice = offset_from_slice_start / sizeof(struct L2PageTable); + + // correctly clear the bit from filled + info->filled &= ~(1u << index_in_slice); + + // if there was only one l2pt in this slice, put it on unallocated + if(info->filled == 00) { + push_to_ll(&pageallocator.unused, info); + } else { + push_to_ll(&pageallocator.l2ptPartialFree, info); + } +} + + +void push_to_ll(struct MemorySliceInfo ** head, struct MemorySliceInfo * entry) { + if (*head != NULL) { + (*head)->prev = entry; + } + entry->next = *head; + *head = entry; +} + +struct MemorySliceInfo * pop_from_ll(struct MemorySliceInfo ** head) { + struct MemorySliceInfo * top = *head; + *head = (*head)->next; + if(*head != NULL){ + (*head)->prev = NULL; + } + + top->next = NULL; + top->prev = NULL; + + return top; +} + +void remove_element_ll(struct MemorySliceInfo ** head, struct MemorySliceInfo * entry) { + if (entry->next != NULL) { + entry->next->prev = entry->prev; + } + + if (entry->prev != NULL) { + entry->prev->next = entry->next; + } else { + *head = entry->next; + } + + entry->next = NULL; + entry->prev = NULL; +} + +size_t first_free(uint16_t filled) { + filled = ~filled; + // 32 because clz on arm counts from the 32nd aka most significant bit. + return 32u - __builtin_clz(filled & (uint16_t)(-filled)) - 1u; +} + + diff --git a/kernel/src/memory/vm/test/test_pagealloc2.c b/kernel/src/memory/vm/test/test_pagealloc2.c new file mode 100644 index 00000000..1ae48a27 --- /dev/null +++ b/kernel/src/memory/vm/test/test_pagealloc2.c @@ -0,0 +1,278 @@ +#include +#include +#include + +size_t listlength(struct MemorySliceInfo * start) { + if (start == NULL) { + return 0; + } + + size_t count = 1; + for (; start->next != NULL; start = start->next) { + count++; + } + + return count; +} + +TEST_CREATE(test_memoryinfo_size, { + ASSERT_EQ(sizeof(struct MemorySliceInfo), 16); +}) + +TEST_CREATE(test_empty, { + ASSERT_NOT_NULL(pageallocator.unused); + ASSERT_EQ(listlength(pageallocator.unused),1278); + ASSERT_EQ(listlength(pageallocator.allocated), 2); + ASSERT_NULL(pageallocator.l2ptPartialFree); + ASSERT_NULL(pageallocator.pagePartialFree); +}) + +TEST_CREATE(test_allocate_pt, { + struct L1PageTable * pt = pagealloc_allocate_l1_pagetable(); + + // Just try to overwrite everything a few times so if something breaks we'll hopefully see in the next tests. + memset(pt, 0, 1024 * 16); + memset(pt, 1, 1024 * 16); + + + ASSERT_NOT_NULL(pageallocator.unused); + ASSERT_EQ(listlength(pageallocator.unused), 1277); + ASSERT_NOT_NULL(pageallocator.allocated); + ASSERT_EQ(listlength(pageallocator.allocated), 3); + ASSERT_NULL(pageallocator.l2ptPartialFree); + ASSERT_NULL(pageallocator.pagePartialFree); + + pagealloc_free_l1_pagetable(pt); + + ASSERT_EQ(listlength(pageallocator.unused), 1278); + ASSERT_EQ(listlength(pageallocator.allocated), 2); +}) + +TEST_CREATE(test_allocate_many_pt, { + int total = listlength(pageallocator.unused); + int totalallocated = listlength(pageallocator.allocated); + + struct L1PageTable * pages[700]; + + for (int i = 0; i < 700; i++) { + + pages[i] = pagealloc_allocate_l1_pagetable(); + ASSERT_NOT_NULL(pages[i]); + ASSERT_EQ(listlength(pageallocator.unused), total - (i + 1u)); + ASSERT_EQ(listlength(pageallocator.allocated), totalallocated + i + 1); + } + + struct L1PageTable * pt = pagealloc_allocate_l1_pagetable(); + + ASSERT_NOT_NULL(pageallocator.unused); + ASSERT_EQ(listlength(pageallocator.unused), 577); + ASSERT_NOT_NULL(pageallocator.allocated); + + ASSERT_EQ(listlength(pageallocator.allocated), 703); + ASSERT_NULL(pageallocator.l2ptPartialFree); + ASSERT_NULL(pageallocator.pagePartialFree); + + pagealloc_free_l1_pagetable(pt); + + for (int i = 0; i < 700; i++) { + pagealloc_free_l1_pagetable(pages[i]); + } + + + ASSERT_NOT_NULL(pageallocator.unused); + ASSERT_EQ(listlength(pageallocator.unused),1278); + ASSERT_EQ(listlength(pageallocator.allocated), 2); + ASSERT_NULL(pageallocator.l2ptPartialFree); + ASSERT_NULL(pageallocator.pagePartialFree); +}) + +// Test the magic :sparkles: +TEST_CREATE(test_get_sliceinfo, { + struct L1PageTable * pt = pagealloc_allocate_l1_pagetable(); + + struct MemorySliceInfo * info = pagealloc_get_sliceinfo_for_slice((union MemorySlice *)pt); + + ASSERT_EQ(&info->slice->l1pt, pt); + + pagealloc_free_l1_pagetable(pt); +}) + +TEST_CREATE(test_doubly_linked_sliceinfo, { + struct MemorySliceInfo * curr = pageallocator.unused; + uint32_t length = listlength(curr); + + uint32_t i = 0; + do { + i++; + ASSERT_EQ(curr->next->prev, curr); + curr = curr->next; + } while(curr->next != NULL); + + ASSERT_EQ(i, length-1); +}) + +TEST_CREATE(test_allocate_l2pt, { + // Save how many slices are allocated now + size_t totalallocated = listlength(pageallocator.allocated); + + // the l2ptPartialFree should start empty + ASSERT_NULL(pageallocator.l2ptPartialFree); + + struct L2PageTable * pt1 = pagealloc_allocate_l2_pagetable(); + // After one allocation, it shouldn't be empty anymore + ASSERT_NOT_NULL(pageallocator.l2ptPartialFree); + // But it's length should be only one + ASSERT_NULL(pageallocator.l2ptPartialFree->next); + // The #allocated should have stayed the same as this node goes on l2ptPartialFree + ASSERT_EQ(listlength(pageallocator.allocated), totalallocated); + + struct L2PageTable * pages[15]; + + for (int i = 0; i < 14; i++) { + pages[i] = pagealloc_allocate_l2_pagetable(); + ASSERT_NULL(pageallocator.l2ptPartialFree->next); + } + pages[14] = pagealloc_allocate_l2_pagetable(); + + ASSERT_NULL(pageallocator.l2ptPartialFree); + + ASSERT_EQ(totalallocated + 1u, listlength(pageallocator.allocated)); + + // Now as we allocate a 17th l1 pagetable, the #allocated should have grown by one + struct L2PageTable * pt17 = pagealloc_allocate_l2_pagetable(); + ASSERT_EQ(listlength(pageallocator.allocated), totalallocated + 1u); + // but l2ptPartialFree should now be of length one again + ASSERT_NOT_NULL(pageallocator.l2ptPartialFree); + ASSERT_NULL(pageallocator.l2ptPartialFree->next); + + ASSERT_EQ(pt1 + 1, pages[0]); + + // Assert pt2 comes after pt1 etc. + for (int i = 0; i < 14; i++) { + ASSERT_EQ(pages[i] + 1, pages[i+1]); + } + + pagealloc_free_l2_pagetable(pt17); + + for (int i = 0; i < 15; i++) { + pagealloc_free_l2_pagetable(pages[i]); + } + + pagealloc_free_l2_pagetable(pt1); + + + ASSERT_NOT_NULL(pageallocator.unused); + ASSERT_EQ(listlength(pageallocator.unused),1278); + ASSERT_EQ(listlength(pageallocator.allocated), 2); + ASSERT_NULL(pageallocator.l2ptPartialFree); + ASSERT_NULL(pageallocator.pagePartialFree); + + + for (int i = 0; i < 100; i++) { + struct L2PageTable * pages2[100]; + + // Allocate 100 l2pts + for (int i = 0; i < 100; i++) { + pages2[i] = pagealloc_allocate_l2_pagetable(); + } + + // Now free them in a very different order + for (int i = 0; i < 50; i++) { + pagealloc_free_l2_pagetable(pages2[i]); + pagealloc_free_l2_pagetable(pages2[99-i]); + } + + ASSERT_NOT_NULL(pageallocator.unused); + ASSERT_EQ(listlength(pageallocator.unused),1278); + ASSERT_EQ(listlength(pageallocator.allocated), 2); + ASSERT_NULL(pageallocator.l2ptPartialFree); + ASSERT_NULL(pageallocator.pagePartialFree); + } +}) + +TEST_CREATE(test_allocate_page, { + // Save how many slices are allocated now + size_t totalallocated = listlength(pageallocator.allocated); + + // the l2ptPartialFree should start empty + ASSERT_NULL(pageallocator.pagePartialFree); + + struct Page * p1 = pagealloc_allocate_page(); + // After one allocation, it shouldn't be empty anymore + ASSERT_NOT_NULL(pageallocator.pagePartialFree); + // But it's length should be only one + ASSERT_NULL(pageallocator.pagePartialFree->next); + // The #allocated should have stayed the same as this node goes on l2ptPartialFree + ASSERT_EQ(listlength(pageallocator.allocated), totalallocated); + + struct Page * pages[3]; + + for (int i = 0; i < 2; i++) { + pages[i] = pagealloc_allocate_page(); + ASSERT_NULL(pageallocator.pagePartialFree->next); + } + pages[2] = pagealloc_allocate_page(); + + ASSERT_NULL(pageallocator.pagePartialFree); + + ASSERT_EQ(totalallocated + 1u, listlength(pageallocator.allocated)); + + // Now as we allocate a 17th l1 pagetable, the #allocated should have grown by one + struct Page * p17 = pagealloc_allocate_page(); + ASSERT_EQ(listlength(pageallocator.allocated), totalallocated + 1u); + // but l2ptPartialFree should now be of length one again + ASSERT_NOT_NULL(pageallocator.pagePartialFree); + ASSERT_NULL(pageallocator.pagePartialFree->next); + + ASSERT_EQ(p1 + 1, pages[0]); + + // Assert pt2 comes after pt1 etc. + for (int i = 0; i < 2; i++) { + ASSERT_EQ(pages[i] + 1, pages[i+1]); + } + + pagealloc_free_page(p17); + + for (int i = 0; i < 3; i++) { + pagealloc_free_page(pages[i]); + } + + pagealloc_free_page(p1); + + + ASSERT_NOT_NULL(pageallocator.unused); + ASSERT_EQ(listlength(pageallocator.unused),1278); + ASSERT_EQ(listlength(pageallocator.allocated), 2); + ASSERT_NULL(pageallocator.l2ptPartialFree); + ASSERT_NULL(pageallocator.pagePartialFree); + + + for (int i = 0; i < 100; i++) { + struct Page * pages2[100]; + + // Allocate 100 l2pts + for (int i = 0; i < 100; i++) { + pages2[i] = pagealloc_allocate_page(); + } + + // Now free them in a very different order + for (int i = 0; i < 50; i++) { + pagealloc_free_page(pages2[i]); + pagealloc_free_page(pages2[99-i]); + } + + ASSERT_NOT_NULL(pageallocator.unused); + ASSERT_EQ(listlength(pageallocator.unused),1278); + ASSERT_EQ(listlength(pageallocator.allocated), 2); + ASSERT_NULL(pageallocator.l2ptPartialFree); + ASSERT_NULL(pageallocator.pagePartialFree); + } +}) + +TEST_CREATE(test_first_free, { + ASSERT_EQ(first_free(0b000010), 0); + ASSERT_EQ(first_free(0b000011), 2); + ASSERT_EQ(first_free(0b000111), 3); + ASSERT_EQ(first_free(0b111101), 1); + ASSERT_EQ(first_free(0b111111), 6); +}) diff --git a/kernel/src/memory/vm/vas2.c b/kernel/src/memory/vm/vas2.c new file mode 100644 index 00000000..72a2b50d --- /dev/null +++ b/kernel/src/memory/vm/vas2.c @@ -0,0 +1,4 @@ +#include + + + diff --git a/kernel/src/memory/vm/vm.c b/kernel/src/memory/vm/vm.c index bd64c2e4..785efd16 100644 --- a/kernel/src/memory/vm/vm.c +++ b/kernel/src/memory/vm/vm.c @@ -44,7 +44,7 @@ void vm_init() struct vm_free_list * free_vas = (struct vm_free_list*) P_L1PTBASE; kprintf("free_vas start location 0x%x\n", free_vas); -// vm_vas_free_list = free_vas; + // vm_vas_free_list = free_vas; vm_vas_free_list = (struct vm_free_list*) ((void*) free_vas + V_L1PTBASE - P_L1PTBASE); struct vm_free_list *last = 0x0; while ((uint32_t) free_vas < P_L1PTBASE + sizeof(struct vas) * num_vas) diff --git a/kernel/src/memory/vm/vm2.c b/kernel/src/memory/vm/vm2.c index 9835539e..a61e0714 100644 --- a/kernel/src/memory/vm/vm2.c +++ b/kernel/src/memory/vm/vm2.c @@ -2,8 +2,12 @@ #include #include #include +#include +#include +#include -struct L1PageTable * l1PageTable = (struct L1PageTable *) L1PagetableLocation; +struct L1PageTable * kernell1PageTable = (struct L1PageTable *) PhysicalL1PagetableLocation; +struct L1PageTable * virtualkernell1PageTable = (struct L1PageTable *) VirtualL1PagetableLocation; bool mmu_started = false; static inline size_t l1pt_index(size_t address) { @@ -18,10 +22,11 @@ void vm2_map_virtual_to_physical_l1(size_t virtual, size_t physical) { panic(); } - if (l1PageTable->entries[l1pt_index(virtual)].entry != 0){ + if (kernell1PageTable->entries[l1pt_index(virtual)].entry != 0){ // The entry is already mapped kprintf("Request for already mapped address denied"); panic(); + } L1PagetableEntry entry = { @@ -33,32 +38,60 @@ void vm2_map_virtual_to_physical_l1(size_t virtual, size_t physical) { .section.accessExtended = 0, // r/w access .section.supersection = 0, .section.nonSecure = 1, - .section.base_address = (physical >> 20u) << 20u, + .section.base_address = l1pt_index(physical), }; - l1PageTable->entries[l1pt_index(virtual)] = entry; + kprintf("Mapping 1mb at virtual: 0x%x to physical: 0x%x\n", l1pt_index(virtual) << 20u, l1pt_index(physical)<<20u); + + kernell1PageTable->entries[l1pt_index(virtual)] = entry; } void vm2_map_nmegabytes_1to1(size_t address, size_t n) { + if(n == 0) { + panic(); + } + // Iterate over the address in 1 MiB chunks. - for (; address < (address + 0x100000u * n) ; address += 0x100000u) { - kprintf("mapping address 0x%x 1:1\n", address); - vm2_map_virtual_to_physical_l1(address, address); + for (size_t newaddress = address; newaddress < (address + Mibibyte * n) ; newaddress += Mibibyte) { + vm2_map_virtual_to_physical_l1(newaddress, newaddress); } } // Prepares the pagetable and add void vm2_prepare() { // Clear the pagetable - memset(l1PageTable, 0, sizeof(struct L1PageTable)); + memset(kernell1PageTable, 0, sizeof(struct L1PageTable)); +} - vm2_map_nmegabytes_1to1(0, 1); -} // Starts the actual MMU after this function we live in Virtual Memory void vm2_start() { + // Temporary, TODO: new range + pagealloc_init(Gibibyte - 25 * Mibibyte, Gibibyte - 5 * Mibibyte); + + /// Identitymap the kernel and the stack. The kernel starts at 0x8000 but we already + /// start mapping at 0x0000 as this is the first address before 0x8000 that's megabyte + /// aligned. This has as a nice bonus that we also identitymap the L1 pagetable + /// which lives at L1PagetableLocation=0x4000, and the interrupt vectors at 0x0. + /// FIXME: We want to _eventually_ switch to a fully higher half kernel + for (size_t i = 0; i < (size_t)KERNEL_TOP; i += Mibibyte) { + vm2_map_nmegabytes_1to1(i, 1); + } + + /// Map the kernel and the stack a second time to high virtual memory. Again this also + /// maps the l1 pagetable here and the interrupt vectors at 0x0. + for (size_t i = 0; i < (size_t)KERNEL_TOP; i += Mibibyte) { + vm2_map_virtual_to_physical_l1(KERNEL_VIRTUAL_START + i, i); + } + + /// Map 1 megabyte for the kernel L2 pagetables. + vm2_map_virtual_to_physical_l1(VirtualL2PagetableLocation, PhysicalL2PagetableLocation); + kprintf("KERNEL_TOP: 0x%x, KERNEL_BASE: 0x%x\n", KERNEL_TOP, KERNEL_BASE); mmu_started = true; } + + + diff --git a/kernel/src/process/include/process.h b/kernel/src/process/include/process.h index 3a9c75cc..1073c5e1 100644 --- a/kernel/src/process/include/process.h +++ b/kernel/src/process/include/process.h @@ -56,11 +56,11 @@ typedef enum PROCESS_STATE #define MAX_PROCESSES 32 -#define STACK_BASE 0x9f000000 +#define P_STACK_BASE 0x9f000000 #define PROC_LOCATION 0x9ff00000 -#define STACK_SIZE (BLOCK_SIZE) -#define STACK_TOP (STACK_BASE + STACK_SIZE) -#define HEAP_BASE 0x90000000 +#define P_STACK_SIZE (BLOCK_SIZE) +#define P_STACK_TOP (P_STACK_BASE + P_STACK_SIZE) +#define HEAP_BASE 0x90000000 typedef struct pcb { diff --git a/kernel/src/process/process.c b/kernel/src/process/process.c index c89c42b3..bd2765fd 100644 --- a/kernel/src/process/process.c +++ b/kernel/src/process/process.c @@ -134,10 +134,10 @@ void __process_elf_init(pcb* pcb_p, const char* name) { */ void __process_stack_init(pcb * pcb_p) { int retval = 0; - for (int i = 0; i < (STACK_SIZE / BLOCK_SIZE); i++) + for (int i = 0; i < (P_STACK_SIZE / BLOCK_SIZE); i++) { retval = vm_allocate_page(pcb_p->stored_vas, - (void*) (STACK_BASE + (i * BLOCK_SIZE)), VM_PERM_USER_RW); + (void*) (P_STACK_BASE + (i * BLOCK_SIZE)), VM_PERM_USER_RW); if (retval) { kprintf("vm_allocate_page error code: %d\n", retval); @@ -147,29 +147,29 @@ void __process_stack_init(pcb * pcb_p) { { kprintf( "A page have been allocated for process stack at vptr: 0x%x\n", - (STACK_BASE + (i * BLOCK_SIZE))); + (P_STACK_BASE + (i * BLOCK_SIZE))); } vm_map_shared_memory(KERNEL_VAS, - (void*) (STACK_BASE + (i * BLOCK_SIZE)), pcb_p->stored_vas, - (void*) (STACK_BASE + (i * BLOCK_SIZE)), VM_PERM_USER_RW); + (void*) (P_STACK_BASE + (i * BLOCK_SIZE)), pcb_p->stored_vas, + (void*) (P_STACK_BASE + (i * BLOCK_SIZE)), VM_PERM_USER_RW); } // Stick a NULL at STACK_TOP-sizeof(int*) - uint32_t *stack_top = (uint32_t*) STACK_TOP; + uint32_t *stack_top = (uint32_t*) P_STACK_TOP; stack_top[-1] = 0; stack_top[-2] = 0; stack_top[-3] = 0; stack_top[-4] = 0; - stack_top[-5] = STACK_BASE; + stack_top[-5] = P_STACK_BASE; stack_top[-6] = 1; - strcpy((char*) STACK_BASE, pcb_p->name); + strcpy((char*) P_STACK_BASE, pcb_p->name); // We need to set sp (r13) to stack_top - 12 - pcb_p->R13 = STACK_TOP - 4 * 6; - for (int i = 0; i < (STACK_SIZE / BLOCK_SIZE); i++) + pcb_p->R13 = P_STACK_TOP - 4 * 6; + for (int i = 0; i < (P_STACK_SIZE / BLOCK_SIZE); i++) { - vm_free_mapping(KERNEL_VAS, (void*) (STACK_BASE + (i * BLOCK_SIZE))); + vm_free_mapping(KERNEL_VAS, (void*) (P_STACK_BASE + (i * BLOCK_SIZE))); } } diff --git a/kernel/src/test/include/test.h b/kernel/src/test/include/test.h index c5f569c4..b9217b90 100644 --- a/kernel/src/test/include/test.h +++ b/kernel/src/test/include/test.h @@ -67,6 +67,7 @@ #define ASSERT_LTEQ(l, r) do { if(l > r) { kprintf("failed assertion: %s at ASSERT_LTEQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) #define ASSERT_NEQ(l, r) do { if(l == r) { kprintf("failed assertion: %s at ASSERT_NEQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) #define ASSERT_NOT_NULL(e) do { if(e == NULL) { kprintf("failed assertion: %s\n at ASSERT_NOT_NULL(%s)", __FILE__, #e); return TEST_FAIL; } } while(0) +#define ASSERT_NULL(e) do { if(e != NULL) { kprintf("failed assertion: %s\n at ASSERT_NULL(%s)", __FILE__, #e); return TEST_FAIL; } } while(0) #else From d274feb38e806e0649da0a6253b559db58adddf3 Mon Sep 17 00:00:00 2001 From: Dany Sluijk Date: Thu, 5 Mar 2020 19:08:24 +0100 Subject: [PATCH 036/104] feat: add initial process, thread and scheduler --- .../src/process/scheduler/include/process.h | 22 ++++++++ .../src/process/scheduler/include/registers.h | 50 +++++++++++++++++++ .../src/process/scheduler/include/scheduler.h | 13 +++++ kernel/src/process/scheduler/include/thread.h | 22 ++++++++ kernel/src/process/scheduler/process.c | 29 +++++++++++ kernel/src/process/scheduler/scheduler.c | 15 ++++++ .../src/process/scheduler/test/process_test.c | 20 ++++++++ .../process/scheduler/test/scheduler_test.c | 10 ++++ .../src/process/scheduler/test/thread_test.c | 14 ++++++ kernel/src/process/scheduler/thread.c | 24 +++++++++ 10 files changed, 219 insertions(+) create mode 100644 kernel/src/process/scheduler/include/process.h create mode 100644 kernel/src/process/scheduler/include/registers.h create mode 100644 kernel/src/process/scheduler/include/scheduler.h create mode 100644 kernel/src/process/scheduler/include/thread.h create mode 100644 kernel/src/process/scheduler/process.c create mode 100644 kernel/src/process/scheduler/scheduler.c create mode 100644 kernel/src/process/scheduler/test/process_test.c create mode 100644 kernel/src/process/scheduler/test/scheduler_test.c create mode 100644 kernel/src/process/scheduler/test/thread_test.c create mode 100644 kernel/src/process/scheduler/thread.c diff --git a/kernel/src/process/scheduler/include/process.h b/kernel/src/process/scheduler/include/process.h new file mode 100644 index 00000000..9bc6433f --- /dev/null +++ b/kernel/src/process/scheduler/include/process.h @@ -0,0 +1,22 @@ +#ifndef COURSE_OS_PROCESS_H +#define COURSE_OS_PROCESS_H + +#include +#include + +#define MAX_PROCESS_PRIORITY 20 +#define DEFAULT_PROCESS_PRIORITY 10 + +typedef struct Process { + uint8_t priority; + size_t pid; + uint8_t exit_code; + struct vas* vas; + VPArrayList *threads; + struct Process *parent; +} Process; + +Process *create_process(void *entry, Process *parent); +void free_process(Process *process); + +#endif //COURSE_OS_PROCESS_H diff --git a/kernel/src/process/scheduler/include/registers.h b/kernel/src/process/scheduler/include/registers.h new file mode 100644 index 00000000..94b5b7ae --- /dev/null +++ b/kernel/src/process/scheduler/include/registers.h @@ -0,0 +1,50 @@ +#ifndef COURSE_OS_REGISTERS_H +#define COURSE_OS_REGISTERS_H + +#include + +typedef struct Registers { + size_t R0; + size_t R1; + size_t R2; + size_t R3; + size_t R4; + size_t R5; + size_t R6; + union { + size_t R7; + size_t WR; + }; + size_t R8; + union { + size_t R9; + size_t SB; + }; + union { + size_t R10; + size_t SL; + }; + union { + size_t R11; + size_t FP; + }; + union { + size_t R12; + size_t IP; + }; + union { + size_t R13; + size_t SP; + }; + union { + size_t R14; + size_t LR; + }; + union { + size_t R15; + size_t PC; + }; + size_t CPSR; +} Registers; + +#endif //COURSE_OS_REGISTERS_H diff --git a/kernel/src/process/scheduler/include/scheduler.h b/kernel/src/process/scheduler/include/scheduler.h new file mode 100644 index 00000000..fcd3c859 --- /dev/null +++ b/kernel/src/process/scheduler/include/scheduler.h @@ -0,0 +1,13 @@ +#ifndef COURSE_OS_SCHEDULER_H +#define COURSE_OS_SCHEDULER_H + +#include + +typedef struct Scheduler { + Thread *current_thread; +} Scheduler; + +Scheduler *create_scheduler(); +void free_scheduler(Scheduler *scheduler); + +#endif //COURSE_OS_SCHEDULER_H diff --git a/kernel/src/process/scheduler/include/thread.h b/kernel/src/process/scheduler/include/thread.h new file mode 100644 index 00000000..a4574415 --- /dev/null +++ b/kernel/src/process/scheduler/include/thread.h @@ -0,0 +1,22 @@ +#ifndef COURSE_OS_THREAD_H +#define COURSE_OS_THREAD_H + +#include "./process.h" +#include "./registers.h" + +typedef enum ThreadState { + Runnable, + Running, + Died, +} ThreadState; + +typedef struct Thread { + Registers registers; + Process *process; + ThreadState state; +} Thread; + +Thread *create_thread(void *entry, Process *process); +void free_thread(Thread *thread); + +#endif //COURSE_OS_THREAD_H diff --git a/kernel/src/process/scheduler/process.c b/kernel/src/process/scheduler/process.c new file mode 100644 index 00000000..4f1153a1 --- /dev/null +++ b/kernel/src/process/scheduler/process.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include + +#include "./include/process.h" +#include "./include/thread.h" + +Process *create_process(void *entry, Process *parent) { + Process *process = kmalloc(sizeof(Process)); + + process->parent = parent; + process->priority = DEFAULT_PROCESS_PRIORITY; + process->vas = vm_new_vas(); + process->threads = vpa_create(10); + + Thread *thread = create_thread(entry, process); + vpa_push(process->threads, thread); + + return process; +} + +void free_process(Process *process) { + vm_free_vas(process->vas); + vpa_free(process->threads, (FreeFunc) free_thread); + + kfree(process); +} diff --git a/kernel/src/process/scheduler/scheduler.c b/kernel/src/process/scheduler/scheduler.c new file mode 100644 index 00000000..72557377 --- /dev/null +++ b/kernel/src/process/scheduler/scheduler.c @@ -0,0 +1,15 @@ +#include +#include + +#include "./include/scheduler.h" + +Scheduler *create_scheduler() { + Scheduler *scheduler = kmalloc(sizeof(Scheduler)); + scheduler->current_thread = NULL; + + return scheduler; +} + +void free_scheduler(Scheduler *scheduler) { + kfree(scheduler); +} diff --git a/kernel/src/process/scheduler/test/process_test.c b/kernel/src/process/scheduler/test/process_test.c new file mode 100644 index 00000000..c041467e --- /dev/null +++ b/kernel/src/process/scheduler/test/process_test.c @@ -0,0 +1,20 @@ +#include +#include +#include + +#include "../include/process.h" + +TEST_CREATE(test_process_smoke, { + Process *process = create_process((void *) 63, NULL); + + ASSERT_EQ(process->priority, DEFAULT_PROCESS_PRIORITY); + ASSERT_NOT_NULL(process->vas); + ASSERT_NOT_NULL(vpa_get(process->threads, 0)); + ASSERT_EQ(vpa_get(process->threads, 1), NULL); + + Thread *thread = vpa_get(process->threads, 0); + ASSERT_EQ(thread->registers.PC, 63); + ASSERT_EQ(thread->process, process); + + free_process(process); +}); diff --git a/kernel/src/process/scheduler/test/scheduler_test.c b/kernel/src/process/scheduler/test/scheduler_test.c new file mode 100644 index 00000000..e56f4ed2 --- /dev/null +++ b/kernel/src/process/scheduler/test/scheduler_test.c @@ -0,0 +1,10 @@ +#include +#include + +#include "../include/scheduler.h" + +TEST_CREATE(test_scheduler_smoke, { + Scheduler *scheduler = create_scheduler(); + + free_scheduler(scheduler); +}); diff --git a/kernel/src/process/scheduler/test/thread_test.c b/kernel/src/process/scheduler/test/thread_test.c new file mode 100644 index 00000000..2927b503 --- /dev/null +++ b/kernel/src/process/scheduler/test/thread_test.c @@ -0,0 +1,14 @@ +#include +#include + +#include + +TEST_CREATE(test_thread_smoke, { + Thread *thread = create_thread((void *) 42, NULL); + + ASSERT_EQ(thread->state, Runnable); + ASSERT_EQ(thread->registers.PC, 42); + ASSERT_NEQ(thread->registers.SP, 0); + + free_thread(thread); +}); diff --git a/kernel/src/process/scheduler/thread.c b/kernel/src/process/scheduler/thread.c new file mode 100644 index 00000000..d33dca85 --- /dev/null +++ b/kernel/src/process/scheduler/thread.c @@ -0,0 +1,24 @@ +#include + +#include "./include/thread.h" +#include "./include/process.h" +#include "./include/registers.h" + +Thread *create_thread(void *entry, Process *process) { + Thread *thread = kmalloc(sizeof(Thread)); + + thread->process = process; + thread->state = Runnable; + thread->registers = (struct Registers){0}; + + // TODO: allocate proper pages. + thread->registers.SP = (size_t) kmalloc(128); + thread->registers.PC = (size_t) entry; + + return thread; +} + +void free_thread(Thread *thread) { + kfree((void *) thread->registers.SP); + kfree(thread); +} From d1b904e02de4fee3a3d6fffcd93849c9849a97f0 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Thu, 5 Mar 2020 21:45:36 +0100 Subject: [PATCH 037/104] checkpoint! Co-authored-by: Victor Roest --- kernel/src/common/start.c | 1 + .../vm/include/tlb_cache_id_allocator.h | 28 +++++++++++++++++++ kernel/src/memory/vm/include/vas2.h | 12 ++++---- kernel/src/memory/vm/include/vm.h | 2 +- kernel/src/memory/vm/include/vm2.h | 7 +++-- kernel/src/memory/vm/tlb_cache_id_allocator.c | 28 +++++++++++++++++++ kernel/src/memory/vm/vas2.c | 20 +++++++++++++ 7 files changed, 87 insertions(+), 11 deletions(-) create mode 100644 kernel/src/memory/vm/include/tlb_cache_id_allocator.h create mode 100644 kernel/src/memory/vm/tlb_cache_id_allocator.c diff --git a/kernel/src/common/start.c b/kernel/src/common/start.c index 70ff57e4..f51deef5 100644 --- a/kernel/src/common/start.c +++ b/kernel/src/common/start.c @@ -58,6 +58,7 @@ void start(uint32_t *p_bootargs) { // This start is what starts the kernel. Note that virtual memory is enabled // at this point (And running, also, in the kernel's VAS). void start2(uint32_t *p_bootargs) { + kprintf("start address: 0x%x\n", start2); // Set up the exception handlers. init_vector_table(); diff --git a/kernel/src/memory/vm/include/tlb_cache_id_allocator.h b/kernel/src/memory/vm/include/tlb_cache_id_allocator.h new file mode 100644 index 00000000..e1d28256 --- /dev/null +++ b/kernel/src/memory/vm/include/tlb_cache_id_allocator.h @@ -0,0 +1,28 @@ +#ifndef TLB_CACHE_ID_ALLOCATOR +#define TLB_CACHE_ID_ALLOCATOR + +#include +#include + +/// Terminology +/// * tlb_cache_id: Hardware process id used for the pagetable cache. +/// * cache_iteration: Which iteration of the cache we are on, determines if we should flush the cache on a process switch or not. +/// * tlb_descriptor: A pair of above two numbers. + +struct TLBDescriptor { + uint32_t tlb_cache_id; + uint32_t cache_iteration; +}; + +struct TLBDescriptor request_tlb_descriptor(); + +/// Updates the current tlb_descriptor you have. +/// If it was able to, it gives you the same tlb_cache_id that you already had. +/// Then it returns false. +/// +/// If all of those were allocated it updates your id and returns true. +/// When this function returns true, flush the caches. +bool get_and_update(struct TLBDescriptor* desc); + + +#endif diff --git a/kernel/src/memory/vm/include/vas2.h b/kernel/src/memory/vm/include/vas2.h index ffe0be58..7982774d 100644 --- a/kernel/src/memory/vm/include/vas2.h +++ b/kernel/src/memory/vm/include/vas2.h @@ -2,16 +2,14 @@ #define VAS_2_H #include +#include -struct vas2 { +struct vas2 { + struct TLBDescriptor tlbDescriptor; struct L1PageTable * l1PageTable; - -}; - -struct L1PageTableAllocator { - -}; + // TODO: Do we want to store L2Tables to make freeing VASes faster? + }; #endif diff --git a/kernel/src/memory/vm/include/vm.h b/kernel/src/memory/vm/include/vm.h index e3111c97..a1bc10dc 100644 --- a/kernel/src/memory/vm/include/vm.h +++ b/kernel/src/memory/vm/include/vm.h @@ -12,7 +12,7 @@ #define PAGE_TABLE_SIZE (1<<14) #define L2_PAGE_TABLE_SIZE (1<<12) -struct vas { +struct vas { // A pointer to the first level of the pagetable. volatile unsigned int *l1_pagetable; volatile unsigned int *l1_pagetable_phys; // The physical address to it diff --git a/kernel/src/memory/vm/include/vm2.h b/kernel/src/memory/vm/include/vm2.h index 7b945454..9b816a2b 100644 --- a/kernel/src/memory/vm/include/vm2.h +++ b/kernel/src/memory/vm/include/vm2.h @@ -251,18 +251,19 @@ typedef union { } __attribute__((packed)) smallpage; } L2PagetableEntry; - +/// The representation of an L1Pagetable struct L1PageTable { L1PagetableEntry entries[0x1000]; }; +/// The representation of an L1Pagetable struct L2PageTable { L2PagetableEntry entries[0x100]; }; - - +/// Should be called early, initiliazes everything vm2 needs void vm2_prepare(); +/// Actually enables the MMU and switches the kernel to higher half void vm2_start(); void vm2_map_virtual_to_physical_l1(size_t virtual, size_t physical); void vm2_map_nmegabytes_1to1(size_t address, size_t n); diff --git a/kernel/src/memory/vm/tlb_cache_id_allocator.c b/kernel/src/memory/vm/tlb_cache_id_allocator.c new file mode 100644 index 00000000..d86eee13 --- /dev/null +++ b/kernel/src/memory/vm/tlb_cache_id_allocator.c @@ -0,0 +1,28 @@ +#include +#include +#include + +uint8_t curr = 0; +uint32_t allocated_ids[256] = {0}; + +struct TLBDescriptor request_tlb_descriptor() { + uint32_t cache_iteration = ++(allocated_ids[curr]); + uint32_t tlb_cache_id = curr++; + + struct TLBDescriptor res = (struct TLBDescriptor) { + .cache_iteration = cache_iteration, + .tlb_cache_id = tlb_cache_id, + }; + + return res; +} + + +bool get_and_update(struct TLBDescriptor* desc) { + if(desc->cache_iteration != allocated_ids[desc->tlb_cache_id]) { + desc->cache_iteration = ++(allocated_ids[desc->tlb_cache_id]); + return true; + } + + return false; +} diff --git a/kernel/src/memory/vm/vas2.c b/kernel/src/memory/vm/vas2.c index 72a2b50d..32b3ccce 100644 --- a/kernel/src/memory/vm/vas2.c +++ b/kernel/src/memory/vm/vas2.c @@ -1,4 +1,24 @@ #include +#include +#include +struct vas2 * create_vas() { + struct vas2 * newvas = kmalloc(sizeof(struct vas2)); + *newvas = (struct vas2) { + .tlbDescriptor = request_tlb_descriptor(), + .l1PageTable = pagealloc_allocate_l1_pagetable(), + }; + + return newvas; +} + + +void switch_to_vas(struct vas2 * vas) { + +} + +void free_vas() { + +} From e2c6a546e55d993c0d97cc2fad7e8e41343b7eba Mon Sep 17 00:00:00 2001 From: Reinout Meliesie Date: Sat, 7 Mar 2020 22:51:30 +0100 Subject: [PATCH 038/104] [WIP] Timer implementation, pagefaults for unknown reason --- kernel/Makefile | 4 +- kernel/src/common/include/interrupt.h | 2 +- kernel/src/common/interrupt.c | 3 +- kernel/src/common/start.c | 1 - kernel/src/drivers/chipset/bcm2836/bcm2836.c | 56 ++--- .../drivers/chipset/bcm2836/include/bcm2836.h | 50 ++--- .../drivers/chipset/bcm2836/include/timer.h | 21 ++ .../drivers/chipset/bcm2836/include/uart.h | 40 ++++ kernel/src/drivers/chipset/bcm2836/timer.c | 193 ++++++++++++++---- kernel/src/drivers/chipset/bcm2836/uart.c | 60 ++---- kernel/src/drivers/chipset/chipset.c | 11 +- kernel/src/drivers/chipset/include/chipset.h | 18 +- kernel/src/klibc/klibc.c | 4 +- 13 files changed, 298 insertions(+), 165 deletions(-) create mode 100644 kernel/src/drivers/chipset/bcm2836/include/timer.h create mode 100644 kernel/src/drivers/chipset/bcm2836/include/uart.h diff --git a/kernel/Makefile b/kernel/Makefile index 1592a7e0..a72ed4e3 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -48,14 +48,14 @@ build_pi: $(BUILDDIR)/kernelPi.img | builddir test: build | builddir #${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -semihosting -kernel build/flash.bin -append "-load 0x410000 0x14000" - ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M raspi2 -cpu arm1176 -nographic -append "-load 0x410000 0x14000" -semihosting + ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M raspi2 -cpu cortex-a7 -nographic -append "-load 0x410000 0x14000" -semihosting run: build | builddir # nographic to turn off the gui # monitor none to disable stdio monitoring so # serial stdio works #${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -semihosting -monitor none -serial stdio -kernel build/flash.bin -append "-load 0x410000 0x14000" - ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M raspi2 -cpu arm1176 -nographic -append "-load 0x410000 0x14000" -semihosting + ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M raspi2 -cpu cortex-a7 -nographic -append "-load 0x410000 0x14000" -semihosting $(BUILDDIR)/kernel.elf: $(OBJECT_FILES) | builddir $(LD) -T linker/kernel.ld -nostartfiles -Wl,-Map,kernel.map $^ -o $@ diff --git a/kernel/src/common/include/interrupt.h b/kernel/src/common/include/interrupt.h index 107dd277..e2ab33e4 100644 --- a/kernel/src/common/include/interrupt.h +++ b/kernel/src/common/include/interrupt.h @@ -13,7 +13,7 @@ * + IRQ - processing "normal" interrupts * + SVC - proctected mode for OS * + UND - processing an undefined instruction exception - * + SYS - also protecteed mode for OS --if anyone wants to clarify, feel free-- + * + SYS - also protected mode for OS --if anyone wants to clarify, feel free-- * These modes can be entered or exited by modifying the CPSR (status register) * * exceptions (e.g. software interrupts, system calls, etc.), Interrupts (IRQ, FIQ) diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index 4c48560d..9cc6487f 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -260,7 +260,6 @@ void reserved_handler(void) // the attribute automatically saves and restores state void __attribute__((interrupt("IRQ"))) irq_handler(void) { - kprintf("IRQ HANDLER\n"); return chipset.handle_irq(); // int * pendingregister = (int *) 0x40000060; @@ -309,7 +308,7 @@ void SemihostingCall(enum SemihostingSWI mode) { /* enable IRQ and/or FIQ */ void enable_interrupt(InterruptType mask) { - kprintf("Enabling interrupts with mask %i\n", mask); + kprintf("Enabling interrupts with mask 0x%x\n", mask); // enable interrupt on the core switch (mask) { diff --git a/kernel/src/common/start.c b/kernel/src/common/start.c index 283e781f..8fc31c3f 100644 --- a/kernel/src/common/start.c +++ b/kernel/src/common/start.c @@ -29,7 +29,6 @@ #include #include #include -#include // This start is what u-boot calls. It's just a wrapper around setting up the // virtual memory for the kernel. diff --git a/kernel/src/drivers/chipset/bcm2836/bcm2836.c b/kernel/src/drivers/chipset/bcm2836/bcm2836.c index c92a8273..857001e5 100644 --- a/kernel/src/drivers/chipset/bcm2836/bcm2836.c +++ b/kernel/src/drivers/chipset/bcm2836/bcm2836.c @@ -1,55 +1,34 @@ -// https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf #include #include #include -#include -#include +#include +#include -volatile struct BCM2836Registers * bcm2836_registers_base = (struct BCM2836Registers *) 0x40000000; +volatile BCM2836Registers* bcm2836_registers_base = (BCM2836Registers*) 0x40000000; const size_t BCM2836_peripheral_base = 0x3F000000; -//static TimerHandle handleindex; - -// uart.c -void bcm2836_uart_init(); -void bcm2836_uart_putc(char c, int uartchannel); -void bcm2836_uart_on_message(UartCallback callback, int uartchannel); - -// timer.c -void bcm2836_timer_init(); -TimerHandle bcm2836_schedule_timer_periodic(TimerCallback callback, uint32_t ms); -TimerHandle bcm2836_schedule_timer_once(TimerCallback callback, uint32_t ms); -void bcm2836_deschedule_timer(TimerHandle handle); - -void bcm2836_on_interrupt(InterruptCallback callback) { +void bcm2836_irq_handler() +{ + volatile const uint32_t pending = bcm2836_registers_base->Core0IRQSource; + switch (pending) { + // Generic timers + case PHYSICAL_SECURE_TIMER: + timer_handle_interrupt(); + break; + } } +void bcm2836_fiq_handler() {} -void bcm2836_late_init() { - bcm2836_timer_init(); - -} - -void bcm2836_irq_handler() { - volatile uint32_t pending = bcm2836_registers_base->Core0IRQSource; - - - kprintf("interrupt: 0x%x", pending); -} - -void bcm2836_fiq_handler() { - -} - -void bcm2836_init() { +void bcm2836_init() +{ bcm2836_uart_init(); chipset.schedule_timer_periodic = &bcm2836_schedule_timer_periodic; chipset.schedule_timer_once = &bcm2836_schedule_timer_once; chipset.deschedule_timer = &bcm2836_deschedule_timer; chipset.uart_putc = &bcm2836_uart_putc; chipset.uart_on_message = &bcm2836_uart_on_message; - chipset.on_interrupt = &bcm2836_on_interrupt; chipset.handle_irq = &bcm2836_irq_handler; chipset.handle_fiq = &bcm2836_fiq_handler; chipset.late_init = &bcm2836_late_init; @@ -60,3 +39,8 @@ void bcm2836_init() { // Map control registers request_identity_mapped_section((size_t)bcm2836_registers_base, 1); } + +void bcm2836_late_init() +{ + bcm2836_timer_init(); +} diff --git a/kernel/src/drivers/chipset/bcm2836/include/bcm2836.h b/kernel/src/drivers/chipset/bcm2836/include/bcm2836.h index 16efc651..4190ebf4 100644 --- a/kernel/src/drivers/chipset/bcm2836/include/bcm2836.h +++ b/kernel/src/drivers/chipset/bcm2836/include/bcm2836.h @@ -1,11 +1,17 @@ // Data sheet: https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf + #ifndef BCM2836_H #define BCM2836_H #include +/* + * Implementation of chipset driver interface for BCM2836 + */ + // Starts at memory address 0x4000_0000 -struct BCM2836Registers { +typedef struct BCM2836Registers +{ uint32_t ControlRegister; uint32_t __unused1; uint32_t CoreTimerPrescaler; @@ -16,7 +22,7 @@ struct BCM2836Registers { uint32_t CoreTimerAccessLS32Bits; uint32_t CoreTimerAccessMS32Bits; uint32_t LocalInterupts0Routing; - uint32_t __LocalInterupts8Routing __attribute__ ((deprecated)); // Deprecated + uint32_t __LocalInterupts8Routing __attribute__((deprecated)); uint32_t AxiOutstandingCounters; uint32_t AxiOutstandingIRQ; uint32_t LocalTimerControlAndStatus; @@ -70,44 +76,40 @@ struct BCM2836Registers { uint32_t Core3Mailbox1ReadClear; uint32_t Core3Mailbox2ReadClear; uint32_t Core3Mailbox3ReadClear; -}; - - - - - - - +} +BCM2836Registers; -enum InterruptSource { +enum InterruptSource +{ // nCNTPSIRQ : Secure physical timer event - PHYSICAL_SECURE_TIMER = (1 << 0), + PHYSICAL_SECURE_TIMER = (1 << 0), // nCNTPNSIRQ : Non-secure physical timer event - PHYSICAL_NONSECURE_TIMER = (1 << 1), + PHYSICAL_NONSECURE_TIMER = (1 << 1), // nCNTHPIRQ: Physical Timer for use in Hypervisor mode. - PHYSICAL_HYPERVISOR_TIMER = (1 << 2), + PHYSICAL_HYPERVISOR_TIMER = (1 << 2), // nCNTVIRQ: Virtual Timer for use in Non-secure PL1 modes. - VIRTUAL_NONSECURE_TIMER = (1 << 3), + VIRTUAL_NONSECURE_TIMER = (1 << 3), - MAILBOX_0 = (1 << 4), - MAILBOX_1 = (1 << 5), - MAILBOX_2 = (1 << 6), - MAILBOX_3 = (1 << 7), + MAILBOX_0 = (1 << 4), + MAILBOX_1 = (1 << 5), + MAILBOX_2 = (1 << 6), + MAILBOX_3 = (1 << 7), - GPU = (1 << 8), - PMU = (1 << 9), + GPU = (1 << 8), + PMU = (1 << 9), - AXI = (1 << 10), - LOCAL_TIMER = (1 << 11), + AXI = (1 << 10), + LOCAL_TIMER = (1 << 11), }; -volatile struct BCM2836Registers * bcm2836_registers_base; +volatile BCM2836Registers* bcm2836_registers_base; void bcm2836_init(); +void bcm2836_late_init(); extern const size_t BCM2836_peripheral_base; diff --git a/kernel/src/drivers/chipset/bcm2836/include/timer.h b/kernel/src/drivers/chipset/bcm2836/include/timer.h new file mode 100644 index 00000000..26db06c9 --- /dev/null +++ b/kernel/src/drivers/chipset/bcm2836/include/timer.h @@ -0,0 +1,21 @@ +#ifndef TIMER_BCM2836_H +#define TIMER_BCM2836_H + +#include +#include + +/* + * ARM Generic Timer driver for BCM2836 + */ + +void bcm2836_timer_init(); + +void timer_handle_interrupt(); + +TimerHandle bcm2836_schedule_timer_once(TimerCallback callback, uint32_t delay_ms); + +TimerHandle bcm2836_schedule_timer_periodic(TimerCallback callback, uint32_t delay_ms); + +void bcm2836_deschedule_timer(TimerHandle handle); + +#endif diff --git a/kernel/src/drivers/chipset/bcm2836/include/uart.h b/kernel/src/drivers/chipset/bcm2836/include/uart.h new file mode 100644 index 00000000..71dad1b4 --- /dev/null +++ b/kernel/src/drivers/chipset/bcm2836/include/uart.h @@ -0,0 +1,40 @@ +#ifndef UART_BCM2836_H +#define UART_BCM2836_H + +#include +#include + +// http://infocenter.arm.com/help/topic/com.arm.doc.ddi0183f/DDI0183.pdf +// Section 3.2: Summary of registers +// https://balau82.wordpress.com/2010/11/30/emulating-arm-pl011-serial-ports/ +// This struct is memory mapped. I call them registers but they all live in memory. +typedef volatile struct BCM2836UartInterface +{ + uint32_t DR; // Data Register + uint32_t RSR_ECR; // Receive Status Register / Error Clear Register + uint8_t reserved1[0x10]; // Reserved + const uint32_t FR; // Flag Register + uint8_t reserved2[0x4]; // Reserved + uint32_t LPR; // IrDA low power counter Register + uint32_t IBRD; // Integer Baud Rate Register + uint32_t FBRD; // Fractional Baud Rate Register + uint32_t LCR_H; // Line Control Register + uint32_t CR; // Control Register + uint32_t IFLS; // Interrupt FIFO Level Select Register + uint32_t IMSC; // Interrupt Mask Set/Clear Register + const uint32_t RIS; // Raw Interrupt Status Register + const uint32_t MIS; // Masked Interrupt Status Register + uint32_t ICR; // Interrupt Clear Register + uint32_t DMACR; // DMA Control Register +} +BCM2836UartInterface; + +void bcm2836_uart_init(); + +void uart_write_byte(BCM2836UartInterface* interface, volatile uint8_t value); + +void bcm2836_uart_putc(char c, int uartchannel); + +void bcm2836_uart_on_message(UartCallback callback, int uartchannel); + +#endif diff --git a/kernel/src/drivers/chipset/bcm2836/timer.c b/kernel/src/drivers/chipset/bcm2836/timer.c index 06af7c4e..021be1cd 100644 --- a/kernel/src/drivers/chipset/bcm2836/timer.c +++ b/kernel/src/drivers/chipset/bcm2836/timer.c @@ -1,74 +1,183 @@ +#include #include -#include -#include #include +#include +#include +#include +#include + +typedef struct ScheduledTimer +{ + uint64_t scheduled_count; + TimerHandle handle; + TimerCallback callback; +} +ScheduledTimer; + +typedef union LittleEndianUint64 +{ + uint64_t dword; + struct { + uint32_t low_word; + uint32_t high_word; + }; +} +LittleEndianUint64; -inline static uint32_t get_frequency() { +/* + * Gives the frequency of the counter in kHz + */ +static inline uint32_t get_frequency() +{ uint32_t val; - asm volatile ("mrc p15, 0, %0, c14, c0, 0" : "=r"(val) ); + // Read CNTFRQ + asm volatile ("mrc p15, 0, %0, c14, c0, 0" : "=r"(val)); return val; } -void write_interrupt_count_value(uint32_t val) { - asm volatile ("mcr p15, 0, %0, c14, c3, 0" :: "r"(val) ); +static prq_handle* scheduled_timers; + +static void unmask_and_enable_timer() +{ + // Disable output mask, enable timer + static const uint32_t cntp_ctl = 0b01; + // Write CNTP_CTL + asm volatile ("mcr p15, 0, %0, c14, c2, 1" :: "r"(cntp_ctl)); } -uint32_t read_interrupt_count_value() { - uint32_t val; - asm volatile ("mrc p15, 0, %0, c14, c3, 0" : "=r"(val) ); +static void mask_and_enable_timer() +{ + // Enable output mask, enable timer + static const uint32_t cntp_ctl = 0b11; + // Write CNTP_CTL + asm volatile ("mcr p15, 0, %0, c14, c2, 1" :: "r"(cntp_ctl)); +} + +static uint64_t get_phy_count() +{ + LittleEndianUint64 val; + // Read CNTPCT + asm volatile ("mrrc p15, 0, %0, %1, c14" : "=r"(val.low_word), "=r"(val.high_word)); + return val.dword; +} + +/* +static int32_t get_phy_timer_val() +{ + int32_t val; + // Read CNTP_TVAL + asm volatile ("mrc p15, 0, %0, c14, c2, 0" : "=r"(val)); return val; } +static void set_phy_timer_val(int32_t val) +{ + // Write CNTP_TVAL + asm volatile ("mcr p15, 0, %0, c14, c2, 0" :: "r"(val)); +} + +static uint64_t get_phy_timer_cmp_val() +{ + LittleEndianUint64 val; + // Read CNTP_CVAL + asm volatile ("mrrc p15, 2, %0, %1, c14" : "=r"(val.low_word), "=r"(val.high_word)); + return val.dword; +} +*/ + +static void set_phy_timer_cmp_val(uint64_t val) +{ + const LittleEndianUint64 le_val = (LittleEndianUint64)val; + // Write CNTP_CVAL + asm volatile ("mcrr p15, 2, %0, %1, c14" :: "r"(le_val.low_word), "r"(le_val.high_word)); +} + +static inline ScheduledTimer* get_prq_node_data(prq_node* node) +{ + return (ScheduledTimer*) node->data; +} + + +static void foo() { + kprintf("Timer callback called\n"); +} +void bcm2836_timer_init() +{ + const uint32_t freq = get_frequency(); + kprintf("System counter frequency: %u kHz\n", freq / 1000); + + bcm2836_registers_base->Core0TimersInterruptControl = PHYSICAL_SECURE_TIMER; + // Init priority queue + scheduled_timers = prq_create(); -// https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf -// Page ~ 117 -struct IRQ_registers { - uint32_t irq_basic_pending; - uint32_t irq_gpu1_pending; - uint32_t irq_gpu2_pending; - uint32_t fiq_control; - uint32_t irq_gpu1_enable; // Interrupt enable register 1 (GPU) - uint32_t irq_gpu2_enable; // Interrupt enable register 2 (GPU) - uint32_t irq_basic_enable; // Base enable register (ARM/CPU) - uint32_t irq_gpu1_disable; - uint32_t irq_gpu2_disable; - uint32_t irq_basic_disable; -}; + mask_and_enable_timer(); -void bcm2836_timer_init() { + // TEMP + bcm2836_schedule_timer_once(foo, 2000); +// set_phy_timer_cmp_val(get_phy_count() + freq * 2000); +// unmask_and_enable_timer(); +} - uint32_t freq = get_frequency(); +// TODO: Handle possibility of timer scheduling functions or interrupt handler being interrupted - kprintf("control frequency: %i\n", freq); - // 1 (milli)second timer - write_interrupt_count_value(freq); +void timer_handle_interrupt() +{ + volatile const uint64_t current_count = get_phy_count(); - kprintf("value: %i\n", read_interrupt_count_value()); - kprintf("value: %i\n", read_interrupt_count_value()); + // Process all timers that are not in the future, if any + prq_node* next_timer_node = prq_peek(scheduled_timers); + while (get_prq_node_data(next_timer_node)->scheduled_count <= current_count) { + prq_dequeue(scheduled_timers); + ScheduledTimer* next_timer = get_prq_node_data(next_timer_node); - // when the register reaches the count value set above, interrupt. -// mmio_write(&bcm2836_registers_base->Core0TimersInterruptControl, VIRTUAL_NONSECURE_TIMER); + next_timer->callback(); + kfree(next_timer); + prq_free_node(next_timer_node); - // Enable timer interrupts. - uint32_t cntv_ctl = 1; - asm volatile ("mcr p15, 0, %0, c14, c3, 1" :: "r"(cntv_ctl) ); + next_timer_node = prq_peek(scheduled_timers); + } + set_phy_timer_cmp_val(get_prq_node_data(next_timer_node)->scheduled_count); - bcm2836_registers_base->PerformanceMonitorRoutingSet = 0xf; + // TEMP +// kprintf("Timer interrupt received\n"); +// mask_and_enable_timer(); } -TimerHandle bcm2836_schedule_timer_periodic(TimerCallback callback, uint32_t ms) { +// TODO: Handle possibility of two timers getting scheduled for the same time (counter value), PRQ needs support +/* + * This implementation may execute timers out of order if their delay is very small + */ +TimerHandle bcm2836_schedule_timer_once(TimerCallback callback, uint32_t delay_ms) +{ + volatile const uint64_t scheduled_count = get_phy_count() + (get_frequency() / 1000) * delay_ms; - return 0; + ScheduledTimer* new_timer = (ScheduledTimer*) kmalloc(sizeof(ScheduledTimer)); + prq_node* new_timer_node = prq_create_node(); + + new_timer->scheduled_count = scheduled_count; + new_timer->callback = callback; + new_timer->handle = (TimerHandle) new_timer_node; + // TODO: Find better way of doing this + new_timer_node->priority = UINT64_MAX - scheduled_count; + new_timer_node->data = new_timer; + + prq_enqueue(scheduled_timers, new_timer_node); + + set_phy_timer_cmp_val(get_prq_node_data(prq_peek(scheduled_timers))->scheduled_count); + + unmask_and_enable_timer(); + + return new_timer->handle; } -TimerHandle bcm2836_schedule_timer_once(TimerCallback callback, uint32_t ms) { +TimerHandle bcm2836_schedule_timer_periodic(TimerCallback callback, uint32_t delay_ms) +{ + // TEMP return 0; } -void bcm2836_deschedule_timer(TimerHandle handle) { - -} +void bcm2836_deschedule_timer(TimerHandle handle) {} diff --git a/kernel/src/drivers/chipset/bcm2836/uart.c b/kernel/src/drivers/chipset/bcm2836/uart.c index 38dffbf0..f76bfc44 100644 --- a/kernel/src/drivers/chipset/bcm2836/uart.c +++ b/kernel/src/drivers/chipset/bcm2836/uart.c @@ -1,7 +1,10 @@ +#include #include #include -#include #include +#include +#include +#include /* // raspberry pi zero, 1, b+ etc @@ -51,50 +54,29 @@ volatile UartInterface * const UART2_ADDRESS = (volatile UartInterface *)0x101f3 //#define CTSEn () // CTS Hardware Control Enable -// http://infocenter.arm.com/help/topic/com.arm.doc.ddi0183f/DDI0183.pdf -// Section 3.2: Summary of registers -// https://balau82.wordpress.com/2010/11/30/emulating-arm-pl011-serial-ports/ -// This struct is memory mappend. I call them registers but they all live in memory. -typedef volatile struct BCM2836UartInterface { - uint32_t DR; // Data Register - uint32_t RSR_ECR; // Receive Status Register / Error Clear Register - uint8_t reserved1[0x10]; // Reserved - const uint32_t FR; // Flag Register - uint8_t reserved2[0x4]; // Reserved - uint32_t LPR; // IrDA low power counter Register - uint32_t IBRD; // Integer Baud Rate Register - uint32_t FBRD; // Fractional Baud Rate Register - uint32_t LCR_H; // Line Control Register - uint32_t CR; // Control Register - uint32_t IFLS; // Interrupt FIFO Level Select Register - uint32_t IMSC; // Interrupt Mask Set/Clear Register - const uint32_t RIS; // Raw Interrupt Status Register - const uint32_t MIS; // Masked Interrupt Status Register - uint32_t ICR; // Interrupt Clear Register - uint32_t DMACR; // DMA Control Register -} BCM2836UartInterface; - -volatile BCM2836UartInterface * BCM2836_UART0_ADDRESS; -volatile BCM2836UartInterface * BCM2836_UART1_ADDRESS; -volatile BCM2836UartInterface * BCM2836_UART2_ADDRESS; -volatile BCM2836UartInterface * BCM2836_UART3_ADDRESS; +static BCM2836UartInterface* BCM2836_UART0_ADDRESS; +static BCM2836UartInterface* BCM2836_UART1_ADDRESS; +static BCM2836UartInterface* BCM2836_UART2_ADDRESS; +static BCM2836UartInterface* BCM2836_UART3_ADDRESS; -void bcm2836_uart_init() { - BCM2836_UART0_ADDRESS = (volatile BCM2836UartInterface *)(BCM2836_peripheral_base + 0x201000); - BCM2836_UART1_ADDRESS = (volatile BCM2836UartInterface *)(BCM2836_peripheral_base + 0x202000); - BCM2836_UART2_ADDRESS = (volatile BCM2836UartInterface *)(BCM2836_peripheral_base + 0x203000); - BCM2836_UART3_ADDRESS = (volatile BCM2836UartInterface *)(BCM2836_peripheral_base + 0x204000); +void bcm2836_uart_init() +{ + BCM2836_UART0_ADDRESS = (BCM2836UartInterface*)(BCM2836_peripheral_base + 0x201000); + BCM2836_UART1_ADDRESS = (BCM2836UartInterface*)(BCM2836_peripheral_base + 0x202000); + BCM2836_UART2_ADDRESS = (BCM2836UartInterface*)(BCM2836_peripheral_base + 0x203000); + BCM2836_UART3_ADDRESS = (BCM2836UartInterface*)(BCM2836_peripheral_base + 0x204000); } -void uart_write_byte(volatile BCM2836UartInterface * interface, volatile uint8_t value) { +void uart_write_byte(BCM2836UartInterface* interface, volatile uint8_t value) +{ // while (interface->FR & TXFF ) { // asm volatile ("nop"); // } interface->DR = (uint32_t)value; } -void bcm2836_uart_putc(char c, int uartchannel) { - +void bcm2836_uart_putc(char c, int uartchannel) +{ if (uartchannel >= 4) { uartchannel = 0; } @@ -104,10 +86,8 @@ void bcm2836_uart_putc(char c, int uartchannel) { case 1: return uart_write_byte(BCM2836_UART1_ADDRESS, c); case 2: return uart_write_byte(BCM2836_UART2_ADDRESS, c); case 3: return uart_write_byte(BCM2836_UART3_ADDRESS, c); - default: __unreachable(); + default: panic(); } - } -void bcm2836_uart_on_message(UartCallback callback, int uartchannel) { -} +void bcm2836_uart_on_message(UartCallback callback, int uartchannel) {} diff --git a/kernel/src/drivers/chipset/chipset.c b/kernel/src/drivers/chipset/chipset.c index 61691948..86308fd4 100644 --- a/kernel/src/drivers/chipset/chipset.c +++ b/kernel/src/drivers/chipset/chipset.c @@ -1,4 +1,3 @@ - #include #include #include @@ -7,8 +6,9 @@ ChipsetInterface chipset; -void init_chipset() { - HardwareInfo * info = get_hardwareinfo(); +void init_chipset() +{ + HardwareInfo* info = get_hardwareinfo(); memset(&chipset, 0, sizeof(ChipsetInterface)); @@ -17,16 +17,15 @@ void init_chipset() { bcm2836_init(); break; default: { - kprintf("Board type not supported for interrupts \n"); + kprintf("Board type not supported for interrupts\n"); panic(); } } for (size_t i = 0; i < sizeof(ChipsetInterface) / sizeof(uint32_t); i++) { - if (((uint32_t **) &chipset)[i] == NULL) { + if (((uint32_t**) &chipset)[i] == NULL) { kprintf("Chipset did not satisfy the required interface. Missing field %i\n", i); panic(); } } - } diff --git a/kernel/src/drivers/chipset/include/chipset.h b/kernel/src/drivers/chipset/include/chipset.h index 9febce36..46f95db5 100644 --- a/kernel/src/drivers/chipset/include/chipset.h +++ b/kernel/src/drivers/chipset/include/chipset.h @@ -3,21 +3,24 @@ #include +/* + * Abstract chipset driver interface + */ + void init_chipset(); // A timer handle is an identifier for a timer so it can be descheduled later. // These handles must be unique. typedef size_t TimerHandle; typedef void (*TimerCallback)(); + typedef void (*UartCallback)(char c); -typedef void (*InterruptCallback)(); -typedef struct ChipsetInterface { +typedef struct ChipsetInterface +{ /// Timer Functions - //TODO: time/duration struct of some sort. TimerHandle (*schedule_timer_periodic)(TimerCallback callback, uint32_t ms); TimerHandle (*schedule_timer_once)(TimerCallback callback, uint32_t ms); - void (*deschedule_timer)(TimerHandle handle); /// UART Functions @@ -34,17 +37,14 @@ typedef struct ChipsetInterface { // is requested that does not exist, input from channel zero shall be given to this callback. void (*uart_on_message)(UartCallback callback, int uartchannel); - // Interrupt numbers are not guaranteed to work from one boardtype/version to another. - // Only use this function after checking hardwareinfo. - void (*on_interrupt)(InterruptCallback callback); - void (*handle_irq)(); void (*handle_fiq)(); // Called for every chipset after interrupts and dynamic memory has been enabled // So the chipset can do some more initialization. void (*late_init)(); -} ChipsetInterface; +} +ChipsetInterface; ChipsetInterface chipset; diff --git a/kernel/src/klibc/klibc.c b/kernel/src/klibc/klibc.c index 72a38bcd..54c4173f 100644 --- a/kernel/src/klibc/klibc.c +++ b/kernel/src/klibc/klibc.c @@ -64,14 +64,14 @@ void splash() { // kprintf("\t██╔════╝██╔═══██╗██║ ██║██╔══██╗██╔════╝██╔════╝██╔═══██╗██╔════╝\n"); // kprintf("\t██║ ██║ ██║██║ ██║██████╔╝███████╗█████╗ ██║ ██║███████╗\n"); // kprintf("\t██║ ██║ ██║██║ ██║██╔══██╗╚════██║██╔══╝ ██║ ██║╚════██║\n"); -// kprintf("\t╚██████╗╚██████╔╝╚██████╔╝██║ ██║███████║███████╗╚██████╔╝██████║\n\n"); +// kprintf("\t╚██████╗╚██████╔╝╚██████╔╝██║ ██║███████║███████╗╚██████╔╝███████║\n\n"); // kprintf("\n\n"); kprintf("\t ██████╗██╗ ██╗██████╗ ███████╗███████╗██████╗ ██████╗ ███████╗\n"); kprintf("\t██╔════╝██║ ██║██╔══██╗██╔════╝██╔════╝██╔═══██╗ ██╔═══██╗██╔════╝\n"); kprintf("\t██║ ██║ ██║██████╔╝███████╗█████╗ ██║ ██║ ██║ ██║███████╗\n"); kprintf("\t██║ ██║ ██║██╔══██╗╚════██║██╔══╝ ██║ ██║ ██║ ██║╚════██║\n"); - kprintf("\t╚██████╗╚██████╔╝██║ ██║███████║███████╗██████╔╝ ╚██████╔╝██████║\n\n"); + kprintf("\t╚██████╗╚██████╔╝██║ ██║███████║███████╗██████╔╝ ╚██████╔╝███████║\n\n"); } /*4-17-15: - Prakash From eeb1772d5b56caa22ef825201c9cfe8f9e0aa980 Mon Sep 17 00:00:00 2001 From: Reinout Meliesie Date: Sat, 7 Mar 2020 23:25:23 +0100 Subject: [PATCH 039/104] Reason is no longer unknown, it was a null ptr --- kernel/src/drivers/chipset/bcm2836/timer.c | 38 +++++++++------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/kernel/src/drivers/chipset/bcm2836/timer.c b/kernel/src/drivers/chipset/bcm2836/timer.c index 021be1cd..e7cd2e39 100644 --- a/kernel/src/drivers/chipset/bcm2836/timer.c +++ b/kernel/src/drivers/chipset/bcm2836/timer.c @@ -37,7 +37,7 @@ static inline uint32_t get_frequency() static prq_handle* scheduled_timers; -static void unmask_and_enable_timer() +static inline void unmask_and_enable_timer() { // Disable output mask, enable timer static const uint32_t cntp_ctl = 0b01; @@ -45,7 +45,7 @@ static void unmask_and_enable_timer() asm volatile ("mcr p15, 0, %0, c14, c2, 1" :: "r"(cntp_ctl)); } -static void mask_and_enable_timer() +static inline void mask_and_enable_timer() { // Enable output mask, enable timer static const uint32_t cntp_ctl = 0b11; @@ -53,7 +53,7 @@ static void mask_and_enable_timer() asm volatile ("mcr p15, 0, %0, c14, c2, 1" :: "r"(cntp_ctl)); } -static uint64_t get_phy_count() +static inline uint64_t get_phy_count() { LittleEndianUint64 val; // Read CNTPCT @@ -62,7 +62,7 @@ static uint64_t get_phy_count() } /* -static int32_t get_phy_timer_val() +static inline int32_t get_phy_timer_val() { int32_t val; // Read CNTP_TVAL @@ -70,13 +70,13 @@ static int32_t get_phy_timer_val() return val; } -static void set_phy_timer_val(int32_t val) +static inline void set_phy_timer_val(int32_t val) { // Write CNTP_TVAL asm volatile ("mcr p15, 0, %0, c14, c2, 0" :: "r"(val)); } -static uint64_t get_phy_timer_cmp_val() +static inline uint64_t get_phy_timer_cmp_val() { LittleEndianUint64 val; // Read CNTP_CVAL @@ -85,7 +85,7 @@ static uint64_t get_phy_timer_cmp_val() } */ -static void set_phy_timer_cmp_val(uint64_t val) +static inline void set_phy_timer_cmp_val(uint64_t val) { const LittleEndianUint64 le_val = (LittleEndianUint64)val; // Write CNTP_CVAL @@ -98,9 +98,6 @@ static inline ScheduledTimer* get_prq_node_data(prq_node* node) } -static void foo() { - kprintf("Timer callback called\n"); -} void bcm2836_timer_init() { const uint32_t freq = get_frequency(); @@ -112,12 +109,6 @@ void bcm2836_timer_init() scheduled_timers = prq_create(); mask_and_enable_timer(); - - - // TEMP - bcm2836_schedule_timer_once(foo, 2000); -// set_phy_timer_cmp_val(get_phy_count() + freq * 2000); -// unmask_and_enable_timer(); } // TODO: Handle possibility of timer scheduling functions or interrupt handler being interrupted @@ -128,7 +119,7 @@ void timer_handle_interrupt() // Process all timers that are not in the future, if any prq_node* next_timer_node = prq_peek(scheduled_timers); - while (get_prq_node_data(next_timer_node)->scheduled_count <= current_count) { + while (next_timer_node != NULL && get_prq_node_data(next_timer_node)->scheduled_count <= current_count) { prq_dequeue(scheduled_timers); ScheduledTimer* next_timer = get_prq_node_data(next_timer_node); @@ -138,12 +129,15 @@ void timer_handle_interrupt() next_timer_node = prq_peek(scheduled_timers); } - set_phy_timer_cmp_val(get_prq_node_data(next_timer_node)->scheduled_count); - - // TEMP -// kprintf("Timer interrupt received\n"); -// mask_and_enable_timer(); + // If there are no more scheduled timers in queue, mask interrupts until one is added again + if (next_timer_node == NULL) { + mask_and_enable_timer(); + } + // If there still are, set compare val to next one + else { + set_phy_timer_cmp_val(get_prq_node_data(next_timer_node)->scheduled_count); + } } // TODO: Handle possibility of two timers getting scheduled for the same time (counter value), PRQ needs support From c540860be900b5000011c79db0d862b7dcd708e3 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Sun, 8 Mar 2020 14:18:57 +0100 Subject: [PATCH 040/104] Vm WoRkS aAaAaAaAaAaAaA Co-authored-by: Victor Roest --- .gitignore | 2 + frameallocatortest/pagealloc2.c | 81 - generate_static_l1pt.c | 237 ++ kernel/Makefile | 13 +- kernel/linker/kernel.ld | 37 +- kernel/linker/kernelPi.ld | 12 - kernel/old/drivers/clock.c | 21 - kernel/old/fs/cmdline/Documents | 159 -- kernel/old/fs/cmdline/Makefile | 39 - kernel/old/fs/cmdline/buildfs | Bin 71056 -> 0 bytes kernel/old/fs/cmdline/fakelibs.c | 70 - .../include/data_structures/bitvector.h | 1 - .../include/data_structures/linked_list.h | 1 - kernel/old/fs/cmdline/include/drivers/mmci.h | 1 - kernel/old/fs/cmdline/include/fs | 1 - kernel/old/fs/cmdline/include/global_defs.h | 1 - kernel/old/fs/cmdline/include/klibc.h | 1 - kernel/old/fs/cmdline/main.c | 113 - kernel/old/fs/fat16/file.c | 2237 ----------------- kernel/old/fs/fat16/test.c | 75 - kernel/old/fs/fat16/test_superblock.data | 1 - kernel/old/fs/fat16/test_superblock.txt | 1 - kernel/old/fs/open_table.c | 117 - kernel/old/include/drivers/clock.h | 7 - kernel/old/include/fs/file.h | 177 -- kernel/old/include/fs/open_table.h | 43 - kernel/old/include/klibc.h | 161 -- kernel/old/include/misc_defs.h | 25 - kernel/old/include/os_setjmp.h | 22 - kernel/old/include/pi_light.h | 8 - kernel/old/include/pm.h | 33 - kernel/old/include/priorityQueue.h | 22 - kernel/old/include/tests.h | 21 - kernel/old/include/tests/test_hash_map.h | 13 - kernel/old/include/tests/test_mem_alloc.h | 13 - .../old/include/tests/test_priority_queue.h | 13 - kernel/old/include/tests/test_vm.h | 13 - kernel/old/legacy/os_longjmp.s | 37 - kernel/old/legacy/os_setjmp.s | 39 - kernel/old/legacy/pm.c | 90 - kernel/old/legacy/priorityQueue.c | 196 -- kernel/old/tests/Makefile | 40 - kernel/old/tests/test_fs.c | 107 - kernel/old/tests/test_hash_map.c | 187 -- kernel/old/tests/test_klibc.h | 52 - kernel/old/tests/test_mem_alloc.c | 99 - kernel/old/tests/test_priority_queue.c | 309 --- .../testingsuite_example/arrayfill/a.out | Bin 8624 -> 0 bytes .../arrayfill/arrayfill.c | 21 - .../arrayfill/arrayfill.h | 9 - .../testingsuite_example/arrayfill/tap.c | 369 --- .../testingsuite_example/arrayfill/tap.h | 117 - .../arrayfill/testarrayfill.c | 28 - kernel/src/common/argparse.c | 170 -- kernel/src/common/hardwareinfo.c | 8 +- kernel/src/common/include/hardwareinfo.h | 1 + kernel/src/common/interrupt.c | 99 +- kernel/src/common/stacks.s | 79 + kernel/src/common/start.c | 38 +- kernel/src/common/startup.s | 132 +- kernel/src/drivers/chipset/bcm2836/bcm2836.c | 35 +- .../drivers/chipset/bcm2836/include/bcm2836.h | 20 +- kernel/src/drivers/chipset/bcm2836/uart.c | 9 +- kernel/src/ds/array_list.c | 122 - kernel/src/ds/bitvector.c | 137 - kernel/src/ds/hash_map.c | 181 -- kernel/src/ds/linked_list.c | 108 - kernel/src/ds/ring_buffer.c.old | 60 - kernel/src/klibc/alloc.c | 87 - kernel/src/klibc/include/constants.h | 8 +- kernel/src/klibc/include/klibc.h | 43 +- kernel/src/kthread/include/kthread.h | 24 - kernel/src/kthread/kthreads.c | 24 - kernel/src/memory/allocator.c | 8 +- kernel/src/memory/include/allocator.h | 4 +- kernel/src/memory/include/mem_alloc.h | 39 +- kernel/src/memory/include/mmap.h | 12 +- kernel/src/memory/mem_alloc.c | 152 +- kernel/src/memory/mmap.c | 162 +- kernel/src/memory/vm/fastlz/6pack.c.old | 636 ----- kernel/src/memory/vm/fastlz/6unpack.c.old | 478 ---- kernel/src/memory/vm/fastlz/LICENSE | 24 - kernel/src/memory/vm/fastlz/README.TXT | 75 - kernel/src/memory/vm/fastlz/fastlz.c.old | 551 ---- kernel/src/memory/vm/fastlz/fastlz.h.old | 100 - kernel/src/memory/vm/frame.c | 62 - .../memory/vm/include/{pagealloc2.h => pmm.h} | 44 +- kernel/src/memory/vm/include/vm.h | 2 +- kernel/src/memory/vm/include/vm2.h | 71 +- kernel/src/memory/vm/{pagealloc2.c => pmm.c} | 105 +- kernel/src/memory/vm/swap_framework.c.old | 259 -- kernel/src/memory/vm/swap_fs.c.old | 161 -- kernel/src/memory/vm/swap_pqueue.c.old | 158 -- kernel/src/memory/vm/test/test_pagealloc2.c | 242 +- kernel/src/memory/vm/vas2.c | 8 +- kernel/src/memory/vm/vm.c | 451 ---- kernel/src/memory/vm/vm2.c | 198 +- kernel/src/process/elf.c | 259 -- kernel/src/process/include/elf.h | 153 -- kernel/src/process/include/loader.h | 13 - kernel/src/process/include/process.h | 169 -- kernel/src/process/include/scheduler.h | 57 - kernel/src/process/include/signals.h.old | 11 - kernel/src/process/loader.c | 76 - kernel/src/process/process.c | 280 --- kernel/src/process/scheduler.c | 512 ---- kernel/src/process/signals.c.old | 20 - kernel/src/test/generate_tests.sh | 3 + kernel/src/test/include/test.h | 100 +- 109 files changed, 1020 insertions(+), 11512 deletions(-) delete mode 100644 frameallocatortest/pagealloc2.c create mode 100644 generate_static_l1pt.c delete mode 100644 kernel/linker/kernelPi.ld delete mode 100644 kernel/old/drivers/clock.c delete mode 100644 kernel/old/fs/cmdline/Documents delete mode 100755 kernel/old/fs/cmdline/Makefile delete mode 100755 kernel/old/fs/cmdline/buildfs delete mode 100644 kernel/old/fs/cmdline/fakelibs.c delete mode 120000 kernel/old/fs/cmdline/include/data_structures/bitvector.h delete mode 120000 kernel/old/fs/cmdline/include/data_structures/linked_list.h delete mode 120000 kernel/old/fs/cmdline/include/drivers/mmci.h delete mode 120000 kernel/old/fs/cmdline/include/fs delete mode 120000 kernel/old/fs/cmdline/include/global_defs.h delete mode 120000 kernel/old/fs/cmdline/include/klibc.h delete mode 100644 kernel/old/fs/cmdline/main.c delete mode 100644 kernel/old/fs/fat16/file.c delete mode 100644 kernel/old/fs/fat16/test.c delete mode 100644 kernel/old/fs/fat16/test_superblock.data delete mode 100644 kernel/old/fs/fat16/test_superblock.txt delete mode 100644 kernel/old/fs/open_table.c delete mode 100644 kernel/old/include/drivers/clock.h delete mode 100644 kernel/old/include/fs/file.h delete mode 100644 kernel/old/include/fs/open_table.h delete mode 100644 kernel/old/include/klibc.h delete mode 100644 kernel/old/include/misc_defs.h delete mode 100644 kernel/old/include/os_setjmp.h delete mode 100644 kernel/old/include/pi_light.h delete mode 100644 kernel/old/include/pm.h delete mode 100644 kernel/old/include/priorityQueue.h delete mode 100644 kernel/old/include/tests.h delete mode 100644 kernel/old/include/tests/test_hash_map.h delete mode 100644 kernel/old/include/tests/test_mem_alloc.h delete mode 100644 kernel/old/include/tests/test_priority_queue.h delete mode 100644 kernel/old/include/tests/test_vm.h delete mode 100644 kernel/old/legacy/os_longjmp.s delete mode 100644 kernel/old/legacy/os_setjmp.s delete mode 100644 kernel/old/legacy/pm.c delete mode 100644 kernel/old/legacy/priorityQueue.c delete mode 100644 kernel/old/tests/Makefile delete mode 100644 kernel/old/tests/test_fs.c delete mode 100644 kernel/old/tests/test_hash_map.c delete mode 100644 kernel/old/tests/test_klibc.h delete mode 100644 kernel/old/tests/test_mem_alloc.c delete mode 100644 kernel/old/tests/test_priority_queue.c delete mode 100755 kernel/old/tests/testingsuite_example/arrayfill/a.out delete mode 100644 kernel/old/tests/testingsuite_example/arrayfill/arrayfill.c delete mode 100644 kernel/old/tests/testingsuite_example/arrayfill/arrayfill.h delete mode 100755 kernel/old/tests/testingsuite_example/arrayfill/tap.c delete mode 100755 kernel/old/tests/testingsuite_example/arrayfill/tap.h delete mode 100644 kernel/old/tests/testingsuite_example/arrayfill/testarrayfill.c delete mode 100644 kernel/src/common/argparse.c create mode 100644 kernel/src/common/stacks.s delete mode 100644 kernel/src/ds/array_list.c delete mode 100644 kernel/src/ds/bitvector.c delete mode 100644 kernel/src/ds/hash_map.c delete mode 100644 kernel/src/ds/linked_list.c delete mode 100644 kernel/src/ds/ring_buffer.c.old delete mode 100644 kernel/src/kthread/include/kthread.h delete mode 100644 kernel/src/kthread/kthreads.c delete mode 100644 kernel/src/memory/vm/fastlz/6pack.c.old delete mode 100644 kernel/src/memory/vm/fastlz/6unpack.c.old delete mode 100644 kernel/src/memory/vm/fastlz/LICENSE delete mode 100644 kernel/src/memory/vm/fastlz/README.TXT delete mode 100644 kernel/src/memory/vm/fastlz/fastlz.c.old delete mode 100644 kernel/src/memory/vm/fastlz/fastlz.h.old delete mode 100644 kernel/src/memory/vm/frame.c rename kernel/src/memory/vm/include/{pagealloc2.h => pmm.h} (75%) rename kernel/src/memory/vm/{pagealloc2.c => pmm.c} (67%) delete mode 100644 kernel/src/memory/vm/swap_framework.c.old delete mode 100644 kernel/src/memory/vm/swap_fs.c.old delete mode 100644 kernel/src/memory/vm/swap_pqueue.c.old delete mode 100644 kernel/src/memory/vm/vm.c delete mode 100644 kernel/src/process/elf.c delete mode 100644 kernel/src/process/include/elf.h delete mode 100644 kernel/src/process/include/loader.h delete mode 100644 kernel/src/process/include/process.h delete mode 100644 kernel/src/process/include/scheduler.h delete mode 100644 kernel/src/process/include/signals.h.old delete mode 100644 kernel/src/process/loader.c delete mode 100644 kernel/src/process/process.c delete mode 100644 kernel/src/process/scheduler.c delete mode 100644 kernel/src/process/signals.c.old diff --git a/.gitignore b/.gitignore index 4085608c..2754487d 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,5 @@ uboot-commands.ubt NOTES /server.PID + +!/.idea/ \ No newline at end of file diff --git a/frameallocatortest/pagealloc2.c b/frameallocatortest/pagealloc2.c deleted file mode 100644 index ff28173b..00000000 --- a/frameallocatortest/pagealloc2.c +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include -#include - -struct PageAllocator allocator; - -void pagealloc_init(size_t start, size_t end) { - - // Create the first sliceinfo at the start address - struct MemorySliceInfo * firstinfo = (struct MemorySliceInfo *)start; - // This start address is itself a memory slice - union MemorySlice * firstslice = (union MemorySlice *)firstinfo; - - // Make the first sliceinfo describe this first slice. - firstinfo->next = NULL; - // It's type is sliceinfo - firstinfo->type = SliceInfo; - // It points to the first slice - firstinfo->slice = (union MemorySlice *)firstinfo; - // And there's one sliceinfo struct in it. This first one. - firstinfo->filled = 1; - - // Now make an allocator with one sliceinfo in the allocated array. - allocator = (struct PageAllocator){ - .start = start, - .end = end, - .l2ptPartialFree = NULL, - .pagePartialFree = NULL, - .allocated = firstinfo, - .unused = NULL, - }; - - // the infoindex is 1 since we just allocated the 0th one above^^^ - size_t infoindex = 1; - union MemorySlice * currentslice = firstslice; - - // Go through all memory and index it with sliceinfo structs. - for (size_t i = start; i < end; i += sizeof(union MemorySlice)) { - struct MemorySliceInfo * currentsliceinfo = ¤tslice->sliceinfo[infoindex]; - - // make this sliceinfo struct point to the right slice - currentsliceinfo->slice = (union MemorySlice *) i; - - // Add the sliceinfo to the unused list - currentsliceinfo->next = allocator.unused; - allocator.unused = currentsliceinfo; - - // continue to the next slicinfo - infoindex++; - - if (infoindex >= SLICEINFO_PER_SLICE) { - // We can now do this as we already made at least one new sliceinfo struct on the unused list - // Which we can use for this. - currentslice = allocate_new_sliceinfo_slice()->slice; - } - } -} - -struct MemorySliceInfo * allocate_new_sliceinfo_slice() { - // Take a slice from the unused list and the the next one to the top of unused. - struct MemorySliceInfo * sliceinfo = allocator.unused; - allocator.unused = sliceinfo->next; - - // Change it's type to typeinfo - sliceinfo->type = SliceInfo; - sliceinfo->filled = 0; - - // Add it to the allocated list - sliceinfo->next = allocator.allocated; - allocator.allocated = sliceinfo; - - return sliceinfo; -} - - -int main() { - size_t size = 128 * 1024 * 1024; - size_t start = (size_t) malloc(size); - - pagealloc_init(start, start + size); -} diff --git a/generate_static_l1pt.c b/generate_static_l1pt.c new file mode 100644 index 00000000..46fbd18d --- /dev/null +++ b/generate_static_l1pt.c @@ -0,0 +1,237 @@ +/// This code helped generate the data section of startup.s by printing out an entire l1pt +#include +#include +#include + +#define pt_size 0x1000 + +uint32_t pt[pt_size] = {0}; + +#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c" +#define BYTE_TO_BINARY(byte) \ + (byte & 0x80000000 ? '1' : '0'), \ + (byte & 0x40000000 ? '1' : '0'), \ + (byte & 0x20000000 ? '1' : '0'), \ + (byte & 0x10000000 ? '1' : '0'), \ + (byte & 0x08000000 ? '1' : '0'), \ + (byte & 0x04000000 ? '1' : '0'), \ + (byte & 0x02000000 ? '1' : '0'), \ + (byte & 0x01000000 ? '1' : '0'), \ + (byte & 0x00800000 ? '1' : '0'), \ + (byte & 0x00400000 ? '1' : '0'), \ + (byte & 0x00200000 ? '1' : '0'), \ + (byte & 0x00100000 ? '1' : '0'), \ + (byte & 0x00080000 ? '1' : '0'), \ + (byte & 0x00040000 ? '1' : '0'), \ + (byte & 0x00020000 ? '1' : '0'), \ + (byte & 0x00010000 ? '1' : '0'), \ + (byte & 0x00008000 ? '1' : '0'), \ + (byte & 0x00004000 ? '1' : '0'), \ + (byte & 0x00002000 ? '1' : '0'), \ + (byte & 0x00001000 ? '1' : '0'), \ + (byte & 0x00000800 ? '1' : '0'), \ + (byte & 0x00000400 ? '1' : '0'), \ + (byte & 0x00000200 ? '1' : '0'), \ + (byte & 0x00000100 ? '1' : '0'), \ + (byte & 0x00000080 ? '1' : '0'), \ + (byte & 0x00000040 ? '1' : '0'), \ + (byte & 0x00000020 ? '1' : '0'), \ + (byte & 0x00000010 ? '1' : '0'), \ + (byte & 0x00000008 ? '1' : '0'), \ + (byte & 0x00000004 ? '1' : '0'), \ + (byte & 0x00000002 ? '1' : '0'), \ + (byte & 0x00000001 ? '1' : '0') + + + +/// A L1PagetableEntry is an entry in the top level pagetable. +/// There is only one L1 pagetable and it is always located at address 0x4000. +/// Relevant manual section: http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf +/// * 6.1 +/// * 6.5 (memory access control) +/// * 6.11.1 (entry layout) +/// * 6.13 (control registers) +/// * 6.10 (page faults and aborts) +typedef union L1PagetableEntry{ + uint32_t entry; + struct { + /// This 2 bit field gives what type of entry this is. + /// 00 for invalid pages (pagefault) + /// 01 for coarse pages (64kb). + /// 10 for sections and supersections. (see bit 18) + /// 11 for invalid pages (pagefault) + /// Note that for supersections you have to repeat this entry 16x to fill up all 1mb entries that would lie within it, + /// and the first of these 16 entries must be on a 16-word boundary + uint32_t type: 2; + + /// Should be zero + uint32_t sbz1: 1; + + /// Non-secure bit. This is used by the security extensions (TrustZone). + uint32_t nonSecure: 1; + + /// Should be zero + uint32_t sbz2: 1; + + /// Domain. This is used by the security extensions (TrustZone). + uint32_t domain: 4; + + /// (P) ECC bit (some processors support this but the ARM1176 does *NOT*) + uint32_t ECC: 1; + + /// Top 22 bits of the base address. Points to a L2 pagetable. + /// formula: + /// base_address = (address >> 10); + uint32_t base_address: 22; + + } coarse; + + struct { + /// This 2 bit field gives what type of entry this is. + /// 00 for invalid pages (pagefault) + /// 01 for coarse pages (64kb). + /// 10 for sections and supersections. (see bit 18) + /// 11 for invalid pages (pagefault) + /// Note that for supersections you have to repeat this entry 16x to fill up all 1mb entries that would lie within it, + /// and the first of these 16 entries must be on a 16-word boundary + uint32_t type: 2; + + /// If set, this page is bufferable + uint32_t bufferable: 1; + + /// If set, this page is cachable + uint32_t cachable: 1; + + /// Should be zero + uint32_t sbz2: 1; + + /// Domain. This is used by the security extensions (TrustZone). + uint32_t domain: 4; + + /// (P) ECC bit (some processors support this but the ARM1176 does *NOT*) + uint32_t ECC: 1; + + /// Access permissions + /// accessExtended = 0: + /// Kernel: User: + /// 00 No access No access (Recommended) + /// 01 Read/Write No access + /// 10 Read/Write Read only + /// 11 Read/Write Read/Write + /// accessExtended = 1: + /// 00 Reserved Reserved + /// 01 Read only No access + /// 10 Read only Read only + /// 11 Read only Read only + uint32_t accessPermissions: 2; + + /// Type Extension + /// TEX C B Description Memory type Sharable + /// 000 0 0 Strongly ordered Strongly ordered yes + /// 000 0 1 Shared device Device yes + /// 000 1 0 Outer and Inner Write-Through,No Allocate on Write Normal Page sharable if S bit is set + /// 000 1 1 Outer and Inner Write-Back,No Allocate on Write Normal Page sharable if S bit is set + /// 001 0 0 Outer and Inner Noncacheable Normal Page sharable if S bit is set + /// 001 0 1 Reserved + /// 001 1 0 Reserved + /// 001 1 1 Outer and Inner Write-Back, Allocate on Write Normal Page sharable if S bit is set + /// 010 0 0 Non shared device Device no + /// 010 0 1 Reserved + /// 010 1 X Reserved + /// 011 X X Reserved + /// 1BB A A Cached Memory Normal Page sharable if S bit is set + /// BB = Outer policy + /// AA = Inner policy + /// + /// BB *or* AA bits: + /// 00 Non-cachable + /// 01 Write-back cached, write allocate + /// 10 Write-through cached, no allocate on write + /// 11 Write-back cached, no allocate on write + /// + /// For more info (and there is a lot more!), see table 6-4 in the ARM1176jzf-s + /// [reference manual](http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf) + uint32_t TEX: 3; + + /// Access extended bit. See `accessPermissions` + uint32_t accessExtended: 1; + + /// Marks the page sharable (see TEX). Also named S-bit + uint32_t sharable: 1; + + /// Not Global (ng). Determines how this is marked in the TLB. + uint32_t notglobal: 1; + + /// Supersection identifier is '1' if this entry is a supersection, is '0' if this is a normal section + uint32_t supersection: 1; + + /// Non-secure bit. This is used by the security extensions (TrustZone). + uint32_t nonSecure: 1; + + /// Top 12 bits of the base address. Pointer to the first byte in a 1mb-large block. + /// If this entry refers to a supersection, the lower 4 bits Should Be Zero. + /// The top 8 bits now refer to a 16mb-large block + /// + /// formulae: + /// section_base_address = (address >> 20); + /// supersection_base_address = (address >> 24); + uint32_t base_address: 12; + } section; +} L1PagetableEntry; + + +static inline uint32_t address_to_index(uint32_t address) { + return address >> 20u; +} + +void map_virtual_to_physical(uint32_t virtual, L1PagetableEntry entry) { + + + if (pt[address_to_index(virtual)] != 0){ + // The entry is already mapped + printf("Request for already mapped address denied"); + exit(-1); + } + + + pt[address_to_index(virtual)] = entry.entry; +} + +int main() { + const int virtual_offset = 0xC0000000; + + uint32_t address = 0x00000000; + + // identitymap the first page + map_virtual_to_physical(address, (L1PagetableEntry) { + .section.type=2, + .section.accessPermissions = 1, //rw kernel + .section.base_address = address_to_index(address) + }); + + + map_virtual_to_physical(address + virtual_offset, (L1PagetableEntry) { + .section.type=2, + .section.accessPermissions = 1, //rw kernel + .section.base_address = address_to_index(address) + }); + + + int numzeros = 0; + for (uint32_t i = 0; i < pt_size; i++) { + if (pt[i] == 0) { + numzeros += 4; + } else { + if (numzeros != 0) { + printf(".skip 0x%x\n", numzeros); + } + numzeros = 0; + printf(".long 0b"BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(pt[i])); + } + } + + if (numzeros > 0) { + printf(".skip 0x%x\n", numzeros); + } +} + diff --git a/kernel/Makefile b/kernel/Makefile index 099ecd23..9408c144 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -9,7 +9,8 @@ CFLAGS += -pipe -std=gnu99 -ffreestanding -Wall -Werror -g -O0 -mcpu=arm1176jzf- # variables to define in the preprocessor. MEMORY = 1G -DEFINITIONS = MEM_DEBUG +DEFINITIONS = MEM_DEBUG ENABLE_TESTS +#DEFINITIONS = MEM_DEBUG test: DEFINITIONS += ENABLE_TESTS # if we execute the test: rule, enable tests before recompiling KERNEL_PARAMS = root=/dev/ram mem=$(MEMORY) SOURCEDIR = src @@ -57,8 +58,18 @@ run: build | builddir #${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -semihosting -monitor none -serial stdio -kernel build/flash.bin -append "-load 0x410000 0x14000" ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M raspi2 -cpu arm1176 -nographic -append "-load 0x410000 0x14000" -semihosting +debug: build | builddir + ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M raspi2 -cpu arm1176 -nographic -append "-load 0x410000 0x14000" -semihosting -S -s + +start_debug: build | builddir + $(GDB) -ex "target remote localhost:1234" -ex "symbol-file $(BUILDDIR)/kernel.sym" + $(BUILDDIR)/kernel.elf: $(OBJECT_FILES) | builddir $(LD) -T linker/kernel.ld -nostartfiles -Wl,-Map,kernel.map $^ -o $@ + $(OBJCOPY) --only-keep-debug $(BUILDDIR)/kernel.elf $(BUILDDIR)/kernel.sym + $(OBJCOPY) --strip-debug $(BUILDDIR)/kernel.elf + + # Begin Pi Make $(BUILDDIR)/kernelPi.elf: $(C_OBJECT_FILES) | builddir diff --git a/kernel/linker/kernel.ld b/kernel/linker/kernel.ld index 71319cf4..75f4d626 100644 --- a/kernel/linker/kernel.ld +++ b/kernel/linker/kernel.ld @@ -1,14 +1,37 @@ ENTRY(_Reset) + +__KERNEL_VIRTUAL_OFFSET = 0x80000000; +__BOOT_ADDRESS = 0x8000; + SECTIONS { - . = 0x8000; - KERNEL_BASE = .; - .startup . : { build/common/startup.o(.text) } - .text : { *(.text) } - .data : { *(.data) } - .bss : { *(.bss COMMON)} + . = __BOOT_ADDRESS; + __BOOT_START = .; + .boot : { + */startup.o (.text) + */startup.o (.data) + */stacks.o (.text) + */startup.o (.bss) + } + __BOOT_END = .; + . += __KERNEL_VIRTUAL_OFFSET; + + __KERNEL_BASE = .; + .text : AT(ADDR(.text) - __KERNEL_VIRTUAL_OFFSET) { + *(EXCLUDE_FILE (*/boot.o */stacks.o) .text) + *(.rodata*) + } + + .data : AT(ADDR(.data) - __KERNEL_VIRTUAL_OFFSET){ + *(EXCLUDE_FILE (*/boot.o */stacks.o) .data) + } + + .bss : AT(ADDR(.bss) - __KERNEL_VIRTUAL_OFFSET) { + *(EXCLUDE_FILE (*/boot.o */stacks.o) COMMON) + *(EXCLUDE_FILE (*/boot.o) .bss) + } /*make kernel top megabyte aligned*/ . = ALIGN(1024 * 1024); - KERNEL_TOP = .; + __KERNEL_TOP = .; } diff --git a/kernel/linker/kernelPi.ld b/kernel/linker/kernelPi.ld deleted file mode 100644 index d2a979d7..00000000 --- a/kernel/linker/kernelPi.ld +++ /dev/null @@ -1,12 +0,0 @@ -ENTRY(_Reset) -SECTIONS -{ - . = 0x8000; - .startup . : { build/common/startup.o(.text) } - .text : { *(.text) } - .data : { *(.data) } - .bss : { *(.bss COMMON) } - . = ALIGN(8); - . = . + 0x1000; - stack_top = .; -} diff --git a/kernel/old/drivers/clock.c b/kernel/old/drivers/clock.c deleted file mode 100644 index e72bce54..00000000 --- a/kernel/old/drivers/clock.c +++ /dev/null @@ -1,21 +0,0 @@ -#include "../../src/klibc//include/stdint.h" -#include "clock.h" - - -void get_time(){ - uint32_t temp_time = *CLOCK; - os_printf("the time is? %x\n", temp_time); - get_seconds(temp_time); - -} - -void get_seconds(uint32_t time_thing){ - uint32_t SECOND_MASK = 0xF; - uint32_t TENS_OF_SECONDS_MASK = 0x7; - uint32_t seconds = time_thing & SECOND_MASK; - uint32_t tens_seconds = (time_thing >> 4) & TENS_OF_SECONDS_MASK; - uint32_t total_seconds = seconds + 10 * tens_seconds; - os_printf("seconds: %d\n", total_seconds); - - -} diff --git a/kernel/old/fs/cmdline/Documents b/kernel/old/fs/cmdline/Documents deleted file mode 100644 index f8955934..00000000 --- a/kernel/old/fs/cmdline/Documents +++ /dev/null @@ -1,159 +0,0 @@ -#ifndef __FILE_H__ -#define __FILE_H__ - - -#include "bitvector.h" -#include - -#define BLOCKSIZE 512 -#define MAX_NAME_LENGTH 32 -#define MAX_DATABLOCKS_PER_INODE 68 -#define DIR_ENTRY_SIZE 40 -#define MAX_NUM_INDIRECT_BLOCKS 50 -#define MAX_DATABLOCKS_PER_INDIRECT_BLOCK ((BLOCKSIZE/4)-2) -#define MAX_DIR_ENTRIES_PER_DATA_BLOCK ((int)((BLOCKSIZE-4)/DIR_ENTRY_SIZE)-2) - -//IMPORTANT!! --------------------------------------------------------------------------------------------------- -//all constants are in units of block NUMBER | -//the indexes of arrays are also in units of block NUMBER relative to the starting offset of their cathegory. | -//--------------------------------------------------------------------------------------------------------------- - -//constants of file system, that wil be filled at boot time -struct superblock -{ - // char* fs_name; // 32 bytes (max length for this field abides by MAX_NAME_LENGTH) - int fs_version; // 36 bytes - int magic_num; // 40 bytes - int sd_card_capacity; // 44 bytes - int block_size; // 48 bytes - int root_inum; // 52 bytes - int max_inodes; // 56 bytes - int inode_size; - int max_data_blocks; // 66 bytes - int inode_bitmap_loc; // 70 bytes - int data_bitmap_loc; // 74 bytes - // int indirect_blocks_bitmap_loc; // - int start_inode_table_loc; // 78 bytes - int start_data_blocks_loc; // 82 bytes, start_inode_table_loc + 200 b/c 200 inode bl - // int start_indirect_block_table_loc; // - // int max_indirect_blocks; - // char spaceholder[???]; Might need this to make the cast from memory to superblock work...not sure??? Don't think we need this, but not sure - // the rest of the superblock will be empty for now (BLOCKSIZE - 82 = 512 - 82 = 430 free/wasted bytes) -}; - -//metadata of each file or directory -struct inode { - int inum; //inum of the file (4bytes) - int fd_refs; //how many times the file is referenced (=appears in the opentable) (4bytes) - int size; // size of the whole file (4 bytes) - int is_dir; // 1 if this is a directory, 0 if this is a file (4 bytes) - int usr_id; // id of the user who created the file (4 bytes) ...not yet used! - int direct_blocks_in_file; // how many direct block are being used (4 bytes) - int data_blocks[MAX_DATABLOCKS_PER_INODE]; // array of data (now long 68) - int indirect_blocks_in_file; // how many indirect block are being used (4 bytes) - int indirect_blocks[MAX_NUM_INDIRECT_BLOCKS]; // 50*4 = 200 bytes ....50 indirect blocks right now - bit_vector* perms; // permissions of the file (12 bytes) -}; - -struct indirect_block // total size is 1 block -{ - int block_num; - int blocks_in_file; //blocks actually used - int data_blocks[MAX_DATABLOCKS_PER_INDIRECT_BLOCK]; // because this is just an array of ints, so it's BLOCKSIZE/4 bytes bc each int is 4 bytes -}; - -struct dir_entry -{ - int inum; - int name_length; //including null terminating string - char name[MAX_NAME_LENGTH]; // 32 chars right now -}; // 8 _ MAX_NAME_LENGTH bytes long...40 bytes right now - -struct dir_data_block -{ - int block_num; - int num_entries; - struct dir_entry dir_entries[MAX_DIR_ENTRIES_PER_DATA_BLOCK]; -}; - -struct data_block -{ - char data[BLOCKSIZE]; -}; - -struct dir_helper //used by helper functions in file.c -{ - int dir_levels; - char* truncated_path; - char* last; -}; - -struct stats //statistics about the file -{ - int size; //size of the file - int fd_refs; //how many times it is open now - int is_dir; //is this a directory -}; - -int kopen(char* filepath, char mode); //opens the file of filepath with permissions mode -int kread(int fd, void* buf, int numBytes); //reads the open file corresponding to fd -int kwrite(int fd, void* buf, int num_bytes); //writes the open file corresponding to fd -int kclose(int fd); //closes the cpen file corresponding to fd -int kseek(int fd, int num_bytes); //moves the offset of the open file fd -int kdelete(char* filepath); //deletes the file or directory following filepath -int kcreate(char* filepath, char mode, int is_this_a_dir); //creates and opens a file or directory with permissions mode in fielpath -int kcopy(char* source, char* dest, char mode); //copies the contents of a file -int kls(char* filepath); //shows contents of one directory -int kfs_init(int inode_table_cache_size, int data_block_table_cache_size, int reformat); -int kfs_shutdown(); - -// // ------------------------------------------------------------------------------------------------------------------------------------------------------- -// /* HELPER FUNCTIONS */ - -//from the index, gets the corresponding indirect block, either from cache or from disk -void get_indirect_block(int index, struct indirect_block* cur_indirect_block); - -//from the inum, gets corresponding inode, either from cache or disk -void get_inode(int inum, struct inode* result_inode); - -//gets the inum of nextpath (file or dir) looking at the direct data blocks of cur_inode -int get_inum_from_direct_data_block(struct inode* cur_inode, char * next_path); - -//gets the inum of netxpath (file or dir) looking at the indirect data blocks of cur_inode -int get_inum_from_indirect_data_block(struct inode * cur_inode, char * next_path); - -//finds the inode (will be result_inode) following filepath, going dir_levels down the path, starting from starting_inum -int kfind_inode(char* filepath, int starting_inum, int dir_levels, struct inode* result_inode); - -//finds the name of the directory path (result->truncated_path) and the name of the ending part (result->last) and the number of levels (result->levels) -//result has to be kmalloc-ed by and kfree-d by whoever calls this functinos. Also remember to free last and truncated_path. -void kfind_dir(char* filepath, struct dir_helper* result); - -//transmits or receives the data block bitvector or the inode bitvecotr to and from disk -// First parameter: TRANSMIT or RECEIVE (defined) -// Second paramter: put pointer to bitvector (example: data_block_bitmap for data, inode_bitmap for inodes) -// Third parameter: put where that bitvecotr starts in memory (example: FS->data_bitmap_loc for data, FS->inode_bitmap_loc for inode) -// Fourth parameter: how many there are (example: FS->max_data_blocks for data, FS->max_inodes for inodes) -// index = index you would put in the bitvector -// all = 0 for only one index, 1 for all the bitvector -int transmit_receive_bitmap(int t_or_r, bit_vector* vec, int starting_loc, int max, int bit_index, int all); - -/* Helper function to add a new dir_entry to a directory file and optinally write it out to disk. - Updates the last data block of the cur_inode (directory) to add a dir_entry that stores the mapping of the new inode to its inum */ -int add_dir_entry(struct inode* cur_inode, int free_inode_loc, struct dir_helper* result); - -int get_block_address(struct inode *file_inode, int block_num); - -// Helper function for kread(): -int read_partial_block(struct inode *c_inode, int offset, void* buf_offset, int bytes_left, void* transfer_space); - -// Helper function for kread(): -int read_full_block(struct inode *c_inode, int offset, void* buf_offset, int bytesLeft, void* transfer_space);; - -int read_inode(struct inode *c_inode, int offset, void* buf, int num_bytes); - -struct stats * get_stats(char * filepath, struct stats * result); - - -#endif - diff --git a/kernel/old/fs/cmdline/Makefile b/kernel/old/fs/cmdline/Makefile deleted file mode 100755 index 6d23e8a2..00000000 --- a/kernel/old/fs/cmdline/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -INCLUDES+=-Iinclude - -CC?=gcc - -CFLAGS+=-O0 -CFLAGS+=-g -CFLAGS+=-D__HOST - -OBJS+=file.o -OBJS+=fakelibs.o -OBJS+=open_table.o -OBJS+=bitvector.o -OBJS+=main.o - -PROG:=buildfs - -all: $(PROG) - -$(PROG): $(OBJS) - $(CC) $(CFLAGS) $(OBJS) -o $(PROG) - -file.o: ../fat16/file.c - $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ - -bitvector.o: ../../../src/ds - $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ - -open_table.o: ../open_table.c - $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ - -%.o: %.c - $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ - -build/card.sd: - dd if=/dev/zero of=$@ conv=notrunc bs=512 count=250000 - -clean: - rm -f $(OBJS) - rm -f $(PROG) diff --git a/kernel/old/fs/cmdline/buildfs b/kernel/old/fs/cmdline/buildfs deleted file mode 100755 index 5715423131c1ae8fd663e7eb3a8009fd89f291a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71056 zcmeFa34D~*)j$5sa%ag-CLv)THVuMd5fCIm0t^hBAQA-u1B8S`LPC=Xi!4Egw2VVE zQP9{@h?dr<*wQL3vS>hSQtMl>wVJlJrhTDK3T;!NHEq%Peb2e~nI(kQ_y7Jr{r^9o zKcmdO=bm%VIrrRi&)uG9QstUA(`Ybg`p2YA(FoemLzZMK#JRXIO|~{ci`BBV!P+3r z0=yajbh@r-kr7CI^wcIn&4iTdH7b19w6CJmQ(ZcxRPTD9R=dRLsg@*RswXI`;I8TZ zyCt2T>iCen4HB<)N!t`ZJ&mkKwh7e8dV#M;r{`6>SCS#Ev}ONv*IA3L&S&8;QHrInj+-8^CZt>edLR+MFq;dZA$5i;ehJ9D*@4-OoB zvi~oC^`)X=zj(Ue_&*L!e*9(9n{*(4L_;5UGK&U#Hx8o${xzQ~uTKlz)zL zC;oN)tU^I|cA&EE%FC`(zU(^Xy{}Wg<2vQ>hVJ$BgMJYHUGssz=aYMn*D5^a`5U%q zlql^74z;Ud z3s{}?8&FCbl3YkxzpA)Yt0>)2UR>%aq-q7)ta-DiP0t&XIeKg;8_tc%9H-^YUOYc< zO+k6V+TsdNLHXkO(@V-q3l^_hT~Yw%YuA^RD&~2Tv|B=$jYhCB;y+VFp2{gMhVlA{ zH(>OmOZ2d-?W=nN;moX^QDrH`#qks&-d1pB?_$g>M(usT^wHzF9)DLVr|MAgS}#vh zYuiV@tmFrUzm1H!~x293KJ_isys)4>`xsX}@p3ooxqK}*>vLng~r+?fHGDl^)ji_W{ z1AR;WYHDYANdqUWPmIj+_sWQJinaQus6pn4f1F;3bVGv#s2m+0`fP5HSt?Hmm1^3~ zh;n^SBlMn#^2qp78&U2cLiMR{kQw4nbC>>UXplK7Pt^;NHa19r%6rNze;;j-0F|f7 z?2Ydm7Pw)78y2`>fg2Y1w-&gZ*#94H?s&WD?sq5- z4n2?W!~xmJ5nM#L_O>8CLw`vyEg{;^G5k}4X(`j*#PC}L(^8`SD8pw7rX@ss1H&f> z76jKa{5^tc$8*VO!_N>*ON92741bkiS{k%3WcV?HX-UwY&G5qn(^8;) z6vMj+rX@hTli>#mrm4R@iQ#gBY07Wc7=D1@M1ng$N5Rn51k=>t-p25K1k+Ni{T#!K z2&N@KdlSQR2&SpO{U~6v_vk;)_Pu+*+xI)S_k72~#q(;!-|m9xYvQXoncR9OES@^; z5ly>N>#mtR3=G^gVh|-0J3XoBs{X)HSJ{JYi34_mxAwY9LH~C`){Ogvl3|~_eI4#I zf12t((`j-W-gLkFxhDk-{#qj$*n(|^i34VY>yv&vCm%yyt@5^9w|DYSL8-ZY7d-K9 z|Kvwd9!zaQQ6L|-cvI{}fnmk#g_(&1c9R;~>xJPw`3v!DUkln?@NhqLsRN#{#_cx` z&0w~!&e2U!dDjYXJo8yF*j(+r8Vr&*HCGQo?mMr(_?zbH4CFND)7Iwd5tM^-HCKQ=8w*^zpYv=cT~fc5(GR88|&Q=8AU*?ngf2jBao-$B%D zu3iWnF>kJ3ta9Coc@K=j&8JEy>Y=3D$71%d7&7R!Vs2*zrC}j;8c2_mK(~K>=Nk8I zaqJBq5lBGoAHB}5;=SbbZNKEJ4ES=-`(2lO;(@(rhAZF`1;{ju0r;j*vskKf%rS5V zysMik6W~?Z*t`eU{WBQ67zgM+f>r?XZa=SiVkC7TY$f~ti7C_)aTOc#<79c&2yqbw z(pDdF^TjVw;Lnb8`%}+RZch4BpZ?t^wjqykb()bWXk#q~75I5%`8T<|FUmK|@|RK2 z?CPKvTucYAc|_pqaQof|&6Qc2=5=)#z_5fXrc88oZ2JYkp#a^!H(#TAfrTJLS#e}p z7Rvm>f+A`_bKteftVSx)AZ{S>XQ#O9&$O91Vd325|Et^WvF_GyJqYUNn2os5GMDEJO8Kd zGrvQGJLj%R8SVBZUF-v-^%`U|RfBD>kZqHgD{Oluajy*_$}f^pBJK8-EV7%c6J+f^ z65dxg+Iq%_f1*@3+C$*!7e7Y{cx}HIb&heJ5zy?+@9c(izB8~Ix9ptT52h&LF|!vP zpkrE4?ORkWsx|&xP`{-&=*!pOqZ%}orS|0pm7qb=$M;b$*GztF3Hg7gDh-XYB#5LJLJH~smJXbH=^rtyVa-|U%-PG)A#Ha{1 zyN;3?GVULo0EK+6kAGK9Z66VqeO$_JK`WbG zFH_}(ak*w4HDs8-q2>w1~G_qadXJkj-X z;@&N2;YCBOjyyuhdIbH6t|N(i2T3H+lP|q;J8^4t`&R@o4foZj;jdi50?7MD(Xtgh z7vGI_TLya0?K|Cy`P1z?b`D8b+g5j=kUq`T8m4iXyMi*ZOmp=mm1}>Aov@lX`S(+) zG;@)EMs1vrtGa9Uw_#rP*AO49M2J+z%L6Eo-S+W#(x=)MrjUcoS8Ya7b9JXKE(zlN z47%(6yQ>3WtelrC%RV%d6ZrQtw;EnDVo;s94T{4`Zr{6?-QR4kzN)kQ8ubB#*YDj9H%P}a z5_tB6Y9jHm=`Z&3vQ7p+uXHCekhu45bcFXb_d{hLFB<|BWS&WEs>Hp&!3q-&1F_tG zxWzN$5C~PBL0;}Uc#-Tf4rLR$EOGBxS=G-9boHW~Ptb^m-XPCWj)bAP5<~O2ukvMI z?ol{?W26&dD}bTnbG^~*YGI#|N&9cfe_U@{hbA&?Ls?s)<1}MEa(C>PiI)(h( zaL%9mcFmk%;`fu>`DgYl7U#U+5=D^seJyLGr?+?e+s>+#u9)3TmEWZ@tT@2UpWEnn zy&+@mO75Oq64Qth8c7eK2&#LxzoBjEiQyZGJ5GJ1a1PAG8QA6pe%67R7>MA-VP01Y z)H>=77$&+}68F+JG)mlG{-GxAuFK_*z#|kXvtij51U*DKwoS9^LpF`yg;H0b+117t z8U>{TX!q_W&#fw(HL^0^>uNRVBxbLx&EWRB0tT<^LxXpF+khQ!!9o14wqdRh{jLwa zO$M~M0K)@}J5VeO7R!RpX4iR^G#Jrc_C*W#1%S8EE{u=2Ab*e1i{KBENv;pK{X9ep z?726oza@_hKdt^hL=fdpjbcO#qi9BL+s=g;0ZWX~#3p}kE6+boEZw&dVc13aPPcDi zQh2Hvh5ZKX*XGL&_~w5&!{=(9;hX=STBJjXn%W?CnV7}hXU}xTQJYS+HCX#wF-V3Mmdaqk19@RKOS+#KCH zEHEO}RTFN6x>vER?W*n~Y_7xVez7`!S%=l_0d?2k33ZSEk=4Cug3i*tX$HbF4F0x# zkFRpK+qZu+RF4cEJiG4$iJI1%u`!2tVrp~k!Q|)dTvO%dyjqG?-k~rx3o+PSd!pz1 zzio$2BIo)>Im$mAjTloTXP^Qpp&`t*#!cgv3uFiW@vk(JT@9F;rI-eYQOk+PuOng$ zL^Qkhadda>_K~AjQ)A&KNnMr&Pm%@^SPaVNP=rtep^Xsg?X)L8x}WSOVZ@I{8c5eJ zO|T^KV@cw}62*rliXTf7Kb9muOjSNCQT(}W7%Lfyja*MQ`WBi|0PEVkO&LB~4epU+ ztI-b*;(Ob=x8ZQ8*nUiqQsUd7q3F2_Ybc+q-n+eC+cFMr;GYLK`0hovULz4CjRc{0 zdxPe|#@p3EMW1D2*^T)p*zRX$sjEn!t6qlav6#_iKb;00JmDzn9Sto&T}S=7^&AwW zcjPBN`gdukJ-iVD9&I4E_>tRt#_U_Xhk^#t%EqIm*e-!88#b7K^nYnoVk7w;y{=JN zA+cg>7o#4Pj`=<{lJpq`t4<&yUf*X@j@S1ykh^wqZ^W$C-VYPBcl$oAQaSeCTiIX@ z$_u&OJZi4-@A%8t_wSb;?4qd}LQhFeX-s%KwIr|U05~+Tfq7zZSG!PN@%M+C2emR2Nwf*wI z-_bACbc9Dv$Hw<|Iuakv<07#Mm1qde#e&f1I^f-YKn|ON*%&qt2ExPU7sEjqJ#5}Y zksLOQ!AuU3uM!#dK#+DkJVcKBa}V$kIUdeBe$5?jYJHeA`BlI zwyGui2vXb8|KK1>?YWsvdK{+>^>SNw&W$|I1q!gA?%dQZ)}MR)6+X}Pk8%4(A+qBb zy=I4vGVi;+Z^BDAcDQ|;a4NOg=JtNv=^lpv&l=8nf7|J6ITJAXns|+P2Ac>7ISC{M*wLmVcdert zK4oV)PTq867$!GbpN^UZH@fZjSaec&y*LsYVzJ&F@Phz(4#-u=Q_u*<O({9hc_57d?01u`z7M_CG+V-}Rms+gr?g#Xt2rZM)oO{@^s6J@XICna%;j⁣z zT$h-U+}XG;ZKw5|V~3K{2o7?TcrqZ7j|8Dh?j={HSAsATfW>5tc2J7bjL7=??By7j3qkcwQ}n&j^iS%m9bu!QET(LuAp02R#Io; z&_pdCsSt;W=$XIVOwGI!+6$0%1L^?EH@|J3&qWL4r_TH#&2Vlg?HpMwim>Vfq}H@{ zh@sQR(6P=!^gl0hJGCt~h-#-rxoqn>83ca}oA6rks56 zDA@l0#*qKoYQ5pRy43`%c5!i($?BoDZnA#pG#v5NOzt;B_x?Wr4euvIUhJpaj8D~+ z;RZo*Zshe;l)lzIT-Yi_3_FvTeGk!JyX5ms}-3QR8Ep@`3h zdaTu5lV$MFms;TXVLlD9z-(WO?_Ia=ALR8*;GV1iX*`)-?G>rb_TgVd_B+^qqdwSj ztBwpImDP>|M-?(eb?kAyhbgobCvE7b`e_J_>A%$j)JVAZPDC)q?IYaPHXY{xuGtlU z9kkczHZCw0{1HDoUQ0(&;3f%?X{ljwOg={#i7h=T3zIq;n@ zoJ8;;9Y+3fk*LhuChP z!x_1E`-j?Q`$OA5q(0n1cK%)t)IR!=Zp)WoF?7N?Y3Sz(`FIHV1d!B0RWx@!MYv5m z?&9`l*Cn87rZ`8o$2K0S>`|iwrJXoI$SU{r*R!iV#HEC|j3zEPdI?^yaT?AE|SH63j;e`BnLx=dE0T z=JT34W`Ayz+U*gMT&o6nws?Gsg# zZD^58^cG%f_9U$%mzpiICmtm&{o>OSy`g`k95>W-y@tMe2@S0>L~6x*m3z2I{1_ZK zpkR5ZAA*t#HfEtCfATB6Be%g)=(DerJpGt;0~Qz3dVlXvOgL0`gf}QyLcPHoln&W+ zUM+>1j=-pz-XWVF@asDc)z?K-Uv5p*6`kJQOejU~kfJf}c>?N)oQ(GqjzTaZgE+gc zi%mPFO(zXtBA#Mqa|Q7vk+LJzP>${U4a!x%ajhfWFONYu+SpP5B3Z9y60BGIOWk@? zU~9VY;njExnfs%DVCOnK$#tq~BVA=-K9uV8f;#@(!*oENPj1%c=7kZWBi~4$rFxO{ z+aMB*41AQ<$}#RR$GBF+ICjK^Hp27T!ne@Y>^cm8)Gls|;_?mRl6&fUQs;G*YGJ9T zAl2_WHOzGwf~4$IA=yCi(fqlP5)y~OYV&SCtR+554|_0@x@YhM(4d>E%L8nv#!#rH zr%veTljfsK9HVJM7)0Lc`~~byljz0q^h8Q?;BN?wbRh$RG!XFaCvYE8fhc&9rT|dI zfC>vf+*?Ko!J{qFa;RT_L;ZTZRmo{@fhE1$12WuyK)3@T+!5fUfLCBFj1IV{n$9X| zVZbxnCZ5iYQO(s+tPQLb|6q1>bABJQwC=8aWT%M^X-b zpd02j#QmM8sggubBJ|D>x&dfBN=9gWR z#ZdEA(|x#~zb`s5=KnMv&hv+#hDeFiOmI3bdm;MS$K;=5xd~Pa@lg z0;OLw)AchB(%R%fnmKgNm0AzZI9rh8HGs*D@1t26JjH^e2I+<8;mmGKd+M&Z{Sh8z z#1c2n^yE$vuG-?DX$JArSG%rDbaqGc67RQTdWLrCuoD?PmsW>TnGVE{SXQP(Dzl80 z31DMRJ%aIhB<6i(FYVWW;}9 zHNr-eJrR1C$yd2Aa(2XRr?f$vgKcnBt-9JjBGdEJONVu{%BPoxKv2jAG%u@j-LuLi#@=EJ=a9nzQpQDQWw75+Kh%@hjC2`>{N*>w0GRT7Wv2& zC3s{C=GP_8!KU**%v$=RGjq}bJ24w)xP8+w!ub+G-mxAH-xFa7nW8=jmBRr1M8z>6FKek*9>cB%haH{1~0|61oM$$v^eAvY^^Z& zceoTDEhIlgfOVQD?h=0NO>i-l)dtsT&5m8WDWV*!}TcExo1akA4}Zn zNvN(DN7~yc3qOX4BUvZiYv3TQ4SbN|P!SiU>M%XA`bjwf1b9_(+j44SMrf*c1!TZK zA|*4Cz9+83wkUKYkD2RcJfaX7^J7-Gjl|R?fSK#+#aWQs#_Zo));;_Al0Da2hFa2W ziByjmxg{e#x<7QOo^%waW!k@kve)SSjlkF9Ne5R$bM-c&z^DBZo028_ z_fu(9R21*u7vVszeg52iXrQ_mKaM6gyLK|0N0`n02ES|P|8hpbHMiW;{0R$M3UoY7 z^?THJuy&$?kg?br^{@u?Vi$e~)x55q6g?Z*Pj@1sqFr8YGm2$f5m&h&aqs7$(7H`Z zY;1Pz=0;8Dh$ZQBcT2S7-Lgk2T+pLJeT!Cs{*PgI#_jIu> z8i~-L3~M8+yLN|6t^&mF#J$hT{%Ry&A3&<0uPE<8p2tzw0P#^XI{2YCXbfF@v#gex zvSr6(xMcweJue}36LUa9ooF@wg>GWL$$NFI^VCgDz|Uc)6^{eUo0wa$3spBUTjrr6 z2c)&cOx>|8lX)=3p#j=4Hw-5cJV}R+;ZBNe^Ks`y0TwN74!GV^jie_U z-(r`=0+}1gelQkiY%l_;NaXY)ro=V}mg|yK^XG+O)+9@ZQEwFI#g2Pm1>Ti=D97go z45zJJOP=DXB-E0FI1ABR@|etr zY`QB9b4$u~7%eH}ym%QJ$d)`$Ic`bQ^|aawPlDDvxem2tBiEspjJ;l+S*U}Sgm!ET zF*UYeYHaeI+v7T=o|A5Ny+^S^o_D=$MT__v2YW7lDwx}S8nIIji^nAab#GgQ*S{x; zmDi6&IKa&iUB+#>6LaOZVVFTIZ-kw(fVj|fr@B2i470IZIt*h?M4qSq_ASx@1K4lk z!CUq0a^kD=aZ}U^ZcTCldjer?~^E;s=&gnsL7*7d+0H{u){|m1Eh>Y?VWIkm7 zpNC=A?}s`J+EMmYv_azZ=lc-9mZ=0T9HjzyxdHQ zx5-A&%it+;*p+ACz_un@Gm&JxMY0$~cohUd;@XDV_jvf2wSOlg6IWlEO)7nzeWN~Dr3T)7GkBpV%`3UG&>XTr&8Lfb!+lO z?%IE2a{Yzvc4=|~|1&0kZisGj`)g!!k{mKQ0lLYljbw6eF)g#GAaQRetmS3%hx$XV zv{aYW0IzD%ApMT)0dhzJrSpWwN}a^Yu`S2Sj;JCYE9)YPz+*YUZkKHtuR;i33_`5w zvTUR0L86|Sq2H#Wcq}6g_brFbsFm73X`e_Za@TuiW+%3Ccv6L~+qTSxJAa1rxxk{+ zT&shc`(1V#`EUopPlsV{S)C38SB*UG-7XeFBrcv2mtE%~Z=ui0eLqmNMF&I_EM>0F zMa>+zv!bX?%LqDQFwdO zmwO2+ljEveY<1h4a1A5e$mQaZCp_Cl&)s1HzCs$xk#-c!yNKmCGw~!0&qEyTU-%+K zZ=Sq{6LV+|Tn%Bk_3{NoedkY4G}es!+CZ48X7ZCr0yU6E6Dgh(BOOk_YVa4n$zDw; zxunOu_^!O6fI9(?mzNkRC(mMtj5amdEg*$uN@2Hfs=-(J#^k>^uy`0u;D$eu?A+m50^`bAYc6*(M1z%ZU^X%fSLhy=mRP ziyG?}cA&a@*?Ki_f1J||j@%Rb4qWz%|GFL?qP8KKaH>e>Ak>uK{u@NgeG-z$PY)MuUdWll%8MQqj-LbLa*fdhmn@3sm@3wVl56ThGP-X3%> zE;+K%|J-PGJ`W#C!IRdn4Xj&&hGU;#5yT6~pI^HKLl?lZr|DSiu3{zW!^A};)JWw^g7 z_Tqq4y*~G}Y-BF;@A3ly%7A}R1{{4o8a{9(?@hc81-aj=IP(L^rCHR{E`oqQ#OPE( z9Q0T0S74Y%I3MD%cl%X-P=q~vhn0~RGr)F#cWn7a4(-$6!(@FmfDvo--$u9-RqyM* zst3<&h$-FS$SmX|I3t*NR=@L0ju?77o@2$NxSV@)?#ao`S**WO=R3U(J`%auZ^7kK zI@Akzu_Jc-T(y2ax$(9Qz|&^ce*wnrYjgWvm&IoS!gmH2H+Xv$v`3M{%{O^nb2Xh$ zf?DIUg|ci(xU43Hrc&)VIW|`}oO_k>GKhcrH}|@xB=<19a@&T5sL6dMVC35&zU0_T zH7_Qk)i~MS+ib2S*z4Mh6%sWEN=AKpKm=-N~M>u?j_!|^b>piwok@w!cvPq{_35%+H`c>jNF=>7kf!KtR8 zby?2xoE16u=j2J(QSZlsKaK|`x-M1RiA4qVKfj33MsbB+A2{2>7ePS9eW zEPsh}2CUTi$B*dggCx8ZQ~nqq(_F_h=IZvrB&YXrXE&!_8;LzhM&c)4+Q@@E=`$Ic;%jH>iQXE@p* zWX-rg^(4~fz)!wQwABGB^`53gs~mtIf}4VeQRL50)Qo$BXlo`@66jC#_<0Br@{oG9 z9F`+SPq$)+(;S$93tokPb(2D6zC#BnZK!gwpMU>(r0$xU4kUgql;=r{aYlnJHY-w7 zO;}zsqeZWhE0BmWM~M&B$B7HRwW{w*4!||Z=i0bBz%-B|%DU*cz2q;w;kUi0e#lnY zHbmvqZ*#;t)`X;ssZNkoUhZ;W4Ya>RoBUP~5~95~)`&1BRj)^!{UORUw3`?q^w3%a zT0H$7YDG2On!&h~XqB`6O)Wa?Se~k;`M{&Zp=NRs3IcU?66z_glcc3obe?iZv<>g`0EFh)EBfFvCP2}^m9EW$I71WcPhz`Sq zKnxQkT4MEgXpa=884Mb)^bl#sN!8?DiF@C}K7+;4-Z%2c=AM3$95V9f3TJ5idxbgo z&a0XH<2!JLaL;Vt`#HI@eSghaoa4Ki>#n)=6pHVjH|#Tn2V3B^BT(VYXC}{p(Z5o^ zzc|nL$voemX81nN38sAH_P%a#PyBV|AL#cqm#xre)5zaQq~Aw;9k!#Cc!qy@6NNWE zH!N_&0yivh!vZ%faKi#OEO5gDH!N_&0yix1f6)R4`q>S9Xj?tI)VZ#(BCoKleElj9 zmtwCo!#RCb`5I?&X|bmme7>7Q@*OSVtuj4Syt{WFUT(_-dLb1q8Y^%>sXGqhH@1f zR^=Bs%QhC2J2jnT!G?nJRi5IqQYZZxE^u63kiV)DT9RhYqE!{(xhkL9yMEPXC;ic_ zP1ICp1^s2M*`*utC$>-re~N3Jv$S&k>H<37;g4bm1(i}!RL-GmVzkmSC;oO@seFCe8psG4L}P72rX1lc*o@wVf!6Wg79)ZAt4aw^uya+I?+EC)~Zrq)&Qkg?gg>*%kq zbtQp8!qy-S!?uf1lPusWFE1+}DBY>75P!fZi^5=2w=N7nFL! zZi^65jPOA1kQx`4I*U2PMd`E(B1&&9SiixuC0uuev!cwYhQn%TQczOhL1WZM`Q!Am z$`a}I_&a%PsB#_@fd4>HNx{Z~lDx_ddBvp|hKOp@X3ugiT(n@?JlA{`Jt+>tp@*)y zR?vu02tiDO-BjC3$TbT}W3+W7P_lMbA{6S8*$HpNaP$;(DP3FO!C&30$S*J6fI!g& zscG!~*LDwvFm)FhZ-lO62|8Z+54ZIW=gSjq`om231j z0yFcqLhV{xshBmiB1XGAXNL2R44R4v8d@=OXoXhd%yQ1pS&}z%_B>bKojLPedGlO% zYJ{=p;7=mLks%mE7vHdM4EGE?j!eo@sld?3G>QI(>15<5JQWPm!$*6*8Vn{OedufW zBOpkRd_5T4fHe7O9A6_Xd?pw?iuAkR2nNp~y@0d>>4a|vgDED|do~!Hfb>_5!Qc|4 zeV-2oHzPgqLNHj5)Q3asQ%FC?b=rqWM}0pSyo&T^Nc);KZ3NDfvyl2<2?m!V-GpaD zwjmvaXY39j{R+}kNO$8A#t)G;;*syGNHg%*dtaex-@}t{Sx8^|uV8Q`(%PQ{gFBJ_ zHxBa;BmL!j!QdN62Ye6=o=5uCUj>6UJo0ezL$n|1&yc#2{t0Oj(!RgOoA^lQAZ)~ zkuE{HryX`jnt@*;sYhCmv<)eJaMsKp!-I=7!{#JIpE#?n7JfkGc=b=)P#+AAB#IeU zx_j1!;NMvMvpor)0G*bQG&3Q6PGamP+fHq2?@71ZHe?V=xh~!?(uTp8hQlYcoP?w= z8>h!xOg9-Jg7Mo>JQluHh&~VFSDAGD0Te%YFc@4+azgbN7ic!R?p9GdoTQMebqVQQE{BD#V_*O7@Fbe+^<4K3ZDDRCi^bUL^#GiCHYvsoD zMR5ygeu#UN`=fX)4ao?g+=Sb)*-`izA-oOk8}Yqh@EhP2l3_d;;!pA5JHRiEs=qi? z-wk{K<2f%1e_se+1pLj%g278s{67xy-vj(*;9tNv49PcrOArCIuMzkiCxgL)sQN2I z^;>{{9r(|p@SP!i0QiPe!QhZ6{sTh%ZScXvh$B0r>TeCz&j8+hHW++3s(sbmJ}2t9 zfiHbM7>tkPPrhVg5!{9n(A8q+7CF?A03gm;2LR}?;*@g$=I_}dWwwjxf3>XVF8bEvH;z&(uDCk95fwQr~| z#{%!ijb=Jngm~P|)mg{Izf4WQ_zP8fsc*E&kWE=*>>;~S} z77W%!+RL<;$LtJLISl+BtO*K;;mm}jM~$-+(jPIo5}Y+=S3<^KF(YBrmo4su30~{0 zgzVCU2{{R)auPD8B{-)gq)$sonwDUrr(?BC;Bypw(ET?)H!N_&0yivh!vZ%faKi#O zEO5gDH!N_&0yix1|62>JOqNYgQYmfK=%c6jjT`ylQ&3IA56$prPrgihDLC+Tnc=e! zWa+GtK77`Iv_s+PoPa(${;!|Q?KGW3(MR8-)vFA)vHYQPDEi1#e4ME%1^KK3<$NZC z6c1NNeN;6Zg2`gqYSO1o)z{B~u|?z$9OReyCAJYM<1OqJfF(n6JPROy#h`h-fq zrPA-K^i7q%uhQSE^lvJ)^pKK!s`Mt6j#ueSmENP$LY3329YX5E=P z%sDZ0Oy+3km{DU!jT(L1D22%>&o6S$D=w|vEb+s2{H$jvIieVw?zj3#uXw@B{O9e?^>(uGD=1PKcoZWTzk@UTW==6VFDyi<(2U3?xl0IXY zPCp}05}dw{!wrPyQnbym2n~8{~MgDnnzY&2R+!Om#5&cX07+N>^043-4O zi5w&*vnVe0Xy$t%UF-)t<1IZWA#b#a5)fN#R@)8&4VF|;n<+1z1evLKN=3#q5s`$L%JCI-y*o599%GXpkzECCq|#M!?FO)bM1NV5NuFt;#} zV*fpqvJ7V+-Tq}_J%WM0_MSv`D+5k@C6Q$^FvLz5h?Y?dWZ0ch!!nwI5n9YQfU+4a z6KyxcBKFhJ*K!BrG<#1{brJ(+`z7L+#emIDKP_XK%s`yIiTF)nAjv+C$fh!oVt<&l z%eD~b^w`@7lf#%sL+qD{_cY7xKpio}&Lw`+6J`OzfQTbY5hi{bGWilF9K#OS``0Ls zSpXKA(K6HK1Qq-gOMvG#lNhq+5H~{y>%J z7dfoSR#Hc^pGVuQ4hJD@cKV$!Yl@xvj)nwzeqs&Aj5WQt1(vj%IvS`F3T$zJt*k`i zJSynJJ#RNo`-sD2RobT0PAA$as`R{G`UGrcn5s&%bq=H8E{1GX+M?5zP-%`T?W@y%6U{VC zQ>8;xY0}KQHG?aq7r5I^NvhClYlq&6WEaECcxt`f)T%RYfq4zHROu+4IsNjFVRq6g z<`Yn~R_>(43~JDvUfUUG3(4>Tw%X={d*UThc&@6g={%c>=e$(3-!+St2{ zbxRyJf}gV`krx^3Ryw{#^v~N;?_&BQ$7>|=h)%y8EvSYtD?7f`Mq?snT}g#zxL0ar zy_0mpT`_D)AH#v)!WvSmdu^$tm8q^}t7N-GvNhGcw^i!3R4)i@b+F?1NkvR`9b2WQ z%cZ8Ky3Vbs#hRg1uh6>HL62P+%51ic5NoR2xy><`RDaOciwtk7+q2DaiQ2kVuX1T? z&-)j!lG>kTqCEgz9rKB*+}4XCjH#|^Tj~Rvp~7Y*zciE+r>VvZcwMI9`=ZKiGwW;j-XpRq|j& zJ``k8Kbz`~RLQ>TAj?WiFayGe)V zIeJn3F}B_`{>TNh2|rnOq_M6@>v1Rb>&;|9W8DndhLcu~kH)&i(%nw!@IvWauUXYFSmJn>tkR^zE2TG{wWh0Kq4oHfl+2Sl zZFWhW_|lto>VyrGnMa=0Nkhw2*SaH_$6B6ssw_CSLu$3k%7f8V7uezGpwO{eFSxoR z?Q_NYd5EJAIsFE!a>h$L94}FYFX;uls~qo>Ugg%_qye0~!YAzI2~))Z;t z2EH=2+GteupdZLJWXc|Uc7_!Bu99pxun2Rd?4V5RAQ=po$R5nJPLl9K*b1uTGWB`0)v34F^VJ)gpQR#B!6=Xiru0z2urdv5b>rTko=SmR_>U8dR6O zYf*u#v5GqVXBOop`>M!HKeMnao9gPhhks__Rhy~qKvmDAY^eu7=7DTHv~V<$&{j*R zf3&pm(Ez#)ZkwQYfsI%}bgh>2$V+1ATCSAe&cfxkZ}DomQd9=%FL} zq^{8nhb-}O94>UcMd9b07AJWd#x}L=TRL`e&uyymFj-e?Ce`mJ8$V;|Az7@^(%#WE zQBFGCf%WcZ>bRWe*j#XWvWl}cqxYbQ&}oiag3E(o=> z)Y4D36k%x%DHagi`6Ux1F+ZDwtl@w+0oLK!I3PGI(G(6+HItsh#Mq;O2H{K6W@Wca5ueEfHhZ6J)+R|3W%n#kewyUG zB>G5r2^;8?=qG0jbc2g5_?ToFqgWP%SoTW9@|kS~l60+pWo90xy1iBDc;KDt^jFJ`DyiqM%sl0wud7(mfLST(cKnk} z{AaToxBIFb-=uEp&=nO@KcnN;w(UO=-wnLDT#9H>g$ub9$b?W2!_ zJ;5Z@Y;d&7kwYzu)e9P`((dQS74Z~}?mQQ02G0<&)B~ovm#Z9SsO=*~e;Ef>rm{7s zh7n;ZqgnaNJlQFY=6=dxvQHY#H_4uNJLss! zaLml3%UHKu8ug+ufLb;uv&kwFo)LPyzIT-9KHTtsnajkdfY>%OqVL1yj7~i zPc*Vhbd;0)v?S>-Bh`{*+8d(EaA}3b(n{&(iPB1LX{B`YG>Km*-K@86l_F`iKDrJo z(|YhzZv-8TI7-LMrcp}A zWa;{*DY}lglaF0C-Klg;=Am%el&5-Hdivi?s%O_oH~v(IiyZ%;q4ZB3#+ZMOj8rFe zd}p{+j-M=LJDv&YSZCs?8^cT5vCec`l#X?#99>5Pc}tz?t|%SrO!>Nwaiqgzx(+L) z&ii#(>HLHaE1kcl!_fKL#9)Ec`AfG*o%v~5*4c#v@Z>hK(*n~_X;*hLM}P$;UTx4q znEo=GVTI0fxm^COHt|{m6SAY4;z5CqUn%Watix-x9xqWNUo>*xJ~K$_z)$tE4sIOU z%QeA^#({FW>D-ab6Vi)D?p#ydl^t?d`l9h}T2AxAmqW;RjB47`7e(JQszs3=9A7f3 zMNw^)<7*`Fb)!S>fUp?cIz(zi8)*8-K=r;+ML(<`e@atJn^7%}5vaa*vm{*s1brMF zsO+W~>Ou<9R}35-O?8K>l3C{~2JRbET|-s!BUJl}VTtr-_+llA`Kv*B>&sQCt2D!> zI(WP)?O7%I*HQzGHer7^C_g+^<;dV*WZ+Xz%X>1?)S_imGIKd*xKp;IX%qGD_jN5k+$2|yKhO)>Hp%mk<9b2ICdZSc$18fl`Asq! zoG_%*DV3@2+}7SJAzz-XG#S*wu5%M@K+fpR32buE4_h0~>IGLe^{%B_e5CP1gF4bU zx|xjdra`S5E^SJi&<|Aj?30Nm&rwu;5)S4f9{>22wv&F&rquouxEP zwc$2t80@gvFx7^+(lFTL@}&D^y`9)H!BSt*!2?y&4tw+h?7&!epFu^R#wr#}&3;60 z<>9K{v?P&A*BZhbD~y`&(coWYuso&oRjVP4nnu!>wOM6Ikz=_;y4Na02I-Hnto2$) z-7>{sxf9g%;g>^@8V>XZN7>#fhMOh*l4Kq;Qw-xJzs1RX?lr}*Sgx(GB~xq+@G<(x zAU936gx0@WpZlo?P14H$z$l@QzIZbnm($&Wi#Nm|Al}Y1{T_1Ctw-_ zOYB<-n9=iI=(*CKMhs@A(DYkmuOz_DT5quTCbHQKc$nETK2eo5CJP$wfiYp)-G zE{6U#jCpuMY%>^HY;@ylu@NGU`i=C8C%>W6IRIjxW3nxj-HnQQj}}mqBUm9hVIWaTh^O`|3o^`g5-N0!pnHkWDB<6>Fc~ zgf%{iFI(>vio8h~sE!L5s-B=OuGb?^AHxCKg!G^*GQ-rKWFSo4J?`ZSL$4B}y2Z)Z z9p~6cO&YaHBZ+oAb9;I*Gtt7_4u`mnPmAI<{-y|S6GGe^^jCEZqnO(hiW_>4KZXNI z9}{*MW49@+3dGR-6Ua)zeZ{a;8W5~o8tNK`SP8yY(GQi(KtI|{^rJzLrYfXVi~%%I zLMyeTyGYys7B}Xa>KpXx19W*@eZYWF^{ZsI-d1Y2SyfltD@cEps&DX=gF;!R2$$xD z-UG>nu!u`3DJTV)kB%mi>e`c+xl{ZqgkgKU18RW z@U24aA3-2D$I}P*Lot4AAl+<9dIf-mo;WaDV|nFa zp(hT^wm3rAEUQRYJ7eg2l_<>g#DO`+w3`UzJ-(P|qtgKk&G16q<6G!%SEze@%Oyw< z>K-2t7ywZB_?9NH5$Yb_LihMW-Q!#69$#czh;zD~?(s2U(7f4bu+u%hm}V&h>WINk zcYI=cLKPs*sPP_#FtO7B=S!Gy4AVXSYb28Imn}VPCxEfg{jw$5`XwMV3*9eU91cR* zEOdro3EwaO7zA;2zidhG{XPgH@0ULWjB7%C$IT-?eOROL{c`;CsAqV9r|=z1Nfh2g zmI++`c63ex-;_KskVGT2Bw|6ZPF>xUXz_VeJ&&v3uBy)pRWCyIBs%ZQ>q$1^~g;dLF6`eeuV%H~- z%6g#@Uwk0m2{y)I{FINrEV}NXG%W&g}#Vg!W8`}Pcw$i_94jP=;ca71=o9#VhKJ)GC{rlRF7BY6@5t$oHj}}6(c2^ zh4J_S5ZoKHw&0p@n%HerV2KtNAb2UWk5lZa5%e(}7z7JReoF^Se(r?Xq~)>%DXl1> zmFh27{FW!IBEeLRjE?pMId#0iSOO0)!4JU>~oT7$OQsrEcpre=jyf{sGyV>s{( zDZ^FfMYnaH-qyr#s7kA49ZfcVp)NsccUPRQJ2z#K0!tu&EXkkB@{<&+?TQtQfo_-b zr}EY_Wb3K7DqAPsq$;h9l0Q9K{)}k(t_b;mC1Z|Z`HwG`Ji_vy3CSPRFRHKcXd=7J z!o=rPrD*x%qvhWoEq_9U{NIxNp)5Z`v0A5^g7#zN%JvV9ZvW6w`=_W%cSf~;ShW0G zqUDbW%a3`RaNrLlpJq0LZ4kBJRCj4d{Iq*CLrelyz{40-N#pL5 zlK-LaOlc;9=Jzp2jxrwW_qlo0iGiA1Nl1L0a7B z%%Bzww&0*!G3Znb`YHzXaM&KC9#JPxL&l859gF6mG6nAetQk2ReuQro4o^c(T9vO_l!^Vp*-#P>X52+ilP2X$)p-o>dxP>--1pq>u zJ{qT?P2UD!LYuy=079ESQYWi4yZ1hz8N5} z*a#6vokx1{ZF6j^N4+4`oBO7u-1=hdcT zkaXgWO)4|)(@zP+Vl}N>8EhSbc3y@Z3@De{TG02z2XZ%s@Y#4pm#iVfz7^~ zfC1^$1xfag2yi-RKb&l@Az)w()ptnc>4_a~Xi)1hWA-A=Ue)(L3Xyg25Ygx}{i0z%$OorRadj6i^1vWRD{=Q#Ce#S+f$dR}t|ZWzj*0GPVy{T`|jy%U343Cp=Q(h{Tn`3O$!FY}+kM+8YYIsUf>BYBqdDyF95Qv0xponw7NZO)e^1flG5k55v#|N31EKPeKnv zvNb6UacGDZ8#@I>;Ht8;1-eO_?Le^VshJY)h@BKWF_u6}B52`mln`ul7)%MVv68@m z0(*P}{REK4Fog(H#70pd?8O-jvmI17ejr4SM4bfA0F^j4g4@(y#&kF-ifp<E=uK)P{*$VN=R@UTdpxqkFLf^?rI!Irl$Ob%_IBf$!TDpqPj6;w$x}*QQg=x8u#yw+Wj~S8-vGN z*8ydT8ZOt4y@-(&J@znsV)T&}tBXp@qw#CP8e*n>PAhfCq{PvkTtL*tJMa26k3 z5FU;&<2Btwy%7p1RNoOPKgz%?#Y#Tzc`sEf18(KO&B!0QGY|s^Z{N5 z5XK84<+N}d61@+JltYwBIdn+$Vi?~803Bx^0xW`JfnbP&l&0fMU_(ph)zHA(f)%L6PDSw#~xm z5hl%OHjNa6D6vfv4y1-T!br)%<+jOUKJ*@1D;yp%r&8Q}LZloNwvANrmZd_R7xp?~ zd0*T;SCkzT>rM!-AybGfk(?<;dBn66LM#zQ-xfI@vFwB>$`YknVz=Rhc*t;&pwt#o zWXlr0=7`kgXjK*~VKi;>L~9{(O^LO_Su2*lC`O+Uy`TV^2mPTyp_sT-+;dPYDir2S zF)UM3b7rVMc;QC z2RkU8$dJuAIF+EZkwVxCMW3a@44$_U&*u>e!X_)s6Sj|uvah6cO3De{QC|31*bkBL zB2%ACk$}!ZPu}SjCYFkCC+T3a4HN^>4{<*dLl24tKO*!US@b=E(6<+g+YX9_nZlHH z8FWj&HYbB+} zEfte(PBHPI$R&ot{#TNdI#Sq-(;dQsmM6^>F_l8B6_!zAjA=`u7$_T0US#kH@$z6X zmfC9iQlaQAQS3?{VKyaU$P8wCPZmo}skVc*T4DJ;Mu`ohPuX{%ftiFB3d>oMVe-_n zcavVGc=VTPun-r-c-C)it<=vWUA+bR^?qO22MfbmQE2L8Yr#OXTqshmW?f27Z%5bm z8z~Z7M885BQle5g+`|5e7$95fBF^wgNYnwr^99l4cm)Jt%3BP>V<<2oZsjTV?y_h@@(f(jwq! z}F4a$VmoD^wj2V4za z(+joGJ27j886&TOybGqibFEmkOT@!TGsT!)BC}S+d&K;Y#a&!DBvXvuC2r+H%Ui@H z?j-AuNU=+H@En*So}3x#FIy|t?-FrY0`;bHy*Q7!?_*KIg@ZH2lwD#(tw5o8OPJSE zci5K+ypMOEsc$BGq?ocvB>qB}Jz^25yF^gGB4SOSE0%f0ge;MNUgRAVTX~3#whb1; zKOj%dwapcU9+876cSJmJP<$Do5QcJI7OC6BO>2emh{%Kw_dg=~?h*-8iT~io#2Al= zGiEzPFZAyrF#7fS8-cL9nY(#p)!)Y6!((nk*_z z@MoNZ+D40>XafyYFu|ZTBNtmF%unls%VdhFg+@z7>~4`o;tF}R7Y+aPcgQO+~P zXNrD^ca{%C;zr@zMUCn?mj<-?0b#2XafqMB;SOP2BVzwc^mt1o7&DTEZHh=H#O=u< zWfIM>VzWs0q5wE!wlcwJnkEHIW2z)K5eOeJ{YhE^ji?m2eL(gc4M$Hvb=!|cU)i)I zO5o&kF^GOaKm*okR}g0188z>U7Cn zRM;ruD#d`^!j5$q%ttcki2hQv2@(4wStH(d1%5t~x^s-F*B4?8Pl{_5Hjfx8Svn<4 z`&^NPxb-x`*Cv4%B^<3H_Enle;eSIhjaWUGX?zOXRM8J>L^ME#O#}vvndBuD_-rtG z5+XBd+$W}BVgc1qkGSg)wLp%~+l(2h6c%Pxij@axUDq2efQV(J1r}PA9266Fi#Z;V z{sE279FzTE)Bsy_IW(XUB{EWIR3ci@aJQ|cj<7a}dC=sR55&+H#l*+NT#xAWff(iy z!w-p>7y}?2h6U_7Vf{c1M`)N-_wdM*7ghoxBqRea*fO@kA7~{$BCsPH z5Xd${Kmxe2a568;YImig-Bq+J1fDkaV5ja!K14H3oBpwgrqgs2z8< zaVO49W9&G8xHHCaI@30ZlQfe*lKy_@-n;wW-IbHH5488a^X})l=bn4+IrrV8cUAR? zlwOYEdK~F1`hg+*LKym%UIl7^0G$7dzTx+QhPz12-;p`EBd@!G`X2n<5UgBqFW;7z zJ*Y_@Z@Mq&6~WIwnoQ~2f~V24R8HSr)eog8NVUGhe(R>3sGrg8Y`UX|W%D9~qnnd! zFl1h2#LYnuB3^4G93feB>xygaR!b=&Kvdwrp5593Ioo7EzyOSx!K3>949;sI0Wc^- zReoG~`=~ZF*G`!Q^fr!uxh0i+lj2Ws(UGvwG6&B^y#u347Am@XffLo*$mvzw9wfUN`Uy;VKDpa&Kx$pYN}9kw0(rw#9d zr!dc8LG_s45_Cb<0u_Si)rKkV?<1;5bsvMO?tzSnX%t*+9z+EGbCxJo7ZXe?;*q-B@+kQzRuljS{ikS{M1p`7h0r<==J|^$g8%;T_3^2!iNUwU8 zvF|^rM=*cvtLn~_ZYQqSkb{Z@Hem7sgq36_LM)?(BrAX=J|x@%avZ7D38cY%HC9|T zSg~+b{~Cxcr&lhLM)m~jQa{iSyrq+`QwZD*Q52OJs_IA0V&ENiSkE{(HWvd!df%t@ z5lEOr0DN!_bLzav(YWjg*~l^^9mZ5G0#omsx&z~QGm>M<0Y&b|+dWnN7={Q&F-YT{ zpjdShv0Y2ZI^vVwDq$L}lpk&Ak|q7Mz}yDwYbgS9!jA$dgKgJ0Bj?4r(s zpoaA3H$kJfk}KT!HS|%xKKzP4Sk+mP9~UFCr5HeFX3h4 ze+Ud_ghKb~gTY1$wH+XTRC@(Ql^^D{zQi%K=WmHgNUpoM>;utP_02#a3$Qn}8zH$8!#CZs9w}3)0$)Q4+l)70A(o;KH2bY5s9ABD=&iKje9STqURh>JS2;MtjUFsw($u9-LISm$Ak=n z1~48E&FMY!l#%*DwrB)uuWjvb5_t&UzKc9WiRu#N8A{@8od5bBOtI*`xyCnrf2KPj z#8UFOMrunW7q9B|SP-7q_+qIpSKWeX6tnEI>lgJ-XuHtsTfw*c5JGm20xLLb~aT7!R1gs(Nr--v>g*s%t&k*a~d{s9U%u)G#CoY7K;HlK*Bj z7nUeUAcZ;ufmLbS)@`-zpbJMyg#@R1i9=TioLr<>>WgNMeH@y z*e(6pUF%Qiz@Yfsh=~NOX^vf#fa*fJWlg&qAC`sFM#r@w8Y%xzHb_KTu6786=n_}xM&WvFs-L4P}u%|Sow zt97XY7DqWol}nd7=8hWQl2PcE&y~aM?CkVZxdK2_ZLrboe(pHSg0fn-KBHTn*(NHC ztHVZoN8^3T5(_xU3F{DajB-`7(cGOW!-`aZl7KT zo&ohVG+Ph>!E|?Q$AV;ysHvaPt1;^=LK?ZB)5Z$Xc-UfOiM3$HG73p?q>YMl3Ob9` zDEYkJJe1dW;oZ%n8lNvhSKsjr1hXOCi3J;nVsP%ft&3hCK#PUxbJKaoB`*Aehi|`8NT1TjZ7a{?d-=Sn4?g$9>JDT zeP2p(&iE|n=C(Kwu*rJSaJ@~68*xf9_U8I^Wy%I=3Wf}?rk*#`4ufU8juiMV+6(?mF50L6_ z9?+XH79bdo>$PYYB*{sQ)pF|>bVqP@RAce93Ybd-t&fTjmoPHYw;4e< zlJ5U^s%knhS-)yN|w;rlAfLoL3+>?6wWvvhCk(2tpmytD8D2aZt3NE{Xk2xUMB`*VXmjx}u zsY08&VLz*&a;=~T3i*kk;}sclosd7lK ze_@)*m6Q=yN?~R)UCd_{%*k`ptPp$`s$zDYk&JIca6-V0JvhwJt7#~1Oku4KrzTXr z#?dG;sfMNyw9!1W+=k2)JRRC%jYClD>X4D?rj`z472N_3j~(5A=(r-rB;T^Uwq9(R zNxdd2j$3$6Y`|{a-=-?h;lbei$RmftgGY`Y7zt188-^D`Q)YPLXt;mh{)b0QpTHBL zbeuYEoJ0a0#r$+OoXk!mBPG60L%K+nRtxS;8*MG>Sdm)S@Z3LHDrEbAqf|t1rHlRe zNUJ{sH<#sXSSt6Q&dwII)3EgSX9^P#IK(Oo670bRorCB12aB8}5sWGEhYLrjN-^o%7&p(;Zk z1}+3&o&eF!@&|r+rz+>{xQNmb$Azs5=s0cNWU4fFNu;O8vc){8zdTu*tZ#9313el9mM}HS#kZ z&)TwR@hd!8nw~%>Mq90nzgHp;qtm!JwZ+DB;@Ai&yjqf*&gM9PZCt@M2*i}5%All7 z)>c-qF4&Fd=(tdwLOCD~z~{3W2}_I$OWi2T^n5X001GmBH!YK{jUY-kmxL9#U=>u< z-zZScY&KVhL(lwFCM4@9m4)AcB1xpCtz&4a%1x*9hTSy|FX0X4$+^lzX}&0g3wDYf zH4dL-yuwQ22q-JV0kB_rWdDhGZ8TO^C2}ZaU^-jH9l#ozlIAP7#iw7E8W~k7RY*#7 ziVQrVDK)wTH=b3(!VTg`Ea2Io7bSe@c!<$%>SalqluTxZ-9QyOrADPNdQhc_>{;g< zRyA~?u(R;^!ILA1gDIuX*;pcdXCnuo$kdTulPmbj6y8=N^8#myIQo=vER7*wfWPcW zRMVJ9uN!i-h?D7tTbt?w#MXekCSF8rk~w&!Nk>JR#<{``(1;a#${TuD7D_aG%w!5bJaYKxv2jeenGBH@vVIuX z;lZOaUxxh3nF7gFQH8>=c_bJn06SesM1aCma0m~a!6UHz)J6}-0;?C*qST}Dt#n1P zR4)>q%>e`_L3L0K<}M(zluT)Qu7IiloQwe8I7Pr(6sfacR8B2vtljo-(-I1bHc*anZr9)H6448v-)Zor& zS4kJJ9I3pZ3}WWQdsH}AoGWK1wzJ;0si+mdQD^K^>C9=k$d=Tn3pmjT+@^*wky>pl zSZb|x5*-7_R8J&Al62j_HAj_sS>yQ}b0JtKbvnYhFq`sTqG60tAVJ9xz3Wi$>4*x5 zd|HNt;a)B;GFvrYnw?M|IC|`W;h_a+?J%slnGz!ln={eN>eQJKwPcW+nk`ozB(>n7 zQp!VGYtjz1NC-O_zlYWRf*;mV9&1erxJ%RQ-6Z(y#5ua3yZQ}55)y$7dpnBA+)HQln zpl-ysg&q)(fm*AcYYJbdUTzA<$0kj#pyrJy{xVSRhz=i)Z&jOIf!f#v%6i_s1pJl; zIFvWoL;n4r`!6_7o58U)9@O8i7QKGQHhF=+?7{D}aOc+uk8(YL-xhf5ad=}rcpb)H zOOt-A0M2rqpCrcR^#uM}n$QEgwORfDVhQ*cmwp?5WFSEnGbtAYMENj{DAe~*ptkD~_!-Z&oLFZnc%i+=_@ zp&I!{9`G*o*Arq6gHq78Vcx?1lSQAlaQ`6g&sw;DM)M^L_fJv1EN~BDc>J=B?`%TD zHp)vD?jJbF!)953|ICs90=%~|d-XUppS?}^LmTD;=5xcXCQ%jXd2JH7xsU!1+W7vV zje9NJKjes~PuY{yqS>eqE&(sueEj3-&Re+edEj>eUyXLXv>3}?eago7kICbSENriT z4)^B-9?yeMUs?kGlFi3I(C#C^Uss}WetB()eE!qs;~#wS<0ayE!LG>q`=_!D2)wcW zx7+ysAtI?I;vWFK6MXO0MU$7~5AR2Eqg*dqxR~t$ zad@VOrd|^z_WNDHi3k7aq@OaM#9H`FzMc|CR~VM!a7Q{5)*yW5Md9w!fSl z?hZeCV~KL#0i1Z=;I*p*>xxduE$(0?*WUGjvs|D5-y!kWsa`K1I(Z`f_(x#vvGAD> zo0_{rBMw-&?;2*z!u_-3k6HNV514!?Z}Cc7xbK%BZ{hwaOclV1hugjSe^%m~Jfpvt zZ9e`XQ-5dS{xOSRv2fqL%+~;Cxp&%f9i6{n;m%2wga5$h@mrk~k- zc6<5v;5<0?i+?`xE(`ZPgd7%l6a(fy4LJFLliOX40^q&wArd}q^Y;&4y1;yZhrPC* zj^3`=_-<(4~~Z{B-FQ)V>qY8o?|(cNWIo!VL9N6RBN0?%mNm z67(&_sZcaP);^n?rM+chu27(+F7gDG5OhJYsOBT#$R@LxzALI~viANaTBFqV-2?Zc zqy}{oUToiu7Y`oWcX%WmIdT9RChDakm4MFj!1$4UhY#+LzY$|MKrms3BM;jg9zJkP zg%6D#9o{z<9)0k^<0B`m0SXcM8FQE^&j~sj)bEWJh|?M9onV3#W1g|fP)NM{#>y+2dI7k)k%(-~E zrX;A(oDLV-&zZSOIUWo3O;5x@O%(gaoD*h6qifz%i(J>q=RksGui>Nu#E553>w8U| zYIL~q2sOoJ2*ooLyHMSq4s+?L>3X!Cb)43+LNcrQEEi{Hp|;G`_s@{7#+L{r?jQQLX&i%d*{%m&m6mBmfQQ4^S$Ya&K~ zsBRzFq1Myft473=AV{{8O@40d|dpaKH-E6CM z3qcs3D$_p0{)y~nVF3{{2D`Ynl>tl)dq})J7G_rlYE!o<{8Bdh9EW(k;>?8hgNT7G zx>=(>Ge|VEr%0&G3>7;-oq2&CAR}*$HO3G+8(H7!RHKc0Y_E}SCrwUlTk%SVA-JrY zTgZN!GG8>!npu8nd%m+q$#ezVT7$Vg3^QlboNm(7Q;&Q6Gu}dwqqmn!rOM|DKncRi ztO+OG9T;GCc1ER&rAju1jpV6Qb5qk3eb`!MK>LOd_Epk(CGRHFA-`y ziKch<9vAkyh&J@o9{~Kv@GbA^@9aV@boIwFO)j?%u#bvofYO%b(mVT+3wcH&FDwHD zPcFTaqkkQ6sA_8Iot?>rTRen$kBUcI{yb8DXOD6rPZ;Fo>hJ35!qa&7vq*Ypw{qcL zCdTF0-$0dm95=+N%g@=jT==|==*suo|CCKXY~wjQmiun=>d!8pm+%5wr&@YvZ~Wdbnf_IzC5ku(c{#h}Pi*=( zZ2KJ=UAe9w{~c)<#ie)l%U3_e+;I4-32MJCy$j#Mn`nBqXrnHe@HzYF0+-H(|BV;X z^iKczoK4^D657zEbKoE0hA>xur$>0nra$W<+R#t`Q@~mNfEUlDAM@ah%gcqvu4Z7- z-*p$v)Ayo4+`DuREZ!#FLnKW8p?OH9B0${w>2C(WhcU(A^ZZq6l#@&3^5atf -#include -#include -#include "../../../src/klibc//include/stdint.h" - -/* Memory management */ - -void *kmalloc(unsigned int len) -{ - return malloc(len); -} - -void kfree(void *ptr) -{ - free(ptr); -} - -/* klibc functions */ - -// GAH src is the 1st argument. -void *os_memcpy(void *src, void *dst, int len) -{ - return memcpy(dst, src, len); -} - -void *os_memset(void *ptr, char c, int len) -{ - return memset(ptr, c, len); -} - -int os_strcmp(char *s1, char *s2) -{ - return strcmp(s1, s2); -} - -char *os_strcpy(char *s1, char *s2) -{ - return strcpy(s1, s2); -} - -int os_strlen(char *s) -{ - return strlen(s); -} - -/* SD card */ - -int init_sd() -{ - // Noop - return 0; -} - -int sd_transmit(void *data, uint32_t addr) -{ - FILE *f = fopen("build/card.sd", "r+"); - fseek(f, addr, SEEK_SET); - fwrite(data, 1, 512, f); - fclose(f); - return 0; -} - -int sd_receive(void *data, uint32_t addr) -{ - FILE *f = fopen("build/card.sd", "r+"); - fseek(f, addr, SEEK_SET); - fread(data, 1, 512, f); - fclose(f); - return 0; -} diff --git a/kernel/old/fs/cmdline/include/data_structures/bitvector.h b/kernel/old/fs/cmdline/include/data_structures/bitvector.h deleted file mode 120000 index e4561579..00000000 --- a/kernel/old/fs/cmdline/include/data_structures/bitvector.h +++ /dev/null @@ -1 +0,0 @@ -../../../../include/data_structures/bitvector.h \ No newline at end of file diff --git a/kernel/old/fs/cmdline/include/data_structures/linked_list.h b/kernel/old/fs/cmdline/include/data_structures/linked_list.h deleted file mode 120000 index 38507f21..00000000 --- a/kernel/old/fs/cmdline/include/data_structures/linked_list.h +++ /dev/null @@ -1 +0,0 @@ -../../../../include/data_structures/linked_list.h \ No newline at end of file diff --git a/kernel/old/fs/cmdline/include/drivers/mmci.h b/kernel/old/fs/cmdline/include/drivers/mmci.h deleted file mode 120000 index 2a88fac5..00000000 --- a/kernel/old/fs/cmdline/include/drivers/mmci.h +++ /dev/null @@ -1 +0,0 @@ -../../../../include/drivers/mmci.h \ No newline at end of file diff --git a/kernel/old/fs/cmdline/include/fs b/kernel/old/fs/cmdline/include/fs deleted file mode 120000 index 52616344..00000000 --- a/kernel/old/fs/cmdline/include/fs +++ /dev/null @@ -1 +0,0 @@ -../../../include/fs \ No newline at end of file diff --git a/kernel/old/fs/cmdline/include/global_defs.h b/kernel/old/fs/cmdline/include/global_defs.h deleted file mode 120000 index 9e8e79ca..00000000 --- a/kernel/old/fs/cmdline/include/global_defs.h +++ /dev/null @@ -1 +0,0 @@ -../../../include/global_defs.h \ No newline at end of file diff --git a/kernel/old/fs/cmdline/include/klibc.h b/kernel/old/fs/cmdline/include/klibc.h deleted file mode 120000 index bc34e179..00000000 --- a/kernel/old/fs/cmdline/include/klibc.h +++ /dev/null @@ -1 +0,0 @@ -../../../include/klibc.h \ No newline at end of file diff --git a/kernel/old/fs/cmdline/main.c b/kernel/old/fs/cmdline/main.c deleted file mode 100644 index 0d627e03..00000000 --- a/kernel/old/fs/cmdline/main.c +++ /dev/null @@ -1,113 +0,0 @@ -/** - * @file - * - * Build FS (Bootstraps the File System) - * - * @author Lane Kolbly, Ginevra Gaudioso - * @version 1.0 - * - * @section NOTE ON CMDLINE FOLDER - * SD card gets run automatically in the makefile, however - * the .h files in the cmdline folder need to be manually updated and - * are independent of the files in the include folder - * > e.g. if someone changes include/file.h then fs/cmdline/file.h - * needs to be updated - * - * - * @section DESCRIPTION - * - * Takes a directory and creates an SD card image from - * it - * - */ -#include "fs/file.h" -#include -#include -#include -#include - -#define BUF_SIZE 4096 -#define MAX_FILE_NAME_LEN 1024 - -/** - * Adds a specific file to the card.sd image - * - * Adds the file at the path specified by filename to the SD card - * image indicated by dst_filename - * - * @param - * - * char *src_file_name - holds the path to the file to add to the SD - * card image - * - * @param - * - * char *dst_file_name - holds the path to the SD card image to - * add the file to - */ -void addFile(const char *src_file_name, const char *dst_file_name) -{ - FILE *f = fopen(src_file_name, "r"); - assert(f); - - // FIXME: should all be const char* - kclose(kcreate((char*) dst_file_name, 'r', 0)); - int fd = kopen((char*) dst_file_name, 'w'); - - char buf[BUF_SIZE]; - int nread; - - while ((nread = fread(buf, 1, BUF_SIZE, f)) > 0) - { - kwrite(fd, buf, nread); - //printf("\t\t%d bytes\n", nread); - } - - kclose(fd); - fclose(f); -} - -int main(int argc, char **argv) -{ - int fd; - int i; - int l; - DIR *dir; - struct dirent *entry; - - char src_file[MAX_FILE_NAME_LEN]; - char dst_file[MAX_FILE_NAME_LEN]; - - kfs_init(0, 0, 1); - - for (i = 1; i < argc; i++) - { - dir = opendir(argv[i]); - if (dir == NULL) - { - printf("Could not find directory %s\n", argv[i]); - printf("SAD :(\n"); - return -1; - } - printf("In %s\n", argv[i]); - - while ((entry = readdir(dir))) - { - if (entry->d_name[0] == '.') - continue; // skip - - l = snprintf(src_file, MAX_FILE_NAME_LEN, "%s/%s", argv[i], entry->d_name); - assert(l < MAX_FILE_NAME_LEN); - l = snprintf(dst_file, MAX_FILE_NAME_LEN, "/%s", entry->d_name); - assert(l < MAX_FILE_NAME_LEN); - - printf("\tAdding %s to %s ...\n", src_file, dst_file); - - addFile(src_file, dst_file); - } - - closedir(dir); - } - - return 0; -} diff --git a/kernel/old/fs/fat16/file.c b/kernel/old/fs/fat16/file.c deleted file mode 100644 index ba4dbfcf..00000000 --- a/kernel/old/fs/fat16/file.c +++ /dev/null @@ -1,2237 +0,0 @@ -/** - * @file - * - * Course OS FS - * - * @author - * - * Joel Iventosh, Ginevra Gaudioso, Weston Sellek, Charlie Cox - * Matt Davidson, Joseph Bourque - * - * @version 1.0 - * - * @section DESCRIPTION - * - * Course OS FS is a custom file system (started out as FAT 16 but changed into this). - * The file system uses a superblock to initialize the file system as well as the SD card - * on boot. Data blocks are stored as array of integers that indexes into the corresponding - * block number on the SD card (note: some blocks are reserved, data blocks use an offset to - * access blocks on the SD card) DO NOT FORGET TO ADD OFFSET TO BLOCK NUMBERS!; Each file or - * directory is stored with an inode which contains metadata about the file as well as the - * list of addresses on disk where the data the file holds is stored. Directories are indicated - * with the is_dir flag and data blocks for directories are dir_entry structs; - * Each file has 100 direct blocks and 20 indirect blocks; no methods are - * currently implemented to keep data contiguous. - * - * CURRENTLY WORKING - * - Have working directories and directory hierarchy - * - Standardized error codes; defined in header file - * - Open file table working - * - Create working - * - Open working - * - Close working - * - Read working - * - Write working - * - * TO FIX - * - Max number of files per directory currently limited to 700 due to error finding - * and opening files; you can technically create more, but open will not find them - * - indirect blocks do not seem to work - * - ls, delete, and copy are untested; could work, but might not; TEST BEFORE USING! - * - permissions - * - */ -#include "../../../src/klibc//include/stdint.h" -#include "klibc.h" -#include "data_structures/bitvector.h" -#include "fs/open_table.h" -#include "fs/file.h" -#include "drivers/mmci.h" - -#define TRANSMIT 0 -#define RECEIVE 1 - -//CONSTANTS: -const int SUPERBLOCK = 1; -// const int MAX_NAME_LENGTH = 32; moved this to a define -int MAX_BLOCKS; -// const int INODE_SIZE = 128; shouldn't need this...should be able to do sizeof(Inode) -int MAX_MEMORY; -int INODE_TABLE_CACHE_SIZE; -int NUM_INODE_TABLE_BLOCKS_TO_CACHE; -int INDIRECT_BLOCK_TABLE_CACHE_SIZE; -int NUM_INDIRECT_BLOCK_TABLE_BLOCKS_TO_CACHE; -int INODES_PER_BLOCK = 1; -int DATA_BLOCK_TABLE_CACHE_SIZE; -int NUM_DATA_BLOCK_TABLE_BLOCKS_TO_CACHE; - - -struct superblock* FS; -bit_vector* inode_bitmap; -bit_vector* data_block_bitmap; - -struct inode** inode_table_cache; //is this right? we want an array of inode pointers... -struct indirect_block** indirect_block_table_cache; // an array of pointers to indirect_blocks -struct inode** inode_table_temp; -struct data_block** data_block_table_cache; -// void* data_table; not sure what this is or why we had/needed/wanted it... - -/** - * Format the SD card for Course OS FS - * - * Creates the super block & metadata for the file system, creates the - * root directory of the file system and writes the first block on the - * SD card as empty. - * - */ -int kfs_format() -{ - os_printf("In kfs_format\n"); - // Lay down the superblock to block 1 - struct superblock sblock; - sblock.fs_version = 1; - sblock.magic_num = 0xDEADBEAF; - sblock.sd_card_capacity = 128000000; - sblock.block_size = BLOCKSIZE; - sblock.root_inum = 0; - sblock.max_inodes = 4000; - sblock.inode_size = BLOCKSIZE; - sblock.max_data_blocks = 200000; - sblock.inode_bitmap_loc = 10; - sblock.data_bitmap_loc = 50; - sblock.start_inode_table_loc = 1000; - sblock.start_data_blocks_loc = 50000; - - void *block = kmalloc(BLOCKSIZE); - os_memset(block, 0, BLOCKSIZE); - os_memcpy((uint32_t*)&sblock, block, sizeof(struct superblock)); - sd_transmit(block, 1*BLOCKSIZE); - - // Lay down the root inode - struct inode root_inode; - root_inode.inum = 0; // Isn't this redundant? - root_inode.fd_refs = 0; - root_inode.size = 0; - root_inode.is_dir = 1; - root_inode.usr_id = 0; - root_inode.direct_blocks_in_file = 1; - // root_inode.data_blocks[0] = sblock.start_data_blocks_loc; - root_inode.data_blocks[0] = 0; - root_inode.indirect_blocks_in_file = 0; - os_memset(block, 0, BLOCKSIZE); - os_memcpy((uint32_t*)&root_inode, block, sizeof(struct inode)); - sd_transmit(block, sblock.start_inode_table_loc*BLOCKSIZE); - - // Lay down the first (empty...) data block for the directory. - struct dir_data_block ddb; - ddb.block_num = 0; - ddb.num_entries = 0; - os_memset(block, 0, BLOCKSIZE); - os_memcpy((uint32_t*)&ddb, block, sizeof(struct dir_data_block)); - sd_transmit(block, sblock.start_data_blocks_loc*BLOCKSIZE); - - // Update the inode bitmap - /*unsigned char i = 0x80; - os_memset(block, 0, BLOCKSIZE); - os_memcpy(&i, block, 1); - sd_transmit(block, sblock.inode_bitmap_loc*BLOCKSIZE);*/ - kfree(block); - return SUCCESS; -} - -/** - * Load file system into memory and initialize the SD card - * - * Initializes the SD card to set it up for data transfer, once the SD card - * is initialized metadata for the file system is loaded into memory and used - * to obtain the free list table and data block table. - * - * @param - * - * int inode_table_cache_size - no longer needed; should be removed - * - * @param - * - * int data_block_table_cache_size - no longer needed; should be removed - * - * @param - * - * int reformat - if this is set to a non-zero value; this formats the file - * system before initialization; if set to 0; initialization occurs with no - * format - * - * @return - * - * Returns 0 if initialization was successful; does not do any error checking - * or reporting at current; will need to be added in at some point in the future - */ -int kfs_init(int inode_table_cache_size, int data_block_table_cache_size, int reformat){ - - INODE_TABLE_CACHE_SIZE = inode_table_cache_size; - DATA_BLOCK_TABLE_CACHE_SIZE = data_block_table_cache_size; - // TODO: Reading the root inode has weird issues (getting is_dir==0) with inode table block cache. - NUM_INODE_TABLE_BLOCKS_TO_CACHE = 0;//((int) INODE_TABLE_CACHE_SIZE/BLOCKSIZE) + 1; - NUM_DATA_BLOCK_TABLE_BLOCKS_TO_CACHE = 0;//((int) DATA_BLOCK_TABLE_CACHE_SIZE/BLOCKSIZE) + 1; - - //initialize the SD Card driver: - if(!init_sd()){ - //initiallized successfully: - os_printf("SD Card initiallized successfully!!!\n"); - }else{ - os_printf("FATAL ERROR!!!!! SD Card NOT initialized successfully!\n"); - //handle errors returned by SD Card...will implement this later... - }//end else - - // Bootstrap the FS... - if (reformat) { - kfs_format(); - } - - //read in the super block from disk and store in memory: - FS = (struct superblock*) kmalloc(BLOCKSIZE); - sd_receive((void*)FS, (SUPERBLOCK*BLOCKSIZE)); // make all blocks addresses, like here - - INODES_PER_BLOCK = (FS->block_size/FS->inode_size); - - //initialize the free list by grabbing it from the SD Card: - inode_bitmap = make_vector(FS->max_inodes); - data_block_bitmap = make_vector(FS->max_data_blocks); - - //HACK...shouldn't need to do this, but do, so leave for now - int m; - for(m = 0; m < FS->max_inodes; m++){ - bv_lower(m, inode_bitmap); - } //end HACK...shouldn't need to do this, but do, so leave for now - - bv_set(0, inode_bitmap); - bv_set(0, data_block_bitmap); - - - // initilize the inode_table_cache in memory: - inode_table_temp = (struct inode**)kmalloc(NUM_INODE_TABLE_BLOCKS_TO_CACHE * BLOCKSIZE); - inode_table_cache = (struct inode**) kmalloc((sizeof(struct inode*))* FS->max_inodes); - int i; - for(i = 0; i < FS->max_inodes; i++){ - if(i < NUM_INODE_TABLE_BLOCKS_TO_CACHE * INODES_PER_BLOCK){ - if(i % INODES_PER_BLOCK == 0){ - sd_receive((((void*)inode_table_temp) + ((i/INODES_PER_BLOCK)*BLOCKSIZE)), (FS->start_inode_table_loc + (i/INODES_PER_BLOCK)) * BLOCKSIZE); - } - inode_table_cache[i] = (struct inode*)((inode_table_temp + (((int)(i/INODES_PER_BLOCK))*BLOCKSIZE)) + ((i % INODES_PER_BLOCK)*FS->inode_size)); - } - //each iteration through the loop will grab 1 inodes, since we can fit 1 inodes per block - else{ - inode_table_cache[i] = NULL; - } - }//end for - // inode_table_cache = (inode*) inode_table_temp; // cast the void pointer to an Inode pointer - - // initilize the data_block_table_cache in memory: - void* data_block_table_temp = (void*) kmalloc(NUM_DATA_BLOCK_TABLE_BLOCKS_TO_CACHE * BLOCKSIZE); - data_block_table_cache = (struct data_block**) kmalloc((sizeof(struct data_block*))* FS->max_data_blocks); - for(i = 0; i < FS->max_data_blocks; i++){ - if(i < NUM_DATA_BLOCK_TABLE_BLOCKS_TO_CACHE){ - sd_receive(data_block_table_temp + (i*BLOCKSIZE), (FS->start_data_blocks_loc) + (i*BLOCKSIZE)); - data_block_table_cache[i] = (struct data_block*)(data_block_table_temp + (i*BLOCKSIZE)); - } else{ - data_block_table_cache[i] = NULL; - } - }//end for - - fs_table_init(); //initializes open_table stuff - - os_printf("Finished initializing table...\n"); - return SUCCESS; -}//end fs_init() function - -/** - * Removes the file system from memory - * - * Writes the filesystem metadata, the free block table and the data block table to disk - * for persistant storage and then frees all memory which was being used to allocate those - * resources - * - * @return - * - * Returns 0 if shutdown successfully loaded everything out of memory; no error handling or - * recording is currently implemented; this needs to be implemented in the future so that - * shutdown does not occur if this is called in the middle of a read or write - */ -int kfs_shutdown(){ - int i; - //TODO: write inodes pointed to by inode_table_cache back to disk to ensure it's up to date: - - //TODO: write indirect_blocks pointed to by data_block_table_cache back to disk to ensure it's up to date: - transmit_receive_bitmap(TRANSMIT, inode_bitmap, FS->inode_bitmap_loc, FS->max_inodes, 0, 1); //transmit inode bitmap - transmit_receive_bitmap(TRANSMIT, data_block_bitmap, FS->data_bitmap_loc, FS->max_data_blocks, 0, 1); //transmit block bitmap - - //free inodes stored in inode_table_cache: - for(i = 0; i < NUM_INODE_TABLE_BLOCKS_TO_CACHE; i++){ - if(inode_table_cache[i] != NULL){ - kfree(inode_table_cache[i]); - }//end if - }//end for - - //free inode_table_cache itself: - kfree(inode_table_cache); - - //free indirect_blocks stored in data_block_table_cache: - for(i = 0; i < NUM_DATA_BLOCK_TABLE_BLOCKS_TO_CACHE; i++){ - if(data_block_table_cache[i] != NULL){ - kfree(data_block_table_cache[i]); - }//end if - }//end for - - //free data_block_table_cache itself: - kfree(data_block_table_cache); - kfree(inode_table_temp); - //TODO: free anything else that needs to be freed... - - fs_table_shutdown(); //frees open_table stuff - return SUCCESS; -}//end kfs_shutdown() function - - -// ------------------------------------------------------------------------------------------------------------------------------------------------------- -/* HELPER FUNCTIONS */ - -/** - * Retrieves an indirect data block from the SD card - * - * Retrieves the specified indirect data block from the SD card using the passed index - * and then sets it as the current indirect block - * - * @param - * - * struct inode* cur_inode - points to the file which we want to read the indirect block - * index from - * - * @param - * - * int index - holds an index which corresponds to a location in the data block table - * - * @param - * - * struct indirect_block* cur_indirect_block - Holds the address of the current indirect - * block - * - */ -void get_indirect_block(struct inode* cur_inode, int index, struct indirect_block* cur_indirect_block) { - // indirect_block is not in the cache table, so get it from disk: - if(cur_inode->indirect_blocks_in_file <= 0){ - transmit_receive_bitmap(RECEIVE, data_block_bitmap, FS->data_bitmap_loc, FS->max_data_blocks, 0, 1); - int new_indirect_block_loc = bv_firstFree(data_block_bitmap); - bv_set(new_indirect_block_loc, data_block_bitmap); - cur_inode->indirect_blocks[0] = new_indirect_block_loc; - cur_inode->indirect_blocks_in_file++; - transmit_receive_bitmap(TRANSMIT, data_block_bitmap, FS->data_bitmap_loc, FS->max_data_blocks, new_indirect_block_loc, 0); - sd_transmit((void*) cur_inode, (cur_inode->inum + FS->start_inode_table_loc) * BLOCKSIZE); - os_memset(cur_indirect_block, 0, BLOCKSIZE); - cur_indirect_block->block_num = new_indirect_block_loc; - cur_indirect_block->blocks_in_file = 0; - }//end if - sd_receive((void*) cur_indirect_block, (index + FS->start_data_blocks_loc)*BLOCKSIZE); // the firs -}//end get_indirect_block - -/** - * gets corresponding inode, from the SD card - * - * Retrieves an inode from the SD card using specified inum storing - * it into a specified address. - * - * @param - * - * int inum - corresponds to a location in the inode table i.e. it is an - * index to a location in the inode table - * - * @param - * - * inode* result_inode - holds a specified address to store the retrieved - * inode at - * - */ -//from the inum, gets corresponding inode, either from cache or disk -void get_inode(int inum, struct inode* result_inode){ - // if(inode_table_cache[inum] != NULL){ - // // the inode is in the inode_cache_table, so get it: - // result_inode = (inode_table_cache[inum]); - // }else{ - // inode is not in the cache table, so get it from disk: - // // struct inode* inode_spaceholder = (void*) kmalloc(BLOCKSIZE); - // sd_receive((void*)inode_spaceholder, ((inum/INODES_PER_BLOCK)+FS->start_inode_table_loc)*BLOCKSIZE); // the firs - // struct inode *block_of_inodes = inode_spaceholder; - // result_inode = block_of_inodes[inum % INODES_PER_BLOCK]; - // kfree(inode_spaceholder); - // need to implement an eviction policy/function to update the inode_table_cache... - // this will function w/o it, but should be implemented for optimization - // }//end if else - sd_receive(result_inode, (inum + FS->start_inode_table_loc)*BLOCKSIZE); -}//end get_inode() helper function - -/** - * gets the inum of nextpath (file or dir) looking at the direct data blocks of cur_inode - * - * Uses the current file's inode in order to retrieve the nested directory's inode - * and then return it - * - * @param - * - * struct inode* cur_inode - holds the inode for the current data block - * - * @param - * - * char * next_path - the path you are searching - * - * @return - * - * Returns the inode of a specific nested directory; at this time there is no error checking - * or reporting on this function; needs to be added in at a later data - */ -int get_inum_from_direct_data_block(struct inode* cur_inode, const char * next_path){ - int inum = -1; - int i; - int file_found = 0; // initialize to false (i.e. file not found) - struct dir_data_block* cur_data_block = (struct dir_data_block*) kmalloc(BLOCKSIZE); - - for(i = 0; i < cur_inode->direct_blocks_in_file; i++){ - sd_receive(cur_data_block, (cur_inode->data_blocks[i] + FS->start_data_blocks_loc)*BLOCKSIZE); - - int j; - for(j = 0; j < (cur_data_block->num_entries); j++){ - struct dir_entry file_dir = cur_data_block->dir_entries[j]; - if(!os_strcmp(file_dir.name, next_path)){ - file_found = 1; //we found the file, so break out of loop - inum = file_dir.inum; - break; - } - if(file_found){ - break; - } - }//inner for - if(file_found){ - break; - } - }//outer for - kfree(cur_data_block); - return inum; -}//end get_inum_from_direct_data_block() helper helper function - -/** - * Returns the index to an inode by searching through an indirect block - * - * gets the inum of netxpath (file or dir) looking at the indirect - * data blocks of cur_inode - * - * @param - * - * struct inode* cur_inode - holds the inode for the current data block - * - * @param - * - * char * next_path - the path you are searching - * - * @return - * - * Returns the inode of a specific nested directory; at this time there is no error checking - * or reporting on this function; needs to be added in at a later data -*/ -int get_inum_from_indirect_data_block(struct inode * cur_inode, const char * next_path) { - int i; - int inum = -1; - int cur_indirect_block_num = -1; - int file_found = 0; // initialize to false (i.e. file not found) - struct indirect_block cur_indirect_block; - for(i = 0; i < cur_inode->indirect_blocks_in_file; i++){ - cur_indirect_block_num = cur_inode->indirect_blocks[i]; - - get_indirect_block(cur_inode, cur_indirect_block_num, &cur_indirect_block); - - void* dir_spaceholder = (void*) kmalloc(BLOCKSIZE); - int j; - int num_indirect_blocks = cur_inode->indirect_blocks_in_file; - for(j = 0; j < num_indirect_blocks; j++){ - sd_receive(dir_spaceholder, (cur_indirect_block.data_blocks[j])*BLOCKSIZE); - struct dir_data_block cur_data_block = *((struct dir_data_block*) dir_spaceholder); - int k; - for(k = 0; k < (cur_data_block.num_entries); k++){ - struct dir_entry file_dir = cur_data_block.dir_entries[k]; // - if(!os_strcmp(file_dir.name, next_path)){ - file_found = 1; //we found the file, so break out of loop - inum = file_dir.inum; - break; - } - }//inner for - if(file_found){ - break; - } - }//outer for - kfree(dir_spaceholder); - if(file_found){ - break; - } - }//end for - return inum; -}//end of get_inum_from_indirect_data_block - -/** - * locates an inode using the file path and store it in the result_inode - * - * finds the inode (will be result_inode) following filepath, going - * dir_levels down the path, starting from starting_inum - * - * @param - * - * char* filepath - holds the filepath leading to the inode - * - * @param - * - * int dir_levels - holds the number of directories the inode is nested - * under - * - * @param - * - * struct inode* result_inode - Used to hold the inode once it has been - * located - * - * @return - * - * Returns 0 if inode was successfully located and stored; otherwise - * returns -1 - */ -int kfind_inode(const char* filepath, int starting_inum, int dir_levels, struct inode* result_inode) { //filepath and starting inum must correspond... - int current_inum = starting_inum; - - int a = 0; - for(a = 0; a < dir_levels-1; a++) { - int k = 1; - // int k = 0; - char next_path[MAX_NAME_LENGTH] = {0}; - - //get path of next inode - while ((filepath[k] != '/') && (k <= MAX_NAME_LENGTH) && (filepath[k] != '\0')) { - next_path[k-1] = filepath[k]; - k++; - }//end of litte while to find next_path - - filepath += k; - - // Store inode with current_inum current_inum in result_inode - get_inode(current_inum, result_inode); - - current_inum = get_inum_from_direct_data_block(result_inode, next_path); - - if(current_inum < 0){ - //current_inum not found in any direct blocks of result_inode - //look for it in the indirect blocks now - current_inum = get_inum_from_indirect_data_block(result_inode, next_path); - } - - if(current_inum < 0){ - //next_path not found in current_inode - os_printf("404 ERROR! File not found.\nPlease ensure full filepath is specified starting from root (/)\n"); - return ERR_404; //file not found - } - }//outer most for loop - //current_inum of target inode found, store that inode in result_inode - - get_inode(current_inum, result_inode); - - return SUCCESS; -}//end kfind_inode() helper function - -/** - * Uses the file path to obtain information about a directory and stores it in result - * - * finds the name of the directory path (result->truncated_path) and the name of the - * ending part (result->last) and the number of levels (result->levels) result has to - * be kmalloc-ed by and kfree-d by whoever calls this functinos. Also remember to free - * last and truncated_path. - * - * @param Description of method's or function's input parameter - * @param ... - * @return Description of the return value - */ -void kfind_dir(const char* filepath, struct dir_helper* result){ - int dir_levels = 0; - int total_chars = 0; - char* iterator = (char*) filepath; //root still level 0, so start from what's next - int index = 0; - while(index < MAX_NAME_LENGTH){ - if(iterator[0] == '\0'){ - //index++; - break; - } - else if(iterator[0] == '/'){ - dir_levels++; - index = 0; - }else{ - index++; - } - iterator++; - total_chars++; - }//end while - total_chars -= index; - - char* truncated_path = (char*)kmalloc(total_chars+1); // do we need to kmalloc this? - char* last = (char*)kmalloc(index+1); - int i; - for(i = 0; i < total_chars; i++){ - truncated_path[i] = filepath[i]; - } - truncated_path[i] = 0; - for (i=0; idir_levels = dir_levels; - result->truncated_path = truncated_path; - result->last = last; - return; //caller of function is responsible for freeing memory for truncated_path and filepath -}//end kfind_dir() function - -/** - * Used to transmit a block to disk or recieve a block from disk - * - * transmits or receives the data block bitvector or the inode bitvecotr to and from disk - * - * @param - * - * int t_or_r - Determines whether operation is a TRANSMIT (0) to disk or a RECIEVE (1) - * from disk - * - * @param - * - * bit_vector* vec - Pointer to a bitvector (either a data_block_bitmap for data or an - * inode_bitmap for inodes) - * - * @param - * - * int starting_loc - holds the location where the bit vector starts in memory - * - * @param - * - * int max - holds the number of blocks to write to disk - * - * @param - * - * int all - Determines whether to only write 1 index (0) or whether to write the entire - * bit vector (1) to disk - * - * @return - * - * Return 0 if the transmission/recieval was successful; otherwise returns an error code - */ -int transmit_receive_bitmap(int t_or_r, bit_vector* vec, int starting_loc, int max, int bit_index, int all){ - int error = 0; - int num_blocks = (max/(8 * BLOCKSIZE)) + 1; - if (t_or_r != TRANSMIT || t_or_r != RECEIVE) { - return ERR_INVALID; - } - if(all){ //transmit or receive all the bitvector - int i; - for(i = 0; i < num_blocks; i++){ - if (t_or_r == TRANSMIT) { - error = sd_transmit((void*) (vec->vector + (i*BLOCKSIZE)), (starting_loc + i)*BLOCKSIZE); - } - else { //receive - error = sd_receive((void*) (vec->vector + (i*BLOCKSIZE)), (starting_loc + i)*BLOCKSIZE); - } - if(error < 0){ - os_printf("ERROR! Failed to transmit or receive\n"); - return error; - } - } - }else{ //transmit or reveive only the block corresponding to the index - int block_to_change = (bit_index/8)/BLOCKSIZE; - if (t_or_r == TRANSMIT) { - error = sd_transmit((void*) (vec->vector + (block_to_change*BLOCKSIZE)), (starting_loc + block_to_change)*BLOCKSIZE); - } - else { //receive - error = sd_receive((void*) (vec->vector + (block_to_change*BLOCKSIZE)), (starting_loc + block_to_change)*BLOCKSIZE); - } - if(error < 0){ - os_printf("ERROR! Failed to transmit or receive\n"); - return error; - } - } - return error; -}//end transmit_receive_bitmap helper function - - -/** - * Adds a new file to an existing directory - * - * Helper function to add a new dir_entry to a directory file and - * optinally write it out to disk. Updates the last data block of - * the cur_inode (directory) to add a dir_entry that stores the - * mapping of the new inode to its inum - * - * @param - * - * struct inode* cur_inode - holds the inode for the current data block - * - * @param - * - * int free_inode_loc - points to a location in the free inode table - * - * @param - * - * struct dir_helper* result - holds information about the directory you - * are trying to add to - * - * @return - * - * Returns 0 if the file was added successfully; otherwise returns an error - */ -int add_dir_entry(struct inode* cur_inode, int free_inode_loc, struct dir_helper* result){ - - int flag_free_cur_indirect_block = 0; - - //first get the appropriate data block, either from the array of direct data blocks from an indirect block: - struct dir_data_block* dir_block = (struct dir_data_block*) kmalloc(BLOCKSIZE); - struct indirect_block* cur_indirect_block; - //if the cur_inode's array of direct data blocks has not reached max capacity, grab the last data block in the array to update: - if((cur_inode->direct_blocks_in_file <= MAX_DATABLOCKS_PER_INODE) && (cur_inode->indirect_blocks_in_file == 0)) { - sd_receive((void*) dir_block, (cur_inode->data_blocks[(cur_inode->direct_blocks_in_file)-1] + FS->start_data_blocks_loc)*BLOCKSIZE); - }else{ - //all the direct data blocks are full, so grab the last indirect block in the array of indirect blocks: - cur_indirect_block = (struct indirect_block*) kmalloc(BLOCKSIZE); - get_indirect_block(cur_inode, (cur_inode->indirect_blocks_in_file - 1), cur_indirect_block); - sd_receive((void*) dir_block, (cur_indirect_block->data_blocks[(cur_indirect_block->blocks_in_file)-1] + FS->start_data_blocks_loc)*BLOCKSIZE); - flag_free_cur_indirect_block = 1; - // kfree(cur_indirect_block); - } - /* dir_block is now a direct data block that holds the content of the last data block in the file - either from cur_inode's array of direct data blocks or from its last indirect data block */ - - //create the new dir_entry and populate it's fields: - struct dir_entry new_dir_entry; - new_dir_entry.inum = free_inode_loc; - os_strcpy(new_dir_entry.name, result->last); - new_dir_entry.name_length = os_strlen(result->last); - - //check to see if the data block we recieved above has room to add a new dir_entry to it; if not, create a new data block, if possible: - if(dir_block->num_entries < MAX_DIR_ENTRIES_PER_DATA_BLOCK){ - //the data block has room to add the new dir_entry, so we add it: - dir_block->dir_entries[dir_block->num_entries] = new_dir_entry; - dir_block->num_entries++; - cur_inode->size += sizeof(struct dir_entry); - - sd_transmit((void*) dir_block, (dir_block->block_num + FS->start_data_blocks_loc) * BLOCKSIZE); - }else{ - /* the data block doesn't have room to add the new dir_entry, so we need to add a new data block.... - either by adding: (1) as a direct data block, - (2) to the current indirect block or - (3) add a new indirect block then add a new data block to that */ - //first kmalloc space for a new_dir_block: - int new_data_block_loc = bv_firstFree(data_block_bitmap); //Consult the data_block_bitmap to find a free block to add the new data block at - if(new_data_block_loc < 0){//disk is full - os_printf("ERROR! Disk full\n"); - kfree(dir_block); - if (cur_indirect_block != NULL) { - kfree(cur_indirect_block); - } - return ERR_FULL; - } - bv_set(new_data_block_loc, data_block_bitmap); - struct dir_data_block* new_dir_block = (struct dir_data_block*) kmalloc(BLOCKSIZE); - - new_dir_block->num_entries = 0; - new_dir_block->block_num = new_data_block_loc; - - if(cur_inode->direct_blocks_in_file < MAX_DATABLOCKS_PER_INODE){ - //Case (1): add a direct data block to cur_inode: - cur_inode->data_blocks[cur_inode->direct_blocks_in_file] = new_dir_block->block_num; - cur_inode->direct_blocks_in_file++; - - new_dir_block->dir_entries[new_dir_block->num_entries] = new_dir_entry; - new_dir_block->num_entries++; - cur_inode->size += sizeof(struct dir_entry); - sd_transmit((void*) new_dir_block, (new_dir_block->block_num + FS->start_data_blocks_loc) * BLOCKSIZE); - transmit_receive_bitmap(TRANSMIT, data_block_bitmap, FS->data_bitmap_loc, FS->max_data_blocks, new_dir_block->block_num, 0); - }else{ - //get the current indirect block and check to see if it has room to add another data block: - if(!flag_free_cur_indirect_block){ - //if we don't have the indirect block, we need to get it from disk: - cur_indirect_block = (struct indirect_block*) kmalloc(BLOCKSIZE); - flag_free_cur_indirect_block = 1; - get_indirect_block(cur_inode, (cur_inode->indirect_blocks_in_file - 1), cur_indirect_block); - sd_receive((void*) dir_block, (cur_indirect_block->data_blocks[(cur_indirect_block->blocks_in_file)-1] + FS->start_data_blocks_loc)*BLOCKSIZE); - // kfree(cur_indirect_block); - } - if(cur_indirect_block->blocks_in_file < MAX_DATABLOCKS_PER_INDIRECT_BLOCK){ - //Case (2): add a new data block to to the current indirect block, then add the new_dir entry to the new data block: - cur_indirect_block->data_blocks[cur_indirect_block->blocks_in_file] = new_dir_block->block_num; - cur_indirect_block->blocks_in_file++; - - new_dir_block->dir_entries[new_dir_block->num_entries] = new_dir_entry; - new_dir_block->num_entries++; - cur_inode->size += sizeof(struct dir_entry); - - sd_transmit((void*) cur_indirect_block, (cur_indirect_block->block_num + FS->start_data_blocks_loc) * BLOCKSIZE); - sd_transmit((void*) new_dir_block, (new_dir_block->block_num + FS->start_data_blocks_loc) * BLOCKSIZE); - transmit_receive_bitmap(TRANSMIT, data_block_bitmap, FS->data_bitmap_loc, FS->max_data_blocks, new_dir_block->block_num, 0); - }else{ - if(cur_inode->indirect_blocks_in_file < MAX_NUM_INDIRECT_BLOCKS){ - /* Case (3): add a new indirect block to the cur_inode, then add a new data block to the new indirect block, - then add the new dir_entry to the new data block: */ - int new_indirect_block_loc = bv_firstFree(data_block_bitmap); //Consult the data_block_bitmap to find a free block to add the new data block at - if (new_indirect_block_loc < 0) { //no free blocks - os_printf("disk space over \n"); - kfree(dir_block); - if (cur_indirect_block != NULL) { - kfree(cur_indirect_block); - } - return ERR_FULL; - } - struct indirect_block* new_indirect_block = (struct indirect_block*) kmalloc(BLOCKSIZE); - - new_indirect_block->blocks_in_file = 0; - new_indirect_block->block_num = new_indirect_block_loc; - - new_indirect_block->data_blocks[new_indirect_block->blocks_in_file] = new_dir_block->block_num; - new_indirect_block->blocks_in_file++; - cur_inode->indirect_blocks[cur_inode->indirect_blocks_in_file] = new_indirect_block->block_num; - cur_inode->indirect_blocks_in_file++; - - new_dir_block->dir_entries[new_dir_block->num_entries] = new_dir_entry; - new_dir_block->num_entries++; - cur_inode->size += sizeof(struct dir_entry); - - if(indirect_block_table_cache[new_indirect_block->block_num] == NULL){ - //TODO: implement eviction policy...add the cur_inode to the cache: - }else{ - *(indirect_block_table_cache[new_indirect_block->block_num]) = *(new_indirect_block); - } - bv_set(new_indirect_block_loc, data_block_bitmap); //taken - sd_transmit((void*) new_indirect_block, (new_indirect_block->block_num + FS->start_data_blocks_loc) * BLOCKSIZE); - sd_transmit((void*) new_dir_block, (new_dir_block->block_num + FS->start_data_blocks_loc) * BLOCKSIZE); - transmit_receive_bitmap(TRANSMIT, data_block_bitmap, FS->data_bitmap_loc, FS->max_data_blocks, new_dir_block->block_num, 0); - kfree(new_indirect_block); - - }else{ - //file has reached max allowable size: - os_printf("ERROR! Operation failed because file has reached max allowable size\n"); - return ERR_FULL; - } - } - } - kfree(new_dir_block); - } - kfree(dir_block); - if(flag_free_cur_indirect_block){ - kfree(cur_indirect_block); - } - return SUCCESS; -}//end add_dir_entry() helper function - -/** - * Obtains address on disk of a specific data block within a file - * - * Uses the passed block number to search through the file's metadata and - * obtain a block address to read off the SD card - * - * @param - * - * inode *file_inode - points to the specific file in which the data block - * resides - * - * @param - * - * int file_block_num - holds the specific data block of the file to - * obtain the address from - * - * @return - * - * Returns 0 if address was successfully retrieved; otherwise returns -1 - */ -int get_block_address(struct inode *file_inode, int file_block_num){ - if(file_block_num < 0){ - os_printf("Invalid block number"); - return ERR_INVALID; - } - if(file_block_num < MAX_DATABLOCKS_PER_INODE){ - if (file_block_num >= file_inode->direct_blocks_in_file) { - return ERR_GEN; - } - return (file_inode->data_blocks[file_block_num] + FS->start_data_blocks_loc) * BLOCKSIZE; - } - //Block must be stored in an indirect block of file_inode - - //Get the indirect block num that contain the target block - int indirect_block_num = (file_block_num - MAX_DATABLOCKS_PER_INODE) / MAX_DATABLOCKS_PER_INDIRECT_BLOCK; - if(indirect_block_num >= file_inode->indirect_blocks_in_file || indirect_block_num > (MAX_NUM_INDIRECT_BLOCKS - 1)){ - return ERR_GEN; - } - - struct indirect_block* cur_indirect_block = (struct indirect_block*) kmalloc(sizeof(struct indirect_block)); - get_indirect_block(file_inode, file_inode->indirect_blocks[indirect_block_num], (struct indirect_block*) cur_indirect_block); - - int indirect_block_direct_block_num = (file_block_num - MAX_DATABLOCKS_PER_INODE) % MAX_DATABLOCKS_PER_INDIRECT_BLOCK; - if (cur_indirect_block->blocks_in_file <= indirect_block_direct_block_num) { - return ERR_GEN; - } - int block_address = cur_indirect_block->data_blocks[indirect_block_direct_block_num]; - block_address = (block_address + FS->start_data_blocks_loc) * BLOCKSIZE; - kfree(cur_indirect_block); - return block_address; -} - -/** - * Reads a partial portion of a block using the specified buffer size - * - * Reads a specified portion of a block from the passed file's inode - * starting at the offset point and then store the results of that in - * buf_offset - * - * @param - * - * struct inode *c_inode - The inode of the file we want to read - * - * @param - * - * int offset - starting point in the file to read from - * - * @param - * - * void* buf_offset - Holds the information read from the file - * - * @param - * - * int bytes_left - Holds the number of bytes to read from the file - * - * @param - * - * void* transfer_space - Used to hold data gotten from SD card block - * however I don't think we need this - * TODO: (maybe) replace transfer_space with buff_offset - * - * @return - * - * Returns the number of bytes which were transferred if successful; - * otherwise returns an error code - */ -int read_partial_block(struct inode *c_inode, int offset, void* buf_offset, int bytes_left, void* transfer_space) { - int local_offset = offset % BLOCKSIZE; // local_offset is the leftmost point in the block - - // Actually get the data for 1 block (the SD Driver will put it in transferSpace for us) - int file_block_num = offset / BLOCKSIZE; - int block_address = get_block_address(c_inode, file_block_num); - if (block_address < 0) { - return block_address; //return same error - } - - int success = sd_receive(transfer_space, block_address); - if(success < 0){ - // failed on a block receive, therefore the whole kread fails; return failure error - return ERR_SD; - }//end if block_num - - if((local_offset == 0) && (bytes_left < BLOCKSIZE)) { - /* ___________________ - |~~~~~~~~~| | - --------------------- */ - // Actually move the data to the user's specified buffer...must first cast void pointers to uint32_t* pointers: - // source is transfer_space - // dest is users buffer - - // note, this updates the buf_offset pointer as it transfer the data - // os_memcpy takes uint32_t* as arguments - os_memcpy(transfer_space, buf_offset, (os_size_t) bytes_left); - return bytes_left; // note, we are returning the number of bytes that were successfully transferred - - } else if((local_offset > 0) && (bytes_left >= (BLOCKSIZE - local_offset))) { - /* _____________________ - | |~~~~~~~~| - ---------------------- */ - // Actually move the data to the user's specified buffer...must first cast void pointers to uint32_t* pointers: - // source is transferSpace - // dest is users buffer - - os_memcpy((transfer_space + local_offset), buf_offset, (os_size_t) (BLOCKSIZE - local_offset)); // note, this updates the buf_offset pointer as it transfer the data - // os_memcpy takes uint32_t* as arguments - // reset transferSpace pointer - // transfer_space -= BLOCKSIZE; - - return (BLOCKSIZE - local_offset); // note, we are returning the number of bytes that were successfully transferred - - } else if((local_offset > 0) && (bytes_left < (BLOCKSIZE - local_offset))){ - /* ______________________ - | |~~~~| | - ----------------------- */ - // Actually move the data to the user's specified buffer...must first cast void pointers to uint32_t* pointers: - // source is transferSpace - // dest is users buffer - - os_memcpy((transfer_space + local_offset), buf_offset, (os_size_t) bytes_left); // note, this updates the buf_offset pointer as it transfer the data - // os_memcpy takes uint32_t* as arguments - // reset transferSpace pointer - transfer_space -= (local_offset + bytes_left); - - return bytes_left; // note, we are returning the number of bytes that were successfully transferred - - } - return ERR_GEN; -}//end of read_partial_block() helper function - - -/** - * Reads a full block using the specified buffer size - * - * Reads a specified block from the passed file's inode - * starting at the offset point and then store the results of that in - * buf_offset - * - * @param - * - * struct inode *c_inode - The inode of the file we want to read - * - * @param - * - * int offset - starting point in the file to read from - * - * @param - * - * void* buf_offset - Holds the information read from the file - * - * @param - * - * int bytes_left - Holds the number of bytes to read from the file - * - * @param - * - * void* transfer_space - Used to hold data gotten from SD card block - * however I don't think we need this - * TODO: (maybe) replace transfer_space with buff_offset - * - * @return - * - * Returns the number of bytes which were transferred if successful; - * otherwise returns an error code - */ -int read_full_block(struct inode *c_inode, int offset, void* buf_offset, int bytesLeft, void* transfer_space) { - // read BLOCKSIZE - // Actually get the data for 1 block (the SD Driver will put it in transfer_space for us) - int file_block_num = offset / BLOCKSIZE; - int block_address = get_block_address(c_inode, file_block_num); - if (block_address < 0) { - return block_address; //return same error - } - int success = sd_receive(transfer_space, block_address); - if(success < 0){ - // failed on a block receive, therefore the whole kread fails; return failure error - os_printf("failed to receive block number %d\n", file_block_num); - return ERR_SD; - }//end if - /* ______________________ - |~~~~~~~~~~~~~~~~~~~~~| - ----------------------- */ - // Actually move the data to the user's specified buffer...must first cast void pointers to uint32_t* pointers: - // source is transferSpace - // dest is users buffer - os_memcpy(transfer_space, buf_offset, (os_size_t) BLOCKSIZE); // note, this updates the buf_offset pointer as it transfer the data - // os_memcpy takes uint32_t* as arguments - // reset transferSpace pointer - return BLOCKSIZE; // note, we are returning the number of bytes that were successfully transferred -}//end read_full_block() helper function - -/** - * Reads the number of bytes specified from the target inode - * - * Calls either read_partial_block or read_full_block based on the number - * of bytes to read; will continue to call these functions until number of bytes - * specified has been met - * - * @param Description of method's or function's input parameter - * @param ... - * @return Description of the return value - */ -int read_inode(struct inode *c_inode, int offset, void* buf, int num_bytes){ - // Allocate space for and create a bitvector to be used repeatedly to transfer the data: - uint32_t *transfer_space = kmalloc(BLOCKSIZE); - int bytes_read = 0; - - if (num_bytes+offset > c_inode->size) { - num_bytes = c_inode->size - offset; - } - - // start of higher-level algo: - if(num_bytes < BLOCKSIZE) { - while(bytes_read < num_bytes) { - int x = read_partial_block(c_inode, offset + bytes_read, buf, (num_bytes-bytes_read),transfer_space); - bytes_read += x; - } - - } else if(num_bytes >= BLOCKSIZE) { - //Read in remainder of current block - bytes_read += read_partial_block(c_inode, offset + bytes_read, buf, (num_bytes-bytes_read),transfer_space); - //Read in maximum number of full blocks - while((num_bytes - bytes_read) >= BLOCKSIZE) { - bytes_read += read_full_block(c_inode, offset + bytes_read, buf+bytes_read, (num_bytes-bytes_read),transfer_space); - } - //If not completely read yet, read in remainder - if(bytes_read < num_bytes) { - bytes_read += read_partial_block(c_inode, offset + bytes_read, buf, (num_bytes-bytes_read),transfer_space); - } - }//end else if - - kfree(transfer_space); - return bytes_read; -} - - -//end of helper functions -// ----------------------------------------------------------------------------------------------------------------------------------------------------------- - -/** - * Kernel level open file; adds a new entry to the open file table - * - * Opens a file using the specified file path and sets it in either - * read or write mode. - * - * @param - * - * char* filepath - holds the pathname to the file to be opened - * - * @param - * - * char mode - holds either r or w indicating whether the file - * is to be opened in read or write mode - * - * @return - * - * Returns 0 if the file was opened correctly; otherwise returns - * -1 - * - */ -int kopen(const char* filepath, const char mode){ - if (filepath == NULL) { - os_printf("no directory specified \n"); - return ERR_INVALID; - } - if (mode == 0) { - os_printf("no mode specified \n"); - return ERR_INVALID; - } - int fd; - int inum = 0; - struct inode* cur_inode = (struct inode*) kmalloc(sizeof(struct inode)); - struct dir_helper* result = (struct dir_helper*) kmalloc(sizeof(struct dir_helper)); - kfind_dir(filepath, result); - int error = kfind_inode(filepath, inum, (result->dir_levels + 1), cur_inode); - - //here we have the file we were looking for! it is cur_inode. - if (error < 0 || cur_inode->is_dir) { - if (error < 0) { - os_printf("file not found, exiting kopen\n"); - } - else { - os_printf("cannot open a directory, make the path end to a file\n"); - error = ERR_INVALID; - } - kfree(cur_inode); - kfree(result->truncated_path); - kfree(result->last); - kfree(result); - - return error; //return same error - } - - // TODO: Permissions need some work, because the bitvector cannot be pulled out like this. :( - /*bit_vector *p = cur_inode->perms; - switch (mode){ - case 'r': - if(bv_get(0, p) == 0){ - os_printf("File Cannot Be Read\n"); - return -1; - } - break; - case 'w': - if(bv_get(1, p) == 0){ - os_printf("File Cannot Be Written\n"); - return -1; - } - break; - case 'a': - if(bv_get(1, p) == 0){ - os_printf("File Cannot Be Appeneded To\n"); - return -1; - } - break; - default: - os_printf("Please specify permission as r to read, w to write and a to append\n"); - }*/ - fd = add_to_opentable(cur_inode, mode); - kfree(result->truncated_path); - kfree(result->last); - kfree(result); - return fd; -}//end kopen() - -/** - * Reads a specified number of bytes from the SD card - * - * read from fd, put it in buf, then return the number of bytes read - * in numBytes - * - * @param - * - * int fd_int - index to a file descriptor in the open file table - * @param - * - * void* buf - buffer to hold the data read from the SD card - * - * @param - * - * int num_bytes - holds the number of bytes to store in the buffer - * - * @return - * - * Returns the number of bytes read from the SD card if successful, - * otherwise returns an error code - */ -int kread(int fd_int, void* buf, int num_bytes) { - if (fd_int < 0 || fd_int >= SYSTEM_SIZE) { - os_printf("kread, fd not valid \n"); - return ERR_INVALID; - } - if (buf == NULL) { - os_printf("no buffer \n"); - return ERR_INVALID; - } - if (num_bytes <= 0) { - os_printf("invalid number of bytes \n"); - return ERR_INVALID; - } - int bytes_read = 0; - uint32_t* buf_offset = buf; //this allows us to move data incrementally to user's buf via buf_offset - //while retaining the original pointer to return back to the user - struct file_descriptor* fd = get_descriptor(fd_int); // note, get_file_descriptor() function has not yet been implemented...will be in open_table.c - - if ((fd->permission != 'r') && (fd->permission != 'b')) { - os_printf("no permission\n"); - return ERR_PERM; - } - bytes_read = read_inode(fd->linked_file, fd->offset, buf_offset, num_bytes); - - fd->offset += bytes_read; - return bytes_read; -} // end kread(); - - -/** - * Write a specified number of bytes to the SD card - * - * write from fd, put it in buf, then return the number of bytes written in - * numBytes - * - * @param - * - * int fd_int - holds the index of a file descriptor in the open file table - * - * @param - * - * void* buf - holds the data to be written out to disk - * - * @param - * - * int num_bytes - holds the number of bytes to write to disk - * - * @return - * Returns the number of bytes written to disk if successful, otherwise - * returns an error code - */ -int kwrite(int fd_int, void* buf, int num_bytes) { - if (fd_int < 0 || fd_int >= SYSTEM_SIZE) { - os_printf("kwrite, fd not valid \n"); - return ERR_INVALID; - } - if (buf == NULL) { - os_printf("no buffer \n"); - return ERR_INVALID; - } - if (num_bytes <= 0) { - os_printf("invalid number of bytes \n"); - return ERR_INVALID; - } - struct file_descriptor* fd = get_descriptor(fd_int); - - if ((fd->permission != 'w' && fd->permission != 'a')){ - os_printf("ERROR! File was opened without write permissions.\nYou may or may not have permission to write to this file.\nTry opneing with 'w' permission\n"); - return ERR_PERM; - } - - int total_bytes_left = num_bytes; - int bytes_written = 0; - - struct indirect_block* cur_indirect_block; - void* buf_offset = buf; - void* transfer_space = kmalloc(BLOCKSIZE); - // os_memcpy(transferSpace, buf_offset, (os_size_t) BLOCKSIZE); - struct inode* cur_inode = fd->linked_file; - // have offset in the file already, just need to move it and copy. - // fd->offset is the offset in the file. - //while(bytes_written < total_bytes_left){ - while (total_bytes_left > 0) { - int file_block_num = fd->offset / BLOCKSIZE; - // need to put things in transfer_space, move pointer back when done - int offset_into_current_block = fd->offset % BLOCKSIZE; - int bytes_left_in_block = BLOCKSIZE - offset_into_current_block; - int block_address = get_block_address(cur_inode, file_block_num); - - //if get_block_address == -1, we know we need to allocate more space for the file - if(block_address < 0){ - int new_data_block_loc = bv_firstFree(data_block_bitmap); - if(new_data_block_loc < 0){//disk is completley full - os_printf("ERROR! disk full\n"); - return ERR_FULL; - } - block_address = (new_data_block_loc + FS->start_data_blocks_loc) * BLOCKSIZE; - bv_set(new_data_block_loc, data_block_bitmap); - - int flag_free_cur_indirect_block = 0; - if(cur_inode->direct_blocks_in_file < MAX_DATABLOCKS_PER_INODE){ - //Case (1): add a direct data block to cur_inode: - cur_inode->data_blocks[cur_inode->direct_blocks_in_file] = new_data_block_loc; - cur_inode->direct_blocks_in_file++; - transmit_receive_bitmap(TRANSMIT, data_block_bitmap, FS->data_bitmap_loc, FS->max_data_blocks, new_data_block_loc, 0); - }else{//(cur_inode->direct_blocks_in_file >= MAX_DATABLOCKS_PER_INODE - //get the current indirect block and check to see if it has room to add another data block: - cur_indirect_block = (struct indirect_block*) kmalloc(BLOCKSIZE); - flag_free_cur_indirect_block = 1; - get_indirect_block(cur_inode, cur_inode->indirect_blocks[cur_inode->indirect_blocks_in_file-1], cur_indirect_block); - - if(cur_indirect_block->blocks_in_file < MAX_DATABLOCKS_PER_INDIRECT_BLOCK && cur_inode->indirect_blocks_in_file != 0){ - //Case (2): add a new data block to to the current indirect block: - cur_indirect_block->data_blocks[cur_indirect_block->blocks_in_file] = new_data_block_loc; - cur_indirect_block->blocks_in_file++; - - // Causes data abort errors for some reason. - /*if(indirect_block_table_cache[cur_indirect_block->block_num] == NULL){ - //TODO: implement eviction policy...add the cur_inode to the cache: - }else{ - *(indirect_block_table_cache[cur_indirect_block->block_num]) = *(cur_indirect_block); - }*/ - - sd_transmit((void*) cur_indirect_block, (cur_indirect_block->block_num + FS->start_data_blocks_loc) * BLOCKSIZE); - transmit_receive_bitmap(TRANSMIT, data_block_bitmap, FS->data_bitmap_loc, FS->max_data_blocks, new_data_block_loc, 0); - }else{ //last indirect block full - if(cur_inode->indirect_blocks_in_file < MAX_NUM_INDIRECT_BLOCKS){ - /* Case (3): add a new indirect block to the cur_inode, then add a new data block to the new indirect block */ - int new_indirect_block_loc = bv_firstFree(data_block_bitmap); //Consult the data_block_bitmap to find a free block to add the new data block at - if(new_indirect_block_loc < 0){ - os_printf("ERROR! Disk full\n"); - return ERR_FULL; - } - bv_set(new_indirect_block_loc, data_block_bitmap); - - struct indirect_block* new_indirect_block = (struct indirect_block*) kmalloc(BLOCKSIZE); - new_indirect_block->blocks_in_file = 0; - new_indirect_block->block_num = new_indirect_block_loc; - - new_indirect_block->data_blocks[new_indirect_block->blocks_in_file] = new_data_block_loc; - new_indirect_block->blocks_in_file++; - cur_inode->indirect_blocks[cur_inode->indirect_blocks_in_file] = new_indirect_block_loc; - cur_inode->indirect_blocks_in_file++; - - /*if(indirect_block_table_cache[new_indirect_block->block_num] == NULL){ - //TODO: implement eviction policy...add the cur_inode to the cache: - }else{ - *(indirect_block_table_cache[new_indirect_block->block_num]) = *(new_indirect_block); - }*/ - - void *buf = kmalloc(BLOCKSIZE); - os_memcpy((uint32_t *) new_indirect_block, buf, sizeof(struct indirect_block)); - sd_transmit(buf, (new_indirect_block->block_num + FS->start_data_blocks_loc) * BLOCKSIZE); - kfree(buf); - transmit_receive_bitmap(TRANSMIT, data_block_bitmap, FS->data_bitmap_loc, FS->max_data_blocks, new_indirect_block_loc, 0); - kfree(new_indirect_block); - - }else{ - //file has reached max allowable size: - os_printf("ERROR! Operation failed because file has reached max allowable size\n"); - return ERR_FULL; - } - } - } - if(flag_free_cur_indirect_block){ - kfree(cur_indirect_block); - } - }//end if(block_address == -1) - - //now we have added new blocks to the file if necessary (and possible), so actually execute the write: - if(total_bytes_left <= bytes_left_in_block){ - //note, that here we are overwriting, but will never have to allocate new data blocks for the file - /* --------------- ----------------- - |~~~~~~~| | OR | |~~~~~| | - ---------------- ----------------- - */ - //Remaining bytes to write will fit in the current block - //first read the block in, so that the first part of it doesn't get ovewritten: - sd_receive(transfer_space, block_address); - // write total_bytes_left - os_memcpy(buf_offset, transfer_space + offset_into_current_block, (os_size_t) total_bytes_left); - //transfer_space -= total_bytes_left; //Purpose of this? - // pointer to start, block_num, where we are in file, length of write - sd_transmit(transfer_space, block_address); - - bytes_written += total_bytes_left; - fd->offset += total_bytes_left; - cur_inode->size += total_bytes_left; - total_bytes_left = 0; //at this point there is nothing left to write, so we're done - } - else{//(total_bytes_left > bytes_left_in_block) so...we might need to allocate new data blocks for the file... - /* - ------------ - | |~~~| - ------------ - write to the end of the block - */ - - //Remaining bytes will not fit in current block, fill up remainder of block - //first read the block in, so that the first part of it doesn't get ovewritten: - sd_receive(transfer_space, block_address); - // write total_bytes_left - os_memcpy(buf_offset, transfer_space + offset_into_current_block, (os_size_t) bytes_left_in_block); - - //transfer_space -= bytes_left_in_block; //Purpose of this? - // pointer to start, blockNum, where we are in file, lengh of write - sd_transmit(transfer_space, block_address); - - bytes_written += bytes_left_in_block; - total_bytes_left -= bytes_left_in_block; - fd->offset += bytes_left_in_block; - buf_offset += bytes_left_in_block; - cur_inode->size += bytes_left_in_block; - } - - }//end while - //update the the cur_inode on disk: - sd_transmit(cur_inode, (cur_inode->inum + FS->start_inode_table_loc) * BLOCKSIZE); - return bytes_written; -} // end kwrite(); - -/** - * Close the file - * - * Remove the file from the open file table and free the file's inode - * - * @param - * - * int fd - holds an index of a file descriptor in the open file table - * - * @return - * - * Returns 1 if the file was successfully closed, otherwise returns an error - */ -int kclose(int fd) { - if (fd < 0 || fd >= SYSTEM_SIZE) { - os_printf("kclose, fd not valid \n"); - return ERR_INVALID; - } - int error; - if(!file_is_open(fd)) { - os_printf("file not open"); - return ERR_GEN; - } - error = delete_from_opentable(fd); //this also frees inode - return error; -} // end kclose(); - -/** - * Increment seek position within a file - * - * Increments the seek pointer of a specific file by a number of - * specified bytes - * - * @param - * - * int fd_int - holds the index of a file descriptor in the open file table - * - * @param - * - * int num_bytes - holds the number of bytes to move the seek pointer by - * - * @return - * - * Returns 0 if the seek pointer was successfully moved; otherwise returns - * an error code - */ -int kseek(int fd_int, int num_bytes) { - if (fd_int < 0 || fd_int >= SYSTEM_SIZE) { - os_printf("kseek, fd not valid \n"); - return ERR_INVALID; - } - if (num_bytes <= 0) { - os_printf("num of bytes not valid \n"); - return ERR_INVALID; - } - struct file_descriptor* fd = get_descriptor(fd_int); - if (fd->permission != 'r' || fd->permission != 'w') { - os_printf("no permission \n"); - return ERR_PERM; - } else if ((num_bytes > 0) && ((fd->offset + num_bytes) > ((fd->linked_file)->size))){ - os_printf("Error! file offset exceeds file size \n"); - return ERR_GEN; - } else if ((num_bytes < 0) && ((fd->offset + num_bytes) < 0)){ - os_printf("Error! file offset exceeds beginning of file \n"); - return ERR_GEN; - }//end if else */ - fd->offset += num_bytes; - return SUCCESS; -} // end kseek(); - - -/** - * Creates a new file or directory in the file system - * - * Creates a new file or directory and all metadata attached to that - * file or directory and adds it to the open file table - * - * NOTE: File/Directory is not persistenly stored at this point! - * - * @param - * - * char* filepath - holds the path to the directory in which the - * new file/directory is to be added - * - * @param - * - * char mode - not used at present, will eventually be used to - * set file permissions - * - * @param - * - * int is_this_a_dir - set to 0 if the object to be created is - * a file; set to 1 if the object to be created is a directory - * - * @return - * - * Returns 0 if the file/directory was created successfully - * otherwise returns -1 - */ -int kcreate(const char* filepath, char mode, int is_this_a_dir) { - if (filepath == NULL) { - os_printf("filepath not valid \n"); - return ERR_INVALID; - } - if (mode == 0) { - os_printf("filepath not valid \n"); - return ERR_INVALID; - } - int fd; - int inum = 0; - struct inode* cur_inode = (struct inode*) kmalloc(sizeof(struct inode)); - struct dir_helper* result = (struct dir_helper*) kmalloc(sizeof(struct dir_helper)); - kfind_dir(filepath, result); - kfind_inode(result->truncated_path, inum, result->dir_levels, cur_inode); - - // at this point, the name of the file or dir to be created is “result->last” and it has to be added to cur_inode - int free_inode_loc = bv_firstFree(inode_bitmap); //Consult the inode_bitmap to find a free space in the inode_table to add the new inode - - if (free_inode_loc < 0) { - os_printf("Disk has reached max number of files allowed. \n"); - kfree(cur_inode); - kfree(result->truncated_path); - kfree(result->last); - kfree(result); - return ERR_FULL; - } - bv_set(free_inode_loc, inode_bitmap); - struct inode * new_inode = (struct inode*) kmalloc(sizeof(struct inode)); // Create the new inode - - /* initialize all fields of inode...note, these next 5 fields are for - all files, whether they are a dir or leaf */ - new_inode->inum = free_inode_loc; - new_inode->fd_refs = 0; //will be incremented in add to opentable - new_inode->size = 0; - new_inode->usr_id = 0; //or something - new_inode->indirect_blocks_in_file = 0; - - /* initialize the fields for new_indoe that are different for dirs and leaves */ - if(is_this_a_dir){ - new_inode->is_dir = 1; - new_inode->direct_blocks_in_file = 1; - - // Lay down the first (empty...) data block for the new directory (NOT root). - - transmit_receive_bitmap(RECEIVE, data_block_bitmap, FS->data_bitmap_loc, FS->max_data_blocks, 0, 1); - int new_data_block_loc = bv_firstFree(data_block_bitmap); - if(new_data_block_loc < 0){//disk is completley full - os_printf("ERROR! disk full\n"); - return ERR_FULL; - }//end if - int block_address = (new_data_block_loc + FS->start_data_blocks_loc) * BLOCKSIZE; - bv_set(new_data_block_loc, data_block_bitmap); - - //WILL THIS FIX IT?????????? - transmit_receive_bitmap(TRANSMIT, data_block_bitmap, FS->data_bitmap_loc, FS->max_data_blocks, 0, 1); - - void *block = kmalloc(BLOCKSIZE); - os_memset(block, 0, BLOCKSIZE); - struct dir_data_block ddb; - ddb.block_num = new_data_block_loc; - ddb.num_entries = 0; - os_memset(block, 0, BLOCKSIZE); - os_memcpy((uint32_t*)&ddb, block, sizeof(struct dir_data_block)); - sd_transmit((void*)block, block_address); - new_inode->data_blocks[0] = new_data_block_loc; - kfree(block); - }else{ /* initialize the fields for new_inode that are different for dirs and leaves */ - new_inode->is_dir = 0; - new_inode->direct_blocks_in_file = 0; - }//end if else - - //new_inode->data_blocks[MAX_DATABLOCKS_PER_INODE] = {0}; - - //new_inode->indirect_blocks[MAX_NUM_INDIRECT_BLOCKS] = {0}; - // TODO: Investigate permissions, and bitvectors/FS in general. - /*switch (mode){ - case 'r': - bv_set(0, new_inode->perms); - bv_lower(1, new_inode->perms); - break; - case 'w': - bv_set(0, new_inode->perms); - bv_set(1, new_inode->perms); - break; - default: - os_printf("Wrong permission. Please insert r for read and w for write\n"); - return -1; - }*/ - //UPDATE DISK by writing memory data structures to disk - - int error = add_dir_entry(cur_inode, new_inode->inum, result); - if (error != 0) { - return error; - } - void *block = kmalloc(BLOCKSIZE); - os_memset(block, 0, BLOCKSIZE); - os_memcpy((uint32_t*)cur_inode, block, sizeof(struct inode)); - sd_transmit(block, (cur_inode->inum + FS->start_inode_table_loc) * BLOCKSIZE); - - os_memset(block, 0, BLOCKSIZE); - os_memcpy((uint32_t*)new_inode, block, sizeof(struct inode)); - sd_transmit(block, (FS->start_inode_table_loc + new_inode->inum * INODES_PER_BLOCK)*BLOCKSIZE); //if there are more than 1 inodeperblock need to change - kfree(block); - // See above... We can't just do this. - //sd_transmit((void*)inode_bitmap, FS->inode_bitmap_loc); - kfree(cur_inode); - if (!is_this_a_dir) { - fd = add_to_opentable(new_inode, mode); - return fd; - }else { //directories are not added to open table - os_printf("Directory Successfully added\n"); - kfree(new_inode); - return SUCCESS; - } - -}//end of kcreate() function - -/** - * Determines whether a directory is empty or not - * - * Determines whether a directory is empty, can also be used to - * determine whether the object is a file instead of a directory as - * well as if the file is not a valid Course OS FS file - * - * @param - * - * struct inode* cur_inode - holds the file/directory to check - * - * @return - * - * Return 1 if it is a directory, return 0 if it not a directory, - * return an error code if something went wrong - */ -int dir_empty(struct inode* cur_inode){ - if(!cur_inode->is_dir){ - os_printf("This file is not a directory\n"); - return FALSE;//return 0, because it's not a dir - }//end else - if((cur_inode->direct_blocks_in_file == 0) && (cur_inode->indirect_blocks_in_file == 0)){ - if(cur_inode->size == 0){ - return TRUE; //return true because the dir is empty - } else { - /* TODO: Remove after debugging */ - os_printf("LOGIC ERROR: File size does not sync with file properties"); - return ERR_GEN;//error bc we should never get here - } - } - else { - os_printf("Your current directory still has files in it\n"); - return FALSE;//return false, bc the dir is not empty - } -} - -/** - * Helper function for kremove_dir_entry actually deletes file/directory - * - * Runs after entry for the file/directory has been removed from the parent - * directory and physically deletes the file/directory - * - * @param - * - * struct inode* cur_inode - inode of the file to check - * - * @return - * - * Returns 0 if the file is OK to remove, otherwise returns an error code - */ -int kdelete_single_helper(struct inode * cur_inode){ - if (cur_inode->is_dir){ - //we know it's a directory - if(dir_empty(cur_inode)) { - - bv_lower(cur_inode->inum, inode_bitmap); - return SUCCESS;//no error - } - else { - os_printf("This file is a non-empty directory, so cannot be deleted"); - return ERR_GEN;//error - } - } - //we know it is a file - else{ - int d; - for(d=0; ddirect_blocks_in_file; d++){ - - int index = cur_inode->data_blocks[d]; - bv_lower(index, data_block_bitmap); - } - struct indirect_block* cur_inder_block = (struct indirect_block*)kmalloc(sizeof(struct indirect_block)); - int i; - for(i=0; iindirect_blocks_in_file; i++){ - int z; - int indy_index_add = (cur_inode->indirect_blocks[i] + FS->start_data_blocks_loc) * BLOCKSIZE; - sd_receive((void*)cur_inder_block, indy_index_add); - for(z=0; zblocks_in_file; z++){ - - int index = cur_inder_block->data_blocks[z]; - bv_lower(index, data_block_bitmap); - } - bv_lower(cur_inder_block->block_num, data_block_bitmap); - } - kfree(cur_inder_block); - bv_lower(cur_inode->inum, inode_bitmap); - } - return SUCCESS; -} // end kdelete_single_helper(); - -/** - * Deletes a single entry in a directory - * - * Deletes a file or directory's entry from a specified directory's inode list - * NOTE: May/May not use recursive delete; this is untested so proceed - * with caution and test whether a recursive delete is done before - * using this function for deleting sub-directories. - * - * @param - * - * struct inode* cur_inode - holds a pointer to the folder which contains the file - * reference to remove - * - * @param - * - * int tgt_inum - Used to hold the index of the inode to be removed - * - * @return - * - * Returns 0 if the entry was successfully removed from the directory; otherwise - * it returns an error code. - */ -int kremove_dir_entry (struct inode* cur_inode, int tgt_inum) {//free_inode_loc = tgt_inum - //first get the appropriate data block, either from the array of direct data blocks from an indirect block: - struct dir_data_block* dir_block = (struct dir_data_block*) kmalloc(BLOCKSIZE); - struct indirect_block* cur_indirect_block; - //if the cur_inode's array of direct data blocks has not reached max capacity, grab the last data block in the array to update: - int i, j, k; - //search through direct data blocks: - for(i = 0; i < cur_inode->direct_blocks_in_file; i++){ - sd_receive((void*) dir_block, (cur_inode->data_blocks[i] + FS->start_data_blocks_loc)*BLOCKSIZE); - for(j = 0; j < dir_block->num_entries; j++){ - struct dir_entry dir_ent = (struct dir_entry) dir_block->dir_entries[j]; - if(dir_ent.inum == tgt_inum){ - /* remove dir_ent from dir_block, by moving the last dir_entry to this - index in the array and decrementing dir_block->num_entries */ - dir_block->dir_entries[j] = dir_block->dir_entries[dir_block->num_entries-1]; - dir_block->num_entries--; - if(dir_block->num_entries == 0){ - /* then this dir_data_block is empty, so we need to: - remove it from the cur_inode->data_blocks[] at index i - remove it from the data_blocks_bitmap */ - bv_lower(cur_inode->data_blocks[i], data_block_bitmap); - cur_inode->data_blocks[i] = cur_inode->data_blocks[cur_inode->direct_blocks_in_file-1]; - cur_inode->direct_blocks_in_file--; - }//end if - cur_inode->size -= sizeof(struct dir_entry); - sd_transmit((void*) dir_block, (cur_inode->data_blocks[i] + FS->start_data_blocks_loc)*BLOCKSIZE); - kfree(dir_block); - return SUCCESS; - }//end if - }//end for - }//end outer for - //search through indirect data blocks: - cur_indirect_block = (struct indirect_block*) kmalloc(BLOCKSIZE); - for(k = 0; k < cur_inode->indirect_blocks_in_file; k++){ - get_indirect_block(cur_inode, k, cur_indirect_block); - for(i = 0; i < cur_indirect_block->blocks_in_file; i++){ - sd_receive((void*) dir_block, (cur_indirect_block->data_blocks[i] + FS->start_data_blocks_loc)*BLOCKSIZE); - for(j = 0; j < dir_block->num_entries; j++){ - struct dir_entry dir_ent = (struct dir_entry) dir_block->dir_entries[j]; - if(dir_ent.inum == tgt_inum){ - /* remove dir_ent from dir_block, by moving the last dir_entry to this - index in the array and decrementing dir_block->num_entries */ - dir_block->dir_entries[j] = dir_block->dir_entries[dir_block->num_entries-1]; - dir_block->num_entries--; - if(dir_block->num_entries == 0){ - /* then this dir_data_block is empty, so we need to: - remove it from the cur_inode->data_blocks[] at index i - remove it from the data_blocks_bitmap */ - bv_lower(cur_indirect_block->data_blocks[i], data_block_bitmap); - cur_indirect_block->data_blocks[i] = cur_indirect_block->data_blocks[cur_inode->direct_blocks_in_file-1]; - cur_indirect_block->blocks_in_file--; - - if(cur_indirect_block->blocks_in_file == 0){ - /* then this indirect_block is empty, so we need to: - remove it from the cur_inode->indirect_blocks[] at index k - remove it from the data_blocks_bitmap */ - bv_lower(cur_inode->indirect_blocks[k],data_block_bitmap); - cur_inode->indirect_blocks[k] = cur_inode->indirect_blocks[cur_inode->indirect_blocks_in_file-1]; - cur_inode->indirect_blocks_in_file--; - }//end if - }//end if - cur_inode->size -= sizeof(struct dir_entry); - sd_transmit((void*) dir_block, (cur_indirect_block->data_blocks[i] + FS->start_data_blocks_loc)*BLOCKSIZE); - kfree(dir_block); - kfree(cur_indirect_block); - return SUCCESS; - }//end if - }//end for - }//end outer for - }//end outer outer for - kfree(dir_block); - kfree(cur_indirect_block); - return ERR_404; -}//end kremove_dir_entry() function - - -/** - * Deletes a single file or from a directory - * - * call delete_single_helper, deletes the lowest level (ie target) file and - * updates all bitmaps, but DOES NOT remove the dir_entry in levelup dir - * - * @param - * - * struct inode* cur_inode - Points to a specific file/directory to remove - * - * @param - * - * struct inode* level_up_inode - points to the directory in which the specifiied - * file/directory resides - * - * @return - * - * Returns 0 if the the file was successfully deleted; returns -1 if the file - * doesn't exist - */ -int kdelete_single(struct inode* cur_inode, struct inode* level_up_inode) { - /* call delete_single_helper, deletes the lowest level (ie target) file and - updates all bitmaps, but DOES NOT remove the dir_entry in levelup dir */ - int error = kdelete_single_helper(cur_inode); - if(!error){ //if kdeletesinglehelper was successful - sd_transmit((void*) cur_inode, (cur_inode->inum + FS->start_inode_table_loc) * BLOCKSIZE); - /* delete dir_entry in levelup dir) */ - error = kremove_dir_entry(level_up_inode, cur_inode->inum); - if(error < 0){ - os_printf("ERROR! Could not find dir_entry in level_up_inode...BIG PROBLEM!!!\n"); - kfree(level_up_inode); - return error; - }//end inner if - sd_transmit((void*) cur_inode, (level_up_inode->inum + FS->start_inode_table_loc) * BLOCKSIZE); - }else{ - kfree(level_up_inode); - return error; //return same error - } - kfree(level_up_inode); - return SUCCESS; -} // end kdelete_single() - - -/** - * Recursively deletes an entire directory - * - * Deletes a directory and any sub-directories and files contained within - * freeing all blocks and metadata for each entry and then updates the - * metadata for the directory which contained it - * - * The logic on this should be good, but still need to... - * TODO: on each sd_recieve() check cache first AND figure out kmalloc - * situation...will this cause heap overflow??? should we limit the - * depth of filepaths to avoid this??? - * - * @param - * - * struct inode* cur_inode - Points to a specific file/directory to remove - * - * @param - * - * struct inode* level_up_inode - points to the directory in which the specifiied - * file/directory resides - * - * @return - * - * Returns 0 if the the directory was successfully deleted, otherwise returns - * an error code - */ -int krec_delete(struct inode * level_up_inode, struct inode * cur_inode){ - //base case - int error; - int status = dir_empty(cur_inode); - if (status == TRUE){ //dir is empty - error = kdelete_single(cur_inode, level_up_inode); - //SHOULDN'T FREE IT kfree(level_up_inode); - }else if(status < 0){ //WTF? - return ERR_GEN; - } - - if (error) { - return error; - } - - //recursive step - else{ //status == 0, meaning is not empty - int i; - int direct_data_block_address; - struct dir_data_block* dir_block = (struct dir_data_block*) kmalloc(sizeof(struct dir_data_block)); - for(i=0; i< cur_inode->direct_blocks_in_file; i++){ - direct_data_block_address = (cur_inode->data_blocks[i]+FS->start_data_blocks_loc) * BLOCKSIZE; - sd_receive(dir_block, direct_data_block_address); - int j; - int inum; - struct dir_entry cur_dir_entry; - for(j = 0; j < dir_block->num_entries; j++){ - cur_dir_entry = dir_block->dir_entries[j]; - inum = cur_dir_entry.inum; - struct inode* next_inode = (struct inode*) kmalloc(sizeof(struct inode)); - // struct inode* next_inode; - get_inode(inum, next_inode); - krec_delete(cur_inode,next_inode); - kfree(next_inode); - }//end - }//end for - int k; - int indirect_data_block_address; - struct indirect_block* cur_indirect_block = (struct indirect_block*) kmalloc(sizeof(struct indirect_block)); - for(k = 0; k < cur_inode->indirect_blocks_in_file; k++){ - indirect_data_block_address = (cur_inode->indirect_blocks[k]+FS->start_data_blocks_loc) * BLOCKSIZE; - sd_receive(cur_indirect_block, indirect_data_block_address); - for(i=0; i < cur_indirect_block->blocks_in_file; i++){ - direct_data_block_address = (cur_indirect_block->data_blocks[i]+FS->start_data_blocks_loc) * BLOCKSIZE; - sd_receive(dir_block, direct_data_block_address); - int j; - int inum; - struct dir_entry cur_dir_entry; - for(j = 0; j < dir_block->num_entries; j++){ - cur_dir_entry = dir_block->dir_entries[j]; - inum = cur_dir_entry.inum; - struct inode* next_inode = (struct inode*) kmalloc(sizeof(struct inode)); - // struct inode* next_inode; - get_inode(inum, next_inode); - krec_delete(cur_inode,next_inode); - kfree(next_inode); - }//end - }//end - }//end outer for - kfree(cur_indirect_block); - kfree(dir_block); - }//end if else - return SUCCESS; -}//end krec_delete() - -//--------------------------------------------------- - -/** - * Deletes a file or directory at the specified filepath - * - * Can be used to delete a single file or directory; can delete - * directories recursively - * - * NOTE: Recursive delete is untested; please test this function - * to ensure it is working properly before using it - * - * @param - * - * char* filepath - Holds the path to the specified file/directory to delete - * - * @param - * - * int recursive - Holds 0 if the target is a single file or empty directory - * holds 1 if the target is a full directory which needs to be deleted recursively - * - * @return - * - * Returns 0 if the file/directory was deleted successfully; otherwise returns an - * error code - */ -//delete the file or directory at filepath. Return -1 if the file does not exist -int kdelete(const char* filepath, int recursive) { - int error; - int inum = 0; - - /* spaceholder for lowest inode */ - struct inode* cur_inode = (struct inode*) kmalloc(sizeof(struct inode)); - struct inode* level_up_inode = (struct inode*) kmalloc(sizeof(struct inode)); - /* spaceholder for helper struct */ - struct dir_helper* result = (struct dir_helper*) kmalloc(sizeof(struct dir_helper)); - - /* find the helper struct */ - kfind_dir(filepath, result); - - /* find the lowest inode */ - error = kfind_inode(filepath, inum, (result->dir_levels + 1), cur_inode); - if(error < 0){ - kfree(cur_inode); - kfree(level_up_inode); - kfree(result->truncated_path); - kfree(result->last); - kfree(result); - return error; - } - /* Check to ensure the file is not currently open...if it is return an error and notify user */ - if(inode_is_open(cur_inode)){ - os_printf("File %d cannot be deleted, because it is currently open\n", cur_inode->inum); - kfree(cur_inode); - kfree(level_up_inode); - kfree(result->truncated_path); - kfree(result->last); - kfree(result); - return ERR_GEN; - } - error = kfind_inode(filepath, inum, (result->dir_levels), level_up_inode); - if(recursive){ - error = krec_delete(level_up_inode,cur_inode); - kfree(cur_inode); - kfree(level_up_inode); - kfree(result->truncated_path); - kfree(result->last); - kfree(result); - transmit_receive_bitmap(TRANSMIT, data_block_bitmap, FS->data_bitmap_loc, FS->max_data_blocks, 0, 1); - transmit_receive_bitmap(TRANSMIT, inode_bitmap, FS->inode_bitmap_loc, FS->max_inodes, 0, 1); - return error; - }else{ - error = kdelete_single(cur_inode, level_up_inode); - kfree(cur_inode); - kfree(level_up_inode); - kfree(result->truncated_path); - kfree(result->last); - kfree(result); - transmit_receive_bitmap(TRANSMIT, data_block_bitmap, FS->data_bitmap_loc, FS->max_data_blocks, 0, 1); - transmit_receive_bitmap(TRANSMIT, inode_bitmap, FS->inode_bitmap_loc, FS->max_inodes, 0, 1); - return error; - }//end if else - os_printf("we should never reach this!!!\n"); - return ERR_GEN; -} // end kdelete() - - -//--------------------------------------------------- - -/** - * Copies contents of a file into a new file - * - * Creates a new file at the destination path and then copies - * all data from the file pointed to by the source path - * - * @param - * - * char* source - holds the file path of the file to copy - * - * @param - * - * char* dest - holds the destination file path to copy to - * - * @param - * - * char mode - Mainly used for permissions; not implemented right - * now however - * - * @return - * - * Retun 0 if the file was copied successfully; otherwise return - * an error code - */ -int kcopy(const char* source, const char* dest, const char mode) { - int error = 0; - int inum = 0; //start from root - - //1. find source - struct dir_helper *source_dir_helper = (struct dir_helper *) kmalloc(sizeof(struct dir_helper)); - kfind_dir(source, source_dir_helper); - struct inode *source_inode = (struct inode*) kmalloc(sizeof(struct inode)); - //find the source inode - error = kfind_inode(source, inum, (source_dir_helper->dir_levels + 1), source_inode); - if (error < 0) { //kfind_inode unsuccessful - os_printf("kfind_inode unsuccessful \n"); - kfree(source_inode); - kfree(source_dir_helper->truncated_path); - kfree(source_dir_helper->last); - kfree(source_dir_helper); - return ERR_404; - } - //at this point source_inode is the inode of the source - int copy_directory = source_inode->is_dir; //checks if we are copying a direcory or a file - - //2. cerate destination - int dest_fd = 0; - dest_fd = kcreate(dest, mode, copy_directory); //creates the new file or directory - if (dest_fd < 0) { //some problem occurred in kcreate - os_printf("kcreate unsuccessful \n"); - kfree(source_inode); - kfree(source_dir_helper->truncated_path); - kfree(source_dir_helper->last); - kfree(source_dir_helper); - return ERR_GEN; - } - - //3. find destination - struct file_descriptor *dest_fd_struct = get_descriptor(dest_fd); - if (dest_fd_struct == NULL) { //get_descriptor had problems - os_printf("get_descriptor unsuccessful \n"); - kfree(source_inode); - kfree(source_dir_helper->truncated_path); - kfree(source_dir_helper->last); - kfree(source_dir_helper); - return ERR_GEN; - } - //at this point dest_inode is the inode of the created destination - - void *buffer = (void*) kmalloc(source_inode->size); - error = read_inode(source_inode, 0, buffer, source_inode->size); - if (!error) { - error = kwrite(dest_fd, buffer, source_inode->size); - } - kfree(buffer); - kfree(source_inode); - kfree(source_dir_helper->truncated_path); - kfree(source_dir_helper->last); - kfree(source_dir_helper); - return error; -}//end kcopy function - - -/** - * Prints the contents of a directory to the screen - * - * @param - * - * char* filepath - holds the filepath to the directory to display - * the contents of - * - * @return - * Returns 0 if the function was executed correctly, otherwise returns - * an error code - */ -int kls(const char* filepath) { - int error = 0; - int inum = 0; //starting from root - struct dir_helper* result = (struct dir_helper *) kmalloc(sizeof(struct dir_helper)); - kfind_dir(filepath, result); - struct inode* cur_inode = (struct inode*) kmalloc(sizeof(struct inode)); - error = kfind_inode(filepath, inum, (result->dir_levels + 1), cur_inode); - if (error < 0 || cur_inode->is_dir == 0) { //kfind_inode unsuccessful or cannot ls - if (error < 0) { //kfind - os_printf("kfind_inode unsuccessful \n"); - } - else { //cannot ls - os_printf("this is not a directory but a file, cannot ls a file \n"); - error = ERR_INVALID; - } - kfree(cur_inode); - kfree(result->truncated_path); - kfree(result->last); - kfree(result); - return error; //return same error - } - //at this point, cur_inode is a directory and we need to print all the names of its contents. - //1. print from direct blocks - int i; - void* dir_spaceholder = (void*) kmalloc(BLOCKSIZE); - for(i = 0; i < cur_inode->direct_blocks_in_file; i++){ - sd_receive(dir_spaceholder, (cur_inode->data_blocks[i])*BLOCKSIZE); - struct dir_data_block cur_data_block = *((struct dir_data_block*) dir_spaceholder); - int j; - for(j = 0; j < (cur_data_block.num_entries); j++){ - struct dir_entry file_dir = cur_data_block.dir_entries[j]; - os_printf("entry: %s \n", file_dir.name); - }//inner for - }//outer for - //2. print from indirect blocks - struct indirect_block *cur_indirect_block = (struct indirect_block *) kmalloc(sizeof(struct indirect_block)); - int cur_indirect_block_num; - for(i = 0; i < cur_inode->indirect_blocks_in_file; i++){ - cur_indirect_block_num = cur_inode->indirect_blocks[i]; - get_indirect_block(cur_inode, cur_indirect_block_num, cur_indirect_block); - int j; - for(j = 0; j < cur_indirect_block->blocks_in_file; j++){ - sd_receive(dir_spaceholder, (cur_indirect_block->data_blocks[j])*BLOCKSIZE); - struct dir_data_block cur_data_block = *((struct dir_data_block*) dir_spaceholder); - int k; - for(k = 0; k < (cur_data_block.num_entries); k++){ - struct dir_entry file_dir = cur_data_block.dir_entries[k]; - os_printf("entry: %s \n", file_dir.name); - }//inner for - }//outer for - }//end for - kfree(cur_indirect_block); - kfree(dir_spaceholder); - kfree(cur_inode); - kfree(result->truncated_path); - kfree(result->last); - kfree(result); - return SUCCESS; -} - -/** - * Used to obtain information about a specified file or directory - * - * Obtains various information about the file at the specified file - * path including: size of the file, how many open copies of the - * file there are, and whether the file is a directory - * - * @param - * - * char* filepath - The path to the file to obtain information from - * - * @param - * - * struct stats* result - Pointer to a location to store information - * about the specified file - * - * @return - * Returns 0 if information was successfully retrieved; otherwise - * returns an error code - */ -int get_stats(const char * filepath, struct stats * result) { - int inum = 0; - struct inode* cur_inode = (struct inode*) kmalloc(sizeof(struct inode)); - struct dir_helper* help_result = (struct dir_helper*) kmalloc(sizeof(struct dir_helper)); - kfind_dir(filepath, help_result); - int error = kfind_inode(filepath, inum, (help_result->dir_levels + 1), cur_inode); - if (error < 0) { - os_printf("file not found, exiting kopen\n"); - kfree(cur_inode); - kfree(help_result->truncated_path); - kfree(help_result->last); - kfree(help_result); - return error; //return same error - } - result->size = cur_inode->size; - result->fd_refs = cur_inode->fd_refs; - result->is_dir = cur_inode->is_dir; - kfree(cur_inode); - kfree(help_result->truncated_path); - kfree(help_result->last); - kfree(help_result); - return SUCCESS; -}//end get_stats function diff --git a/kernel/old/fs/fat16/test.c b/kernel/old/fs/fat16/test.c deleted file mode 100644 index 5f002434..00000000 --- a/kernel/old/fs/fat16/test.c +++ /dev/null @@ -1,75 +0,0 @@ -#include -#include -#include -#include - - -int main(int argc, char *argv[]) { - char cwd[1024]; - if (getcwd(cwd, sizeof(cwd)) != NULL) - fprintf(stdout, "Current working dir: %s\n", cwd); - else - perror("getcwd() error"); - - char* buf = (void*) malloc(sizeof(char) * 512); - char* original_buf = buf; - *buf = "courseOSfsaaaaaaaaaaaaaaaaaaaaa"; - buf +=32; - - *((int*)buf) = (int)1; - buf +=4; - - buf = (int*)buf; - - *(buf) = (int)2; - buf +=4; - - *(buf) = (int)512; - buf +=4; - - *(buf) = (int)2; - buf +=4; - - *(buf) = (int)100; - buf +=4; - - *(buf) = (int)900; - buf +=4; - - *(buf) = (int)11; - buf +=4; - - *(buf) = (int)12; - buf +=4; - - *(buf) = (int)333; - buf +=4; - - *(buf) = (int)444; - buf +=4; - - // 12 512000 512 2 100 900 11 12 333 444 - fprintf("TESTING***************\n") - int fd = open("superblock_1.data", 'O_RDWR'); - write(fd, original_buf, 512); - close(fd); - - - // FILE *params_file = fopen("superblock_1.data", "w"); // write only - // // test to ensure that the file was actually created and exists: - // if (params_file == NULL){ - // printf("1. Error! Could not create file\n"); - // exit(-1); // must include stdlib.h - // }//end if - - // fprintf(params_file, "PARAMS\n"); - // fprintf(params_file, "nx=%d,ny=%d,nz=%d\n", nx, ny, nz); - // fprintf(params_file, "dx=%lg,dy=%lg,dz=%lg\n", dx, dy, dz); - // fprintf(params_file, "numFiles=%d\n", numFiles); - // fprintf(params_file, "numParticles=%d\n", numParticles); - // fclose(params_file); - - - - return 0; -} diff --git a/kernel/old/fs/fat16/test_superblock.data b/kernel/old/fs/fat16/test_superblock.data deleted file mode 100644 index cca4d90a..00000000 --- a/kernel/old/fs/fat16/test_superblock.data +++ /dev/null @@ -1 +0,0 @@ -courseOSfsaaaaaaaaaaaaaaaaaaaaaa1 2 512000 512 2 100 900 11 12 333 444 \ No newline at end of file diff --git a/kernel/old/fs/fat16/test_superblock.txt b/kernel/old/fs/fat16/test_superblock.txt deleted file mode 100644 index cca4d90a..00000000 --- a/kernel/old/fs/fat16/test_superblock.txt +++ /dev/null @@ -1 +0,0 @@ -courseOSfsaaaaaaaaaaaaaaaaaaaaaa1 2 512000 512 2 100 900 11 12 333 444 \ No newline at end of file diff --git a/kernel/old/fs/open_table.c b/kernel/old/fs/open_table.c deleted file mode 100644 index 1ff25d8c..00000000 --- a/kernel/old/fs/open_table.c +++ /dev/null @@ -1,117 +0,0 @@ -//This file contains the table of open files, implemented as an array -// with methods like add_to_opentable and delete_from_opentable to be called in open and close -//Since methods are provided, other files should not touch neither the free LL or the arrray, -// but just use the premade methods. - -#include "klibc.h" -#include "fs/file.h" -#include "fs/open_table.h" -#include "data_structures/bitvector.h" -#include "../../src/klibc//include/stdint.h" - - -//called by file.c initialization function, initializes free list and table -void fs_table_init() { - open_table_free_list = make_vector(SYSTEM_SIZE); //create bitvector of free indexes - table = (struct file_descriptor**)kmalloc(SYSTEM_SIZE * (sizeof(struct file_descriptor*))); //malloc the table - os_memset(table, 0, SYSTEM_SIZE * (sizeof(struct file_descriptor*))); -} - -//at shutdown, memory with the free list is freed -void fs_table_shutdown() { - bv_free(open_table_free_list); - int i; - for (i = 0; i < SYSTEM_SIZE; i++) { - if (table[i] != NULL) { //deal with users that forget to close files - if (table[i]->linked_file != NULL) { //"if" added because we never know what can happen... - kfree(table[i]->linked_file); - } - kfree(table[i]); - } - } - kfree(table); -} - - -//returns struct of descriptor at index fd -//if invalid, returns NULL. -struct file_descriptor* get_descriptor(int fd){ - if (file_is_open(fd)) { - return table[fd]; - } - return NULL; -} - -// this function can be used to insert a file in the table -// and returns the requested index if successful, else -1 -int add_to_opentable(struct inode * f, char perm) { - int fd = (int) bv_firstFree(open_table_free_list); //gets free index from bitvector - if (fd == -1) { - return ERR_FULL; //reached max num of files open - } - bv_set((uint32_t)fd, open_table_free_list); //index is now taken - struct file_descriptor* to_add = (struct file_descriptor*) kmalloc(sizeof(struct file_descriptor)); //malloc new struct - int inum = f->inum; - int i; - for (i=0; ilinked_file->inum == inum) { - to_add->linked_file->fd_refs++; //increment the number of references - to_add->linked_file = table[i]->linked_file; //point to same file - to_add->permission = perm; //assign new permission - to_add->offset = 0; //restart offset from 0 - table[fd] = to_add; //add to table - return fd; - } - } - to_add->linked_file = f; - to_add->linked_file->fd_refs = 1; - to_add->permission = perm; - to_add->offset = 0; - table[fd] = to_add; //add to table - if (perm == 'a') { //append, need to move offset to very end - table[fd]->offset = table[fd]->linked_file->size; - } - return fd; -} - - -//this function can be used to delete a file from the list -//returns 0 if all ok, -1 if wrong -int delete_from_opentable(int fd) { - if (!file_is_open(fd)) { - return ERR_INVALID; //invalid entry - } - table[fd]->linked_file->fd_refs--; - if (table[fd]->linked_file->fd_refs == 0) { //free inode only if was referenced only once - kfree(table[fd]->linked_file); - } - kfree(table[fd]); //free space in table - bv_lower ((uint32_t)fd, open_table_free_list); //index is not taken anymore - return SUCCESS; -} - - -//this function checks whether the file is open or not -int file_is_open(int fd) { - if (fd<0 || fd>=SYSTEM_SIZE) { - return FALSE; - } - if (table[fd] == NULL) { - return FALSE; - } - return TRUE; -} - -//this function checks whether the file is open or not -int inode_is_open(struct inode* cur_inode) { - int i; - for(i = 0; i < SYSTEM_SIZE; i++){ - if(table[i] != NULL){ - if((table[i]->linked_file)->inum == cur_inode->inum){ - return TRUE; // file is open - } - } - } - return FALSE; -} - diff --git a/kernel/old/include/drivers/clock.h b/kernel/old/include/drivers/clock.h deleted file mode 100644 index a8d73a21..00000000 --- a/kernel/old/include/drivers/clock.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef CLOCK_H -#define CLOCK_H - -#include "../../../src/klibc//include/stdint.h" -#include "mmap.h" - -#endif diff --git a/kernel/old/include/fs/file.h b/kernel/old/include/fs/file.h deleted file mode 100644 index 7efc8557..00000000 --- a/kernel/old/include/fs/file.h +++ /dev/null @@ -1,177 +0,0 @@ -#ifndef __FILE_H__ -#define __FILE_H__ - -#include "global_defs.h" -#include "data_structures/bitvector.h" -#include "data_structures/linked_list.h" -#include "../../../../../src/klibc//include/stdint.h" - -#define BLOCKSIZE 512 -#define MAX_NAME_LENGTH 32 -#define MAX_DATABLOCKS_PER_INODE 100 -#define DIR_ENTRY_SIZE 40 -#define MAX_NUM_INDIRECT_BLOCKS 20 -#define MAX_DATABLOCKS_PER_INDIRECT_BLOCK ((BLOCKSIZE/4)-2) -#define MAX_DIR_ENTRIES_PER_DATA_BLOCK ((int)((BLOCKSIZE-4)/DIR_ENTRY_SIZE)-2) - - -//error codes used in return: -#define ERR_GEN -1 //general error -#define ERR_FULL -2 //error signaling end of resources -#define ERR_INVALID -3 //invalid parameter -#define ERR_404 -4 //file not found -#define ERR_SD -5 //sd card error -#define ERR_PERM -6 //permission error -#define SUCCESS 0 //no error - - -//IMPORTANT!! --------------------------------------------------------------------------------------------------- -//all constants are in units of block NUMBER | -//the indexes of arrays are also in units of block NUMBER relative to the starting offset of their cathegory. | -//--------------------------------------------------------------------------------------------------------------- - -//constants of file system, that wil be filled at boot time -struct superblock -{ - // char* fs_name; // 32 bytes (max length for this field abides by MAX_NAME_LENGTH) - int fs_version; // 36 bytes - int magic_num; // 40 bytes - int sd_card_capacity; // 44 bytes - int block_size; // 48 bytes - int root_inum; // 52 bytes - int max_inodes; // 56 bytes - int inode_size; - int max_data_blocks; // 66 bytes - int inode_bitmap_loc; // 70 bytes - int data_bitmap_loc; // 74 bytes - // int indirect_blocks_bitmap_loc; // - int start_inode_table_loc; // 78 bytes - int start_data_blocks_loc; // 82 bytes, start_inode_table_loc + 200 b/c 200 inode bl - // int start_indirect_block_table_loc; // - // int max_indirect_blocks; - // char spaceholder[???]; Might need this to make the cast from memory to superblock work...not sure??? Don't think we need this, but not sure - // the rest of the superblock will be empty for now (BLOCKSIZE - 82 = 512 - 82 = 430 free/wasted bytes) -}; - -//metadata of each file or directory -struct inode { - int inum; //inum of the file (4bytes) - int fd_refs; //how many times the file is referenced (=appears in the opentable) (4bytes) - int size; // size of the whole file (4 bytes) - int is_dir; // 1 if this is a directory, 0 if this is a file (4 bytes) - int usr_id; // id of the user who created the file (4 bytes) ...not yet used! - int direct_blocks_in_file; // how many direct block are being used (4 bytes) - int data_blocks[MAX_DATABLOCKS_PER_INODE]; // array of data (now long 70) - int indirect_blocks_in_file; // how many indirect block are being used (4 bytes) - int indirect_blocks[MAX_NUM_INDIRECT_BLOCKS]; // 50*4 = 200 bytes ....50 indirect blocks right now - bit_vector* perms; // permissions of the file (4 bytes) -}; - -struct indirect_block // total size is 1 block -{ - int block_num; - int blocks_in_file; //blocks actually used - int data_blocks[MAX_DATABLOCKS_PER_INDIRECT_BLOCK]; // because this is just an array of ints, so it's BLOCKSIZE/4 bytes bc each int is 4 bytes -}; - -struct dir_entry -{ - int inum; - int name_length; //including null terminating string - char name[MAX_NAME_LENGTH]; // 32 chars right now -}; // 8 _ MAX_NAME_LENGTH bytes long...40 bytes right now - -struct dir_data_block -{ - int block_num; - int num_entries; - struct dir_entry dir_entries[MAX_DIR_ENTRIES_PER_DATA_BLOCK]; -}; - -struct data_block -{ - char data[BLOCKSIZE]; -}; - -struct dir_helper //used by helper functions in file.c -{ - int dir_levels; - char* truncated_path; - char* last; -}; - -struct stats //statistics about the file -{ - int size; //size of the file - int fd_refs; //how many times it is open now - int is_dir; //is this a directory -}; - -int kopen(const char* filepath, const char mode); //opens the file of filepath with permissions mode -int kread(int fd, void* buf, int numBytes); //reads the open file corresponding to fd -int kwrite(int fd, void* buf, int num_bytes); //writes the open file corresponding to fd -int kclose(int fd); //closes the cpen file corresponding to fd -int kseek(int fd, int num_bytes); //moves the offset of the open file fd -int kdelete(const char* filepath, int recursive); //deletes the file or directory following filepath -int kcreate(const char* filepath, const char mode, int is_this_a_dir); //creates and opens a file or directory with permissions mode in fielpath -int kcopy(const char* source, const char* dest, const char mode); //copies the contents of a file -int kls(const char* filepath); //shows contents of one directory -int kfs_init(int inode_table_cache_size, int data_block_table_cache_size, int reformat); // initialize the filesystem: -int kfs_shutdown(); - -// // ------------------------------------------------------------------------------------------------------------------------------------------------------- -// /* HELPER FUNCTIONS */ -int get_stats(const char * filepath, struct stats * result); - -int kdelete_single_helper(struct inode * cur_inode); - -//delete the file or directory at filepath. Return -1 if the file does not exist -int kdelete_single(struct inode* cur_inode, struct inode* level_up_inode); - -/* deletes a single dir_entry */ -int kremove_dir_entry (struct inode* cur_inode, int tgt_inum); - -//from the index, gets the corresponding indirect block, either from cache or from disk -void get_indirect_block(struct inode* cur_inode, int index, struct indirect_block* cur_indirect_block); - -//from the inum, gets corresponding inode, either from cache or disk -void get_inode(int inum, struct inode* result_inode); - -//gets the inum of nextpath (file or dir) looking at the direct data blocks of cur_inode -int get_inum_from_direct_data_block(struct inode* cur_inode, const char * next_path); - -//gets the inum of netxpath (file or dir) looking at the indirect data blocks of cur_inode -int get_inum_from_indirect_data_block(struct inode * cur_inode, const char * next_path); - -//finds the inode (will be result_inode) following filepath, going dir_levels down the path, starting from starting_inum -int kfind_inode(const char* filepath, int starting_inum, int dir_levels, struct inode* result_inode); - -//finds the name of the directory path (result->truncated_path) and the name of the ending part (result->last) and the number of levels (result->levels) -//result has to be kmalloc-ed by and kfree-d by whoever calls this functinos. Also remember to free last and truncated_path. -void kfind_dir(const char* filepath, struct dir_helper* result); - -//transmits or receives the data block bitvector or the inode bitvecotr to and from disk -// First parameter: TRANSMIT or RECEIVE (defined) -// Second paramter: put pointer to bitvector (example: data_block_bitmap for data, inode_bitmap for inodes) -// Third parameter: put where that bitvecotr starts in memory (example: FS->data_bitmap_loc for data, FS->inode_bitmap_loc for inode) -// Fourth parameter: how many there are (example: FS->max_data_blocks for data, FS->max_inodes for inodes) -// index = index you would put in the bitvector -// all = 0 for only one index, 1 for all the bitvector -int transmit_receive_bitmap(int t_or_r, bit_vector* vec, int starting_loc, int max, int bit_index, int all); - -/* Helper function to add a new dir_entry to a directory file and optinally write it out to disk. - Updates the last data block of the cur_inode (directory) to add a dir_entry that stores the mapping of the new inode to its inum */ -int add_dir_entry(struct inode* cur_inode, int free_inode_loc, struct dir_helper* result); - -int get_block_address(struct inode *file_inode, int block_num); - -// Helper function for kread(): -int read_partial_block(struct inode *c_inode, int offset, void* buf_offset, int bytes_left, void* transfer_space); - -// Helper function for kread(): -int read_full_block(struct inode *c_inode, int offset, void* buf_offset, int bytesLeft, void* transfer_space);; - -int read_inode(struct inode *c_inode, int offset, void* buf, int num_bytes); - - -#endif diff --git a/kernel/old/include/fs/open_table.h b/kernel/old/include/fs/open_table.h deleted file mode 100644 index 3262cf9b..00000000 --- a/kernel/old/include/fs/open_table.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef __OPEN_TABLE_H__ -#define __OPEN_TABLE_H__ - -//header for the open table file -//that implements the open table for the file system -//please use provided functinos to add/remove items - -#include "global_defs.h" -#include "klibc.h" -#include "fs/file.h" -#include "data_structures/bitvector.h" - -#define SYSTEM_SIZE 512 //how many files can be open at the same time - -// Each cell of the array is a struct with infos about the file. -// More fields can be added if necessary. -struct file_descriptor { - char permission; - struct inode* linked_file; //pointer to inode struct - int offset; //keeps track of where we are reading -}; - -// Array of open files -struct file_descriptor** table; - -//list of free indexes -bit_vector * open_table_free_list; - - -void fs_table_init(); //initializes fs open table at boot up time -void fs_table_shutdown(); //closes the open table at shutdown time - -int add_to_opentable(struct inode* f, char perm); //adds a file to the opentable, returns fd if successful and -1 if not - -int delete_from_opentable(int fd); //deletes a file from the opentable, returns 0 if successful, -1 if not - -int file_is_open(int fd); //checks if there is an entry corrensponding to that fd - -int inode_is_open(struct inode* cur_inode); - -struct file_descriptor* get_descriptor(int fd); //returns the filedescriptor struct linked to fd - -#endif diff --git a/kernel/old/include/klibc.h b/kernel/old/include/klibc.h deleted file mode 100644 index 554a224f..00000000 --- a/kernel/old/include/klibc.h +++ /dev/null @@ -1,161 +0,0 @@ -/******************************************************************** - * libc.h - * - * (Any collaborators, please add your name) - * Author: Jared McArthur, Taylor Smith, Sheldon Sandbekkhaug, Kaelen Haag - * - * Last edited: 20 April 2014 - * - * Purpose: Provide basic libc funtionality for CourseOS - * This header provides function skeletons - * for libc.c - * - * Usage: Compile into kernel. Adaptations of normal libc functions - * can be used by prepending os_ suffix. - ********************************************************************/ - -/* LOG: - * 3/30 added os_printf function - Taylor Smith - * 4/1 working more on os_printf - Taylor Smith - * 4/20 Added os_memset, os_strchrnul, os_strcpy, os_strlen, os_strtok, - * os_strspn, and os_strcspn from MUSL - Sheldon - * 4/21 Added os_memcpy for loader - Kaelen - * --------------Spring 2015--------------- - * 4/15/15: Added implementation of assert() - */ -#ifndef __KLIBC_H__ -#define __KLIBC_H__ - -#include "../../src/klibc//include/stdint.h" -#include "../../src/klibc//include/stdarg.h" -#include "global_defs.h" - -#ifndef __NO_WFI -#define SLEEP while (1) asm volatile("wfi") -#else -#define SLEEP for(;;) -#endif - -typedef unsigned int os_size_t; - -// useful macros -#define MAX(a, b) ((a) > (b) ? a : b) -#define MIN(a, b) ((a) < (b) ? a : b) - -// basic constants -#define M_E 2.71828182845904523536 -#define M_LOG2E 1.44269504088896340736 -#define M_LOG10E 0.434294481903251827651 -#define M_LN2 0.693147180559945309417 -#define M_LN10 2.30258509299404568402 -#define M_PI 3.14159265358979323846 -#define M_PI_2 1.57079632679489661923 -#define M_PI_4 0.785398163397448309616 -#define M_1_PI 0.318309886183790671538 -#define M_2_PI 0.636619772367581343076 -#define M_1_SQRTPI 0.564189583547756286948 -#define M_2_SQRTPI 1.12837916709551257390 -#define M_SQRT2 1.41421356237309504880 -#define M_SQRT_2 0.707106781186547524401 - -#define os_printf(...) printf(__VA_ARGS__) - -/* string.h type functionality for comparing strings or mem blocks */ -int os_memcmp(const void *left, const void *right, os_size_t num); -int os_strcmp(const char *left, const char *right); - - -//4-17-15: Working assert implementation - Prakash -#define assert(X){\ - if ( (X) || _assert_fail(__FILE__, __LINE__, #X));\ -} - -/** - * Note: os_printf is restricted to printing only 256 characters. - * Supported format string conversions: - * X: upper-case hexadecimal print. - * x: lower-case hexadecimal print. - * d: signed integer. - * u: unsigned integer. - * c: ASCII character. - * s: string. - * %: the percent sign itself. - * - * Supported options: - * 0: zero-pad the result (applies to X,x,d,u). For example: - * os_printf("'%05d %05d %05u'\n", 15, -15, -15); - * prints '00015 -0015 4294967281' - */ -int os_vsnprintf(char *buf, int buflen, const char *str_buf, va_list args); -int os_snprintf(char *buf, int buflen, const char *fmt_string, ...); -int os_printf(const char *str_buf, ...); - -void *os_memset(void *dest, char c, os_size_t n); -char *__strchrnul(const char *s, char c); -char *os_strcpy(char *dest, const char *src); -char *os_strncpy(char *dest, const char *src, os_size_t n); -os_size_t os_strlen(const char *s); -char *os_strtok(char *s, const char *sep); -os_size_t os_strspn(const char *s, const char *accept); -os_size_t os_strcspn(const char *s, const char *reject); - -void os_memcpy(uint32_t * source, uint32_t * dest, os_size_t size); -/* TODO: create print function for kernel debugging purposes */ - -void* kmalloc(uint32_t size); -void* kmalloc_aligned(uint32_t size, uint32_t alignment); -void kfree(void* ptr); -uint32_t km_size(); -uint32_t kmcheck(); - -/** - * umalloc allocates memory on the user heap - * - * @param size of the block of memory allocated - * @param uint32_t size - * @return returns a pointer to the allocated block of memory - */ -void* umalloc(uint32_t size); //does user level malloc work - -/** - * ualigned alloc allocates memory on the user heap - * according to a specified alignemnt - * - * @param size of the block of memory allocated, and alignment desired - * @param uint32_t size, uint32_alignment - * @return returns a pointer to the allocated block of memory - * that is a multiple of the specified allignement - */ -void* ualigned_alloc(uint32_t size, uint32_t alignment); //does user level aligned_alloc work - -/** - * free's an allocated block of memory on the heap - * - * @param pointer to a block of memeory on the heap - * @param void* ptr - * @return nothing returned - */ -void ufree(void*); //does user level free work - -int32_t abs(int32_t); -unsigned int rand(); - -// as the codebase grows, it is important to use these macros -// so that we can filter out unnecessary messages esp. during -// development -#define LOG_LEVEL 5 - -#define DEBUG(...) if(LOG_LEVEL >= 5) os_printf(__VA_ARGS__) -#define LOG(...) if(LOG_LEVEL >= 4) os_printf(__VA_ARGS__) -#define INFO(...) if(LOG_LEVEL >= 3) os_printf(__VA_ARGS__) -#define WARN(...) if(LOG_LEVEL >= 2) os_printf(__VA_ARGS__) -#define ERROR(...) if(LOG_LEVEL >= 1) os_printf(__VA_ARGS__) - -//4-17-15: Initial panic * assert_fail functions added -void panic(); -int _assert_fail(char *_file, unsigned int _line, char *_func); - //__attribute__ ((__noreturn__)); - -void splash(void); - -#endif diff --git a/kernel/old/include/misc_defs.h b/kernel/old/include/misc_defs.h deleted file mode 100644 index 884361fd..00000000 --- a/kernel/old/include/misc_defs.h +++ /dev/null @@ -1,25 +0,0 @@ -#include "../../src/klibc//include/stdint.h" - -/* - Contained within this file is the base addresses to many of the Rasberry Pi's peripherals, - along with definitions for some of the important offsets from these case addresses. -*/ -#define USB_BASE_ADDRESS 0x20980000 - -#define USB_MDIO_CNTL (USB_BASE_ADDRESS +0x080) // MDIO interface control -#define USB_MDIO_GEN (USB_BASE_ADDRESS + 0x084) // Datat for MDIO interface -#define USB_VBUS_DRV (USB_BASE_ADDRESS + 0x088) // Vbus and other miscellaneous controls - -// BSC stands for Broadcom Serial Controller, from the documentation, it looks like its used for HDMI -#define BSC_MASTER_0 0x20205000 -#define BSC_MASTER_1 0x20804000 -#define BSC_MASTER_2 0x20805000 -//Offsets can be used with any of the above three BSC register BSC register bases -#define BSC_CONTROL 0x0 -#define BSC_STATUS 0x4 -#define BSC_DATA_LENGTH 0x8 -#define BSC_SLAVE_ADDRESS 0xC -#define BSC_FIFO 0x10 -#define BSC_CLOCK_DIVIDER 0x14 -#define BSC_DATA_DELAY 0x18 - diff --git a/kernel/old/include/os_setjmp.h b/kernel/old/include/os_setjmp.h deleted file mode 100644 index b13af54c..00000000 --- a/kernel/old/include/os_setjmp.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _SETJMP_H -#define _SETJMP_H - -#include - -typedef struct __jmp_buf_tag { - __jmp_buf __jb; - unsigned long __fl; - unsigned long __ss[128/sizeof(long)]; -} jmp_buf[1]; - -// typedef jmp_buf sigjmp_buf; -// int sigsetjmp (sigjmp_buf, int); -// _Noreturn void siglongjmp (sigjmp_buf, int); - -int setjmp (jmp_buf); -_Noreturn void longjmp (jmp_buf, int); - -#define setjmp setjmp -#define longjmp longjmp - -#endif diff --git a/kernel/old/include/pi_light.h b/kernel/old/include/pi_light.h deleted file mode 100644 index 0e292d66..00000000 --- a/kernel/old/include/pi_light.h +++ /dev/null @@ -1,8 +0,0 @@ -#include "mmap.h" - -#define GPIO_BASE 0x20200000 -#define LED_PIN 16 - -void set_up_LED(); -void light_on(); -void light_off(); \ No newline at end of file diff --git a/kernel/old/include/pm.h b/kernel/old/include/pm.h deleted file mode 100644 index 98980e69..00000000 --- a/kernel/old/include/pm.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef _PM_H -#define _PM_H -#include "klibc.h" -#include "global_defs.h" -#include "../../src/klibc//include/stdint.h" -#include "mmap.h" - -typedef struct -{ - - //CPU peripherals - uint32_t PIC; - uint32_t VFP; - uint32_t PMU; - - //registers - uint32_t R0; - uint32_t R1; - uint32_t R2; - uint32_t R3; - uint32_t R4; - uint32_t R5; - uint32_t R6; - uint32_t R7; - uint32_t R8; - uint32_t R9; - uint32_t R10; - uint32_t R11; - uint32_t R12; - uint32_t R13; - uint32_t R14; - uint32_t R15; -} cpu_state; diff --git a/kernel/old/include/priorityQueue.h b/kernel/old/include/priorityQueue.h deleted file mode 100644 index 124c6ee6..00000000 --- a/kernel/old/include/priorityQueue.h +++ /dev/null @@ -1,22 +0,0 @@ -#include "../../src/process/include/process.h" -#include "global_defs.h" - -#define NOT_SET -1 - -/* Data Structure: Doubly Linked List */ -typedef struct { - struct node *next; - struct node *prev; - pcb *PCB; // Pointer to the process control block - int priority; -} Node; - - -void pqueue_init(); -int pqueue_add(void *PCB, int priority); -pcb* pqueue_remove(pcb *PCB); -void pqueue_join(pcb *other_PCB); -void dispatch(pcb *PCB); -void schedule(); -void task_yield(); -Boolean is_in_queue(int pid); diff --git a/kernel/old/include/tests.h b/kernel/old/include/tests.h deleted file mode 100644 index 40a07760..00000000 --- a/kernel/old/include/tests.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _TESTS_H_ -#define _TESTS_H_ - -#include "global_defs.h" - -// Each test consists of a descriptor and function pointer to the test function. -typedef struct Test { - char *test_name; - int (*testptr)(); -} Test; - -// Run_tests takes an array of tests which it runs and prints the results. -void run_tests(Test *test_group[], int num_tests); -void run_fs_tests(); - -int test1(); -int test2(); - -Test* create_test(char *name, int (*test_function)()); - -#endif diff --git a/kernel/old/include/tests/test_hash_map.h b/kernel/old/include/tests/test_hash_map.h deleted file mode 100644 index 4a0d4e34..00000000 --- a/kernel/old/include/tests/test_hash_map.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * test_hash_map.h - * - * Created on: Apr 20, 2015 - * Author: kittenRainbow - */ - -#ifndef KERNEL_INCLUDE_TESTS_TEST_HASH_MAP_H_ -#define KERNEL_INCLUDE_TESTS_TEST_HASH_MAP_H_ - -void run_hmap_tests(); - -#endif /* KERNEL_INCLUDE_TESTS_TEST_HASH_MAP_H_ */ diff --git a/kernel/old/include/tests/test_mem_alloc.h b/kernel/old/include/tests/test_mem_alloc.h deleted file mode 100644 index b7f93d17..00000000 --- a/kernel/old/include/tests/test_mem_alloc.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * test_hash_map.h - * - * Created on: Apr 20, 2015 - * Author: kittenRainbow - */ - -#ifndef KERNEL_INCLUDE_TESTS_TEST_MEM_ALLOC_H_ -#define KERNEL_INCLUDE_TESTS_TEST_MEM_ALLOC_H_ - -void run_mem_alloc_tests(); - -#endif /* KERNEL_INCLUDE_TESTS_TEST_MEM_ALLOC_H_ */ diff --git a/kernel/old/include/tests/test_priority_queue.h b/kernel/old/include/tests/test_priority_queue.h deleted file mode 100644 index b177d57e..00000000 --- a/kernel/old/include/tests/test_priority_queue.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * test_priority_queue.h - * - * Created on: Apr 16, 2015 - * Author: mwkurian - */ - -#ifndef KERNEL_INCLUDE_TESTS_TEST_PRIORITY_QUEUE_H_ -#define KERNEL_INCLUDE_TESTS_TEST_PRIORITY_QUEUE_H_ - -void run_prq_tests(); - -#endif /* KERNEL_INCLUDE_TESTS_TEST_PRIORITY_QUEUE_H_ */ diff --git a/kernel/old/include/tests/test_vm.h b/kernel/old/include/tests/test_vm.h deleted file mode 100644 index 41b2fd3c..00000000 --- a/kernel/old/include/tests/test_vm.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * test_vm.h - * - * Created on: Apr 23, 2015 - * Author: mwkurian - */ - -#ifndef KERNEL_INCLUDE_TESTS_TEST_VM_H_ -#define KERNEL_INCLUDE_TESTS_TEST_VM_H_ - -void run_vm_tests(); - -#endif /* KERNEL_INCLUDE_TESTS_TEST_VM_H_ */ diff --git a/kernel/old/legacy/os_longjmp.s b/kernel/old/legacy/os_longjmp.s deleted file mode 100644 index aff15fbd..00000000 --- a/kernel/old/legacy/os_longjmp.s +++ /dev/null @@ -1,37 +0,0 @@ -.global _longjmp -.global longjmp -.type _longjmp,%function -.type longjmp,%function -_longjmp: -longjmp: - mov ip,r0 - movs r0,r1 - moveq r0,#1 - ldmia ip!, {v1,v2,v3,v4,v5,v6,sl,fp,sp,lr} - - adr r1,1f - ldr r2,1f - ldr r1,[r1,r2] - - tst r1,#0x260 - beq 3f - tst r1,#0x20 - beq 2f - ldc p2, cr4, [ip], #48 -2: tst r1,#0x40 - beq 2f - ldc p11, cr8, [ip], #64 -2: tst r1,#0x200 - beq 3f - ldcl p1, cr10, [ip], #8 - ldcl p1, cr11, [ip], #8 - ldcl p1, cr12, [ip], #8 - ldcl p1, cr13, [ip], #8 - ldcl p1, cr14, [ip], #8 - ldcl p1, cr15, [ip], #8 -3: tst lr,#1 - moveq pc,lr - bx lr - -.hidden __hwcap -1: .word __hwcap-1b diff --git a/kernel/old/legacy/os_setjmp.s b/kernel/old/legacy/os_setjmp.s deleted file mode 100644 index b74dfc68..00000000 --- a/kernel/old/legacy/os_setjmp.s +++ /dev/null @@ -1,39 +0,0 @@ -.global __setjmp -.global _setjmp -.global setjmp -.type __setjmp,%function -.type _setjmp,%function -.type setjmp,%function -__setjmp: -_setjmp: -setjmp: - mov ip,r0 - stmia ip!,{v1,v2,v3,v4,v5,v6,sl,fp,sp,lr} - mov r0,#0 - - adr r1,1f - ldr r2,1f - ldr r1,[r1,r2] - - tst r1,#0x260 - beq 3f - tst r1,#0x20 - beq 2f - stc p2, cr4, [ip], #48 -2: tst r1,#0x40 - beq 2f - stc p11, cr8, [ip], #64 -2: tst r1,#0x200 - beq 3f - stcl p1, cr10, [ip], #8 - stcl p1, cr11, [ip], #8 - stcl p1, cr12, [ip], #8 - stcl p1, cr13, [ip], #8 - stcl p1, cr14, [ip], #8 - stcl p1, cr15, [ip], #8 -3: tst lr,#1 - moveq pc,lr - bx lr - -.hidden __hwcap -1: .word __hwcap-1b diff --git a/kernel/old/legacy/pm.c b/kernel/old/legacy/pm.c deleted file mode 100644 index 7d0a2328..00000000 --- a/kernel/old/legacy/pm.c +++ /dev/null @@ -1,90 +0,0 @@ -#include "pm.h" -#include "../../src/klibc//include/stdint.h" -#include "../../src/klibc//include/stdarg.h" -#include "interruptold.h" -#include "klibc.h" -#include "stack.h" - -stack *stack = create_stack(); - -//method to set CPU to idle -int cpu_idle(int *fp) -{ - save_registers(); - clear_cache(); - return 0; -} - -//method to return CPU to regular operation -int cpu_resume(int *fp) -{ - enable_cache(); - return 0; -} - -//method to save registers on stack -void save_registers() -{ -push(stack, asm volatile ("r0")); -push(stack, asm volatile ("r1")); -push(stack, asm volatile ("r2")); -push(stack, asm volatile ("r3")); -push(stack, asm volatile ("r4")); -push(stack, asm volatile ("r5")); -push(stack, asm volatile ("r6")); -push(stack, asm volatile ("r7")); -push(stack, asm volatile ("r8")); -push(stack, asm volatile ("r9")); -push(stack, asm volatile ("r10")); -push(stack, asm volatile ("r11")); -push(stack, asm volatile ("r12")); - -push(stack, asm volatile ("ip")); -push(stack, asm volatile ("lr")); -push(stack, asm volatile ("pc")); -push(stack, asm volatile ("sp")); - -} - -void restore_registers() -{ - -} - -//method to clear L1 -void clear_cache() -{ -/* still need to push & pop the stack */ -/* disable cache */ -asm volatile("mov r0, #0"); -//clear r0 -asm volatile("mrc p15, 0, r0, c1, c0, 0"); -//mv control register to r0 -asm volatile("bic r0, #4"); -//!& with 4 - clears bit 2, cache bit -asm volatile("mcr p15, 0, r0, c1, c0, 0"); -//write r0 to control register - -/* clean and flush cache */ -asm volatile("mov r2, #0"); -//clear r2 -asm volatile("mcr p15, 0, r2, c7, c14, 0"); -//clean and flush data cache -asm volatile("mov r2, #0"); -//clear r2 -asm volatile("mcr p15, 0, r2, c7, c5, 0"); -//clean and flush instruction cache -} - -void enable_cache() -{ -/* enable cache */ -asm volatile("mov r0, #0"); -//clear r0 -asm volatile("mrc p15, 0, r0, c1, c0, 0"); -//mv control register to r0 -asm volatile("bic r0, #4"); -//!& with 4 - enables bit 2, cache bit -asm volatile("mcr p15, 0, r0, c1, c0, 0"); -//write r0 to control register -} diff --git a/kernel/old/legacy/priorityQueue.c b/kernel/old/legacy/priorityQueue.c deleted file mode 100644 index c37fa7f9..00000000 --- a/kernel/old/legacy/priorityQueue.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - Spring 2015 pcb_exec subteam: Sathya Sankaran, Jason Sim, Rakan Stanbouly - */ - -#include "priorityQueue.h" -#include "global_defs.h" -#include "vm.h" - -/* Global Variables */ -Node *head; -Node *currentNode; -/********************/ - -/* Initializes all the global variables */ -void pqueue_init() -{ - head = (Node *) mem_alloc(sizeof(Node)); - head->next = NULL; - head->prev = NULL; - head->PCB = NULL; - head->priority = NOT_SET; - head->PCB->current_state = NOT_SET; - currentNode = head; -} - -/* Add a PCB to the queue with a given priority. - Return 1 if successful. - */ -int pqueue_add(void *PCB, int priority) -{ - if (head == NULL) - { - init(); - } - - Node *newTask = (Node *) mem_alloc(sizeof(Node)); - newTask->next = NULL; - newTask->prev = NULL; - newTask->PCB = PCB; - newTask->priority = priority; - newTask->priority = PROCESS_READY; - - if (head->next == NULL) - { - head->next = (struct node *) newTask; - newTask->next = (struct node *) head; - newTask->prev = (struct node *) head; - head->prev = (struct node *) newTask; - } - else - { - // Add the new task into the correct position based on priority - currentNode = head; - while ((currentNode->next != (struct node *) head) - && (currentNode->next->priority > newTask->priority)) - { - currentNode = (Node *) currentNode->next; - } - newTask->next = currentNode->next; - newTask->prev = (struct node *) currentNode; - currentNode->next->prev = newTask; - currentNode->next = (struct node *) newTask; - } - - return 1; // Change if there should be a condition for not adding a PCB to the priority queue. -} - -/* Remove the node with the same PID as the process in the given process - control block. - - Return a pointer to the PCB removed. - */ -pcb* pqueue_remove(pcb *PCB) -{ - //PCB abstraction will change the parameters, can search for processes by PID. - currentNode = head; - while (currentNode->next->PCB->PID != PCB->PID) - { - currentNode = (Node *) currentNode->next; - } - Node *nodeToRemove = (Node *) currentNode->next; - currentNode->next = nodeToRemove->next; - currentNode->next->prev = currentNode; - nodeToRemove->next = nodeToRemove->prev = NULL; - return nodeToRemove->PCB; -} - -/* Wait for a task to finish. Then set the current task's state to READY */ -void pqueue_join(pcb *other_PCB) -{ - // TODO: Do we need to store which task(s) we are blocked on? - currentNode->PCB->current_state = PROCESS_BLOCKED; - - // Wait for the other thread to exit - while (other_PCB->current_state != PROCESS_DYING - || is_in_queue(other_PCB->PID)) - { - task_yield(); - } - currentNode->PCB->current_state = PROCESS_RUNNING; -} - -/* If the task has not been started yet, start it. - Else if the task was previously started, restore its state. - */ -void dispatch(pcb *PCB) -{ - //4-15-15: Dispatch deals with both new and old processes - if (!PCB->current_state || PCB->current_state == PROCESS_NEW) // TODO: not sure if this is correct - { - PCB->current_state = PROCESS_RUNNING; - execute_process(PCB); // Found in process.c - } - else - { - //4-15-15: This will load the VAS and jump to the location the state was saved in task_yield() - //TODO: is this all that needs to be done here to switch into the process? - vm_enable_vas(PCB->stored_vas); - load_process_state(PCB); // From process.c - ///execute_process(PCB); //This is incorrect - } -} - -/* Schedule a new task and call dispatch() to run it. */ -void schedule() -{ - // When dispatch() returns, we must schedule again, so we have use "while" - while (head->next != NULL) - { - Node *nodeToDispatch = (Node *) head->next; - - if (nodeToDispatch->PCB->current_state == PROCESS_READY) - { - nodeToDispatch->PCB->current_state = PROCESS_RUNNING; - dispatch(nodeToDispatch->PCB); - } - else - { - // If the task isn't ready, schedule another. - head = (Node *) head->next; - } - - head = head->next; - } - - // If we ever reach this part, we are out of things to schedule -} - -/* I heard we wanted voluntary yielding to start. Tasks should call this - function every so often. - */ -void task_yield() -{ - /* Save the state of the task that is currently running. We'll jump - back to here later. - */ - currentNode->PCB->current_state = PROCESS_READY; - //4-15-15: also save the VAS for the process. Hopefully this is all we need to do. - currentNode->PCB->stored_vas = vm_get_current_vas(); - int has_jumped = save_process_state(currentNode->PCB); - - if (has_jumped == FALSE) - { - // If the jump has NOT happened, schedule() - schedule(); - } - else - { - // If the jump has happened, return to the task - //4-15-15: and restore the VAS - vm_enable_vas(currentNode->PCB->stored_vas); - currentNode->PCB->current_state = PROCESS_RUNNING; - return; - } -} - -/* Return TRUE if a process with a PID of pid is in the queue. - Return FALSE otherwise. - */ -Boolean is_in_queue(int pid) -{ - Node *node_ptr = head; - - // Iterate through the list - while ((Node *) node_ptr->next != head) - { - if (node_ptr->PCB->PID == pid) - { - return TRUE; - } - - node_ptr = (Node *) node_ptr->next; - } - - return FALSE; -} diff --git a/kernel/old/tests/Makefile b/kernel/old/tests/Makefile deleted file mode 100644 index 0006c0c7..00000000 --- a/kernel/old/tests/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -include $(CURDIR)/../../config.mk - -TOOLCHAIN_PATH:=$(CURDIR)/../../$(TOOLCHAIN_DIR)/$(BARE_METAL_TARGET)/bin -CC:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gcc -INCL:=$(CURDIR)/../include/ -MAKE:=$(CURDIR)/../ -CFLAGS = -pipe -std=c99 -ffreestanding - -default: tests - -tests: test_vm.o test_hash_map.o test_mem_alloc.o test_priority_queue.o test_fs.o - $(MAKE)Makefile - $(CC) $(CFLAGS) -lc -o tests test_hash_map.o test_mem_alloc.o test_priority_queue.o test_vm.o test_fs.o - -test_fs.o: test_fs.c $(INCL)/tests.h $(INCL)/file.h ../fs/cmdline/file.h - $(CC) $(CFLAGS) -lc -o test_fs test_fs.c - -test_hash_map.o: test_hash_map.c $(INCL)/tests.h $(INCL)/tests/test_hash_map.h $(INCL)hash_map.h $(INCL)/klibc.h - $(CC) $(CFLAGS) -lc -o test_hash_map test_hash_map.c - -test_mem_alloc.o: test_mem_alloc.c $(INCL)/tests.h $(INCL)/tests/test_mem_alloc.h $(INCL)/klibc.h $(INCL)/vm.h - $(CC) $(CFLAGS) -lc -o test_mem_alloc test_mem_alloc.c - -test_priority_queue.o: test_priority_queue.c $(INCL)/tests.h $(INCL)/tests/test_priority_queue.h $(INCL)/priority_queue.h $(INCL)/klibc.h - $(CC) $(CFLAGS) -lc -o test_priority_queue test_priority_queue.c - -test_vm.o: test_vm.c $(INCL)/tests.h $(INCL)/klibc.h $(INCL)/memory.h $(INCL)/vm.h - $(CC) $(CFLAGS) -lc -o test_vm test_vm.c - -%.o: %.c - $(CC) $(CFLAGS) -c -mcpu=arm1176jzf-s $< -o $@ - -clean: - rm -f *.o - rm -f tests - rm -f test_fs - rm -f test_vm - rm -f test_hash_map - rm -f test_mem_alloc - rm -f test_priority_queue \ No newline at end of file diff --git a/kernel/old/tests/test_fs.c b/kernel/old/tests/test_fs.c deleted file mode 100644 index 6230a4ea..00000000 --- a/kernel/old/tests/test_fs.c +++ /dev/null @@ -1,107 +0,0 @@ -#include "tests.h" -#include "klibc.h" -#include "fs/file.h" - - - -int test_fs_1() -{ - os_printf("\nCREATING /foo\n"); - int fd1 = kcreate("/foo", 'w', 1); - - os_printf("\nCREATING /bar\n"); - int fd2 = kcreate("/bar", 'w', 1); - - os_printf("\nCREATING /foo/baz.txt\n"); - int fd3 = kcreate("/foo/baz.txt", 'w', 0); - - os_printf("closing /foo/baz.txt \n"); - kclose(fd3); - - os_printf("\nnow opening file: /foo/baz.txt\n"); - int fd_new = kopen("/foo/baz.txt", 'w'); - os_printf("file descriptor is: %d\n", fd_new); - os_printf("closing /foo/baz.txt \n"); - kclose(fd_new); - - os_printf("\nnow opening file: /foo/baz.txt again to write to it\n"); - fd_new = kopen("/foo/baz.txt", 'w'); - char *s = "Hellooooooooooooooooooooooolllllllllllll world!!!"; - kwrite(fd_new, s, os_strlen(s)); - kclose(fd_new); - os_printf("closing /foo/baz.txt \n"); - - os_printf("\nnow opening file: /foo/baz.txt to read from it\n"); - fd_new = kopen("/foo/baz.txt", 'r'); - char buf[256]; - os_memset(&buf, 0, 256); - int nbytes = kread(fd_new, buf, 256); - os_printf("Read %d bytes from file.\n", nbytes); - os_printf("the buffer is: '%s'\n", buf); - kclose(fd_new); - kclose (fd1); - kclose (fd2); - kclose (fd3); - - return 0; -}//end test_fs_1() - -int test_fs_1_old() -{ - - return 0; -}//end test_fs1() - - - - -int test_fs_2() { - LOG("\nWriting a lot of data to /foobar2...\n"); - - int fd = kcreate("/foobar2", 'w', 0); - kclose(fd); - - // Okay, let's try making /foobar really big. - fd = kopen("/foobar2", 'w'); - int buf[256]; - int i; - for (i=0; i<256; i++) { - buf[i] = i*3; - } - // Write buf out 128 times -#define CNT 64 - for (i=0; iis_dir); - return 0; -} - -void run_fs_tests() { - Test *tests[1]; - tests[0] = create_test("test_fs_1", &test_fs_1); - //tests[1] = create_test("test_fs_2", &test_fs_2); - //run_tests(tests, 2); - // tests[1] = create_test("test_fs_2", &test_fs_2); - run_tests(tests, 1); -} diff --git a/kernel/old/tests/test_hash_map.c b/kernel/old/tests/test_hash_map.c deleted file mode 100644 index 1de3f2e2..00000000 --- a/kernel/old/tests/test_hash_map.c +++ /dev/null @@ -1,187 +0,0 @@ -#include "tests.h" -#include "tests/test_hash_map.h" -#include "data_structures/hash_map.h" -#include "klibc.h" - -#define NUM_TESTS 4 - -#define new(a) ((a*) kmalloc(sizeof(a))) - -//This is where you define the tests you want to run. They return 1 on success and 0 on failure. - -//Tests the create function -int test_hmap_1() { - hmap_handle* hmap1 = hmap_create(); - hmap_handle* hmap2 = hmap_create_fixed(3); - - if (!hmap1) { - kprintf("expected value"); - return TEST_FAIL; - } - - if (!hmap2) { - kprintf("expected value"); - return TEST_FAIL; - } - - return TEST_OK; -} - -// Test put and get functions -int test_hmap_2() { - hmap_handle* hmap; - hmap = hmap_create(); - - int* data1; - int* data2; - int* data3; - - data1 = new(int); - *data1 = 0; - hmap_put(hmap, (long) (*data1), data1); - - data2 = new(int); - *data2 = 1; - hmap_put(hmap, (long) (*data2), data2); - - data3 = new(int); - *data3 = 2; - hmap_put(hmap, (long) (*data3), data3); - - if (hmap_get(hmap, (long) (*data1)) != data1 - || hmap_get(hmap, (long) (*data2)) != data2 - || hmap_get(hmap, (long) (*data3)) != data3) { - kfree(data1); - kfree(data2); - kfree(data3); - hmap_free(hmap); - return TEST_FAIL; - } - - return TEST_OK; -} - -// Test remove function -int test_hmap_3() { - hmap_handle* hmap; - hmap = hmap_create(); - - int* data1; - int* data2; - int* data3; - - data1 = new(int); - *data1 = 0; - hmap_put(hmap, (long) (*data1), data1); - - data2 = new(int); - *data2 = 1; - hmap_put(hmap, (long) (*data2), data2); - - data3 = new(int); - *data3 = 2; - hmap_put(hmap, (long) (*data3), data3); - - int* tmp1 = hmap_remove(hmap, (long) (*data1)); - int* tmp2 = hmap_remove(hmap, (long) (*data2)); - int* tmp3 = hmap_remove(hmap, (long) (*data3)); - - if (tmp1 != data1 || tmp2 != data2 || tmp3 != data3 - || hmap_count(hmap) != 0) { - kfree(tmp1); - kfree(tmp2); - kfree(tmp3); - hmap_free(hmap); - return TEST_FAIL; - } - - kfree(tmp1); - kfree(tmp2); - kfree(tmp3); - hmap_free(hmap); - return TEST_OK; -} - -// Test count function -int test_hmap_4() { - hmap_handle* hmap; - hmap = hmap_create(); - - int* data1; - int* data2; - int* data3; - int* data4; - - data1 = new(int); - *data1 = 0; - hmap_put(hmap, (long) (*data1), data1); - - if (hmap_count(hmap) != 1) { - kfree(data1); - hmap_free(hmap); - return TEST_FAIL; - } - - data2 = new(int); - *data2 = 1; - hmap_put(hmap, (long) (*data2), data2); - - if (hmap_count(hmap) != 2) { - kfree(data1); - kfree(data2); - hmap_free(hmap); - return TEST_FAIL; - } - - data3 = new(int); - *data3 = 2; - hmap_put(hmap, (long) (*data3), data3); - - if (hmap_count(hmap) != 3) { - kfree(data1); - kfree(data2); - kfree(data3); - hmap_free(hmap); - return TEST_FAIL; - } - - kfree(hmap_remove(hmap, (long) (*data2))); - - if (hmap_count(hmap) != 2) { - kfree(data1); - kfree(data3); - hmap_free(hmap); - return TEST_FAIL; - } - - data4 = new(int); - *data4 = 3; - hmap_put(hmap, (long) (*data4), data4); - - if (hmap_count(hmap) != 3) { - kfree(data1); - kfree(data3); - kfree(data4); - hmap_free(hmap); - return TEST_FAIL; - } - - kfree(data1); - kfree(data2); - kfree(data3); - kfree(data4); - hmap_free(hmap); - return TEST_OK; -} - -//function running tests -void run_hmap_tests() { - Test *tests[NUM_TESTS]; - tests[0] = create_test("test_hmap_1", &test_hmap_1); - tests[1] = create_test("test_hmap_2", &test_hmap_2); - tests[2] = create_test("test_hmap_3", &test_hmap_3); - tests[3] = create_test("test_hmap_4", &test_hmap_4); - - run_tests(tests, NUM_TESTS); -} - diff --git a/kernel/old/tests/test_klibc.h b/kernel/old/tests/test_klibc.h deleted file mode 100644 index ac6eb649..00000000 --- a/kernel/old/tests/test_klibc.h +++ /dev/null @@ -1,52 +0,0 @@ -#include "tests.h" -#include "klibc.h" - -#define NUM_TESTS 3 - -int test_os_memcmp_1() { - char buffer1[] = "DWgaOtP12df0"; - char buffer2[] = "DWGAOTP12DF0"; - - int i = os_memcmp(buffer1, buffer2, sizeof(buffer1)); - - if (i > 0) { - return TEST_OK; - } else { - return TEST_FAIL; - } -} - -int test_os_memcmp_2() { - char buffer1[] = "DWgaOtP12df0"; - char buffer2[] = "DWgaOtP12df0"; - - int i = os_memcmp(buffer1, buffer2, sizeof(buffer1)); - - if (i == 0) { - return TEST_OK; - } else { - return TEST_FAIL; - } -} - -int test_os_memcmp_3() { - char buffer1[] = "DWGAOTP12DF0"; - char buffer2[] = "DWgaOtP12df0"; - - int i = os_memcmp(buffer1, buffer2, sizeof(buffer1)); - - if (i < 0) { - return TEST_OK; - } else { - return TEST_FAIL; - } -} - -void run_klibc_tests() { - Test *tests[NUM_TESTS]; - tests[0] = create_test("test_os_memcmp_1", &test_os_memcmp_1); - tests[1] = create_test("test_os_memcmp_2", &test_os_memcmp_2); - tests[2] = create_test("test_os_memcmp_3", &test_os_memcmp_3); - - run_tests(tests, NUM_TESTS); -} diff --git a/kernel/old/tests/test_mem_alloc.c b/kernel/old/tests/test_mem_alloc.c deleted file mode 100644 index 62b11ecb..00000000 --- a/kernel/old/tests/test_mem_alloc.c +++ /dev/null @@ -1,99 +0,0 @@ -#include "tests.h" -#include "tests/test_mem_alloc.h" -#include "klibc.h" -#include "vm.h" - -#define NUM_TESTS 1 - -/* -objects += .o files of testthen make blah blah blah of build targetof upper make file, will make kernel with tests -*/ - -int vm_count_free_frames(); - -//nbits is 0-22 -uint32_t gen_rand(uint64_t *state, int nbits) { - *state = *state * 41 + (*state >> 5); - uint32_t mask = ((1 << nbits) - 1) << 10; - uint32_t v = (*state & mask); - return v >> 10; -} - -//Tests the create function -int test_mem_alloc_1() { - if (kmcheck()) { - ERROR("Inconsistent memory to begin with...\n"); - return TEST_FAIL; - } - - // Allocate some memory - char *p = kmalloc(15); - p = kmalloc(15); - os_strcpy(p, "Hello!"); - - DEBUG("%s\n", p); - - if (kmcheck()) { - ERROR("allocate(15) failed.\n\n"); - return TEST_FAIL; - } - - // Allocate a bunch of blocks of "random" size - uint64_t rng = 1234567891; - - char *pntrs[256]; - uint32_t alloced = 0; - int i; - DEBUG("Starting out w/ %u bytes of heap\n", km_size()); - - for (i = 0; i < 256; i++) { - uint32_t size = gen_rand(&rng, 15); - pntrs[i] = kmalloc(size); - alloced += size; - DEBUG("%u %u %u %u %d\n", i, km_size(), size, alloced, - vm_count_free_frames()); - } - - // Test one of them - pntrs[230][0] = 1; - - if(pntrs[230][0] != 1){ - ERROR("%d != 1\n", pntrs[230][0]); - return TEST_FAIL; - } - - if (kmcheck()) { - ERROR("Memory is inconsistent :-(\n"); - return TEST_FAIL; - } - - // Free all the pntrs - for (i = 0; i < 256; i++) { - if (pntrs[i]) { - kfree(pntrs[i]); - } - } - - kfree(p); - - if (kmcheck()) { - ERROR("Memory is inconsistent :-(\n"); - return TEST_FAIL; - } - - DEBUG("heap_size = %d bytes\n", km_size()); - - return TEST_OK; -} - -//function running tests -void run_mem_alloc_tests() { - Test *tests[NUM_TESTS]; - Test a; // We can't rely on kmalloc for a kmalloc test. - a.test_name = "test_mem_alloc_1"; - a.testptr = &test_mem_alloc_1; - tests[0] = &a; - //tests[0] = create_test("test_mem_alloc_1", &test_mem_alloc_1); - os_printf("asdf\n"); - run_tests(tests, NUM_TESTS); -} diff --git a/kernel/old/tests/test_priority_queue.c b/kernel/old/tests/test_priority_queue.c deleted file mode 100644 index 2dad0562..00000000 --- a/kernel/old/tests/test_priority_queue.c +++ /dev/null @@ -1,309 +0,0 @@ -#include "tests.h" -#include "tests/test_priority_queue.h" -#include "data_structures/priority_queue.h" -#include "klibc.h" - -#define NUM_TESTS 6 -#define DEFAULT_COUNT 10 -#define MIN_PRIORITY 20 -#define MAX_PRIORITY -20 - -#define new(a) ((a*) kmalloc(sizeof(a))) -#define del(a) {if(a) kfree(a); a = 0;} -#define ret(q, e) {prq_free(q); return e;} - -//This is where you define the tests you want to run. They return 1 on success and 0 on failure. - -//Tests the create function -int test_prq_1() { - prq_handle * queue; - queue = prq_create(); - if (!queue) { - ERROR("expected value"); - ret(queue, TEST_FAIL); - } - - ret(queue, TEST_OK); - -} - -//Tests the enqueue and dequeue functions -int test_prq_2() { - - prq_handle * queue; - prq_node * hn; - int i; - - queue = prq_create(); - - // Add reverse - for (i = MIN_PRIORITY; i >= MAX_PRIORITY; i--) { - hn = new(prq_node); - hn->priority = i; - prq_enqueue(queue, hn); - } - - // Add forward - for (i = MAX_PRIORITY; i <= MIN_PRIORITY; i++) { - hn = new(prq_node); - hn->priority = i; - prq_enqueue(queue, hn); - } - - for (i = MAX_PRIORITY; i <= MIN_PRIORITY; i++) { - - hn = prq_dequeue(queue); - int priority_1 = hn->priority; - del(hn); - - hn = prq_dequeue(queue); - int priority_2 = hn->priority; - del(hn); - - if (priority_1 != priority_2) { - ERROR("[%d]: expected [%d]\n", priority_1, priority_2); - ret(queue, TEST_FAIL); - } - if (priority_1 != i) { - ERROR("[%d]: expected [%d]\n", priority_1, i); - ret(queue, TEST_FAIL); - } - if (priority_2 != i) { - ERROR("[%d]: expected [%d]\n", priority_2, i); - ret(queue, TEST_FAIL); - } - } - - ret(queue, TEST_OK); -} - -//Tests the enqueue and dequeue functions -int test_prq_3() { - prq_handle * queue; - prq_node * hn; - int p; - - queue = prq_create(); - - hn = new(prq_node); - hn->priority = 0; - prq_enqueue(queue, hn); - - hn = new(prq_node); - hn->priority = -2; - prq_enqueue(queue, hn); - - hn = new(prq_node); - hn->priority = 1; - prq_enqueue(queue, hn); - - hn = new(prq_node); - hn->priority = -10; - prq_enqueue(queue, hn); - - hn = new(prq_node); - hn->priority = 30; - prq_enqueue(queue, hn); - - hn = prq_dequeue(queue); - p = hn->priority; - del(hn); - - if (p != -10) { - ERROR("[%d]: expected [%d]\n", p, -10); - ret(queue, TEST_FAIL); - } - - hn = prq_dequeue(queue); - p = hn->priority; - del(hn); - - if (p != -2) { - ERROR("[%d]: expected [%d]\n", p, -2); - ret(queue, TEST_FAIL); - } - - hn = new(prq_node); - hn->priority = 2; - prq_enqueue(queue, hn); - - hn = prq_dequeue(queue); - p = hn->priority; - del(hn); - - if (p != 0) { - ERROR("[%d]: expected [%d]\n", p, 0); - ret(queue, TEST_FAIL); - } - - prq_dequeue(queue); - - hn = prq_dequeue(queue); - p = hn->priority; - del(hn); - - if (p != 2) { - ERROR("[%d]: expected [%d]\n", p, 2); - ret(queue, TEST_FAIL); - } - - hn = prq_dequeue(queue); - p = hn->priority; - del(hn); - - if (p != 30) { - ERROR("[%d]: expected [%d]\n", p, 30); - ret(queue, TEST_FAIL); - } - - ret(queue, TEST_OK); - -} - -//testing peek function -int test_prq_4() { - prq_handle * queue; - prq_node * hn; - queue = prq_create(); - - if (prq_peek(queue) && queue->count < 1) { - ERROR("expected [%d]\n", 0); - ret(queue, TEST_FAIL); - } - - hn = new(prq_node); - hn->priority = 0; - prq_enqueue(queue, hn); - - hn = new(prq_node); - hn->priority = 1; - prq_enqueue(queue, hn); - - hn = new(prq_node); - hn->priority = 3; - prq_enqueue(queue, hn); - - hn = prq_dequeue(queue); - del(hn); - - hn = prq_dequeue(queue); - del(hn); - - hn = prq_dequeue(queue); - del(hn); - - if (prq_peek(queue) && queue->count < 1) { - ERROR("expected [%d]\n", 0); - ret(queue, TEST_FAIL); - } - - ret(queue, TEST_OK); - -} - -//testing functionality of prq_create vs prq_fixed_create -int test_prq_5() { - prq_handle * queue1; - prq_node * hn1; - queue1 = prq_create(); - - hn1 = new(prq_node); - hn1->priority = 0; - prq_enqueue(queue1, hn1); - - prq_handle * queue2; - prq_node * hn2; - queue2 = prq_create_fixed(DEFAULT_COUNT); - - hn2 = new(prq_node); - hn2->priority = 0; - prq_enqueue(queue2, hn2); - - if (queue1->heap_size != queue2->heap_size) { - ERROR("expected equal heap_size"); - ret(queue1, TEST_FAIL); - } - - ret(queue1, TEST_OK); -} - -// Test remove function -int test_prq_6() { - prq_handle * queue1; - prq_handle * queue2; - prq_node * hn1; - prq_node * hn2; - prq_node * hn3; - prq_node * hn4; - prq_node * tmp1; - prq_node * tmp2; - - queue1 = prq_create(); - queue2 = prq_create(); - - hn1 = new(prq_node); - hn1->priority = 1; - - hn2 = new(prq_node); - hn2->priority = 2; - - hn3 = new(prq_node); - hn3->priority = 3; - - hn4 = new(prq_node); - hn4->priority = 4; - - prq_enqueue(queue1, hn1); - prq_enqueue(queue1, hn2); - prq_enqueue(queue1, hn3); - prq_enqueue(queue1, hn4); - prq_remove(queue1, hn1); - prq_remove(queue1, hn3); - // Double remove - prq_remove(queue1, hn3); - - prq_enqueue(queue2, hn2); - prq_enqueue(queue2, hn4); - - - if (queue1->count != queue2->count) { - ERROR("expected equal heap_size"); - for(int i = 0; i < queue1->count; ++i) { - prq_node * tmp = prq_dequeue(queue1); - del(tmp); - } - del(queue2); - ret(queue1, TEST_FAIL); - } - - for (int size = 0; size < queue1->count; ++size) { - tmp1 = prq_dequeue(queue1); - tmp2 = prq_dequeue(queue2); - if (tmp1->priority != tmp2->priority) { - del(tmp1); - for(int i = 0; i < queue1->count; ++i) { - prq_node * tmp = prq_dequeue(queue1); - del(tmp); - } - del(queue2); - ret(queue1, TEST_FAIL); - } - del(tmp1); - } - del(queue2); - ret(queue1, TEST_OK); -} - -//function running tests -void run_prq_tests() { - Test *tests[NUM_TESTS]; - tests[0] = create_test("test_prq_1", &test_prq_1); - tests[1] = create_test("test_prq_2", &test_prq_2); - tests[2] = create_test("test_prq_3", &test_prq_3); - tests[3] = create_test("test_prq_4", &test_prq_4); - tests[4] = create_test("test_prq_5", &test_prq_5); - tests[5] = create_test("test_prq_6", &test_prq_6); - - run_tests(tests, NUM_TESTS); -} - diff --git a/kernel/old/tests/testingsuite_example/arrayfill/a.out b/kernel/old/tests/testingsuite_example/arrayfill/a.out deleted file mode 100755 index 1be2cdbf4290cff0a75033ba96aed6a12a053628..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8624 zcmeHN(Q6z<7@tk9ZD`ZvA}W;{*p?>N3W-X=NUdBXi&v}~(-ft&o!(tGy_3C5*xNuN z6$(*l2!Z3>9U^z+|A!X#xM;yh{j(4>OHv`v~+D|(r8F4vjOIeTR ziuKK@cD%9P7_VDL7~3RtX}q0!BF2+tKbZAH%(dfklr8Hk)uXUdyQl-& z@gj|v(SF)VNnyhwrC*lQVWH~BQSEs18t;k*p^azbvBG^FQTsYJIyssM!~UiA)$DI# zUx{n5rK||#!i?s;kNMxoAR9o;JT7n2XSs+ zW`HY17rHL=`_LP4UF8xv^gPGpi2mEKiFM%s&O7=&Q1(gT{Zo^?B>f!ck#C;;q>snW zh4S1C&(*`>pi&&3S_r0KQ}#o-jswowKfe9!_~5mkZ_Yowf4*=CbD&a)-Mf_@F*fHQ zhjG8myVrKEd7Tj`eerW}4NG@g*T(fvEz~2wI`q~M)=?=U5W>71w3X+;GI=wlLZDWD zu~Zs9IyAyDhO$2NiUt`(G}n8@jro63+YQ*1m!S01CjV9}1C{~HfMvikU>UFsSO%Vi zfz$b=KbJmTyXCF(?d+Df!KA;^L2dnhi0=07>*6h3xIj11(Rtk-OR5X{}2&BLd9x7noY>{OTS*no2gjc zi$?i>zR?`G38Oji6WWt2{okV-J=Gle8hxXTMm)HWtCso3`rvnr2Buu`H0L4CClkV% z&pO%eU0wX`a1?XTLwgWMd4oZe44k4T`$b2Fuj6}nW?n;wB(xOf@h8MnaavQq-fok3 z4pFT<7%91+fB$`~`;^lfmI2FvWxz6E8L$jk1}p=X0n318z%pPNunhb!8R$Eho#4Xz zaxBiNVz?|;YEvj)e-Mg>2(x`TIg0{xG)-$Ct+}XFF3?GFBx>`WvRan@ykDA&eAK=R zOdl+Sp*T`4RBGaNRgvqMt^@%-RJ_?KuJ)s-c#q9ju0p{~{H5d3-EMxH8H1`M^!yyc zj~@a)c88&~P04ppqO?c9DpxYO*HM*375pr1d@M0_TGk(XfnxqIz`7%C))fiPx+8iH smAr~JX&-B|QEXKIQP8!}oUvV0innqj$qgGtiBu#RmN)s`vLRf^zx+QefB*mh diff --git a/kernel/old/tests/testingsuite_example/arrayfill/arrayfill.c b/kernel/old/tests/testingsuite_example/arrayfill/arrayfill.c deleted file mode 100644 index b811254b..00000000 --- a/kernel/old/tests/testingsuite_example/arrayfill/arrayfill.c +++ /dev/null @@ -1,21 +0,0 @@ -#include "arrayfill.h" - -void arrfill(int n) { - int i; - int temp = 1; - for (i = 0; i < n; i++) { - arr[i] = temp; - temp++; - } -} - -int main () { - arrfill(5); - int i; - int size = 5; - for (i = 0; i < size; ++i) { - printf("%d ", arr[i]); - } - printf("\n"); - return 0; -} \ No newline at end of file diff --git a/kernel/old/tests/testingsuite_example/arrayfill/arrayfill.h b/kernel/old/tests/testingsuite_example/arrayfill/arrayfill.h deleted file mode 100644 index 9f0833f3..00000000 --- a/kernel/old/tests/testingsuite_example/arrayfill/arrayfill.h +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include -#define SIZEARRAY(x) (sizeof(x) / sizeof ((x[0])) - -int arr[100]; - -void arrfill(int); - -void print(); \ No newline at end of file diff --git a/kernel/old/tests/testingsuite_example/arrayfill/tap.c b/kernel/old/tests/testingsuite_example/arrayfill/tap.c deleted file mode 100755 index a7303d4a..00000000 --- a/kernel/old/tests/testingsuite_example/arrayfill/tap.c +++ /dev/null @@ -1,369 +0,0 @@ -/* -libtap - Write tests in C -Copyright 2012 Jake Gelbman -This file is licensed under the GPLv2 or any later version -*/ - -#define _DEFAULT_SOURCE 1 - -#include -#include -#include "../../../../src/klibc//include/stdarg.h" -#include -#include "tap.h" - -static int expected_tests = NO_PLAN; -static int failed_tests; -static int current_test; -static char *todo_mesg; - -static char * -vstrdupf (const char *fmt, va_list args) { - char *str; - int size; - va_list args2; - va_copy(args2, args); - if (!fmt) - fmt = ""; - size = vsnprintf(NULL, 0, fmt, args2) + 2; - str = malloc(size); - if (!str) { - perror("malloc error"); - exit(1); - } - vsprintf(str, fmt, args); - va_end(args2); - return str; -} - -void -tap_plan (int tests, const char *fmt, ...) { - expected_tests = tests; - if (tests == SKIP_ALL) { - char *why; - va_list args; - va_start(args, fmt); - why = vstrdupf(fmt, args); - va_end(args); - printf("1..0 "); - note("SKIP %s\n", why); - exit(0); - } - if (tests != NO_PLAN) { - printf("1..%d\n", tests); - } -} - -int -vok_at_loc (const char *file, int line, int test, const char *fmt, - va_list args) -{ - char *name = vstrdupf(fmt, args); - if (!test) - printf("not "); - printf("ok %d", ++current_test); - if (*name) - printf(" - %s", name); - if (todo_mesg) { - printf(" # TODO"); - if (*todo_mesg) - printf(" %s", todo_mesg); - } - printf("\n"); - if (!test) { - fprintf(stderr, "# Failed "); - if (todo_mesg) - fprintf(stderr, "(TODO) "); - fprintf(stderr, "test "); - if (*name) - fprintf(stderr, "'%s'\n# ", name); - fprintf(stderr, "at %s line %d.\n", file, line); - if (!todo_mesg) - failed_tests++; - } - free(name); - return test; -} - -int -ok_at_loc (const char *file, int line, int test, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - vok_at_loc(file, line, test, fmt, args); - va_end(args); - return test; -} - -static int -mystrcmp (const char *a, const char *b) { - return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b); -} - -#define eq(a, b) (!mystrcmp(a, b)) -#define ne(a, b) (mystrcmp(a, b)) - -int -is_at_loc (const char *file, int line, const char *got, const char *expected, - const char *fmt, ...) -{ - int test = eq(got, expected); - va_list args; - va_start(args, fmt); - vok_at_loc(file, line, test, fmt, args); - va_end(args); - if (!test) { - diag(" got: '%s'", got); - diag(" expected: '%s'", expected); - } - return test; -} - -int -isnt_at_loc (const char *file, int line, const char *got, const char *expected, - const char *fmt, ...) -{ - int test = ne(got, expected); - va_list args; - va_start(args, fmt); - vok_at_loc(file, line, test, fmt, args); - va_end(args); - if (!test) { - diag(" got: '%s'", got); - diag(" expected: anything else"); - } - return test; -} - -int -cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b, - const char *fmt, ...) -{ - int test = eq(op, "||") ? a || b - : eq(op, "&&") ? a && b - : eq(op, "|") ? a | b - : eq(op, "^") ? a ^ b - : eq(op, "&") ? a & b - : eq(op, "==") ? a == b - : eq(op, "!=") ? a != b - : eq(op, "<") ? a < b - : eq(op, ">") ? a > b - : eq(op, "<=") ? a <= b - : eq(op, ">=") ? a >= b - : eq(op, "<<") ? a << b - : eq(op, ">>") ? a >> b - : eq(op, "+") ? a + b - : eq(op, "-") ? a - b - : eq(op, "*") ? a * b - : eq(op, "/") ? a / b - : eq(op, "%") ? a % b - : diag("unrecognized operator '%s'", op); - va_list args; - va_start(args, fmt); - vok_at_loc(file, line, test, fmt, args); - va_end(args); - if (!test) { - diag(" %d", a); - diag(" %s", op); - diag(" %d", b); - } - return test; -} - -static int -find_mem_diff (const char *a, const char *b, size_t n, size_t *offset) { - size_t i; - if (a == b) - return 0; - if (!a || !b) - return 2; - for (i = 0; i < n; i++) { - if (a[i] != b[i]) { - *offset = i; - return 1; - } - } - return 0; -} - -int -cmp_mem_at_loc (const char *file, int line, const void *got, - const void *expected, size_t n, const char *fmt, ...) -{ - size_t offset; - int diff = find_mem_diff(got, expected, n, &offset); - va_list args; - va_start(args, fmt); - vok_at_loc(file, line, !diff, fmt, args); - va_end(args); - if (diff == 1) { - diag(" Difference starts at offset %d", offset); - diag(" got: 0x%02x", ((unsigned char *)got)[offset]); - diag(" expected: 0x%02x", ((unsigned char *)expected)[offset]); - } - else if (diff == 2) { - diag(" got: %s", got ? "not NULL" : "NULL"); - diag(" expected: %s", expected ? "not NULL" : "NULL"); - } - return !diff; -} - -static void -vdiag_to_fh (FILE *fh, const char *fmt, va_list args) { - char *mesg, *line; - int i; - if (!fmt) - return; - mesg = vstrdupf(fmt, args); - line = mesg; - for (i = 0; *line; i++) { - char c = mesg[i]; - if (!c || c == '\n') { - mesg[i] = '\0'; - fprintf(fh, "# %s\n", line); - if (!c) - break; - mesg[i] = c; - line = mesg + i + 1; - } - } - free(mesg); - return; -} - -int -diag (const char *fmt, ...) { - va_list args; - va_start(args, fmt); - vdiag_to_fh(stderr, fmt, args); - va_end(args); - return 0; -} - -int -note (const char *fmt, ...) { - va_list args; - va_start(args, fmt); - vdiag_to_fh(stdout, fmt, args); - va_end(args); - return 0; -} - -int -exit_status () { - int retval = 0; - if (expected_tests == NO_PLAN) { - printf("1..%d\n", current_test); - } - else if (current_test != expected_tests) { - diag("Looks like you planned %d test%s but ran %d.", - expected_tests, expected_tests > 1 ? "s" : "", current_test); - retval = 2; - } - if (failed_tests) { - diag("Looks like you failed %d test%s of %d run.", - failed_tests, failed_tests > 1 ? "s" : "", current_test); - retval = 1; - } - return retval; -} - -int -bail_out (int ignore, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - printf("Bail out! "); - vprintf(fmt, args); - printf("\n"); - va_end(args); - exit(255); - return 0; -} - -void -tap_skip (int n, const char *fmt, ...) { - char *why; - va_list args; - va_start(args, fmt); - why = vstrdupf(fmt, args); - va_end(args); - while (n --> 0) { - printf("ok %d ", ++current_test); - note("skip %s\n", why); - } - free(why); -} - -void -tap_todo (int ignore, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - todo_mesg = vstrdupf(fmt, args); - va_end(args); -} - -void -tap_end_todo () { - free(todo_mesg); - todo_mesg = NULL; -} - -#ifndef _WIN32 -#include -#include -#include - -#if defined __APPLE__ || defined BSD -#define MAP_ANONYMOUS MAP_ANON -#endif - -/* Create a shared memory int to keep track of whether a piece of code executed -dies. to be used in the dies_ok and lives_ok macros. */ -int -tap_test_died (int status) { - static int *test_died = NULL; - int prev; - if (!test_died) { - test_died = mmap(0, sizeof (int), PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANONYMOUS, -1, 0); - *test_died = 0; - } - prev = *test_died; - *test_died = status; - return prev; -} - -int -like_at_loc (int for_match, const char *file, int line, const char *got, - const char *expected, const char *fmt, ...) -{ - int test; - regex_t re; - va_list args; - int err = regcomp(&re, expected, REG_EXTENDED); - if (err) { - char errbuf[256]; - regerror(err, &re, errbuf, sizeof errbuf); - fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n", - expected, errbuf, file, line); - exit(255); - } - err = regexec(&re, got, 0, NULL, 0); - regfree(&re); - test = for_match ? !err : err; - va_start(args, fmt); - vok_at_loc(file, line, test, fmt, args); - va_end(args); - if (!test) { - if (for_match) { - diag(" '%s'", got); - diag(" doesn't match: '%s'", expected); - } - else { - diag(" '%s'", got); - diag(" matches: '%s'", expected); - } - } - return test; -} -#endif - diff --git a/kernel/old/tests/testingsuite_example/arrayfill/tap.h b/kernel/old/tests/testingsuite_example/arrayfill/tap.h deleted file mode 100755 index 90e4e6f9..00000000 --- a/kernel/old/tests/testingsuite_example/arrayfill/tap.h +++ /dev/null @@ -1,117 +0,0 @@ -/* -libtap - Write tests in C -Copyright 2012 Jake Gelbman -This file is licensed under the GPLv2 or any later version -*/ - -#ifndef __TAP_H__ -#define __TAP_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef va_copy -#ifdef __va_copy -#define va_copy __va_copy -#else -#define va_copy(d, s) ((d) = (s)) -#endif -#endif - -#include -#include -#include "../../../../src/klibc//include/stdarg.h" - -int vok_at_loc (const char *file, int line, int test, const char *fmt, - va_list args); -int ok_at_loc (const char *file, int line, int test, const char *fmt, - ...); -int is_at_loc (const char *file, int line, const char *got, - const char *expected, const char *fmt, ...); -int isnt_at_loc (const char *file, int line, const char *got, - const char *expected, const char *fmt, ...); -int cmp_ok_at_loc (const char *file, int line, int a, const char *op, - int b, const char *fmt, ...); -int cmp_mem_at_loc (const char *file, int line, const void *got, - const void *expected, size_t n, const char *fmt, ...); -int bail_out (int ignore, const char *fmt, ...); -void tap_plan (int tests, const char *fmt, ...); -int diag (const char *fmt, ...); -int note (const char *fmt, ...); -int exit_status (void); -void tap_skip (int n, const char *fmt, ...); -void tap_todo (int ignore, const char *fmt, ...); -void tap_end_todo (void); - -#define NO_PLAN -1 -#define SKIP_ALL -2 -#define ok(...) ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) -#define is(...) is_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) -#define isnt(...) isnt_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) -#define cmp_ok(...) cmp_ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) -#define cmp_mem(...) cmp_mem_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL); -#define plan(...) tap_plan(__VA_ARGS__, NULL) -#define done_testing() return exit_status() -#define BAIL_OUT(...) bail_out(0, "" __VA_ARGS__, NULL) -#define pass(...) ok(1, "" __VA_ARGS__) -#define fail(...) ok(0, "" __VA_ARGS__) - -#define skip(test, ...) do {if (test) {tap_skip(__VA_ARGS__, NULL); break;} -#define end_skip } while (0) - -#define todo(...) tap_todo(0, "" __VA_ARGS__, NULL) -#define end_todo tap_end_todo() - -#define dies_ok(...) dies_ok_common(1, __VA_ARGS__) -#define lives_ok(...) dies_ok_common(0, __VA_ARGS__) - -#ifdef _WIN32 -#define like(...) tap_skip(1, "like is not implemented on Windows") -#define unlike tap_skip(1, "unlike is not implemented on Windows") -#define dies_ok_common(...) \ - tap_skip(1, "Death detection is not supported on Windows") -#else -#define like(...) like_at_loc(1, __FILE__, __LINE__, __VA_ARGS__, NULL) -#define unlike(...) like_at_loc(0, __FILE__, __LINE__, __VA_ARGS__, NULL) -int like_at_loc (int for_match, const char *file, int line, - const char *got, const char *expected, - const char *fmt, ...); -#include -#include -#include -int tap_test_died (int status); -#define dies_ok_common(for_death, code, ...) \ - do { \ - int cpid; \ - int it_died; \ - tap_test_died(1); \ - cpid = fork(); \ - switch (cpid) { \ - case -1: \ - perror("fork error"); \ - exit(1); \ - case 0: \ - close(1); \ - close(2); \ - code \ - tap_test_died(0); \ - exit(0); \ - } \ - if (waitpid(cpid, NULL, 0) < 0) { \ - perror("waitpid error"); \ - exit(1); \ - } \ - it_died = tap_test_died(0); \ - if (!it_died) \ - {code} \ - ok(for_death ? it_died : !it_died, "" __VA_ARGS__); \ - } while (0) -#endif - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/kernel/old/tests/testingsuite_example/arrayfill/testarrayfill.c b/kernel/old/tests/testingsuite_example/arrayfill/testarrayfill.c deleted file mode 100644 index 1c2a6fd8..00000000 --- a/kernel/old/tests/testingsuite_example/arrayfill/testarrayfill.c +++ /dev/null @@ -1,28 +0,0 @@ -// #include -// #include "arrayfill.h" - -// int first_element() { -// if (arr[0] == 1) { -// return 1; -// } -// else { -// return 0; -// } -// } - -// int common() { -// plan(1); -// ok(first_element(), "checks the first element"); -// done_testing(); -// } - -#include "tap.h" -int main() { - plan(1); - ok(3 == 3); - done_testing(); -} - - - - diff --git a/kernel/src/common/argparse.c b/kernel/src/common/argparse.c deleted file mode 100644 index 7dd350f4..00000000 --- a/kernel/src/common/argparse.c +++ /dev/null @@ -1,170 +0,0 @@ -#include -#include -#include -#include -#include -#include - -static void argparse_parse(char *); - -/* Get the command-line arguments and run the functions to process them. */ -void argparse_process(uint32_t *p_bootargs) -{ - for (atag_iterator(tag, p_bootargs)) - { - kprintf("tag (+%d) %d\n", - (((uint32_t) ((uint32_t *) tag)) - ((uint32_t) p_bootargs)), - tag->header.tag); - atag_print(tag); - if (tag->header.tag == ATAG_CMDLINE) - { - argparse_parse((char*) &tag->content.cmdline.cmdline); - } - } -} - -void atag_print(struct atag *t) -{ - switch (t->header.tag) - { - case ATAG_CORE: - if (t->header.size == 2) - { - kprintf("ATAG_CORE\n"); - } - else - { - kprintf("ATAG_CORE (FLAGS=%d, PAGESIZE=%d, ROOTDEV=%d)\n", - t->content.core.flags, t->content.core.pagesize, - t->content.core.rootdev); - } - break; - case ATAG_MEM: - kprintf("ATAG_MEM (SIZE=%d, START=%d)\n", t->content.mem.size, - t->content.mem.start); - break; - case ATAG_CMDLINE: - kprintf("ATAG_CMDLINE (%s)\n", &t->content.cmdline.cmdline); - break; - } -} - -/* - Pulls name, start location, and size of file from command line - Opens file for process, then moves the process from - file to a location in memory. - Creates a process using the start location of process, - enables the VAS for the process, sets up the stack and heap, - then executes it. - @param Character pointer to command line - @param char* cmdline - - */ - -static void argparse_parse(char *cmdline) -{ - - char* token = os_strtok(cmdline, " "); - - while (token != NULL) - { - kprintf("token: %s\n", token); - - if (strcmp("-load", token) == 0) - { - char* name = os_strtok(NULL, " "); - - pcb* proc = process_create(name); - assert(proc != NULL); - process_execute(proc); - - } - else if (strcmp("-test", token) == 0) - { - kprintf("RUNNING TESTS\n"); - kprintf("Running tests...\n"); -// Test *tests[2]; -// tests[0] = create_test("This passes", &test1); -// tests[1] = create_test("This fails", &test2); -// run_tests(tests, 2); - } - - token = os_strtok(NULL, " "); - } -} - -/* We return a signed integer because we need a way to detect errors. - - Read a string of characters and interpret them as an unsigned integer. - Return -1 if the string cannot be read as an unsigned integer. - Return an integer representing the value of the string otherwise. - */ -int string_to_unsigned_int(char *input, int base) -{ - int i = strlen(input) - 1; // Index in the string - - if (hex_value_of_character(input[i]) == -1) - { - // Return -1 if the string cannot be read as an unsigned integer - return -1; - } - - int n = 0; // Number of digits - int result = 0; - - // Starting from the end of the string, read each character - while (i >= 0) - { - // Get the value of one character - int digit = hex_value_of_character(input[i]); - - if (digit == -1) - { - // If we hit a non-digit character such as 'x', return - return result; - } - - // Add the digit's value to the integer - result = result | (digit << (n * 4)); - - i--; - n++; - } - return result; -} - -/* Return the hexidecimal value of the single character c */ -int hex_value_of_character(char c) -{ - if (c >= '0' && c <= '9') - { - return (int) (c - '0'); - } - else if (c >= 'A' && c <= 'F') - { - return (int) (c - 'A' + 10); - } - else if (c >= 'a' && c <= 'f') - { - return (int) (c - 'a' + 10); - } - - // Return -1 if c was not a hex digit - return -1; -} - -uint32_t round_up(uint32_t c) -{ - - c--; - c |= c >> 1; - - c |= c >> 2; - c |= c >> 4; - c |= c >> 8; - - c |= c >> 16; - c++; - return c; - -} diff --git a/kernel/src/common/hardwareinfo.c b/kernel/src/common/hardwareinfo.c index 2587f170..dc1f7cb6 100644 --- a/kernel/src/common/hardwareinfo.c +++ b/kernel/src/common/hardwareinfo.c @@ -1,5 +1,6 @@ #include #include +#include static HardwareInfo hardware_info; @@ -7,9 +8,10 @@ BoardType detect_boardtype() { uint32_t reg; // read system register - asm volatile ("mrc p15,0,r0,c0,c0,0" : "=r" (reg)); + asm ("mrc p15,0,%0,c0,c0,0" : "=r" (reg)); + + uint32_t type = (reg >> 4u) & 0xFFFu; - uint32_t type = (reg >> 4) & 0xFFF; switch (type) { case 0xB76: return RaspberryPiZero; // bcm2835 @@ -24,7 +26,7 @@ BoardType detect_boardtype() { void init_hardwareinfo() { hardware_info = (HardwareInfo){ .cpuType = ARM1176, - .boardType = RaspBerryPiTwo, + .boardType = detect_boardtype(), }; } diff --git a/kernel/src/common/include/hardwareinfo.h b/kernel/src/common/include/hardwareinfo.h index 2e11ea29..58d4234e 100644 --- a/kernel/src/common/include/hardwareinfo.h +++ b/kernel/src/common/include/hardwareinfo.h @@ -24,5 +24,6 @@ void init_hardwareinfo(); // Get a pointer to the hardwareinfo struct. HardwareInfo * get_hardwareinfo(); void print_hardwareinfo(); +BoardType detect_boardtype(); #endif diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index 6c6595c0..f1596936 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include /* copy vector table from wherever QEMU loads the kernel to 0x00 */ @@ -20,24 +20,24 @@ void init_vector_table() { */ /* Primary Vector Table */ - mmio_write(0x0, BRANCH_INSTRUCTION); - mmio_write(0x04, BRANCH_INSTRUCTION); - mmio_write(0x08, BRANCH_INSTRUCTION); - mmio_write(0x0C, BRANCH_INSTRUCTION); - mmio_write(0x10, BRANCH_INSTRUCTION); - mmio_write(0x14, BRANCH_INSTRUCTION); - mmio_write(0x18, BRANCH_INSTRUCTION); - mmio_write(0x1C, BRANCH_INSTRUCTION); + mmio_write(KERNEL_VIRTUAL_OFFSET + 0x0, BRANCH_INSTRUCTION); + mmio_write(KERNEL_VIRTUAL_OFFSET + 0x04, BRANCH_INSTRUCTION); + mmio_write(KERNEL_VIRTUAL_OFFSET + 0x08, BRANCH_INSTRUCTION); + mmio_write(KERNEL_VIRTUAL_OFFSET + 0x0C, BRANCH_INSTRUCTION); + mmio_write(KERNEL_VIRTUAL_OFFSET + 0x10, BRANCH_INSTRUCTION); + mmio_write(KERNEL_VIRTUAL_OFFSET + 0x14, BRANCH_INSTRUCTION); + mmio_write(KERNEL_VIRTUAL_OFFSET + 0x18, BRANCH_INSTRUCTION); + mmio_write(KERNEL_VIRTUAL_OFFSET + 0x1C, BRANCH_INSTRUCTION); /* Secondary Vector Table */ - mmio_write(0x20, &reset_handler); - mmio_write(0x24, &undef_instruction_handler); - mmio_write(0x28, &software_interrupt_handler); - mmio_write(0x2C, &prefetch_abort_handler); - mmio_write(0x30, &data_abort_handler); - mmio_write(0x34, &reserved_handler); - mmio_write(0x38, &irq_handler); - mmio_write(0x3C, &fiq_handler); + mmio_write(KERNEL_VIRTUAL_OFFSET + 0x20, &reset_handler); + mmio_write(KERNEL_VIRTUAL_OFFSET + 0x24, &undef_instruction_handler); + mmio_write(KERNEL_VIRTUAL_OFFSET + 0x28, &software_interrupt_handler); + mmio_write(KERNEL_VIRTUAL_OFFSET + 0x2C, &prefetch_abort_handler); + mmio_write(KERNEL_VIRTUAL_OFFSET + 0x30, &data_abort_handler); + mmio_write(KERNEL_VIRTUAL_OFFSET + 0x34, &reserved_handler); + mmio_write(KERNEL_VIRTUAL_OFFSET + 0x38, &irq_handler); + mmio_write(KERNEL_VIRTUAL_OFFSET + 0x3C, &fiq_handler); } @@ -177,30 +177,10 @@ long __attribute__((interrupt("SWI"))) software_interrupt_handler(void) kprintf("Yet to be implemented\n"); return -1; - case SYSCALL_MALLOC: - kprintf("malloc system call called!\n"); - - void *ptr = umalloc(r0); - - kprintf("malloc is about to return %x\n", ptr); - - return (long) ptr; - case SYSCALL_ALIGNED_ALLOC: - kprintf("aligned_alloc system call called!\n"); - void *ptr2 = ualigned_alloc(r0, r1); - - kprintf("ualigned_alloc is about to return %x\n", ptr2); - - return (long) ptr2; - case SYSCALL_FREE: - kprintf("Free system call called!\n"); - - ufree((void*) r0); - return 0L; case SYSCALL_PRINTF: kprintf("Printf system call called!\n"); - kprintf((const char *) r0); + kprintf((const char *) r0); return 0L; default: kprintf("That wasn't a syscall you knob!\n"); @@ -219,8 +199,10 @@ void __attribute__((interrupt("ABORT"))) prefetch_abort_handler(void) panic(); } -void __attribute__((interrupt("ABORT"))) data_abort_handler(void) -{ +void __attribute__((interrupt("ABORT"))) data_abort_handler(void) { + + // TODO Check if the address is valid according to the kernel and add it to the currently loaded pagetables if so. + int lr; asm volatile("mov %0, lr" : "=r" (lr)); int pc = lr - 8; @@ -228,32 +210,22 @@ void __attribute__((interrupt("ABORT"))) data_abort_handler(void) int far; asm volatile("mrc p15, 0, %0, c6, c0, 0" : "=r" (far)); - kprintf("DATA ABORT HANDLER (Page Fault)\n"); - kprintf("faulting address: 0x%x\n", far); - if (far >= V_KDSBASE) { - kprintf("(address is in kernel address range)\n"); + DEBUG("DATA ABORT HANDLER (Page Fault)"); + DEBUG("faulting address: 0x%x", far); + if (far >= KERNEL_VIRTUAL_OFFSET) { + DEBUG("(address is in kernel address range)\n"); } - kprintf("violating instruction (at 0x%x): %x\n", pc, *((int *) pc)); + DEBUG("violating instruction (at 0x%x): %x", pc, *((int *) pc)); - // Get the DSFR - int dsfr; - asm volatile("MRC p15, 0, %0, c5, c0, 0" : "=r" (dsfr)); - //os_printf("DSFR: 0x%X\n", dsfr); + // Get the Data Fault Status Register + int dfsr; + asm volatile("MRC p15, 0, %0, c5, c0, 0" : "=r" (dfsr)); + DEBUG("DFSR: 0x%x", dfsr); -#ifdef ENABLE_TESTS - panic(); -#endif - switch (dsfr) - { - case 6: // Access bit. - // Set it to 1 so we don't get notified again. - // TODO: The eviction policy will listen to this. - *((unsigned int*) (V_L1PTBASE + 2 * PAGE_TABLE_SIZE)) |= (1 << 4); - break; - default: - break; - }; + #ifdef ENABLE_TESTS + panic(); + #endif } void reserved_handler(void) @@ -298,8 +270,7 @@ void __attribute__((interrupt("FIQ"))) fiq_handler(void) { // SUBS PC, R14_fiq, #4 } -void SemihostingCall(enum SemihostingSWI mode) { - +void __attribute__((always_inline)) inline SemihostingCall(enum SemihostingSWI mode) { int a = mode; asm volatile ( "MOV r0, #0x18\n" diff --git a/kernel/src/common/stacks.s b/kernel/src/common/stacks.s new file mode 100644 index 00000000..82175576 --- /dev/null +++ b/kernel/src/common/stacks.s @@ -0,0 +1,79 @@ +// This code creates multiple areas that are used as stacks for each of the +// CPU operating modes. + +// Codes for the various execution modes +// https://heyrick.eu/armwiki/Processor_modes +.equ Mode_USR, 0x10 // User +.equ Mode_FIQ, 0x11 // Fast interrupt +.equ Mode_IRQ, 0x12 // Normal iterrupt +.equ Mode_SVC, 0x13 // Supervisor mode, this is the privileged moded for the OS (/Kernel) +.equ Mode_MON, 0x16 // Monitor, more info: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.prd29-genc-009492c/CACJBHJA.html +.equ Mode_ABT, 0x17 // Abort, for virtual memory and memory protection +.equ Mode_UND, 0x1B // Undefined, +.equ Mode_SYS, 0x1F // System, a hybrid between SVC and + +.text + +.global stacks +stacks: + // FIQ Stack + MSR CPSR_c, #Mode_FIQ // Switch to FIQ Mode + LDR sp, =FIQ_STACK_TOP // Set the FIQ stack pointer + + // IRQ Stack + MSR CPSR_c, #Mode_IRQ + LDR sp, =IRQ_STACK_TOP + + // MON Stack + MSR CPSR_c, #Mode_MON + LDR sp, =MON_STACK_TOP + + // ABT Stack + MSR CPSR_c, #Mode_ABT + LDR sp, =ABT_STACK_TOP + + // UND Stack + MSR CPSR_c, #Mode_UND + LDR sp, =UND_STACK_TOP + + // SYS Stack + MSR CPSR_c, #Mode_SYS + LDR sp, =SYS_STACK_TOP + + // Switch back SVC/Kernel + MSR CPSR_c, #Mode_SVC + ADD fp, sp, #0 // ??? + + bx lr + +.section .bss +.global KERNEL_STACK_TOP +KERNEL_STACK_START: + .space 0x10000 // 16 KiB of stack should be enough +KERNEL_STACK_TOP: + +FIQ_STACK_START: + .space 1024 // 1 KiB of stack for the FIQ handlers +FIQ_STACK_TOP: + +IRQ_STACK_START: + .space 1024 // 1 KiB of stack for the FIQ handlers +IRQ_STACK_TOP: + +ABT_STACK_START: + .space 1024 // 1 KiB of stack for abort modes +ABT_STACK_TOP: + +// TODO: We are not quite sure what this processor mode is and why it needs a stack, +// TODO: but the previous people gave it as stack as well so it seems useful... +MON_STACK_START: + .space 1024 // 1 KiB of stack for monitor modes +MON_STACK_TOP: + +UND_STACK_START: + .space 1024 // 1 KiB of stack for undefined modes +UND_STACK_TOP: + +SYS_STACK_START: + .space 1024 // 1 KiB of stack for undefined modes +SYS_STACK_TOP: diff --git a/kernel/src/common/start.c b/kernel/src/common/start.c index f51deef5..edda33d2 100644 --- a/kernel/src/common/start.c +++ b/kernel/src/common/start.c @@ -18,11 +18,7 @@ #include #include -#include -#include #include -#include -#include #include #include #include @@ -32,8 +28,6 @@ // This start is what u-boot calls. It's just a wrapper around setting up the // virtual memory for the kernel. void start(uint32_t *p_bootargs) { - prepare_pagetable(); - vm2_prepare(); // Before this point, all code has to be hardware independent. // After this point, code can request the hardware info struct to find out what @@ -43,29 +37,28 @@ void start(uint32_t *p_bootargs) { // Initialize the chipset and enable uart init_chipset(); - print_hardwareinfo(); + INFO("Started chipset specific handlers"); - kprintf("Enabling MMU...\n"); - vm_init(); - kprintf("Initialized VM datastructures.\n"); + // just cosmetic (and for debugging) + print_hardwareinfo(); + detect_boardtype(); + // start proper virtual and physical memory management. + // Even though we already enabled the mmu in startup.s to + // create a higher half kernel. The pagetable created there + // was temporary and has to be replaced here. + INFO("Initializing the physical and virtual memory managers."); vm2_start(); - // Paging and virtual memory is initialized. This code jumps us to start2. - mmap(p_bootargs); -} - -// This start is what starts the kernel. Note that virtual memory is enabled -// at this point (And running, also, in the kernel's VAS). -void start2(uint32_t *p_bootargs) { - kprintf("start address: 0x%x\n", start2); - + INFO("Setting up interrupt vector tables"); // Set up the exception handlers. init_vector_table(); + INFO("Setting up heap"); // After this point kmalloc and kfree can be used for dynamic memory management. init_heap(); + splash(); @@ -75,13 +68,6 @@ void start2(uint32_t *p_bootargs) { // Call the chipset again to do post-interrupt-enable initialization chipset.late_init(); - process_init(); - - // FIXME: temporary - sched_init(); - - kprintf("bootargs: 0x%x\n", p_bootargs); - #ifndef ENABLE_TESTS // argparse_process(p_bootargs); diff --git a/kernel/src/common/startup.s b/kernel/src/common/startup.s index c0a496af..88b2311a 100644 --- a/kernel/src/common/startup.s +++ b/kernel/src/common/startup.s @@ -1,15 +1,5 @@ -.global _Reset -// Codes for the various execution modes -// https://heyrick.eu/armwiki/Processor_modes -.equ Mode_USR, 0x10 // User -.equ Mode_FIQ, 0x11 // Fast interrupt -.equ Mode_IRQ, 0x12 // Normal iterrupt -.equ Mode_SVC, 0x13 // Supervisor mode, this is the privileged moded for the OS (/Kernel) -.equ Mode_MON, 0x16 // Monitor, more info: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.prd29-genc-009492c/CACJBHJA.html -.equ Mode_ABT, 0x17 // Abort, for virtual memory and memory protection -.equ Mode_UND, 0x1B // Undefined, -.equ Mode_SYS, 0x1F // System, a hybrid between SVC and +.global _Reset _Reset: // Disable other cores @@ -18,72 +8,66 @@ _Reset: cmp r1, #0 bne loop - LDR sp, =KERNEL_STACK_TOP // Set the kernel/SVC stack - - // FIQ Stack - MSR CPSR_c, #Mode_FIQ // Switch to FIQ Mode - LDR sp, =FIQ_STACK_TOP // Set the FIQ stack pointer - - // IRQ Stack - MSR CPSR_c, #Mode_IRQ - LDR sp, =IRQ_STACK_TOP - - // MON Stack - MSR CPSR_c, #Mode_MON - LDR sp, =MON_STACK_TOP - - // ABT Stack - MSR CPSR_c, #Mode_ABT - LDR sp, =ABT_STACK_TOP - - // UND Stack - MSR CPSR_c, #Mode_UND - LDR sp, =UND_STACK_TOP - - // SYS Stack - MSR CPSR_c, #Mode_SYS - LDR sp, =SYS_STACK_TOP + ldr sp, =EARLY_KERNEL_STACK_TOP // Set the kernel/SVC stack + push {r0-r11} + + // Identity map 0x00000000 (the kernel) + ldr r0, =0x4000 + mov r1, #0 + orr r1, #0x02 + orr r1, #0x400 + str r1, [r0] + + // Map the lowest 1Mb to 0x8000000 + ldr r0, =__KERNEL_BASE + lsr r0, #20 + lsl r0, #2 + ldr r1, =0x4000 + add r0, r1, r0 + + mov r1, #0 + orr r1, #0x02 + orr r1, #0x400 + str r1, [r0] + + mov r0, #0 + // invalidate caches + mcr p15, 0, r0, c7, c7, 0 + // invalidate tlb + mcr p15, 0, r0, c8, c7, 0 + // data sync barrier + mcr p15, 0, r0, c7,c10, 4 + + // set domains + mov r2, #0x01 + mcr p15, 0, r2, c3, c0, 0 + + ldr r0, =0x4000 + // Give the pagetable addr to the MMU + mcr p15, 0, r0, c2, c0, 0 + mcr p15, 0, r0, c2, c0, 1 + + mrc p15, 0, r3, c1, c0, 0 + orr r3, #0x800000 + orr r3, r3, #0x1 // Enable MMU bit + mcr p15, 0, r3, c1, c0, 0 // Set p15 + + pop {r0-r11} + ldr sp, =KERNEL_STACK_TOP // Set the kernel/SVC stack + push {r0-r11} + + // Setup + bl stacks + + // Jumpt to the start of the kernel + bl start - // Switch back SVC/Kernel - MSR CPSR_c, #Mode_SVC - ADD fp, sp, #0 // ??? - - MOV R0, R2 // boot args in R0 - BL start loop: WFI B loop -.section .bss -//.global KERNEL_STACK_TOP, KERNEL_STACK_BASE, FIQ_STACK_START, FIQ_STACK_TOP, IRQ_STACK_START, IRQ_STACK_TOP - -KERNEL_STACK_START: - .space 4096 // 4 KiB of stack should be enough -KERNEL_STACK_TOP: - -FIQ_STACK_START: - .space 1024 // 1 KiB of stack for the FIQ handlers -FIQ_STACK_TOP: - -IRQ_STACK_START: - .space 1024 // 1 KiB of stack for the FIQ handlers -IRQ_STACK_TOP: - -ABT_STACK_START: - .space 1024 // 1 KiB of stack for abort modes -ABT_STACK_TOP: - -// TODO: We are not quite sure what this processor mode is and why it needs a stack, -// TODO: but the previous people gave it as stack as well so it seems useful... -MON_STACK_START: - .space 1024 // 1 KiB of stack for monitor modes -MON_STACK_TOP: - -UND_STACK_START: - .space 1024 // 1 KiB of stack for undefined modes -UND_STACK_TOP: - -SYS_STACK_START: - .space 1024 // 1 KiB of stack for undefined modes -SYS_STACK_TOP: +.bss +EARLY_KERNEL_STACK_BOTTOM: + .space 128 +EARLY_KERNEL_STACK_TOP: diff --git a/kernel/src/drivers/chipset/bcm2836/bcm2836.c b/kernel/src/drivers/chipset/bcm2836/bcm2836.c index c89c8b45..93b3281b 100644 --- a/kernel/src/drivers/chipset/bcm2836/bcm2836.c +++ b/kernel/src/drivers/chipset/bcm2836/bcm2836.c @@ -6,9 +6,6 @@ #include #include -volatile struct BCM2836Registers * bcm2836_registers_base = (struct BCM2836Registers *) 0x40000000; -const size_t BCM2836_peripheral_base = 0x3F000000; - //static TimerHandle handleindex; // uart.c @@ -43,7 +40,6 @@ void bcm2836_fiq_handler() { } void bcm2836_init() { - bcm2836_uart_init(); chipset.schedule_timer_periodic = &bcm2836_schedule_timer_periodic; chipset.schedule_timer_once = &bcm2836_schedule_timer_once; chipset.deschedule_timer = &bcm2836_deschedule_timer; @@ -54,17 +50,26 @@ void bcm2836_init() { chipset.handle_fiq = &bcm2836_fiq_handler; chipset.late_init = &bcm2836_late_init; - // Mapping memory used by bcm2836 peripherals - // TEMP (vm1): - request_identity_mapped_section(BCM2836_peripheral_base, 4); + bcm2836_registers_base = (struct BCM2836Registers * ) vm2_map_peripheral(BCM2836_REGISTERS_PHYSICAL_BASE, 1); + bcm2836_peripheral_base = vm2_map_peripheral(BCM2836_PERIPHERALS_PHYSICAL_BASE, 4); - // TODO: remove vm1 code and leave only this vm2 call - vm2_map_nmegabytes_1to1(BCM2836_peripheral_base, 4); - - // Map control registers - // TEMP (vm1): - request_identity_mapped_section((size_t)bcm2836_registers_base, 1); + bcm2836_uart_init(); - // TODO: remove vm1 code and leave only this vm2 call - vm2_map_nmegabytes_1to1((size_t)bcm2836_registers_base, 1); +// // Mapping memory used by bcm2836 peripherals +// // TEMP (vm1): +// request_identity_mapped_section(BCM2836_peripheral_base, 4); +// +// +// vm2_map_peripheral() +// // TODO: remove vm1 code and leave only this vm2 call +// vm2_map_nmegabytes_1to1(BCM2836_PERIPHERALS_PHYSICAL_BASE, 4); +// vm2_map_peripheral() +// +// +// // Map control registers +// // TEMP (vm1): +// request_identity_mapped_section((size_t)bcm2836_registers_base, 1); +// +// // TODO: remove vm1 code and leave only this vm2 call +// vm2_map_nmegabytes_1to1((size_t)bcm2836_registers_base, 1); } diff --git a/kernel/src/drivers/chipset/bcm2836/include/bcm2836.h b/kernel/src/drivers/chipset/bcm2836/include/bcm2836.h index 16efc651..de1c7e1b 100644 --- a/kernel/src/drivers/chipset/bcm2836/include/bcm2836.h +++ b/kernel/src/drivers/chipset/bcm2836/include/bcm2836.h @@ -4,6 +4,9 @@ #include +#define BCM2836_REGISTERS_PHYSICAL_BASE 0x40000000 +#define BCM2836_PERIPHERALS_PHYSICAL_BASE 0x3F000000 + // Starts at memory address 0x4000_0000 struct BCM2836Registers { uint32_t ControlRegister; @@ -72,19 +75,12 @@ struct BCM2836Registers { uint32_t Core3Mailbox3ReadClear; }; - - - - - - - enum InterruptSource { // nCNTPSIRQ : Secure physical timer event - PHYSICAL_SECURE_TIMER = (1 << 0), + PHYSICAL_SECURE_TIMER = (1u << 0u), // nCNTPNSIRQ : Non-secure physical timer event - PHYSICAL_NONSECURE_TIMER = (1 << 1), + PHYSICAL_NONSECURE_TIMER = (1u << 1), // nCNTHPIRQ: Physical Timer for use in Hypervisor mode. PHYSICAL_HYPERVISOR_TIMER = (1 << 2), @@ -104,11 +100,9 @@ enum InterruptSource { LOCAL_TIMER = (1 << 11), }; -volatile struct BCM2836Registers * bcm2836_registers_base; - void bcm2836_init(); - -extern const size_t BCM2836_peripheral_base; +volatile struct BCM2836Registers * bcm2836_registers_base; +size_t bcm2836_peripheral_base; #endif diff --git a/kernel/src/drivers/chipset/bcm2836/uart.c b/kernel/src/drivers/chipset/bcm2836/uart.c index 38dffbf0..0ac90832 100644 --- a/kernel/src/drivers/chipset/bcm2836/uart.c +++ b/kernel/src/drivers/chipset/bcm2836/uart.c @@ -80,10 +80,10 @@ volatile BCM2836UartInterface * BCM2836_UART2_ADDRESS; volatile BCM2836UartInterface * BCM2836_UART3_ADDRESS; void bcm2836_uart_init() { - BCM2836_UART0_ADDRESS = (volatile BCM2836UartInterface *)(BCM2836_peripheral_base + 0x201000); - BCM2836_UART1_ADDRESS = (volatile BCM2836UartInterface *)(BCM2836_peripheral_base + 0x202000); - BCM2836_UART2_ADDRESS = (volatile BCM2836UartInterface *)(BCM2836_peripheral_base + 0x203000); - BCM2836_UART3_ADDRESS = (volatile BCM2836UartInterface *)(BCM2836_peripheral_base + 0x204000); + BCM2836_UART0_ADDRESS = (volatile BCM2836UartInterface *)(bcm2836_peripheral_base + 0x201000); + BCM2836_UART1_ADDRESS = (volatile BCM2836UartInterface *)(bcm2836_peripheral_base + 0x202000); + BCM2836_UART2_ADDRESS = (volatile BCM2836UartInterface *)(bcm2836_peripheral_base + 0x203000); + BCM2836_UART3_ADDRESS = (volatile BCM2836UartInterface *)(bcm2836_peripheral_base + 0x204000); } void uart_write_byte(volatile BCM2836UartInterface * interface, volatile uint8_t value) { @@ -91,6 +91,7 @@ void uart_write_byte(volatile BCM2836UartInterface * interface, volatile uint8_t // asm volatile ("nop"); // } interface->DR = (uint32_t)value; + } void bcm2836_uart_putc(char c, int uartchannel) { diff --git a/kernel/src/ds/array_list.c b/kernel/src/ds/array_list.c deleted file mode 100644 index 02bb235a..00000000 --- a/kernel/src/ds/array_list.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * array_list.c - * - * Created on: Apr 21, 2015 - * Author: kittenRainbow - */ -/// FIXME: All usages of this array list should be replaced with vp_array_list or even u8_array_list where applicable. - -#include -#include -#include -#include - -arrl_handle* arrl_create() { - return arrl_create_fixed(DEFAULT_BUCKET_SIZE); -} - -arrl_handle* arrl_create_fixed(uint32_t bucket_size) { - arrl_handle* result = (arrl_handle *) kmalloc(sizeof(arrl_handle)); - void** bucket = kmalloc(bucket_size * sizeof(void*)); - llist_handle * l = llist_create(bucket); - result->linked_list = l; - result->size = 0; - result->capacity = bucket_size; - return result; -} - -void arrl_append(arrl_handle* arrl, void* elem) { - llist_node * curr_bucket; - uint32_t list_size; - uint32_t last_bucket_size; - - if (arrl->capacity == arrl->size) { - void* data = kmalloc(arrl->bucket_size * sizeof(void*)); - llist_enqueue(arrl->linked_list, data); - arrl->capacity += arrl->bucket_size; - } - - curr_bucket = arrl->linked_list->head; - list_size = arrl->size / arrl->bucket_size; - last_bucket_size = arrl->size % arrl->bucket_size; - - for(uint32_t i=0; i < list_size; ++i) { - curr_bucket= curr_bucket->next; - } - *(((int**)curr_bucket->data) + last_bucket_size) = (int*)elem; -} - -void arrl_remove(arrl_handle* arrl, void* elem) { - uint32_t bucket_size; - uint32_t list_size; - uint32_t bucket_index; - uint32_t list_index; - llist_node* curr_bucket; - llist_node* tail; - - bucket_size = arrl->bucket_size; - list_size = arrl->linked_list->count; - curr_bucket = arrl->linked_list->head; - tail = arrl->linked_list->tail; - - for (list_index = 0; list_index < list_size; ++list_index) { - for (bucket_index = 0; bucket_index < bucket_size; ++bucket_index) { - //if (elem == curr_bucket->data[bucket_index]) { - kfree(elem); - goto out; - //} - } - curr_bucket = curr_bucket->next; - } - - // Except the last bucket, shift each bucket up by one and copy first element of the next bucket to the last cell of the current bucket - out: while (curr_bucket != tail) { - memcpy(*(((uint32_t**)curr_bucket->data) + bucket_index + 1), - *(((uint32_t**)curr_bucket->data) + bucket_index + 0), - bucket_size - bucket_index - 1); - bucket_index = 0; - *(((int**)curr_bucket->data) + bucket_size - 1) = *((int**)curr_bucket->next->data); - curr_bucket = curr_bucket->next; - } - - --arrl->size; -} - -uint32_t arrl_contains(arrl_handle* arrl, void* elem) { - uint32_t bucket_size = arrl->bucket_size; - uint32_t list_size = arrl->linked_list->count; - llist_node* bucket = arrl->linked_list->head; - - for (uint32_t list_index = 0; list_index < list_size; ++list_index) { - for (uint32_t bucket_index = 0; bucket_index < bucket_size; - ++bucket_index) { - //if (elem == bucket->data[bucket_index]) { - return 1; - //} - } - bucket = bucket->next; - } - return 0; -} - -uint32_t arrl_index_of(arrl_handle* arrl, void* elem) { - int bucket_size = arrl->bucket_size; - int list_size = arrl->linked_list->count; - llist_node* bucket = arrl->linked_list->head; - - for (int list_index = 0; list_index < list_size; ++list_index) { - for (int bucket_index = 0; bucket_index < bucket_size; - ++bucket_index) { - //if (elem == bucket->data[bucket_index]) { - return list_index * DEFAULT_BUCKET_SIZE + bucket_index; - //} - } - bucket = bucket->next; - } - return -1; -} - -uint32_t arrl_count(arrl_handle* arrl) { - return arrl->size; -} - diff --git a/kernel/src/ds/bitvector.c b/kernel/src/ds/bitvector.c deleted file mode 100644 index 62a117ed..00000000 --- a/kernel/src/ds/bitvector.c +++ /dev/null @@ -1,137 +0,0 @@ -#include -#include -#include - -uint32_t const WORD_SIZE = 32; - -/* return a pointer to a bit_vector struct of length size */ -bit_vector *make_vector(uint32_t size) { - // make the array - bit_vector *BV = (bit_vector*) kmalloc(sizeof(bit_vector)); - if((size % 32) == 0) { - uint32_t array[size >> 5]; - uint32_t x; - for(x = 0; (x < (size >> 5)); x++){ - array[x] = 0; - } - uint32_t *bit_vec = (uint32_t*) kmalloc(sizeof(array)); - BV->vector = bit_vec; - BV->length = size; - BV->actualLength = (size >> 5); - return BV; - } else { - uint32_t array[(size >> 5) + 1]; - uint32_t y; - for(y = 0; (y < ((size >> 5)+1)); y++){ - array[y] = 0; - } - uint32_t *bit_vec = (uint32_t*) kmalloc(sizeof(array)); - BV->vector = bit_vec; - BV->length = size; - BV->actualLength = (size >> 5) + 1; - return BV; - } -} - -/* return a whatever number, 1 or 0 is at position index */ -int32_t bv_get (uint32_t index, bit_vector* bit_vec) { - - if(index < bit_vec->length && index >= 0) { - - uint32_t val = (index >> 5); - uint32_t oneWord = bit_vec->vector[val]; - oneWord = oneWord >> (31 - (index % WORD_SIZE)); - uint32_t mask = 0x1; - return oneWord & mask; - } else {return -1;} // invalid index -} - -/* toggles the bit a position index */ -int32_t bv_toggle (uint32_t index, bit_vector* bit_vec) { - - if(index < bit_vec->length && index >= 0) { - - uint32_t val = (index >> 5); - uint32_t oneWord = bit_vec->vector[val]; - uint32_t mask = 0x1 << (31 - (index % WORD_SIZE)); - bit_vec->vector[val] = oneWord ^ mask; - return 1; - } else {return -1;} // invalid index -} - -/* puts a 1 at the position index */ -int32_t bv_set (uint32_t index, bit_vector* bit_vec) { - - if(index < bit_vec->length && index >= 0) { - - uint32_t val = (index >> 5); - uint32_t oneWord = bit_vec->vector[val]; - uint32_t mask = 0x1 << (31 - (index % WORD_SIZE)); - bit_vec->vector[val] = oneWord | mask; - return 1; - } else {return -1;} // invalid index -} - -/* puts a 0 at the position index */ -int32_t bv_lower (uint32_t index, bit_vector* bit_vec) { - - if(index < bit_vec->length && index >= 0) { - - uint32_t val = (index >> 5); - uint32_t oneWord = bit_vec->vector[val]; - uint32_t mask = ~(0x1 << (31 - (index % WORD_SIZE))); - bit_vec->vector[val] = oneWord & mask; - return 1; - } else {return -1;} // invalid index -} - -/* returns the first free index, if none are free return -1 */ -int32_t bv_firstFree (bit_vector* bit_vec) { - - uint32_t mask = 0x1; - uint32_t returner = 0; - uint32_t oneWord; - uint32_t x; - oneWord = bit_vec->vector[0]; - - for(x = 0; x < bit_vec->actualLength; x++) { - - uint32_t index = 0; - while(index < WORD_SIZE) { - - oneWord = bit_vec->vector[x]; - oneWord = (oneWord >> (31 - index)) & mask; - - if(!oneWord) { - return returner += index; - } - index++; - } returner += WORD_SIZE; - } - return -1; //no free spots -} - -/* returns whether the given index is free; 1 - true, 0 - false, -1 - invalid index*/ -int32_t bv_isfree(uint32_t index, bit_vector* bit_vec) -{ - uint32_t val; - uint32_t word; - if (index < bit_vec->length && index >= 0){ - val = (index >> 5); - word = bit_vec->vector[val]; - word = (word >> (31 - index)) & 0x1; - if (!word){ - return 1; - } - return 0; - } - return -1; -} - -/* free the bv from memory */ -int32_t bv_free (bit_vector* bit_vec) { - - kfree(bit_vec->vector); - kfree(bit_vec); - return 1; -} diff --git a/kernel/src/ds/hash_map.c b/kernel/src/ds/hash_map.c deleted file mode 100644 index 6e7f8f8a..00000000 --- a/kernel/src/ds/hash_map.c +++ /dev/null @@ -1,181 +0,0 @@ -#include -#include -#include -#include -#include - -/* this should be prime */ -#define TABLE_STARTSIZE 1021 -#define ACTIVE 1 - -static unsigned long __hmap_is_prime(unsigned long val) { - int i, p, exp, a; - - for (i = 9; i--;) { - a = (rand() % (val - 4)) + 2; - p = 1; - exp = val - 1; - while (exp) { - if (exp & 1) { - p = (p * a) % val; - } - - a = (a * a) % val; - exp >>= 1; - } - if (p != 1) { - return 0; - } - } - return 1; -} - -static int __hmap_find_prime_greater_than(int val) { - if (val & 1) { - val += 2; - } else { - val++; - } - - while (!__hmap_is_prime(val)) { - val += 2; - } - - return val; -} - -static void __hmap_rehash(hmap_handle* hmap) { - long size = hmap->size; - hmap_entry* table = hmap->table; - - hmap->size = __hmap_find_prime_greater_than(size << 1); - hmap->table = (hmap_entry*) kmalloc(sizeof(hmap_entry) * hmap->size); - memset(hmap->table, 0, sizeof(hmap_entry) * hmap->size); - hmap->count = 0; - - while (--size >= 0) { - if (table[size].flags == ACTIVE) { - hmap_put(hmap, table[size].key, table[size].data); - } - } - - kfree(table); -} - -hmap_handle* hmap_create(){ - return hmap_create_fixed(TABLE_STARTSIZE); -}; - -hmap_handle* hmap_create_fixed(int startsize) { - hmap_handle* hmap = (hmap_handle*) kmalloc(sizeof(hmap_handle)); - - if (!startsize) { - startsize = TABLE_STARTSIZE; - } else { - startsize = __hmap_find_prime_greater_than(startsize - 2); - } - - hmap->table = (hmap_entry*) kmalloc(sizeof(hmap_entry) * startsize); - - memset(hmap->table, 0, startsize); - - hmap->size = startsize; - hmap->count = 0; - - return hmap; -} - -void hmap_put(hmap_handle* hmap, unsigned long key, const void* data) { - long index, i, step; - - if (hmap->size <= hmap->count) - __hmap_rehash(hmap); - - do { - index = key % hmap->size; - step = (key % (hmap->size - 2)) + 1; - - for (i = 0; i < hmap->size; i++) { - if (hmap->table[index].flags & ACTIVE) { - if (hmap->table[index].key == key) { - hmap->table[index].data = (void*) data; - return; - } - } else { - hmap->table[index].flags |= ACTIVE; - hmap->table[index].data = (void*) data; - hmap->table[index].key = key; - ++hmap->count; - return; - } - - index = (index + step) % hmap->size; - } - - /* it should not be possible that we EVER come this far, but unfortunately - not every generated prime number is prime (Carmichael numbers...) */ - __hmap_rehash(hmap); - } while (1); -} - -void* hmap_remove(hmap_handle* hmap, unsigned long key) { - long index, i, step; - - index = key % hmap->size; - step = (key % (hmap->size - 2)) + 1; - - for (i = 0; i < hmap->size; i++) { - if (hmap->table[index].data) { - if (hmap->table[index].key == key) { - if (hmap->table[index].flags & ACTIVE) { - hmap->table[index].flags &= ~ACTIVE; - --hmap->count; - return hmap->table[index].data; - } else { - /* in, but not active (i.e. deleted) */ - return 0; - } - } - } else { - /* found an empty place (can't be in) */ - return 0; - } - - index = (index + step) % hmap->size; - } - /* everything searched through, but not in */ - return 0; -} - -void* hmap_get(hmap_handle* hmap, unsigned long key) { - if (hmap->count) { - long index, i, step; - index = key % hmap->size; - step = (key % (hmap->size - 2)) + 1; - - for (i = 0; i < hmap->size; i++) { - if (hmap->table[index].key == key) { - if (hmap->table[index].flags & ACTIVE) { - return hmap->table[index].data; - } - break; - } else if (!hmap->table[index].data) { - break; - } - - index = (index + step) % hmap->size; - } - } - - return 0; -} - -long hmap_count(hmap_handle* hash) { - return hash->count; -} - -void hmap_free(hmap_handle* hash) { - kfree(hash->table); - kfree(hash); -} - diff --git a/kernel/src/ds/linked_list.c b/kernel/src/ds/linked_list.c deleted file mode 100644 index 72f7486a..00000000 --- a/kernel/src/ds/linked_list.c +++ /dev/null @@ -1,108 +0,0 @@ -/******************************************************************** - * linked_list.c - * - * Author: Brandon Olivier // any collaborators, please add name - * - * Date: 14 April 2014 - * - * Purpose: Provide basic linked list for CourseOS - * Implementation file - * - * TODO: Use locks or atomic operations to ensure that - * functions are safe - * - * - * - * - * - ********************************************************************/ - -#include -#include -#include - -llist_node* llist_create_node(void *data) { - llist_node *node = (llist_node*) kmalloc(sizeof(llist_node)); - node->data = data; - return node; -} - -llist_handle* llist_create(void *data) { /* create more space than needed -- less resizing */ - llist_handle *result = (llist_handle *) kmalloc(sizeof(llist_node)); - result->count = 0; - llist_insert(result, llist_create_node(data), 0); - return result; -} - -void llist_enqueue(llist_handle * list, void * data) { - llist_insert(list, data, 0); -} - -void* llist_get_data(llist_handle *l, int index) { - return llist_get_node(l, index)->data; -} - -void* llist_dequeue(llist_handle * list) { - void * data = llist_get_data(list, 0); - llist_remove_at(list, 0); - return data; -} - -/* TODO: implmement free */ -void llist_free(llist_handle *l) { /* since free isn't really implemented, it's not going to do anything */ - llist_node *tmp = l->head; - llist_node *next = tmp->next; - while (tmp->next) { - kfree(tmp); - tmp = next; - next = tmp->next; - } - kfree(l); -} - -void llist_free_node(llist_node *node) { - kfree(node->data); - kfree(node); -} - -void llist_insert(llist_handle *l, void *data, int index) { - llist_node *next = l->head; - llist_node *prev = NULL; - l->count++; - for (int i = 0; i < index; i++) { - prev = next; - next = next->next; - } - llist_node *new_node = llist_create_node(data); - prev->next = prev ? new_node : 0; - next->next = next ? new_node : 0; - if (l->tail->next) { - l->tail = l->tail->next; - } -} - -int llist_count(llist_handle *l) -{ - return l->count; -} - -void llist_remove_at(llist_handle *l, int index) { - llist_node *prev = llist_get_node(l, index); - llist_node *to_delete = prev->next; - prev->next = to_delete->next; - llist_free_node(to_delete); -} - - - -llist_node* llist_get_node(llist_handle *l, int index) { - llist_node *tmp = l->head; - for (int i = 0; i < index; i++) { - tmp = tmp->next; - } - return tmp; -} - -void llist_set_data(llist_node *l, void *data) { - l->data = data; -} diff --git a/kernel/src/ds/ring_buffer.c.old b/kernel/src/ds/ring_buffer.c.old deleted file mode 100644 index 6858004b..00000000 --- a/kernel/src/ds/ring_buffer.c.old +++ /dev/null @@ -1,60 +0,0 @@ -/******************************************************************** - * ring_buffer.c - * - * Author: Brandon Olivier // any collaborators, please add name - * - * Date: 14 April 2014 - * - * Purpose: Provide ring buffer implementation for CourseOS - * - * TODO: Add locks or mutexes or something - * - ********************************************************************/ - -#include - -ring_buffer* create(int size) -{ - ring_buffer* rb = (ring_buffer *) malloc(sizeof(ring_buffer) * size); - rb->size_limit = size; - return rb; -} - -int put(ring_buffer *r, void *data) -{ /* do a size check */ - if(r->size >= r->size_limit) - return 0; // no space - r->size++; - rb_node* node = (rb_node *) malloc(sizeof(rb_node)); - node->data = data; - r->head->next = node; - r->head = node; - node->next = r->tail; - return 1; -} - -rb_node* get(ring_buffer *r) -{ - return r->tail; -} - -void clear(ring_buffer *r) -{ - rb_node* clear = r->tail; - r->tail = clear->next; - r->head->next = r->tail; - //free(clear->data); // nots sure if good idea - free(clear); -} - -ring_buffer* increase_size(ring_buffer *r, int by) -{ - int new_limit = r->size + by; - ring_buffer *new = (ring_buffer *) malloc(sizeof(ring_buffer) * new_limit); - new->size_limit = new_limit; - new->size = r->size; - new->tail = r->tail; - new->head = r->head; - free(r); - return new; -} diff --git a/kernel/src/klibc/alloc.c b/kernel/src/klibc/alloc.c index 9f8e4674..a9426e6a 100644 --- a/kernel/src/klibc/alloc.c +++ b/kernel/src/klibc/alloc.c @@ -3,32 +3,6 @@ #include #include -void *kmalloc_aligned(uint32_t size, uint32_t alignment) { - void *block; - void *ptr; - - switch (alignment) { - case 4: - block = kmalloc(size + 4); - ptr = (void *) (((uint32_t) block + 4) & ~0x3); - return ptr; - case 1024: - block = kmalloc(size + 1024); - ptr = (void *) (((uint32_t) block + 1024) & ~0x1ff); - return ptr; - case 4096: - block = kmalloc(size + 4096); - ptr = (void *) (((uint32_t) block + 4096) & ~0x7ff); - return ptr; - case 16 * 1024: - block = kmalloc(size + 16 * 1024); - ptr = (void *) (((uint32_t) block + 16 * 1024) & ~0x1fff); - return ptr; - default: - return kmalloc(size); - } -} - void kfree(void *ptr) { deallocate((uint32_t *) ptr); } @@ -59,8 +33,6 @@ uint32_t kmalloc_size(void* ptr) { // TODO: Implement in-place realloc if the next block is free. // Resize memory pointed to by ptr to new size void * krealloc(void *ptr, uint32_t newsize) { -// os_printf("Size: %u, newsize: %u\n", kmalloc_size(ptr), size); - uint32_t oldsize = kmalloc_size(ptr); if (newsize == 0) { @@ -79,62 +51,3 @@ void * krealloc(void *ptr, uint32_t newsize) { return newptr; } } - -/** - * umalloc allocates memory on the user heap - * - * @param size of the block of memory allocated - * @param uint32_t size - * @return returns a pointer to the allocated block of memory - */ -void *umalloc(uint32_t size) { - void *block = (void *) proc_allocate(size); - return block; -} - -/** - * ualigned alloc allocates memory on the user heap - * according to a specified alignemnt - * - * @param size of the block of memory allocated, and alignment desired - * @param uint32_t size, uint32_alignment - * @return returns a pointer to the allocated block of memory - * that is a multiple of the specified allignement - */ - -void *ualigned_alloc(uint32_t size, uint32_t alignment) { - void *block; - void *ptr; - - switch (alignment) { - case 4: - block = umalloc(size + 4); - ptr = (void *) (((uint32_t) block + 4) & ~0x3); - return ptr; - case 1024: - block = umalloc(size + 1024); - ptr = (void *) (((uint32_t) block + 1024) & ~0x1ff); - return ptr; - case 4096: - block = umalloc(size + 4096); - ptr = (void *) (((uint32_t) block + 4096) & ~0x7ff); - return ptr; - case 16 * 1024: - block = umalloc(size + 16 * 1024); - ptr = (void *) (((uint32_t) block + 16 * 1024) & ~0x1fff); - return ptr; - default: - return umalloc(size); - } -} - -/** - * free's an allocated block of memory on the heap - * - * @param pointer to a block of memeory on the heap - * @param void* ptr - * @return nothing returned - */ -void ufree(void *ptr) { - proc_deallocate((uint32_t *) ptr); -} diff --git a/kernel/src/klibc/include/constants.h b/kernel/src/klibc/include/constants.h index 59e8068a..8227a032 100644 --- a/kernel/src/klibc/include/constants.h +++ b/kernel/src/klibc/include/constants.h @@ -5,10 +5,10 @@ /// SI Binary prefixes #define Kibibyte ((size_t)(1024u)) -#define Mibibyte ((size_t)(Kibibyte * 1024u)) -#define Gibibyte ((size_t)(Mibibyte * 1024u)) -#define Tibibyte ((size_t)(Gibibyte * 1024u)) -#define Pebibyte ((size_t)(Tibibyte * 1024u)) +#define Mebibyte ((size_t)(Kibibyte * 1024u)) +#define Gibibyte ((size_t)(Mebibyte * 1024u)) +#define Tebibyte ((size_t)(Gibibyte * 1024u)) +#define Pebibyte ((size_t)(Tebibyte * 1024u)) #define Exbibyte ((size_t)(Pebibyte * 1024u)) #define Zebibyte ((size_t)(Exbibyte * 1024u)) #define Yobibyte ((size_t)(Zebibyte * 1024u)) diff --git a/kernel/src/klibc/include/klibc.h b/kernel/src/klibc/include/klibc.h index 4ad723e3..4ae87d88 100644 --- a/kernel/src/klibc/include/klibc.h +++ b/kernel/src/klibc/include/klibc.h @@ -59,7 +59,6 @@ os_size_t os_strspn(char *s, char *accept); os_size_t os_strcspn(char *s, char *reject); void os_memcpy(uint32_t * source, uint32_t * dest, os_size_t size); -/* TODO: create print function for kernel debugging purposes */ uint32_t km_size(); @@ -68,33 +67,31 @@ uint32_t kmcheck(); unsigned int rand(); -// as the codebase grows, it is important to use these macros -// so that we can filter out unnecessary messages esp. during -// development -#define LOG_LEVEL 5 - -//#if LOG_LEVEL >= 5 -#define DEBUG(...) kprintf("DEBUG: " __VA_ARGS__) // :+1: -//#else -//#define DEBUG(...) -//#endif -#define LOG(...) kprintf(__VA_ARGS__) -#define INFO(...) kprintf(__VA_ARGS__) -#define WARN(...) kprintf(__VA_ARGS__) // :+1: -#define ERROR(...) kprintf(__VA_ARGS__); - -#define ___asm_opcode_swab32(x) ( \ - (((x) << 24) & 0xFF000000) \ - | (((x) << 8) & 0x00FF0000) \ - | (((x) >> 8) & 0x0000FF00) \ - | (((x) >> 24) & 0x000000FF) \ -) +#define LOG_LEVEL 4 + +#if LOG_LEVEL > 3 +#define TRACE(format, ...) kprintf("\e[90m[TRACE] " format "\e[0m\n", ##__VA_ARGS__) +#else +#define TRACE(...) +#endif + +#if LOG_LEVEL > 2 +#define DEBUG(format, ...) kprintf("[DEBUG] \e[92m%s:%i\e[0m " format "\n", __FILE__, __LINE__, ##__VA_ARGS__) +#else +#define DEBUG(...) +#endif +#if LOG_LEVEL > 1 +#define INFO(format, ...) kprintf("\e[96m[INFO]\e[0m " format "\n", ##__VA_ARGS__) +#else +#define INFO(...) +#endif +//#define WARN(format, ...) kprintf("\e[38;5;208m[WARN] " format "\e[0m\n", ##__VA_ARGS__) // Defines an instruction that will raise an undefined instruction code on both ARM (and hopefully THUMB2) #define UNDEFINED_INSTRUCTION_BYTES 0xF7F1A2F3 #define STRINGIFY2(X) #X #define STRINGIFY(X) STRINGIFY2(X) -#define FATAL() asm volatile(".long " STRINGIFY(UNDEFINED_INSTRUCTION_BYTES)); +#define FATAL(format, ...) kprintf("\e[38;5;160m[FATAL] \e[38;5;208m%s:%i\e[38;5;160m " format "\e[0m\n", __FILE__, __LINE__, ##__VA_ARGS__); panic() //4-17-15: Initial panic * assert_fail functions added void panic() __attribute__ ((noreturn)); diff --git a/kernel/src/kthread/include/kthread.h b/kernel/src/kthread/include/kthread.h deleted file mode 100644 index deee3d28..00000000 --- a/kernel/src/kthread/include/kthread.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * kthread.h - * - * Created on: Apr 23, 2015 - * Author: mwkurian - */ - -#ifndef KERNEL_INCLUDE_KTHREAD_H_ -#define KERNEL_INCLUDE_KTHREAD_H_ - -#include - -typedef void (*kthread_callback_handler)(); - -typedef struct kthread_handle { - uint32_t parent_pid; - int niceness; - int state; - kthread_callback_handler cb_handler; -} kthread_handle; - - - -#endif /* KERNEL_INCLUDE_KTHREAD_H_ */ diff --git a/kernel/src/kthread/kthreads.c b/kernel/src/kthread/kthreads.c deleted file mode 100644 index f90d6dc9..00000000 --- a/kernel/src/kthread/kthreads.c +++ /dev/null @@ -1,24 +0,0 @@ -/* - * kthreads.c - * - * Created on: Apr 23, 2015 - * Author: mwkurian - */ - -#include -#include -#include - -kthread_handle* kthread_create(kthread_callback_handler cb_handler) -{ - kthread_handle * kthread = kmalloc(sizeof(kthread_handle)); - kthread->cb_handler = cb_handler; - return kthread; -} - -uint32_t kthread_start(kthread_handle * kthread) -{ - sched_task * task = sched_create_task_from_kthread(kthread, 0); - return sched_add_task(task); -} - diff --git a/kernel/src/memory/allocator.c b/kernel/src/memory/allocator.c index c0fab18a..1d41d34b 100644 --- a/kernel/src/memory/allocator.c +++ b/kernel/src/memory/allocator.c @@ -108,7 +108,7 @@ void *heap_alloc(heap_t *heap, uint32_t size) { #ifdef MEM_DEBUG heap->bytes_allocated += found->size; - kprintf("MEM_DEBUG: ALLOC %i bytes at 0x%x\n", found->size, &found->next); + TRACE("[MEM DEBUG] ALLOC %i bytes at 0x%x", found->size, &found->next); #endif return &found->next; @@ -133,7 +133,7 @@ void heap_free(heap_t *heap, void *p) { #ifdef MEM_DEBUG heap->bytes_allocated -= head->size; - kprintf("MEM_DEBUG: FREE %i bytes\n", head->size); + TRACE("[MEM DEBUG] FREE %i bytes", head->size); #endif if (head == (node_t *) (uintptr_t) heap->start) { @@ -179,7 +179,7 @@ void heap_free(heap_t *heap, void *p) { // these are left here to implement contraction / expansion uint32_t expand(heap_t *heap, uint32_t sz) { - kprintf("Trying to expand\n"); + TRACE("[MEM DEBUG] Trying to expand"); return 0; // fail for now } @@ -239,4 +239,4 @@ node_t *get_wilderness(heap_t *heap) { uint32_t get_alloc_size(void * ptr) { node_t *head = (node_t *) (ptr - offset); return head->size; -} \ No newline at end of file +} diff --git a/kernel/src/memory/include/allocator.h b/kernel/src/memory/include/allocator.h index 6e0f8306..6f8f9e03 100644 --- a/kernel/src/memory/include/allocator.h +++ b/kernel/src/memory/include/allocator.h @@ -1,3 +1,5 @@ +// Adapted from https://github.com/CCareaga/heap_allocator + #ifndef ALLOCATOR_H #define ALLOCATOR_H @@ -71,4 +73,4 @@ node_t *get_last_node(bin_t *list); node_t *next(node_t *current); node_t *prev(node_t *current); -#endif \ No newline at end of file +#endif diff --git a/kernel/src/memory/include/mem_alloc.h b/kernel/src/memory/include/mem_alloc.h index 7b3865c1..2cfc3b39 100644 --- a/kernel/src/memory/include/mem_alloc.h +++ b/kernel/src/memory/include/mem_alloc.h @@ -1,45 +1,14 @@ -#ifndef __MEM_ALLOC_H__ -#define __MEM_ALLOC_H__ +#ifndef MEM_ALLOC_H +#define MEM_ALLOC_H #include #include -#define MEM_START 0x500000 -#define PROC_START 0x90000000 -struct vas; - -uint32_t init_heap(); +void init_heap(); void *allocate(uint32_t size); void deallocate(void *ptr); -/** - * Initializes a processes heap, in the same manner that the - * kernel heap is initialized - * - * @param pointer to virtual address space (the process's VAS) - * @param struct vas* vas - * @return returns status code (for error or for ok) - */ -uint32_t init_process_heap(struct vas* vas); - -/** - * Allocates memory on the heap for a process - * - * @param size of allocated memory - * @param uint32_t size - * @return a pointer to allocated memory - */ -void *proc_allocate(uint32_t); - -/** - * Deallocates memory on the heap for a process - * - * @param pointer to allocated memory - * @param void* ptr - * @return nothing - */ -void proc_deallocate(void*); heap_t* mem_get_allocator(); uint32_t mem_get_heap_size(); @@ -47,4 +16,6 @@ uint32_t mem_get_heap_size(); uint32_t allocation_size(void* ptr); uint32_t proc_blocksize(void* ptr); +size_t heap_end; + #endif diff --git a/kernel/src/memory/include/mmap.h b/kernel/src/memory/include/mmap.h index a3e335bb..104c2890 100644 --- a/kernel/src/memory/include/mmap.h +++ b/kernel/src/memory/include/mmap.h @@ -1,5 +1,5 @@ /* - * Memory Mapped I/O addresses + * Memory Mapped I/O addresses */ #ifndef MMAP_H @@ -14,11 +14,11 @@ // Hence the 4 hours it took us to make timer.c work...... static inline void mmio_write_internal(volatile uint32_t * address, volatile uint32_t value ) { asm volatile ( - "ldr r1, %1\n" - "str r1, %0\n" - :: - "m" (*address), - "m" (value) + "ldr r1, %1\n" + "str r1, %0\n" + :: + "m" (*address), + "m" (value) ); } diff --git a/kernel/src/memory/mem_alloc.c b/kernel/src/memory/mem_alloc.c index 8e6ed633..b5cb941f 100644 --- a/kernel/src/memory/mem_alloc.c +++ b/kernel/src/memory/mem_alloc.c @@ -3,30 +3,11 @@ #include #include #include +#include +#include -uint32_t *nextBlock = (uint32_t*) MEM_START; -uint32_t buffer_size; heap_t * allocator; -uint32_t __mem_extend_heap(uint32_t amt); - -heap_t * proc_allocator; -uint32_t proc_buffer_size; -uint32_t __mem_extend_proc_heap(uint32_t amt); - -//bump pointer allocation -void *mem_alloc(uint32_t size) -{ - uint32_t temp = size / 4; - - if ((size % 4) > 0) - { - temp++; - } - uint32_t* allocBlock = nextBlock; - nextBlock = nextBlock + size; - - return allocBlock; -} +size_t heap_end; /* * The kernel heap is organized in blocks. Each block has a header and a @@ -43,125 +24,46 @@ void *mem_alloc(uint32_t size) * should merge with the blocks on the left or right of us, respectively. */ -// TODO: what if there's an error allocating the page? -// Returns a pointer to the new (big) free block's header -uint32_t __mem_extend_heap(uint32_t amt) -{ - uint32_t amt_added = 0; - while (amt_added < amt) { - int retval = vm_allocate_page(KERNEL_VAS, - (void*) (MEM_START + buffer_size), VM_PERM_PRIVILEGED_RW); - if (retval) { - kprintf("ERROR: vm_allocate_page(,%d,) returned %d\n", - MEM_START + amt_added, retval); - break; - } - amt_added += BLOCK_SIZE; - buffer_size += BLOCK_SIZE; - } - - return amt_added; -} +void init_heap() { + size_t heap_end = KERNEL_HEAP_BASE; -uint32_t init_heap() -{ // Allocate space for the heap_t struct. is too large but at least big enough. - int retval = vm_allocate_page(KERNEL_VAS, (void*) MEM_START, VM_PERM_PRIVILEGED_RW); - if (retval) { - kprintf("ERROR: vm_allocate_page returned %d\n", retval); - return STATUS_FAIL; + void * ret = vm2_allocate_kernel_page(kernell1PageTable, KERNEL_HEAP_BASE, false); + if (ret == NULL) { + FATAL("Couldn't allocate page for the kernel heap"); } - heap_t * heap = (heap_t * ) MEM_START; + heap_t * heap = (heap_t *) KERNEL_HEAP_BASE; + memset(heap, 0, sizeof(heap_t)); - uint32_t addr = (uint32_t)((void *) MEM_START + sizeof(heap_t)); + heap_end += sizeof(heap_t); for(int i = 0; i < BIN_COUNT; i++) { - heap->bins[i] = (bin_t *) addr; + heap->bins[i] = (bin_t *) heap_end; memset(heap->bins[0], 0, sizeof(bin_t)); - addr += sizeof(bin_t); + heap_end += sizeof(bin_t); } - assert(MEM_START + sizeof(heap_t) + BIN_COUNT * sizeof(bin_t) == addr) - + assert(KERNEL_HEAP_BASE + sizeof(heap_t) + BIN_COUNT * sizeof(bin_t) == heap_end); - // Find the next page boundary above addr - addr = (addr & ~(BLOCK_SIZE-1)) + BLOCK_SIZE; - - void * ret = vm_allocate_pages(KERNEL_VAS, (void *) addr, HEAP_INIT_SIZE, VM_PERM_PRIVILEGED_RW); - if(addr + HEAP_INIT_SIZE != (uint32_t) ret) { - kprintf("ERROR: vm_allocate_pages allocated a different amount than requested\n"); - return STATUS_FAIL; - } + // current heap end. + size_t heap_start = heap_end; - // allocator = alloc_create((uint32_t*) MEM_START, buffer_size, &__mem_extend_heap); - create_heap(heap, addr); - allocator = heap; - return STATUS_OK; -} - -uint32_t init_process_heap(struct vas* vas) { - int retval = vm_allocate_page(vas, (void*) PROC_START, VM_PERM_USER_RW); - if (retval) { - kprintf("ERROR: vm_allocate_page returned %d\n", retval); - return STATUS_FAIL; - } - - heap_t * heap = (heap_t * ) PROC_START; - uint32_t addr = (uint32_t)((void *) PROC_START + sizeof(heap_t)); - - for(int i = 0; i < BIN_COUNT; i++) { - heap->bins[i] = (bin_t *) addr; - addr += sizeof(bin_t); - } - - // Find the next page boundary above addr - addr = (addr & ~(BLOCK_SIZE-1)) + BLOCK_SIZE; - - void * ret = vm_allocate_pages(vas, (void *) addr, HEAP_INIT_SIZE, VM_PERM_USER_RW); - if(addr + HEAP_INIT_SIZE != (uint32_t) ret){ - kprintf("ERROR: vm_allocate_pages allocated a different amount than requested\n"); - return STATUS_FAIL; - } - - create_heap(heap, addr); - proc_allocator = heap; - vm_free_mapping(KERNEL_VAS, (void*) PROC_START); // ? - return STATUS_OK; -} - -uint32_t __mem_extend_proc_heap(uint32_t amt) { - struct vas* pvas = vm_get_current_vas(); - - uint32_t amt_added = 0; - while (amt_added < amt) - { - int retval = vm_allocate_page(pvas, (void*) PROC_START, VM_PERM_USER_RW); - vm_map_shared_memory(KERNEL_VAS, (void*)PROC_START, pvas, (void*)PROC_START, VM_PERM_USER_RW); - if (retval) { - kprintf("ERROR: vm_allocate_page returned %d\n", retval); - return STATUS_FAIL; - } - else{ - kprintf("Page allocated for process heap at %x:\n", PROC_START); + while(heap_end < (heap_start + HEAP_INIT_SIZE + PAGE_SIZE)) { + if (vm2_allocate_kernel_page(kernell1PageTable, heap_end, false) == NULL) { + FATAL("Allocation of the kernel heap went wrong!"); } - amt_added += BLOCK_SIZE; - proc_buffer_size += BLOCK_SIZE; + + heap_end += PAGE_SIZE; } - vm_free_mapping(KERNEL_VAS,(void*)PROC_START); - return amt_added; -} + assert(heap_end >= (heap_start + HEAP_INIT_SIZE)); -void* proc_allocate(uint32_t size) -{ - return heap_alloc(proc_allocator, size); -} + create_heap(heap, heap_start); + allocator = heap; -void proc_deallocate(void* ptr) -{ - return heap_free(proc_allocator, ptr); + INFO("Heap successfully initialized."); } void *allocate(uint32_t size) { @@ -180,10 +82,6 @@ heap_t * mem_get_allocator(){ return allocator; } -heap_t * mem_get_proc_allocator(){ - return proc_allocator; -} - uint32_t mem_get_heap_size(){ return allocator->end - allocator->start; } diff --git a/kernel/src/memory/mmap.c b/kernel/src/memory/mmap.c index 95c40d95..a0bab95b 100644 --- a/kernel/src/memory/mmap.c +++ b/kernel/src/memory/mmap.c @@ -21,31 +21,29 @@ int vm_build_free_frame_list(void *start, void *end); -volatile unsigned int * first_level_pt = (unsigned int *) (P_L1PTBASE + PAGE_TABLE_SIZE); -extern struct vm_free_list *vm_vas_free_list; -extern struct vm_free_list *vm_l1pt_free_list; -extern struct vm_free_list *vm_l2pt_free_list; +volatile unsigned int * first_level_pt __attribute__((deprecated)) = (unsigned int *) (P_L1PTBASE + PAGE_TABLE_SIZE) ; +//extern struct vm_free_list *vm_vas_free_list; +//extern struct vm_free_list *vm_l1pt_free_list; +//extern struct vm_free_list *vm_l2pt_free_list; bool mmapped = false; + // Must be called before mmap and after vm.c -void request_identity_mapped_section(size_t start_address, size_t megabytes) { - - if (mmapped) { - // TODO: Technically possible if we were to flush the cache - kprintf("Can only request identity mapping before mmap is called."); - panic(); - } - kprintf("Identity mapping %i megabyte(s) at 0x%x\n", megabytes, start_address); - - for (unsigned int i = 0; i < megabytes; i++) { - first_level_pt[(start_address + (i * 0x100000)) >> 20] = ((start_address + (i *0x100000)) & 0xFFF00000) | 0x0400 | 2; - } -} +//void request_identity_mapped_section(size_t start_address, size_t megabytes) { +// +// if (mmapped) { +// // TODO: Technically possible if we were to flush the cache +// kprintf("Can only request identity mapping before mmap is called."); +// panic(); +// } +// kprintf("Identity mapping %i megabyte(s) at 0x%x\n", megabytes, start_address); +// +// for (unsigned int i = 0; i < megabytes; i++) { +//// first_level_pt[(start_address + (i * 0x100000)) >> 20] = ((start_address + (i *0x100000)) & 0xFFF00000) | 0x0400 | 2; +// } +//} -void prepare_pagetable() { - memset((uint32_t *)first_level_pt,0, PAGE_TABLE_SIZE); -} // 0x00000000 // --- --- @@ -58,7 +56,7 @@ void mmap(void *p_bootargs) { kprintf("Boot arguments location: %X\n", p_bootargs); - kprintf("first_level_pt=%X\n", first_level_pt); +// kprintf("first_level_pt=%X\n", first_level_pt); // for (int i = 0; i < PAGE_TABLE_SIZE >> 2; i++) { // first_level_pt[i] = 0; @@ -71,25 +69,25 @@ void mmap(void *p_bootargs) { // 0x00000010 //1MB for static kernel data structures (stacks and l1 pt) - first_level_pt[V_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; +// first_level_pt[V_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; //first_level_pt[0xfff00000>>20] = first_level_pt[0xfff] = 0x0x7f04010 //map the kernel where its currently loaded in the same location temporarily //should be less than a MB - first_level_pt[P_KERNBASE >> 20] = 0 << 20 | 0x0400 | 2; +// first_level_pt[P_KERNBASE >> 20] = 0 << 20 | 0x0400 | 2; //also map it to high memory at 0xf0000000 (vpn = 3840) - first_level_pt[V_KERNBASE >> 20] = 0 << 20 | 0x0400 | 2; - first_level_pt[(V_KERNBASE + 0x100000) >> 20] = 0x100000 | 0x0400 | 2; // 0xf...; +// first_level_pt[V_KERNBASE >> 20] = 0 << 20 | 0x0400 | 2; +// first_level_pt[(V_KERNBASE + 0x100000) >> 20] = 0x100000 | 0x0400 | 2; // 0xf...; //map ~2MB of peripheral registers one-to-one // first_level_pt[PERIPHBASE >> 20] = PERIPHBASE | 0x0400 | 2; // PERIPHBASE + 1 MiB // first_level_pt[(PERIPHBASE + 0x100000) >> 20] = (PERIPHBASE + 0x100000) | 0x0400 | 2; // first_level_pt[(PERIPHBASE + 0x200000) >> 20] = (PERIPHBASE + 0x200000) | 0x0400 | 2; - first_level_pt[(0x20000000) >> 20] = (0x20000000) | 0x0400 | 2; - - first_level_pt[BCM2836BASE >> 20] = (BCM2836BASE & 0xFFF00000) | 0x0400 | 2; // TIMERBASE + 1 MiB - first_level_pt[(PERIPHBASE) >> 20] = (PERIPHBASE + 0x300000) | 0x0400 | 2; +// first_level_pt[(0x20000000) >> 20] = (0x20000000) | 0x0400 | 2; +// +// first_level_pt[BCM2836BASE >> 20] = (BCM2836BASE & 0xFFF00000) | 0x0400 | 2; // TIMERBASE + 1 MiB +// first_level_pt[(PERIPHBASE) >> 20] = (PERIPHBASE + 0x300000) | 0x0400 | 2; // TODO: re enable when we actually need it. 700mb seems a bit excessive though. @@ -99,7 +97,7 @@ void mmap(void *p_bootargs) { // first_level_pt[i] = pci_bus_addr | 0x0400 | 2; // pci_bus_addr += 0x100000; // } - request_identity_mapped_section(Gibibyte - 25 * Mibibyte, 20); +// request_identity_mapped_section(Gibibyte - 25 * Mebibyte, 20); // Quick coarse page table address //unsigned int coarse_page_table_address = P_L1PTBASE + 2*PAGE_TABLE_SIZE; @@ -108,12 +106,12 @@ void mmap(void *p_bootargs) { //remap 62MB of physical memory after the kernel // (KERNTOP to end of physical RAM (PMAPTOP)) // This is where we allocate frames from. Except for the first one. - unsigned int phys_addr = P_KERNTOP; +// unsigned int phys_addr = P_KERNTOP; // +1 to skip L1PTBASE - for (int i = (PMAPBASE >> 20); i < (PMAPTOP >> 20); i++) { - first_level_pt[i] = phys_addr | 0x0400 | 2; - phys_addr += 0x100000; - } +// for (int i = (PMAPBASE >> 20); i < (PMAPTOP >> 20); i++) { +// first_level_pt[i] = phys_addr | 0x0400 | 2; +// phys_addr += 0x100000; +// } // Fill in the coarse page table @@ -123,17 +121,17 @@ void mmap(void *p_bootargs) { //*(unsigned int*)coarse_page_table_address = phys_addr | 0x20 | 2; //os_printf("0x%X\n", *(unsigned int*)coarse_page_table_address); - first_level_pt[V_L1PTBASE >> 20] = P_L1PTBASE | 0x0400 | 2; +// first_level_pt[V_L1PTBASE >> 20] = P_L1PTBASE | 0x0400 | 2; // We have to empty out the first MB of that, so we can use it as an array of VASs // The first slot is actually the kernel's VAS - ((struct vas*) P_L1PTBASE)->l1_pagetable = (unsigned int*) (V_L1PTBASE + PAGE_TABLE_SIZE); //first_level_pt; - ((struct vas*) P_L1PTBASE)->l1_pagetable_phys = first_level_pt; - ((struct vas*) P_L1PTBASE)->next = 0x0; - vm_vas_free_list = (struct vm_free_list*) ((void*) vm_vas_free_list + sizeof(struct vas)); - vm_l1pt_free_list = (struct vm_free_list*) ((void*) vm_l1pt_free_list + PAGE_TABLE_SIZE); +// ((struct vas*) P_L1PTBASE)->l1_pagetable = (unsigned int*) (V_L1PTBASE + PAGE_TABLE_SIZE); //first_level_pt; +// ((struct vas*) P_L1PTBASE)->l1_pagetable_phys = first_level_pt; +// ((struct vas*) P_L1PTBASE)->next = 0x0; +// vm_vas_free_list = (struct vm_free_list*) ((void*) vm_vas_free_list + sizeof(struct vas)); +// vm_l1pt_free_list = (struct vm_free_list*) ((void*) vm_l1pt_free_list + PAGE_TABLE_SIZE); - unsigned int pt_addr = (unsigned int) first_level_pt; +// unsigned int pt_addr = (unsigned int) first_level_pt; /*CONTROL REGISTER * Enable MMU by setting 0 @@ -144,41 +142,41 @@ void mmap(void *p_bootargs) { * We disable high vectors, since low vectors work just fine. */ - asm volatile ( - // invalidate caches - "mcr p15, 0, %[r], c7, c7, 0\n" - // invalidate tlb - "mcr p15, 0, %[r], c8, c7, 0\n" - // data sync barrier - "mcr p15, 0, %[r], c7,c10, 4\n" - - // set domains - "mov r2, #0x01\n" -// "ldr r2, =0x55555555\n" // [added] full r/w to everyone - "mcr p15, 0, r2, c3, c0, 0\n" - - "mcr p15, 0, %[addr], c2, c0, 0\n" // Give the pagetable addr to the MMU - "mcr p15, 0, %[addr], c2, c0, 1\n" - - "mrc p15, 0, r3, c1, c0, 0\n" // Read p15 -// "mov r4, #0x1000 \n" -// "add r4, #0x7 \n" -// "orr r3, r4 \n" - "orr r3, #0x800000\n" // Enable Armv6 bit -// "orr r3, #0x1000\n" - "orr r3, r3, #0x1\n" // Enable MMU bit - "mcr p15, 0, r3, c1, c0, 0 \n" // Set p15 - : - : [addr] "r" (pt_addr), - [r] "r" (0x0) - ); - - mmapped = true; +// asm volatile ( +// // invalidate caches +// "mcr p15, 0, %[r], c7, c7, 0\n" +// // invalidate tlb +// "mcr p15, 0, %[r], c8, c7, 0\n" +// // data sync barrier +// "mcr p15, 0, %[r], c7,c10, 4\n" +// +// // set domains +// "mov r2, #0x01\n" +//// "ldr r2, =0x55555555\n" // [added] full r/w to everyone +// "mcr p15, 0, r2, c3, c0, 0\n" +// +// "mcr p15, 0, %[addr], c2, c0, 0\n" // Give the pagetable addr to the MMU +// "mcr p15, 0, %[addr], c2, c0, 1\n" +// +// "mrc p15, 0, r3, c1, c0, 0\n" // Read p15 +//// "mov r4, #0x1000 \n" +//// "add r4, #0x7 \n" +//// "orr r3, r4 \n" +// "orr r3, #0x800000\n" // Enable Armv6 bit +//// "orr r3, #0x1000\n" +// "orr r3, r3, #0x1\n" // Enable MMU bit +// "mcr p15, 0, r3, c1, c0, 0 \n" // Set p15 +// : +// : [addr] "r" (pt_addr), +// [r] "r" (0x0) +// ); + +// mmapped = true; // SemihostingCall(OSSpecific); // Build the free frame list - vm_build_free_frame_list((void*) PMAPBASE + 0x100000, (void*) PMAPTOP); //(void*)PMAPBASE+(unsigned int)((PMAPTOP)-(PMAPBASE))); +// vm_build_free_frame_list((void*) PMAPBASE + 0x100000, (void*) PMAPTOP); //(void*)PMAPBASE+(unsigned int)((PMAPTOP)-(PMAPBASE))); //restore register state asm volatile("pop {r0-r11}"); @@ -189,13 +187,13 @@ void mmap(void *p_bootargs) { // asm volatile("cpsie if"); asm volatile (".include \"src/memory/stacks.s\""); - void start2(uint32_t *p_bootargs); - kprintf("Location of start2: 0x%x\n", &start2); - //branch to proper kernel at start -// asm volatile("bl start2"); - - void * oldstart2 = start2; - void (*newstart2)(uint32_t *) = oldstart2 + V_KERNBASE; - - newstart2(p_bootargs); +// void start2(uint32_t *p_bootargs); +// kprintf("Location of start2: 0x%x\n", &start2); +// //branch to proper kernel at start +//// asm volatile("bl start2"); +// +// void * oldstart2 = start2; +// void (*newstart2)(uint32_t *) = oldstart2 + V_KERNBASE; +// +// newstart2(p_bootargs); } diff --git a/kernel/src/memory/vm/fastlz/6pack.c.old b/kernel/src/memory/vm/fastlz/6pack.c.old deleted file mode 100644 index 604b17d7..00000000 --- a/kernel/src/memory/vm/fastlz/6pack.c.old +++ /dev/null @@ -1,636 +0,0 @@ -/* - 6PACK - file compressor using FastLZ (lightning-fast compression library) - - Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -#include -#include -#include - -#define SIXPACK_VERSION_MAJOR 0 -#define SIXPACK_VERSION_MINOR 1 -#define SIXPACK_VERSION_REVISION 0 -#define SIXPACK_VERSION_STRING "snapshot 20070615" - -#include "fastlz.h.old" - -#undef PATH_SEPARATOR - -#if defined(MSDOS) || defined(__MSDOS__) || defined(MSDOS) -#define PATH_SEPARATOR '\\' -#endif - -#if defined(WIN32) || defined(__NT__) || defined(_WIN32) || defined(__WIN32__) -#define PATH_SEPARATOR '\\' -#if defined(__BORLANDC__) || defined(_MSC_VER) -#define inline __inline -#endif -#endif - -#ifndef PATH_SEPARATOR -#define PATH_SEPARATOR '/' -#endif - -#undef SIXPACK_BENCHMARK_WIN32 -#if defined(WIN32) || defined(__NT__) || defined(_WIN32) || defined(__WIN32__) -#if defined(_MSC_VER) || defined(__GNUC__) -#define SIXPACK_BENCHMARK_WIN32 -#include -#endif -#endif - -/* magic identifier for 6pack file */ -static unsigned char sixpack_magic[8] = {137, '6', 'P', 'K', 13, 10, 26, 10}; - -#define BLOCK_SIZE (2*64*1024) - -/* prototypes */ -static inline unsigned long update_adler32(unsigned long checksum, const void *buf, int len); -void usage(void); -int detect_magic(FILE *f); -void write_magic(FILE *f); -void write_chunk_header(FILE* f, int id, int options, unsigned long size, -unsigned long checksum, unsigned long extra); -unsigned long block_compress(const unsigned char* input, unsigned long length, unsigned char* output); -int pack_file_compressed(const char* input_file, int method, int level, FILE* f); -int pack_file(int compress_level, const char* input_file, const char* output_file); - -/* for Adler-32 checksum algorithm, see RFC 1950 Section 8.2 */ -#define ADLER32_BASE 65521 -static inline unsigned long update_adler32(unsigned long checksum, const void *buf, int len) -{ - const unsigned char* ptr = (const unsigned char*)buf; - unsigned long s1 = checksum & 0xffff; - unsigned long s2 = (checksum >> 16) & 0xffff; - - while(len>0) - { - unsigned k = len < 5552 ? len : 5552; - len -= k; - - while(k >= 8) - { - s1 += *ptr++; s2 += s1; - s1 += *ptr++; s2 += s1; - s1 += *ptr++; s2 += s1; - s1 += *ptr++; s2 += s1; - s1 += *ptr++; s2 += s1; - s1 += *ptr++; s2 += s1; - s1 += *ptr++; s2 += s1; - s1 += *ptr++; s2 += s1; - k -= 8; - } - - while(k-- > 0) - { - s1 += *ptr++; s2 += s1; - } - s1 = s1 % ADLER32_BASE; - s2 = s2 % ADLER32_BASE; - } - return (s2 << 16) + s1; -} - -void usage(void) -{ - printf("6pack: high-speed file compression tool\n"); - printf("Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)\n"); - printf("\n"); - printf("Usage: 6pack [options] input-file output-file\n"); - printf("\n"); - printf("Options:\n"); - printf(" -1 compress faster\n"); - printf(" -2 compress better\n"); - printf(" -v show program version\n"); -#ifdef SIXPACK_BENCHMARK_WIN32 - printf(" -mem check in-memory compression speed\n"); -#endif - printf("\n"); -} - -/* return non-zero if magic sequence is detected */ -/* warning: reset the read pointer to the beginning of the file */ -int detect_magic(FILE *f) -{ - unsigned char buffer[8]; - size_t bytes_read; - int c; - - fseek(f, SEEK_SET, 0); - bytes_read = fread(buffer, 1, 8, f); - fseek(f, SEEK_SET, 0); - if(bytes_read < 8) - return 0; - - for(c = 0; c < 8; c++) - if(buffer[c] != sixpack_magic[c]) - return 0; - - return -1; -} - -void write_magic(FILE *f) -{ - fwrite(sixpack_magic, 8, 1, f); -} - -void write_chunk_header(FILE* f, int id, int options, unsigned long size, - unsigned long checksum, unsigned long extra) -{ - unsigned char buffer[16]; - - buffer[0] = id & 255; - buffer[1] = id >> 8; - buffer[2] = options & 255; - buffer[3] = options >> 8; - buffer[4] = size & 255; - buffer[5] = (size >> 8) & 255; - buffer[6] = (size >> 16) & 255; - buffer[7] = (size >> 24) & 255; - buffer[8] = checksum & 255; - buffer[9] = (checksum >> 8) & 255; - buffer[10] = (checksum >> 16) & 255; - buffer[11] = (checksum >> 24) & 255; - buffer[12] = extra & 255; - buffer[13] = (extra >> 8) & 255; - buffer[14] = (extra >> 16) & 255; - buffer[15] = (extra >> 24) & 255; - - fwrite(buffer, 16, 1, f); -} - -int pack_file_compressed(const char* input_file, int method, int level, FILE* f) -{ - FILE* in; - unsigned long fsize; - unsigned long checksum; - const char* shown_name; - unsigned char buffer[BLOCK_SIZE]; - unsigned char result[BLOCK_SIZE*2]; /* FIXME twice is too large */ - unsigned char progress[20]; - int c; - unsigned long percent; - unsigned long total_read; - unsigned long total_compressed; - int chunk_size; - - /* sanity check */ - in = fopen(input_file, "rb"); - if(!in) - { - printf("Error: could not open %s\n", input_file); - return -1; - } - - /* find size of the file */ - fseek(in, 0, SEEK_END); - fsize = ftell(in); - fseek(in, 0, SEEK_SET); - - /* already a 6pack archive? */ - if(detect_magic(in)) - { - printf("Error: file %s is already a 6pack archive!\n", input_file); - fclose(in); - return -1; - } - - /* truncate directory prefix, e.g. "foo/bar/FILE.txt" becomes "FILE.txt" */ - shown_name = input_file + strlen(input_file) - 1; - while(shown_name > input_file) - if(*(shown_name-1) == PATH_SEPARATOR) - break; - else - shown_name--; - - /* chunk for File Entry */ - buffer[0] = fsize & 255; - buffer[1] = (fsize >> 8) & 255; - buffer[2] = (fsize >> 16) & 255; - buffer[3] = (fsize >> 24) & 255; -#if 0 - buffer[4] = (fsize >> 32) & 255; - buffer[5] = (fsize >> 40) & 255; - buffer[6] = (fsize >> 48) & 255; - buffer[7] = (fsize >> 56) & 255; -#else - /* because fsize is only 32-bit */ - buffer[4] = 0; - buffer[5] = 0; - buffer[6] = 0; - buffer[7] = 0; -#endif - buffer[8] = (strlen(shown_name)+1) & 255; - buffer[9] = (strlen(shown_name)+1) >> 8; - checksum = 1L; - checksum = update_adler32(checksum, buffer, 10); - checksum = update_adler32(checksum, shown_name, strlen(shown_name)+1); - write_chunk_header(f, 1, 0, 10+strlen(shown_name)+1, checksum, 0); - fwrite(buffer, 10, 1, f); - fwrite(shown_name, strlen(shown_name)+1, 1, f); - total_compressed = 16 + 10 + strlen(shown_name)+1; - - /* for progress status */ - memset(progress, ' ', 20); - if(strlen(shown_name) < 16) - for(c = 0; c < (int)strlen(shown_name); c++) - progress[c] = shown_name[c]; - else - { - for(c = 0; c < 13; c++) - progress[c] = shown_name[c]; - progress[13] = '.'; - progress[14] = '.'; - progress[15] = ' '; - } - progress[16] = '['; - progress[17] = 0; - printf("%s", progress); - for(c = 0; c < 50; c++) - printf("."); - printf("]\r"); - printf("%s", progress); - - /* read file and place in archive */ - total_read = 0; - percent = 0; - for(;;) - { - int compress_method = method; - int last_percent = (int)percent; - size_t bytes_read = fread(buffer, 1, BLOCK_SIZE, in); - if(bytes_read == 0) - break; - total_read += bytes_read; - - /* for progress */ - if(fsize < (1<<24)) - percent = total_read * 100 / fsize; - else - percent = total_read/256 * 100 / (fsize >>8); - percent >>= 1; - while(last_percent < (int)percent) - { - printf("#"); - last_percent++; - } - - /* too small, don't bother to compress */ - if(bytes_read < 32) - compress_method = 0; - - /* write to output */ - switch(compress_method) - { - /* FastLZ */ - case 1: - chunk_size = fastlz_compress_level(level, buffer, bytes_read, result); - checksum = update_adler32(1L, result, chunk_size); - write_chunk_header(f, 17, 1, chunk_size, checksum, bytes_read); - fwrite(result, 1, chunk_size, f); - total_compressed += 16; - total_compressed += chunk_size; - break; - - /* uncompressed, also fallback method */ - case 0: - default: - checksum = 1L; - checksum = update_adler32(checksum, buffer, bytes_read); - write_chunk_header(f, 17, 0, bytes_read, checksum, bytes_read); - fwrite(buffer, 1, bytes_read, f); - total_compressed += 16; - total_compressed += bytes_read; - break; - } - } - - fclose(in); - if(total_read != fsize) - { - printf("\n"); - printf("Error: reading %s failed!\n", input_file); - return -1; - } - else - { - printf("] "); - if(total_compressed < fsize) - { - if(fsize < (1<<20)) - percent = total_compressed * 1000 / fsize; - else - percent = total_compressed/256 * 1000 / (fsize >>8); - percent = 1000 - percent; - printf("%2d.%d%% saved", (int)percent/10, (int)percent%10); - } - printf("\n"); - } - - return 0; -} - -int pack_file(int compress_level, const char* input_file, const char* output_file) -{ - FILE* f; - int result; - - f = fopen(output_file, "rb"); - if(f) - { - fclose(f); - printf("Error: file %s already exists. Aborted.\n\n", output_file); - return -1; - } - - f = fopen(output_file, "wb"); - if(!f) - { - printf("Error: could not create %s. Aborted.\n\n", output_file); - return -1; - } - - write_magic(f); - - result = pack_file_compressed(input_file, 1, compress_level, f); - fclose(f); - - return result; -} - -#ifdef SIXPACK_BENCHMARK_WIN32 -int benchmark_speed(int compress_level, const char* input_file); - -int benchmark_speed(int compress_level, const char* input_file) -{ - FILE* in; - unsigned long fsize; - unsigned long maxout; - const char* shown_name; - unsigned char* buffer; - unsigned char* result; - size_t bytes_read; - - /* sanity check */ - in = fopen(input_file, "rb"); - if(!in) - { - printf("Error: could not open %s\n", input_file); - return -1; - } - - /* find size of the file */ - fseek(in, 0, SEEK_END); - fsize = ftell(in); - fseek(in, 0, SEEK_SET); - - /* already a 6pack archive? */ - if(detect_magic(in)) - { - printf("Error: no benchmark for 6pack archive!\n"); - fclose(in); - return -1; - } - - /* truncate directory prefix, e.g. "foo/bar/FILE.txt" becomes "FILE.txt" */ - shown_name = input_file + strlen(input_file) - 1; - while(shown_name > input_file) - if(*(shown_name-1) == PATH_SEPARATOR) - break; - else - shown_name--; - - maxout = 1.05 * fsize; - maxout = (maxout < 66) ? 66 : maxout; - buffer = (unsigned char*)malloc(fsize); - result = (unsigned char*)malloc(maxout); - if(!buffer || !result) - { - printf("Error: not enough memory!\n"); - free(buffer); - free(result); - fclose(in); - return -1; - } - - printf("Reading source file....\n"); - bytes_read = fread(buffer, 1, fsize, in); - if(bytes_read != fsize) - { - printf("Error reading file %s!\n", shown_name); - printf("Read %d bytes, expecting %d bytes\n", bytes_read, fsize); - free(buffer); - free(result); - fclose(in); - return -1; - } - -/* shamelessly copied from QuickLZ 1.20 test program */ - { - unsigned int j, y; - size_t i, u = 0; - double mbs, fastest; - unsigned long compressed_size; - - printf("Setting HIGH_PRIORITY_CLASS...\n"); - SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); - - printf("Benchmarking FastLZ Level %d, please wait...\n", compress_level); - - i = bytes_read; - fastest = 0.0; - for (j = 0; j < 3; j++) - { - y = 0; - mbs = GetTickCount(); - while(GetTickCount() == mbs); - mbs = GetTickCount(); - while(GetTickCount() - mbs < 3000) /* 1% accuracy with 18.2 timer */ - { - u = fastlz_compress_level(compress_level, buffer, bytes_read, result); - y++; - } - - mbs = ((double)i*(double)y)/((double)(GetTickCount() - mbs)/1000.)/1000000.; - /*printf(" %.1f Mbyte/s ", mbs);*/ - if (fastest < mbs) - fastest = mbs; - } - - printf("\nCompressed %d bytes into %d bytes (%.1f%%) at %.1f Mbyte/s.\n", (unsigned int)i, (unsigned int)u, (double)u/(double)i*100., fastest); - -#if 1 - fastest = 0.0; - compressed_size = u; - for (j = 0; j < 3; j++) - { - y = 0; - mbs = GetTickCount(); - while(GetTickCount() == mbs); - mbs = GetTickCount(); - while(GetTickCount() - mbs < 3000) /* 1% accuracy with 18.2 timer */ - { - u = fastlz_decompress(result, compressed_size, buffer, bytes_read); - y++; - } - - mbs = ((double)i*(double)y)/((double)(GetTickCount() - mbs)/1000.)/1000000.; - /*printf(" %.1f Mbyte/s ", mbs);*/ - if (fastest < mbs) - fastest = mbs; - } - - printf("\nDecompressed at %.1f Mbyte/s.\n\n(1 MB = 1000000 byte)\n", fastest); -#endif - } - - fclose(in); - return 0; -} -#endif /* SIXPACK_BENCHMARK_WIN32 */ - - -int main(int argc, char** argv) -{ - int i; - int compress_level; - int benchmark; - char* input_file; - char* output_file; - - /* show help with no argument at all*/ - if(argc == 1) - { - usage(); - return 0; - } - - /* default compression level, not the fastest */ - compress_level = 2; - - /* do benchmark only when explicitly specified */ - benchmark = 0; - - /* no file is specified */ - input_file = 0; - output_file = 0; - - for(i = 1; i <= argc; i++) - { - char* argument = argv[i]; - - if(!argument) - continue; - - /* display help on usage */ - if(!strcmp(argument, "-h") || !strcmp(argument, "--help")) - { - usage(); - return 0; - } - - /* check for version information */ - if(!strcmp(argument, "-v") || !strcmp(argument, "--version")) - { - printf("6pack: high-speed file compression tool\n"); - printf("Version %s (using FastLZ %s)\n", - SIXPACK_VERSION_STRING, FASTLZ_VERSION_STRING); - printf("Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)\n"); - printf("\n"); - return 0; - } - - /* test compression speed? */ - if(!strcmp(argument, "-mem")) - { - benchmark = 1; - continue; - } - - /* compression level */ - if(!strcmp(argument, "-1") || !strcmp(argument, "--fastest")) - { - compress_level = 1; - continue; - } - if(!strcmp(argument, "-2")) - { - compress_level = 2; - continue; - } - - /* unknown option */ - if(argument[0] == '-') - { - printf("Error: unknown option %s\n\n", argument); - printf("To get help on usage:\n"); - printf(" 6pack --help\n\n"); - return -1; - } - - /* first specified file is input */ - if(!input_file) - { - input_file = argument; - continue; - } - - /* next specified file is output */ - if(!output_file) - { - output_file = argument; - continue; - } - - /* files are already specified */ - printf("Error: unknown option %s\n\n", argument); - printf("To get help on usage:\n"); - printf(" 6pack --help\n\n"); - return -1; - } - - if(!input_file) - { - printf("Error: input file is not specified.\n\n"); - printf("To get help on usage:\n"); - printf(" 6pack --help\n\n"); - return -1; - } - - if(!output_file && !benchmark) - { - printf("Error: output file is not specified.\n\n"); - printf("To get help on usage:\n"); - printf(" 6pack --help\n\n"); - return -1; - } - -#ifdef SIXPACK_BENCHMARK_WIN32 - if(benchmark) - return benchmark_speed(compress_level, input_file); - else -#endif - return pack_file(compress_level, input_file, output_file); - - /* unreachable */ - return 0; -} diff --git a/kernel/src/memory/vm/fastlz/6unpack.c.old b/kernel/src/memory/vm/fastlz/6unpack.c.old deleted file mode 100644 index 6527cbcc..00000000 --- a/kernel/src/memory/vm/fastlz/6unpack.c.old +++ /dev/null @@ -1,478 +0,0 @@ -/* - 6PACK - file compressor using FastLZ (lightning-fast compression library) - - Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -#include -#include -#include - -#define SIXPACK_VERSION_MAJOR 0 -#define SIXPACK_VERSION_MINOR 1 -#define SIXPACK_VERSION_REVISION 0 -#define SIXPACK_VERSION_STRING "0.1.0" - -#include "fastlz.h.old" - -#if defined(WIN32) || defined(__NT__) || defined(_WIN32) || defined(__WIN32__) -#if defined(__BORLANDC__) || defined(_MSC_VER) -#define inline __inline -#endif -#endif - -/* magic identifier for 6pack file */ -static unsigned char sixpack_magic[8] = {137, '6', 'P', 'K', 13, 10, 26, 10}; - -#define BLOCK_SIZE 65536 - -/* prototypes */ -static inline unsigned long update_adler32(unsigned long checksum, const void *buf, int len); -void usage(void); -int detect_magic(FILE *f); -static inline unsigned long readU16(const unsigned char* ptr); -static inline unsigned long readU32(const unsigned char* ptr); -void read_chunk_header(FILE* f, int* id, int* options, unsigned long* size, -unsigned long* checksum, unsigned long* extra); -int unpack_file(const char* archive_file); - -/* for Adler-32 checksum algorithm, see RFC 1950 Section 8.2 */ -#define ADLER32_BASE 65521 -static inline unsigned long update_adler32(unsigned long checksum, const void *buf, int len) -{ - const unsigned char* ptr = (const unsigned char*)buf; - unsigned long s1 = checksum & 0xffff; - unsigned long s2 = (checksum >> 16) & 0xffff; - - while(len>0) - { - unsigned k = len < 5552 ? len : 5552; - len -= k; - - while(k >= 8) - { - s1 += *ptr++; s2 += s1; - s1 += *ptr++; s2 += s1; - s1 += *ptr++; s2 += s1; - s1 += *ptr++; s2 += s1; - s1 += *ptr++; s2 += s1; - s1 += *ptr++; s2 += s1; - s1 += *ptr++; s2 += s1; - s1 += *ptr++; s2 += s1; - k -= 8; - } - - while(k-- > 0) - { - s1 += *ptr++; s2 += s1; - } - s1 = s1 % ADLER32_BASE; - s2 = s2 % ADLER32_BASE; - } - return (s2 << 16) + s1; -} - -void usage(void) -{ - printf("6unpack: uncompress 6pack archive\n"); - printf("Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)\n"); - printf("\n"); - printf("Usage: 6unpack archive-file\n"); - printf("\n"); -} - -/* return non-zero if magic sequence is detected */ -/* warning: reset the read pointer to the beginning of the file */ -int detect_magic(FILE *f) -{ - unsigned char buffer[8]; - size_t bytes_read; - int c; - - fseek(f, SEEK_SET, 0); - bytes_read = fread(buffer, 1, 8, f); - fseek(f, SEEK_SET, 0); - if(bytes_read < 8) - return 0; - - for(c = 0; c < 8; c++) - if(buffer[c] != sixpack_magic[c]) - return 0; - - return -1; -} - -static inline unsigned long readU16( const unsigned char* ptr ) -{ - return ptr[0]+(ptr[1]<<8); -} - -static inline unsigned long readU32( const unsigned char* ptr ) -{ - return ptr[0]+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24); -} - -void read_chunk_header(FILE* f, int* id, int* options, unsigned long* size, -unsigned long* checksum, unsigned long* extra) -{ - unsigned char buffer[16]; - fread(buffer, 1, 16, f); - - *id = readU16(buffer) & 0xffff; - *options = readU16(buffer+2) & 0xffff; - *size = readU32(buffer+4) & 0xffffffff; - *checksum = readU32(buffer+8) & 0xffffffff; - *extra = readU32(buffer+12) & 0xffffffff; -} - -int unpack_file(const char* input_file) -{ - FILE* in; - unsigned long fsize; - int c; - unsigned long percent; - unsigned char progress[20]; - int chunk_id; - int chunk_options; - unsigned long chunk_size; - unsigned long chunk_checksum; - unsigned long chunk_extra; - unsigned char buffer[BLOCK_SIZE]; - unsigned long checksum; - - unsigned long decompressed_size; - unsigned long total_extracted; - int name_length; - char* output_file; - FILE* f; - - unsigned char* compressed_buffer; - unsigned char* decompressed_buffer; - unsigned long compressed_bufsize; - unsigned long decompressed_bufsize; - - /* sanity check */ - in = fopen(input_file, "rb"); - if(!in) - { - printf("Error: could not open %s\n", input_file); - return -1; - } - - /* find size of the file */ - fseek(in, 0, SEEK_END); - fsize = ftell(in); - fseek(in, 0, SEEK_SET); - - /* not a 6pack archive? */ - if(!detect_magic(in)) - { - fclose(in); - printf("Error: file %s is not a 6pack archive!\n", input_file); - return -1; - } - - printf("Archive: %s", input_file); - - /* position of first chunk */ - fseek(in, 8, SEEK_SET); - - /* initialize */ - output_file = 0; - f = 0; - total_extracted = 0; - decompressed_size = 0; - percent = 0; - compressed_buffer = 0; - decompressed_buffer = 0; - compressed_bufsize = 0; - decompressed_bufsize = 0; - - /* common loop */ - for(;;) - { - /* end of file? */ - size_t pos = ftell(in); - if(pos >= fsize) - break; - - read_chunk_header(in, &chunk_id, &chunk_options, - &chunk_size, &chunk_checksum, &chunk_extra); - - if((chunk_id == 1) && (chunk_size > 10) && (chunk_size < BLOCK_SIZE)) - { - /* close current file, if any */ - printf("\n"); - free(output_file); - output_file = 0; - if(f) - fclose(f); - - /* file entry */ - fread(buffer, 1, chunk_size, in); - checksum = update_adler32(1L, buffer, chunk_size); - if(checksum != chunk_checksum) - { - free(output_file); - output_file = 0; - fclose(in); - printf("\nError: checksum mismatch!\n"); - printf("Got %08lX Expecting %08lX\n", checksum, chunk_checksum); - return -1; - } - - decompressed_size = readU32(buffer); - total_extracted = 0; - percent = 0; - - /* get file to extract */ - name_length = (int)readU16(buffer+8); - if(name_length > (int)chunk_size - 10) - name_length = chunk_size - 10; - output_file = (char*)malloc(name_length+1); - memset(output_file, 0, name_length+1); - for(c = 0; c < name_length; c++) - output_file[c] = buffer[10+c]; - - /* check if already exists */ - f = fopen(output_file, "rb"); - if(f) - { - fclose(f); - printf("File %s already exists. Skipped.\n", output_file); - free(output_file); - output_file = 0; - f = 0; - } - else - { - /* create the file */ - f = fopen(output_file, "wb"); - if(!f) - { - printf("Can't create file %s. Skipped.\n", output_file); - free(output_file); - output_file = 0; - f = 0; - } - else - { - /* for progress status */ - printf("\n"); - memset(progress, ' ', 20); - if(strlen(output_file) < 16) - for(c = 0; c < (int)strlen(output_file); c++) - progress[c] = output_file[c]; - else - { - for(c = 0; c < 13; c++) - progress[c] = output_file[c]; - progress[13] = '.'; - progress[14] = '.'; - progress[15] = ' '; - } - progress[16] = '['; - progress[17] = 0; - printf("%s", progress); - for(c = 0; c < 50; c++) - printf("."); - printf("]\r"); - printf("%s", progress); - } - } - } - - if((chunk_id == 17) && f && output_file && decompressed_size) - { - unsigned long remaining; - - /* uncompressed */ - switch(chunk_options) - { - /* stored, simply copy to output */ - case 0: - /* read one block at at time, write and update checksum */ - total_extracted += chunk_size; - remaining = chunk_size; - checksum = 1L; - for(;;) - { - unsigned long r = (BLOCK_SIZE < remaining) ? BLOCK_SIZE: remaining; - size_t bytes_read = fread(buffer, 1, r, in); - if(bytes_read == 0) - break; - fwrite(buffer, 1, bytes_read, f); - checksum = update_adler32(checksum, buffer, bytes_read); - remaining -= bytes_read; - } - - /* verify everything is written correctly */ - if(checksum != chunk_checksum) - { - fclose(f); - f = 0; - free(output_file); - output_file = 0; - printf("\nError: checksum mismatch. Aborted.\n"); - printf("Got %08lX Expecting %08lX\n", checksum, chunk_checksum); - } - break; - - /* compressed using FastLZ */ - case 1: - /* enlarge input buffer if necessary */ - if(chunk_size > compressed_bufsize) - { - compressed_bufsize = chunk_size; - free(compressed_buffer); - compressed_buffer = (unsigned char*)malloc(compressed_bufsize); - } - - /* enlarge output buffer if necessary */ - if(chunk_extra > decompressed_bufsize) - { - decompressed_bufsize = chunk_extra; - free(decompressed_buffer); - decompressed_buffer = (unsigned char*)malloc(decompressed_bufsize); - } - - /* read and check checksum */ - fread(compressed_buffer, 1, chunk_size, in); - checksum = update_adler32(1L, compressed_buffer, chunk_size); - total_extracted += chunk_extra; - - /* verify that the chunk data is correct */ - if(checksum != chunk_checksum) - { - fclose(f); - f = 0; - free(output_file); - output_file = 0; - printf("\nError: checksum mismatch. Skipped.\n"); - printf("Got %08lX Expecting %08lX\n", checksum, chunk_checksum); - } - else - { - /* decompress and verify */ - remaining = fastlz_decompress(compressed_buffer, chunk_size, decompressed_buffer, chunk_extra); - if(remaining != chunk_extra) - { - fclose(f); - f = 0; - free(output_file); - output_file = 0; - printf("\nError: decompression failed. Skipped.\n"); - } - else - fwrite(decompressed_buffer, 1, chunk_extra, f); - } - break; - - default: - printf("\nError: unknown compression method (%d)\n", chunk_options); - fclose(f); - f = 0; - free(output_file); - output_file = 0; - break; - } - - /* for progress, if everything is fine */ - if(f) - { - int last_percent = (int)percent; - if(decompressed_size < (1<<24)) - percent = total_extracted * 100 / decompressed_size; - else - percent = total_extracted / 256 * 100 / (decompressed_size >>8); - percent >>= 1; - while(last_percent < (int)percent) - { - printf("#"); - last_percent++; - } - } - } - - /* position of next chunk */ - fseek(in, pos + 16 + chunk_size, SEEK_SET); - } - printf("\n\n"); - - /* free allocated stuff */ - free(compressed_buffer); - free(decompressed_buffer); - free(output_file); - - /* close working files */ - if(f) - fclose(f); - fclose(in); - - /* so far so good */ - return 0; -} - -int main(int argc, char** argv) -{ - int i; - const char* archive_file; - - /* show help with no argument at all*/ - if(argc == 1) - { - usage(); - return 0; - } - - /* check for help on usage */ - for(i = 1; i <= argc; i++) - if(argv[i]) - if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) - { - usage(); - return 0; - } - - /* check for version information */ - for(i = 1; i <= argc; i++) - if(argv[i]) - if(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) - { - printf("6unpack: high-speed file compression tool\n"); - printf("Version %s (using FastLZ %s)\n", - SIXPACK_VERSION_STRING, FASTLZ_VERSION_STRING); - printf("Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)\n"); - printf("\n"); - return 0; - } - - /* needs at least two arguments */ - if(argc <= 1) - { - usage(); - return 0; - } - - archive_file = argv[1]; - - return unpack_file(archive_file); -} diff --git a/kernel/src/memory/vm/fastlz/LICENSE b/kernel/src/memory/vm/fastlz/LICENSE deleted file mode 100644 index 4a6abd6a..00000000 --- a/kernel/src/memory/vm/fastlz/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -FastLZ - lightning-fast lossless compression library - -Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) -Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) -Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - diff --git a/kernel/src/memory/vm/fastlz/README.TXT b/kernel/src/memory/vm/fastlz/README.TXT deleted file mode 100644 index 581e9e8a..00000000 --- a/kernel/src/memory/vm/fastlz/README.TXT +++ /dev/null @@ -1,75 +0,0 @@ -FastLZ - lightning-fast lossless compression library - -Author: Ariya Hidayat -Official website: http://www.fastlz.org - -FastLZ is distributed using the MIT license, see file LICENSE -for details. - -FastLZ consists of two files: fastlz.h and fastlz.c. Just add these -files to your project in order to use FastLZ. For information on -compression and decompression routines, see fastlz.h. - -A simple file compressor called 6pack is included as an example -on how to use FastLZ. The corresponding decompressor is 6unpack. - -To compile using GCC: - - gcc -o 6pack 6pack.c fastlz.c - gcc -o 6unpack 6unpack.c fastlz.c - -To compile using MinGW: - - mingw32-gcc -o 6pack 6pack.c fastlz.c - mingw32-gcc -o 6unpack 6unpack.c fastlz.c - -To compile using Microsoft Visual C++: - - cl 6pack.c fastlz.c - cl 6unpack.c fastlz.c - -To compile using Borland C++: - - bcc32 6pack.c fastlz.c - bcc32 6unpack.c fastlz.c - -To compile using OpenWatcom C/C++: - - cl386 6pack.c fastlz.c - cl386 6unpack.c fastlz.c - -To compile using Intel C++ compiler for Windows: - - icl 6pack.c fastlz.c - icl 6unpack.c fastlz.c - -To compile using Intel C++ compiler for Linux: - - icc -o 6pack 6pack.c fastlz.c - icc -o 6unpack 6unpack.c fastlz.c - -To compile 6pack using LCC-Win32: - - lc 6pack.c fastlz.c - lc 6unpack.c fastlz.c - -To compile 6pack using Pelles C: - - pocc 6pack.c - pocc 6unpack.c - pocc fastlz.c - polink 6pack.obj fastlz.obj - polink 6unpack.obj fastlz.obj - -For speed optimization, always use proper compile flags for optimization options. -Typical compiler flags are given below: - -* GCC (pre 4.2): -march=pentium -O3 -fomit-frame-pointer -mtune=pentium -* GCC 4.2 or later: -march=pentium -O3 -fomit-frame-pointer -mtune=generic -* Digital Mars C/C++: -o+all -5 -* Intel C++ (Windows): /O3 /Qipo -* Intel C++ (Linux): -O2 -march=pentium -mtune=pentium -* Borland C++: -O2 -5 -* LCC-Win32: -O -* Pelles C: /O2 - diff --git a/kernel/src/memory/vm/fastlz/fastlz.c.old b/kernel/src/memory/vm/fastlz/fastlz.c.old deleted file mode 100644 index 0e7a2ae4..00000000 --- a/kernel/src/memory/vm/fastlz/fastlz.c.old +++ /dev/null @@ -1,551 +0,0 @@ -/* - FastLZ - lightning-fast lossless compression library - - Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) - Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) - Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -#if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) - -/* - * Always check for bound when decompressing. - * Generally it is best to leave it defined. - */ -#define FASTLZ_SAFE - -/* - * Give hints to the compiler for branch prediction optimization. - */ -#if defined(__GNUC__) && (__GNUC__ > 2) -#define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1)) -#define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0)) -#else -#define FASTLZ_EXPECT_CONDITIONAL(c) (c) -#define FASTLZ_UNEXPECT_CONDITIONAL(c) (c) -#endif - -/* - * Use inlined functions for supported systems. - */ -#if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C) -#define FASTLZ_INLINE inline -#elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__) -#define FASTLZ_INLINE __inline -#else -#define FASTLZ_INLINE -#endif - -/* - * Prevent accessing more than 8-bit at once, except on x86 architectures. - */ -#if !defined(FASTLZ_STRICT_ALIGN) -#define FASTLZ_STRICT_ALIGN -#if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */ -#undef FASTLZ_STRICT_ALIGN -#elif defined(__i486__) || defined(__i586__) || defined(__i686__) /* GNU C */ -#undef FASTLZ_STRICT_ALIGN -#elif defined(_M_IX86) /* Intel, MSVC */ -#undef FASTLZ_STRICT_ALIGN -#elif defined(__386) -#undef FASTLZ_STRICT_ALIGN -#elif defined(_X86_) /* MinGW */ -#undef FASTLZ_STRICT_ALIGN -#elif defined(__I86__) /* Digital Mars */ -#undef FASTLZ_STRICT_ALIGN -#endif -#endif - -/* - * FIXME: use preprocessor magic to set this on different platforms! - */ -typedef unsigned char flzuint8; -typedef unsigned short flzuint16; -typedef unsigned int flzuint32; - -/* prototypes */ -int fastlz_compress(const void* input, int length, void* output); -int fastlz_compress_level(int level, const void* input, int length, void* output); -int fastlz_decompress(const void* input, int length, void* output, int maxout); - -#define MAX_COPY 32 -#define MAX_LEN 264 /* 256 + 8 */ -#define MAX_DISTANCE 8192 - -#if !defined(FASTLZ_STRICT_ALIGN) -#define FASTLZ_READU16(p) *((const flzuint16*)(p)) -#else -#define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8) -#endif - -#define HASH_LOG 13 -#define HASH_SIZE (1<< HASH_LOG) -#define HASH_MASK (HASH_SIZE-1) -#define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; } - -#undef FASTLZ_LEVEL -#define FASTLZ_LEVEL 1 - -#undef FASTLZ_COMPRESSOR -#undef FASTLZ_DECOMPRESSOR -#define FASTLZ_COMPRESSOR fastlz1_compress -#define FASTLZ_DECOMPRESSOR fastlz1_decompress -static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); -static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); -#include "fastlz.c.old" - -#undef FASTLZ_LEVEL -#define FASTLZ_LEVEL 2 - -#undef MAX_DISTANCE -#define MAX_DISTANCE 8191 -#define MAX_FARDISTANCE (65535+MAX_DISTANCE-1) - -#undef FASTLZ_COMPRESSOR -#undef FASTLZ_DECOMPRESSOR -#define FASTLZ_COMPRESSOR fastlz2_compress -#define FASTLZ_DECOMPRESSOR fastlz2_decompress -static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); -static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); -#include "fastlz.c.old" - -int fastlz_compress(const void* input, int length, void* output) -{ - /* for short block, choose fastlz1 */ - if(length < 65536) - return fastlz1_compress(input, length, output); - - /* else... */ - return fastlz2_compress(input, length, output); -} - -int fastlz_decompress(const void* input, int length, void* output, int maxout) -{ - /* magic identifier for compression level */ - int level = ((*(const flzuint8*)input) >> 5) + 1; - - if(level == 1) - return fastlz1_decompress(input, length, output, maxout); - if(level == 2) - return fastlz2_decompress(input, length, output, maxout); - - /* unknown level, trigger error */ - return 0; -} - -int fastlz_compress_level(int level, const void* input, int length, void* output) -{ - if(level == 1) - return fastlz1_compress(input, length, output); - if(level == 2) - return fastlz2_compress(input, length, output); - - return 0; -} - -#else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ - -static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output) -{ - const flzuint8* ip = (const flzuint8*) input; - const flzuint8* ip_bound = ip + length - 2; - const flzuint8* ip_limit = ip + length - 12; - flzuint8* op = (flzuint8*) output; - - const flzuint8* htab[HASH_SIZE]; - const flzuint8** hslot; - flzuint32 hval; - - flzuint32 copy; - - /* sanity check */ - if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4)) - { - if(length) - { - /* create literal copy only */ - *op++ = length-1; - ip_bound++; - while(ip <= ip_bound) - *op++ = *ip++; - return length+1; - } - else - return 0; - } - - /* initializes hash table */ - for (hslot = htab; hslot < htab + HASH_SIZE; hslot++) - *hslot = ip; - - /* we start with literal copy */ - copy = 2; - *op++ = MAX_COPY-1; - *op++ = *ip++; - *op++ = *ip++; - - /* common loop */ - while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) - { - const flzuint8* ref; - flzuint32 distance; - - /* minimum match length */ - flzuint32 len = 3; - - /* comparison starting-point */ - const flzuint8* anchor = ip; - - /* check for a run */ -#if FASTLZ_LEVEL==2 - if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1)) - { - distance = 1; - ip += 3; - ref = anchor - 1 + 3; - goto match; - } -#endif - - /* find potential match */ - HASH_FUNCTION(hval,ip); - hslot = htab + hval; - ref = htab[hval]; - - /* calculate distance to the match */ - distance = anchor - ref; - - /* update hash table */ - *hslot = anchor; - - /* is this a match? check the first 3 bytes */ - if(distance==0 || -#if FASTLZ_LEVEL==1 - (distance >= MAX_DISTANCE) || -#else - (distance >= MAX_FARDISTANCE) || -#endif - *ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++) - goto literal; - -#if FASTLZ_LEVEL==2 - /* far, needs at least 5-byte match */ - if(distance >= MAX_DISTANCE) - { - if(*ip++ != *ref++ || *ip++!= *ref++) - goto literal; - len += 2; - } - - match: -#endif - - /* last matched byte */ - ip = anchor + len; - - /* distance is biased */ - distance--; - - if(!distance) - { - /* zero distance means a run */ - flzuint8 x = ip[-1]; - while(ip < ip_bound) - if(*ref++ != x) break; else ip++; - } - else - for(;;) - { - /* safe because the outer check against ip limit */ - if(*ref++ != *ip++) break; - if(*ref++ != *ip++) break; - if(*ref++ != *ip++) break; - if(*ref++ != *ip++) break; - if(*ref++ != *ip++) break; - if(*ref++ != *ip++) break; - if(*ref++ != *ip++) break; - if(*ref++ != *ip++) break; - while(ip < ip_bound) - if(*ref++ != *ip++) break; - break; - } - - /* if we have copied something, adjust the copy count */ - if(copy) - /* copy is biased, '0' means 1 byte copy */ - *(op-copy-1) = copy-1; - else - /* back, to overwrite the copy count */ - op--; - - /* reset literal counter */ - copy = 0; - - /* length is biased, '1' means a match of 3 bytes */ - ip -= 3; - len = ip - anchor; - - /* encode the match */ -#if FASTLZ_LEVEL==2 - if(distance < MAX_DISTANCE) - { - if(len < 7) - { - *op++ = (len << 5) + (distance >> 8); - *op++ = (distance & 255); - } - else - { - *op++ = (7 << 5) + (distance >> 8); - for(len-=7; len >= 255; len-= 255) - *op++ = 255; - *op++ = len; - *op++ = (distance & 255); - } - } - else - { - /* far away, but not yet in the another galaxy... */ - if(len < 7) - { - distance -= MAX_DISTANCE; - *op++ = (len << 5) + 31; - *op++ = 255; - *op++ = distance >> 8; - *op++ = distance & 255; - } - else - { - distance -= MAX_DISTANCE; - *op++ = (7 << 5) + 31; - for(len-=7; len >= 255; len-= 255) - *op++ = 255; - *op++ = len; - *op++ = 255; - *op++ = distance >> 8; - *op++ = distance & 255; - } - } -#else - - if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2)) - while(len > MAX_LEN-2) - { - *op++ = (7 << 5) + (distance >> 8); - *op++ = MAX_LEN - 2 - 7 -2; - *op++ = (distance & 255); - len -= MAX_LEN-2; - } - - if(len < 7) - { - *op++ = (len << 5) + (distance >> 8); - *op++ = (distance & 255); - } - else - { - *op++ = (7 << 5) + (distance >> 8); - *op++ = len - 7; - *op++ = (distance & 255); - } -#endif - - /* update the hash at match boundary */ - HASH_FUNCTION(hval,ip); - htab[hval] = ip++; - HASH_FUNCTION(hval,ip); - htab[hval] = ip++; - - /* assuming literal copy */ - *op++ = MAX_COPY-1; - - continue; - - literal: - *op++ = *anchor++; - ip = anchor; - copy++; - if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) - { - copy = 0; - *op++ = MAX_COPY-1; - } - } - - /* left-over as literal copy */ - ip_bound++; - while(ip <= ip_bound) - { - *op++ = *ip++; - copy++; - if(copy == MAX_COPY) - { - copy = 0; - *op++ = MAX_COPY-1; - } - } - - /* if we have copied something, adjust the copy length */ - if(copy) - *(op-copy-1) = copy-1; - else - op--; - -#if FASTLZ_LEVEL==2 - /* marker for fastlz2 */ - *(flzuint8*)output |= (1 << 5); -#endif - - return op - (flzuint8*)output; -} - -static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout) -{ - const flzuint8* ip = (const flzuint8*) input; - const flzuint8* ip_limit = ip + length; - flzuint8* op = (flzuint8*) output; - flzuint8* op_limit = op + maxout; - flzuint32 ctrl = (*ip++) & 31; - int loop = 1; - - do - { - const flzuint8* ref = op; - flzuint32 len = ctrl >> 5; - flzuint32 ofs = (ctrl & 31) << 8; - - if(ctrl >= 32) - { -#if FASTLZ_LEVEL==2 - flzuint8 code; -#endif - len--; - ref -= ofs; - if (len == 7-1) -#if FASTLZ_LEVEL==1 - len += *ip++; - ref -= *ip++; -#else - do - { - code = *ip++; - len += code; - } while (code==255); - code = *ip++; - ref -= code; - - /* match from 16-bit distance */ - if(FASTLZ_UNEXPECT_CONDITIONAL(code==255)) - if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8))) - { - ofs = (*ip++) << 8; - ofs += *ip++; - ref = op - ofs - MAX_DISTANCE; - } -#endif - -#ifdef FASTLZ_SAFE - if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit)) - return 0; - - if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output)) - return 0; -#endif - - if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) - ctrl = *ip++; - else - loop = 0; - - if(ref == op) - { - /* optimize copy for a run */ - flzuint8 b = ref[-1]; - *op++ = b; - *op++ = b; - *op++ = b; - for(; len; --len) - *op++ = b; - } - else - { -#if !defined(FASTLZ_STRICT_ALIGN) - const flzuint16* p; - flzuint16* q; -#endif - /* copy from reference */ - ref--; - *op++ = *ref++; - *op++ = *ref++; - *op++ = *ref++; - -#if !defined(FASTLZ_STRICT_ALIGN) - /* copy a byte, so that now it's word aligned */ - if(len & 1) - { - *op++ = *ref++; - len--; - } - - /* copy 16-bit at once */ - q = (flzuint16*) op; - op += len; - p = (const flzuint16*) ref; - for(len>>=1; len > 4; len-=4) - { - *q++ = *p++; - *q++ = *p++; - *q++ = *p++; - *q++ = *p++; - } - for(; len; --len) - *q++ = *p++; -#else - for(; len; --len) - *op++ = *ref++; -#endif - } - } - else - { - ctrl++; -#ifdef FASTLZ_SAFE - if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit)) - return 0; - if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit)) - return 0; -#endif - - *op++ = *ip++; - for(--ctrl; ctrl; ctrl--) - *op++ = *ip++; - - loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit); - if(loop) - ctrl = *ip++; - } - } - while(FASTLZ_EXPECT_CONDITIONAL(loop)); - - return op - (flzuint8*)output; -} - -#endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ diff --git a/kernel/src/memory/vm/fastlz/fastlz.h.old b/kernel/src/memory/vm/fastlz/fastlz.h.old deleted file mode 100644 index f87bc7be..00000000 --- a/kernel/src/memory/vm/fastlz/fastlz.h.old +++ /dev/null @@ -1,100 +0,0 @@ -/* - FastLZ - lightning-fast lossless compression library - - Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) - Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) - Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -#ifndef FASTLZ_H -#define FASTLZ_H - -#define FASTLZ_VERSION 0x000100 - -#define FASTLZ_VERSION_MAJOR 0 -#define FASTLZ_VERSION_MINOR 0 -#define FASTLZ_VERSION_REVISION 0 - -#define FASTLZ_VERSION_STRING "0.1.0" - -#if defined (__cplusplus) -extern "C" { -#endif - -/** - Compress a block of data in the input buffer and returns the size of - compressed block. The size of input buffer is specified by length. The - minimum input buffer size is 16. - - The output buffer must be at least 5% larger than the input buffer - and can not be smaller than 66 bytes. - - If the input is not compressible, the return value might be larger than - length (input buffer size). - - The input buffer and the output buffer can not overlap. -*/ - -int fastlz_compress(const void* input, int length, void* output); - -/** - Decompress a block of compressed data and returns the size of the - decompressed block. If error occurs, e.g. the compressed data is - corrupted or the output buffer is not large enough, then 0 (zero) - will be returned instead. - - The input buffer and the output buffer can not overlap. - - Decompression is memory safe and guaranteed not to write the output buffer - more than what is specified in maxout. - */ - -int fastlz_decompress(const void* input, int length, void* output, int maxout); - -/** - Compress a block of data in the input buffer and returns the size of - compressed block. The size of input buffer is specified by length. The - minimum input buffer size is 16. - - The output buffer must be at least 5% larger than the input buffer - and can not be smaller than 66 bytes. - - If the input is not compressible, the return value might be larger than - length (input buffer size). - - The input buffer and the output buffer can not overlap. - - Compression level can be specified in parameter level. At the moment, - only level 1 and level 2 are supported. - Level 1 is the fastest compression and generally useful for short data. - Level 2 is slightly slower but it gives better compression ratio. - - Note that the compressed data, regardless of the level, can always be - decompressed using the function fastlz_decompress above. -*/ - -int fastlz_compress_level(int level, const void* input, int length, void* output); - -#if defined (__cplusplus) -} -#endif - -#endif /* FASTLZ_H */ diff --git a/kernel/src/memory/vm/frame.c b/kernel/src/memory/vm/frame.c deleted file mode 100644 index f1a5acf8..00000000 --- a/kernel/src/memory/vm/frame.c +++ /dev/null @@ -1,62 +0,0 @@ -#include "vm.h" -//#include "frame.h" -#include "klibc.h" - -struct vm_free_frame -{ - void *next; // Next free frame -}; - -struct vm_free_frame *vm_free_list = 0x0; - -int vm_build_free_frame_list(void *start, void *end) -{ - vm_free_list = start; - struct vm_free_frame *p = start; - for (p = start; (void*) p < end; p = (void*) p + BLOCK_SIZE) - { - p->next = (void*) p + BLOCK_SIZE; - if ((unsigned int) ((void*) p + BLOCK_SIZE) >= (unsigned int) end) - { - p->next = 0x0; - } - } - return 0; -} - -void *vm_get_free_frame() { - // Check if there are no frames - if (vm_free_list == 0x0) - { - return 0x0; - } - void *p = vm_free_list; - vm_free_list = vm_free_list->next; - return p - 0xf0000000; // Convert from VPTR to PPTR -} - -void vm_release_frame(void *p) -{ - // TODO: Check if p is actually a valid frame - p += 0xf0000000; // Convert from PPTR to VPTR - struct vm_free_frame *flist = p; - flist->next = vm_free_list; - kprintf("%X %X\n", flist, vm_free_list); - vm_free_list = p; -} - -int vm_count_free_frames() -{ - int cnt = 0; - struct vm_free_frame *p = vm_free_list; - while ((p = p->next)) - { - if (p == p->next) - { - ERROR("Fatal problem: The free frame list has a cycle.\n"); - return -1; - } - cnt++; - } - return cnt; -} diff --git a/kernel/src/memory/vm/include/pagealloc2.h b/kernel/src/memory/vm/include/pmm.h similarity index 75% rename from kernel/src/memory/vm/include/pagealloc2.h rename to kernel/src/memory/vm/include/pmm.h index 379a8f63..33368e63 100644 --- a/kernel/src/memory/vm/include/pagealloc2.h +++ b/kernel/src/memory/vm/include/pmm.h @@ -39,16 +39,17 @@ /// The 1024 byte constant you might see popping up refers to the maximum number of 16 byte sliceinfo structs /// can fit in a single 16kb slice. +// TODO: Excluded regions. (for mmio for example) +// TODO: detect memory size. +#define PMM_TOP 0x10000000 // 256 MiB and less than all Peripheral bases -#ifndef PAGE_ALLOC_H -#define PAGE_ALLOC_H +#ifndef PMM_H +#define PMM_H #include #include #include "vm2.h" -// TODO: detect memory size. -#define PAGEALLOC_TOP 0x8000000 // 128 MiB and less than all Peripheral bases #define SLICEINFO_PER_SLICE 1024 @@ -99,8 +100,7 @@ union MemorySlice { }; -/// The page allocator allocates ***Physical*** pages. -struct PageAllocator { +struct PhysicalMemoryManager { /// Two linked lists of unused and allocated slices, referred to by their SliceInfos. struct MemorySliceInfo * unused; struct MemorySliceInfo * allocated; @@ -115,30 +115,22 @@ struct PageAllocator { size_t end; }; -struct PageAllocator pageallocator; +struct PhysicalMemoryManager physicalMemoryManager; // Allocator specific operations -void pagealloc_init(size_t start, size_t end); -struct MemorySliceInfo * allocate_new_sliceinfo_slice(); -struct MemorySliceInfo * pagealloc_get_sliceinfo_for_slice(union MemorySlice * slice); +void pmm_init(size_t start, size_t end); +struct MemorySliceInfo * pmm_new_sliceinfo_slice(); +struct MemorySliceInfo * pmm_get_sliceinfo_for_slice(union MemorySlice * slice); // Element operations -struct L1PageTable * pagealloc_allocate_l1_pagetable(); -void pagealloc_free_l1_pagetable(struct L1PageTable * pt); -struct L2PageTable * pagealloc_allocate_l2_pagetable(); -void pagealloc_free_l2_pagetable(struct L2PageTable * pt); -struct Page * pagealloc_allocate_page(); -void pagealloc_free_page(struct Page * p); - -// Returns the index of the first zero from the LSB -size_t first_free(uint16_t); - -// MemorySliceInfo linked list helper functions. -void push_to_ll(struct MemorySliceInfo ** head, struct MemorySliceInfo * entry); -struct MemorySliceInfo * pop_from_ll(struct MemorySliceInfo ** head); -// It's important that for this function you give it the correct head. If it's not it may happen -// That the head you give it will be mixed up with the actual head of the list it was in. -void remove_element_ll(struct MemorySliceInfo ** head, struct MemorySliceInfo * entry); +struct L1PageTable * pmm_allocate_l1_pagetable(); +void pmm_free_l1_pagetable(struct L1PageTable * pt); +struct L2PageTable * pmm_allocate_l2_pagetable(); +void pmm_free_l2_pagetable(struct L2PageTable * pt); +struct Page * pmm_allocate_page(); +void pmm_free_page(struct Page * p); + + #endif diff --git a/kernel/src/memory/vm/include/vm.h b/kernel/src/memory/vm/include/vm.h index a1bc10dc..e3111c97 100644 --- a/kernel/src/memory/vm/include/vm.h +++ b/kernel/src/memory/vm/include/vm.h @@ -12,7 +12,7 @@ #define PAGE_TABLE_SIZE (1<<14) #define L2_PAGE_TABLE_SIZE (1<<12) -struct vas { +struct vas { // A pointer to the first level of the pagetable. volatile unsigned int *l1_pagetable; volatile unsigned int *l1_pagetable_phys; // The physical address to it diff --git a/kernel/src/memory/vm/include/vm2.h b/kernel/src/memory/vm/include/vm2.h index 9b816a2b..1333bd86 100644 --- a/kernel/src/memory/vm/include/vm2.h +++ b/kernel/src/memory/vm/include/vm2.h @@ -3,6 +3,8 @@ #include #include +#include + /// A L1PagetableEntry is an entry in the top level pagetable. /// There is only one L1 pagetable and it is always located at address 0x4000. @@ -14,6 +16,9 @@ /// * 6.10 (page faults and aborts) typedef union L1PagetableEntry{ uint32_t entry; + /// A coarse l1pt entry means an l1pt entry that points to an l2pt. + /// The other possibility is a (super)section, where the l1pt maps a + /// far larger area of memory at once, without requiring an l2pt. struct { /// This 2 bit field gives what type of entry this is. /// 00 for invalid pages (pagefault) @@ -140,7 +145,7 @@ typedef union L1PagetableEntry{ } L1PagetableEntry; /// -typedef union { +typedef union L2PagetableEntry{ uint32_t entry; struct { /// This 2 bit field gives what type of entry this is. @@ -196,7 +201,6 @@ typedef union { /// formula: /// base_address = (address >> 16); uint32_t base_address: 16; - } __attribute__((packed)) largepage; struct { @@ -204,7 +208,7 @@ typedef union { /// 0 for invalid pages (pagefault) /// 1 for large pages (64kb). /// 2 for extended small pages (4kb) - /// 3 for exetended *non-executable* small pages. (4kb) + /// 3 for extended *non-executable* small pages. (4kb) /// Note that for large pages you have to repeat this entry 16x to fill up all 4kb entries that would lie within it, /// and the first of these 16 entries must be on a 16-word boundary uint32_t type: 2; @@ -262,31 +266,64 @@ struct L2PageTable { }; /// Should be called early, initiliazes everything vm2 needs -void vm2_prepare(); /// Actually enables the MMU and switches the kernel to higher half void vm2_start(); -void vm2_map_virtual_to_physical_l1(size_t virtual, size_t physical); -void vm2_map_nmegabytes_1to1(size_t address, size_t n); + +/// Takes an L1PageTableEntry containing a physical address (in .*.base_address) and maps it to a physical addres. +/// The `bool remap` can be set to true and then this will overwrite whatever was previously mapped at this virtual address +/// in the pagetable. Will return if it did replace something. Generally remap should be set to false, and the kernel +/// should panic when this happen. It usually indicates something went terribly enormously incredibly really really *really* wrong. +bool vm2_l1_map_physical_to_virtual(struct L1PageTable * pt, union L1PagetableEntry entry, size_t virtual, bool remap); + +/// Peripheral mappings +/// Request a section of n megabytes virtual memory which is mapped to a physical section of ram of the +/// same n megabytes in which some mmio is located. Returns the virtual address. +size_t vm2_map_peripheral(size_t physical, size_t n_mebibytes); + +/// Maps a new 4kb page with kernel permissions at a virtual address. Returns a reference to this page +/// or null if unsuccesfull. The physical location of this page is determined by the pmm. +/// Since this allocates a 4kb page, it has to go through l2 pagetables. It will create the right +/// l2 pagetables as it needs. You can make the allocated page executable with the last parameter. +void * vm2_allocate_kernel_page(struct L1PageTable * l1pt, size_t virtual, bool executable); + +/// Should be called after updating a pagetable. +void vm2_flush_caches(); + +/// +struct L1PageTable * kernell1PageTable; /// From the `kernel.ld` linker file. These are not arrays but this is how you refer to the pointers by the linker script. -extern const size_t KERNEL_BASE[]; // 0x8000 -extern const size_t KERNEL_TOP[]; -extern const size_t STACK_TOP[]; +extern const size_t __KERNEL_BASE[]; +extern const size_t __KERNEL_TOP[]; +extern const size_t __KERNEL_VIRTUAL_OFFSET[]; + +/// Above 2Gigs is the virtual kernel area, this also includes all Virtual Memory constructs, and the kernel stack. +#define KERNEL_VIRTUAL_OFFSET ((size_t)__KERNEL_VIRTUAL_OFFSET) + +#define PHYS2VIRT(address) ((size_t)(address) + KERNEL_VIRTUAL_OFFSET) +#define VIRT2PHYS(address) ((size_t)(address) - KERNEL_VIRTUAL_OFFSET) + +/// Make the kernel start in virtual memory at 2GB +#define KERNEL_VIRTUAL_START ((size_t)__KERNEL_BASE) +#define KERNEL_VIRTUAL_END ((size_t)__KERNEL_TOP) + +/// Location of the Kernel's Physical Memory Manager's Info structs. Can grow to a max of 16MiB when using 4GiB RAM. +#define KERNEL_PMM_BASE KERNEL_VIRTUAL_END + +/// From this address down, mmio devices are mapped in the kernel's virtual address space. +#define KERNEL_MMIO_BASE (4 * Gibibyte) -/// Above 3Gigs is the virtual kernel area, this also includes all Virtual Memory constructs, and the kernel stack. -#define KERNEL_VIRTUAL_OFFSET (3u * Gibibyte) +/// Address space for the kernel heap, grows towards the mmio +#define KERNEL_HEAP_BASE (3 * Gibibyte) -/// Make the kernel start in virtual memory at 3GB -#define KERNEL_VIRTUAL_START (KERNEL_VIRTUAL_OFFSET + (size_t)KERNEL_BASE) -#define KERNEL_VIRTUAL_END (KERNEL_VIRTUAL_OFFSET + (size_t)KERNEL_TOP) +#define KERNEL_PHYSICAL_START (KERNEL_VIRTUAL_START - KERNEL_VIRTUAL_OFFSET) +#define KERNEL_PHYSICAL_END (KERNEL_VIRTUAL_END - KERNEL_VIRTUAL_OFFSET) /// The L1 pagetable starts at 0x4000 and is itself 0x4000 bytes long. (0x1000 entries of 4 bytes). /// The kernel starts at 0x8000 which is exactly at the end of the pagetable. (What a coincidence *gasp*) #define PhysicalL1PagetableLocation 0x4000 #define VirtualL1PagetableLocation (KERNEL_VIRTUAL_OFFSET + PhysicalL1PagetableLocation) -// The end of the kernel is guaranteed 1MiB aligned due to our linking script -#define VirtualL2PagetableLocation KERNEL_VIRTUAL_END -#define PhysicalL2PagetableLocation ((size_t)KERNEL_TOP) +#define PAGE_SIZE (4 * Kibibyte) #endif diff --git a/kernel/src/memory/vm/pagealloc2.c b/kernel/src/memory/vm/pmm.c similarity index 67% rename from kernel/src/memory/vm/pagealloc2.c rename to kernel/src/memory/vm/pmm.c index bef46f43..0da0666c 100644 --- a/kernel/src/memory/vm/pagealloc2.c +++ b/kernel/src/memory/vm/pmm.c @@ -1,9 +1,22 @@ -#include +#include #include #include +#include +#include +/// Private functions +// Returns the index of the first zero from the LSB +size_t first_free(uint16_t); -void pagealloc_init(size_t start, size_t end) { +// MemorySliceInfo linked list helper functions. +void push_to_ll(struct MemorySliceInfo ** head, struct MemorySliceInfo * entry); +struct MemorySliceInfo * pop_from_ll(struct MemorySliceInfo ** head); +// It's important that for this function you give it the correct head. If it's not it may happen +// That the head you give it will be mixed up with the actual head of the list it was in. +void remove_element_ll(struct MemorySliceInfo ** head, struct MemorySliceInfo * entry); + +void pmm_init(size_t start, size_t end) { + INFO("Building pmm from 0x%x to 0x%x of size 0x%x", start, end, end - start); // Create the first sliceinfo at the start address struct MemorySliceInfo * firstinfo = (struct MemorySliceInfo *)start; @@ -20,8 +33,8 @@ void pagealloc_init(size_t start, size_t end) { // And there's one sliceinfo struct in it. This first one. firstinfo->filled = 1; - // Now make an allocator with one sliceinfo in the allocated array. - pageallocator = (struct PageAllocator){ + // Now make a pmm with one sliceinfo in the allocated array. + physicalMemoryManager = (struct PhysicalMemoryManager){ .start = start, .end = end, .l2ptPartialFree = NULL, @@ -45,7 +58,7 @@ void pagealloc_init(size_t start, size_t end) { currentsliceinfo->slice = i; // Add the sliceinfo to the unused list - push_to_ll(&pageallocator.unused, currentsliceinfo); + push_to_ll(&physicalMemoryManager.unused, currentsliceinfo); // continue to the next sliceinfo infoindex++; @@ -53,28 +66,28 @@ void pagealloc_init(size_t start, size_t end) { if (infoindex >= SLICEINFO_PER_SLICE) { // We can now do this as we already made at least one new sliceinfo struct on the unused list // Which we can use for this. - currentslice = allocate_new_sliceinfo_slice()->slice; + currentslice = pmm_new_sliceinfo_slice()->slice; infoindex = 0; } } } -struct MemorySliceInfo * allocate_new_sliceinfo_slice() { +struct MemorySliceInfo * pmm_new_sliceinfo_slice() { // Take a slice from the unused list and the the next one to the top of unused. - struct MemorySliceInfo * sliceinfo = pop_from_ll(&pageallocator.unused); + struct MemorySliceInfo * sliceinfo = pop_from_ll(&physicalMemoryManager.unused); // Change it's type to typeinfo sliceinfo->type = BucketInfo; sliceinfo->filled = 0; // Add it to the allocated list - push_to_ll(&pageallocator.allocated, sliceinfo); + push_to_ll(&physicalMemoryManager.allocated, sliceinfo); return sliceinfo; } -struct MemorySliceInfo * pagealloc_get_sliceinfo_for_slice(union MemorySlice * slice) { +struct MemorySliceInfo * pmm_get_sliceinfo_for_slice(union MemorySlice * slice) { // TODO: think about changing SLICEINFO_PER_SLICE to 512 instead of 682. This adds quite some memory overhead // TODO: but makes the division and multiplication below a lot faster. (or even unnecessary as it can be replaced with a single logical AND) @@ -84,7 +97,7 @@ struct MemorySliceInfo * pagealloc_get_sliceinfo_for_slice(union MemorySlice * s // each bucket is a sliceinfo struct describing a slice with sliceinfo structs in it. // The buckets therefore describes (682 * 16K) blocks. - size_t offset_from_allocator_start = (size_t)slice - pageallocator.start; + size_t offset_from_allocator_start = (size_t)slice - physicalMemoryManager.start; // divide by blocksize size_t bucketindex = (offset_from_allocator_start) / (bucketsize); @@ -102,7 +115,7 @@ struct MemorySliceInfo * pagealloc_get_sliceinfo_for_slice(union MemorySlice * s // Multiply by blocksize again (NOTE: this is so we round down! The division and multiplication DO NOT CANCEL OUT) // Subtract two as the bucket is actually the last page of the previous bucket. - union MemorySlice * bucketinfo = ((union MemorySlice *)(pageallocator.start + bucketindex * bucketsize)) - correction; + union MemorySlice * bucketinfo = ((union MemorySlice *)(physicalMemoryManager.start + bucketindex * bucketsize)) - correction; // The first non-information slice in a bucket is always the slice after the information slice. // Except for the first bucket. @@ -117,47 +130,47 @@ struct MemorySliceInfo * pagealloc_get_sliceinfo_for_slice(union MemorySlice * s return info; } -void pagealloc_free_l1_pagetable(struct L1PageTable * pt) { +void pmm_free_l1_pagetable(struct L1PageTable * pt) { if (pt == NULL) { return; } - struct MemorySliceInfo * sliceinfo = pagealloc_get_sliceinfo_for_slice((union MemorySlice *) pt); + struct MemorySliceInfo * sliceinfo = pmm_get_sliceinfo_for_slice((union MemorySlice *) pt); - remove_element_ll(&pageallocator.allocated, sliceinfo); + remove_element_ll(&physicalMemoryManager.allocated, sliceinfo); // now push it on the unused list. - push_to_ll(&pageallocator.unused, sliceinfo); + push_to_ll(&physicalMemoryManager.unused, sliceinfo); // Since it's the first thing on the unused list, make prev null. sliceinfo->prev = NULL; } -struct L1PageTable * pagealloc_allocate_l1_pagetable() { +struct L1PageTable * pmm_allocate_l1_pagetable() { - if(pageallocator.unused == NULL) { + if(physicalMemoryManager.unused == NULL) { return NULL; } // Take a slice from the unused list. - struct MemorySliceInfo * sliceinfo = pop_from_ll(&pageallocator.unused); + struct MemorySliceInfo * sliceinfo = pop_from_ll(&physicalMemoryManager.unused); // Change it's type to typeinfo sliceinfo->type = L1PageTable; // Put it on the allocated stack - push_to_ll(&pageallocator.allocated, sliceinfo); + push_to_ll(&physicalMemoryManager.allocated, sliceinfo); return &sliceinfo->slice->l1pt; } -struct L2PageTable * pagealloc_allocate_l2_pagetable() { +struct L2PageTable * pmm_allocate_l2_pagetable() { // First test if there's a partial allocated l2 pagetable - if (pageallocator.l2ptPartialFree != NULL) { + if (physicalMemoryManager.l2ptPartialFree != NULL) { - struct MemorySliceInfo * sliceinfo = pageallocator.l2ptPartialFree; + struct MemorySliceInfo * sliceinfo = physicalMemoryManager.l2ptPartialFree; uint32_t index = first_free(sliceinfo->filled); @@ -169,32 +182,32 @@ struct L2PageTable * pagealloc_allocate_l2_pagetable() { if(sliceinfo->filled == 0xffff) { // Remove from the partial free list // We can ignore the return value here as we already got it. - pop_from_ll(&pageallocator.l2ptPartialFree); + pop_from_ll(&physicalMemoryManager.l2ptPartialFree); // add to allocated list - push_to_ll(&pageallocator.allocated, sliceinfo); + push_to_ll(&physicalMemoryManager.allocated, sliceinfo); } return newl2pt; } else { - struct MemorySliceInfo * sliceinfo = pop_from_ll(&pageallocator.unused); + struct MemorySliceInfo * sliceinfo = pop_from_ll(&physicalMemoryManager.unused); // Change it's type to typeinfo sliceinfo->type = L2PageTable; sliceinfo->filled = 1; // Put it on the partially allocated list - push_to_ll(&pageallocator.l2ptPartialFree, sliceinfo); + push_to_ll(&physicalMemoryManager.l2ptPartialFree, sliceinfo); return &sliceinfo->slice->l2pt[0]; } } -struct Page * pagealloc_allocate_page() { +struct Page * pmm_allocate_page() { // First test if there's a partial allocated page page - if (pageallocator.pagePartialFree != NULL) { + if (physicalMemoryManager.pagePartialFree != NULL) { - struct MemorySliceInfo * sliceinfo = pageallocator.pagePartialFree; + struct MemorySliceInfo * sliceinfo = physicalMemoryManager.pagePartialFree; uint32_t index = first_free(sliceinfo->filled); @@ -207,35 +220,35 @@ struct Page * pagealloc_allocate_page() { if(sliceinfo->filled == 0xf) { // Remove from the partial free list // We can ignore the return value here as we already got it. - pop_from_ll(&pageallocator.pagePartialFree); + pop_from_ll(&physicalMemoryManager.pagePartialFree); // add to allocated list - push_to_ll(&pageallocator.allocated, sliceinfo); + push_to_ll(&physicalMemoryManager.allocated, sliceinfo); } return newpage; } else { - struct MemorySliceInfo * sliceinfo = pop_from_ll(&pageallocator.unused); + struct MemorySliceInfo * sliceinfo = pop_from_ll(&physicalMemoryManager.unused); // Change it's type to typeinfo sliceinfo->type = Page; sliceinfo->filled = 0b0001; // Put it on the partially allocated list - push_to_ll(&pageallocator.pagePartialFree, sliceinfo); + push_to_ll(&physicalMemoryManager.pagePartialFree, sliceinfo); return &sliceinfo->slice->page[0]; } } -void pagealloc_free_page(struct Page * p) { +void pmm_free_page(struct Page * p) { // works cuz rounding (we think, might just work because random luck) - struct MemorySliceInfo * info = pagealloc_get_sliceinfo_for_slice((union MemorySlice *) p); + struct MemorySliceInfo * info = pmm_get_sliceinfo_for_slice((union MemorySlice *) p); if (info->filled == 0xf) { - remove_element_ll(&pageallocator.allocated, info); + remove_element_ll(&physicalMemoryManager.allocated, info); } else { - remove_element_ll(&pageallocator.pagePartialFree, info); + remove_element_ll(&physicalMemoryManager.pagePartialFree, info); } // compute which subelement we are @@ -247,20 +260,20 @@ void pagealloc_free_page(struct Page * p) { // if there was only one l2pt in this slice, put it on unallocated if(info->filled == 00) { - push_to_ll(&pageallocator.unused, info); + push_to_ll(&physicalMemoryManager.unused, info); } else { - push_to_ll(&pageallocator.pagePartialFree, info); + push_to_ll(&physicalMemoryManager.pagePartialFree, info); } } -void pagealloc_free_l2_pagetable(struct L2PageTable * pt) { +void pmm_free_l2_pagetable(struct L2PageTable * pt) { // works cuz rounding (we think, might just work because random luck) - struct MemorySliceInfo * info = pagealloc_get_sliceinfo_for_slice((union MemorySlice *) pt); + struct MemorySliceInfo * info = pmm_get_sliceinfo_for_slice((union MemorySlice *) pt); if (info->filled == 0xffff) { - remove_element_ll(&pageallocator.allocated, info); + remove_element_ll(&physicalMemoryManager.allocated, info); } else { - remove_element_ll(&pageallocator.l2ptPartialFree, info); + remove_element_ll(&physicalMemoryManager.l2ptPartialFree, info); } // compute which subelement we are @@ -272,9 +285,9 @@ void pagealloc_free_l2_pagetable(struct L2PageTable * pt) { // if there was only one l2pt in this slice, put it on unallocated if(info->filled == 00) { - push_to_ll(&pageallocator.unused, info); + push_to_ll(&physicalMemoryManager.unused, info); } else { - push_to_ll(&pageallocator.l2ptPartialFree, info); + push_to_ll(&physicalMemoryManager.l2ptPartialFree, info); } } diff --git a/kernel/src/memory/vm/swap_framework.c.old b/kernel/src/memory/vm/swap_framework.c.old deleted file mode 100644 index e4a3efd6..00000000 --- a/kernel/src/memory/vm/swap_framework.c.old +++ /dev/null @@ -1,259 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "fastlz/fastlz.h.old" - -// NOTE: SWAPPING CANNOT WORK UNTIL FILESYSTEMS CAN ALLOCATE MORE THAN 16 PAGES AT A TIME -void swap_init() -{ - // initialize a swap space struct to hold values to then pass - // TODO: change to guarantee allocation in RAM - holder = (struct swap_space*) kmalloc(sizeof(struct swap_space)); -} - -// INCOMPLETE -uint32_t store_page_LZ(void *page, uint32_t *ID) -{ - struct node *LZ_swap = (struct node*) pqueue_peek(2); - - // allocate this on RAM this is where you os_memcpy the given page!! - // NOTE: THAT 1.05 DOESN'T MULTIPLY TO A CLEAN NUMBER - void *e_page = kmalloc(PAGE_SIZE * 1.05); // output buffer needs to be at least 5% bigger than input - - int32_t cmp_size; - cmp_size = fastlz_compress(page, PAGE_SIZE, e_page); - - /*if compressed size is greater than uncompressed size, input may not be - compressible; return error */ - if (cmp_size > PAGE_SIZE) - { - return 0; - } - - struct swap_entry *curr_ent = LZ_swap->e_head; - int i = 0; - while (curr_ent->cmp_page != NULL) - { - curr_ent += sizeof(struct swap_entry); - i++; - } - *ID = i; - curr_ent->cmp_size = cmp_size; - curr_ent->e_flags = 1; //NOT CORRECT, put wherever it comes from here - struct vas *kvas = KERNEL_VAS; - int curr_add = 0x200000; - - // loop until free physical memory frame is found - while (vm_allocate_page(kvas, curr_add, 4) == 0) - { - curr_add += PAGE_SIZE; - } - - // after deciding physical memory location, store physical memory location in cmp_page - curr_ent->cmp_page = curr_add; - kfree(e_page); // after copying over relevant bits of cmp data in this oversized buffer - if (curr_ent->cmp_page != NULL) - { - curr_ent += sizeof(struct swap_entry); - curr_ent = (struct swap_entry*) kmalloc(sizeof(struct swap_entry)); - } - memory_count += 4096; - return *ID; -} - -uint32_t store_page(void *page, uint32_t *ID) -{ - uint8_t lowbits = *((uint32_t*) page) & 0x000000FF; - if (swapfs_store(page, ID, lowbits) == -1) - { - return 0; - } - memory_count += 4096; - return *ID; -} - -// INCOMPLETE -uint32_t retrieve_page_LZ(void *page, uint32_t *ID) -{ - struct node *lz_swap = (struct node*) pqueue_peek(2); - struct swap_entry *curr_ent = lz_swap->e_head; - for (int i = 0; i < *ID; i++) - { - curr_ent += sizeof(struct swap_entry); - } - void *uncomp_page = kmalloc(PAGE_SIZE); - int uncomp_size = fastlz_decompress(curr_ent->cmp_page, /*constant?*/ - COMPRESSED_SIZE / PAGE_ENTRIES, uncomp_page, PAGE_SIZE); - - /* if uncompressed size is not the size of a page or is 0 - (indicating corrupted data or a too small output buffer (the latter of - which should never happen)), returns error */ - if (uncomp_size != PAGE_SIZE || uncomp_size == 0) - { - return 0; - } - // place the decompressed page back into memory. - os_memcpy(page, uncomp_page, PAGE_SIZE); - kfree(uncomp_page); - struct vas* kvas = KERNEL_VAS; - vm_free_page(kvas, curr_ent->cmp_page); - curr_ent->e_flags = 0; - curr_ent->cmp_page = NULL; - memory_count -= 4096; - return *ID; -} - -uint32_t retrieve_page(void *page, uint32_t *ID) -{ - uint8_t lowbits = *((uint32_t*) page) & 0x000000FF; -// if (swapfs_retrieve(page, ID, lowbits) == -1) { // GIVES ERROR FOR SOME REASON?? -// return 0; -// } - memory_count -= 4096; - return *ID; -} - -os_size_t sum_stored() -{ - return memory_count; -} - -uint32_t vm_swapin_page(void *page, uint32_t *ID) -{ - struct node *swap_area; - uint8_t ssid = *((uint32_t*) page) & 0x000000FF; -// uint32_t sse = *((uint32_t*)page) & 0xFFFFFF00; - - // check if swap space exists - if ((swap_area = pqueue_find(ssid)) == NULL) - { - /// check if there's enough memory for LZ compression - // NOTE: always false until store/retrieve_page_LZ works - if (0/*vm_count_free_frames() > COMPRESSED_SIZE/PAGE_ENTRIES*/) - { - vm_register_swap_space(store_page_LZ, retrieve_page_LZ, 0, -1); - swap_area = pqueue_find(-1); - } - else - { - vm_register_swap_space(store_page, retrieve_page, 1, ssid); - swap_area = pqueue_find(ssid); - } - } - - return swap_area->store_func(page, ID); -} - -uint32_t vm_swapout_page(void *page, uint32_t *ID) -{ - uint8_t ssid = *((uint32_t*) page) & 0x000000FF; - struct node *swap_area = pqueue_find(ssid); - return swap_area->retrieve_func(page, ID); -} - -int vm_register_swap_space(func store_p, func retrieve_p, int priority, - int16_t ssid) -{ - /* waiting on fs team to increase 16 page limit, parameters - SHOULD be (PAGE_ENTRIES, ssid) or (sse, ssid) */ - - if (priority == 1) - { - swapfs_init(PAGE_ENTRIES, ssid); - holder->e_head = NULL; - } - if (priority == 0) - { - if (holder->e_head = (struct swap_entry*) kmalloc( - sizeof(struct swap_entry)) == NULL) - { - return -1; - } -// holder->e_head->next = NULL; - holder->e_head->e_flags = 0; - holder->e_head->cmp_page = NULL; - } - holder->lower_bits = ssid; - holder->priority = priority; - holder->store_func = store_p; - holder->retrieve_func = retrieve_p; - pqueue_push(holder); - return 1; -} - -void vm_deregister_swap_space(uint8_t ssid) -{ - pqueue_pop_at(ssid); -} - -uint32_t vm_page_fault(void *page) -{ - /* TODO: - * check if memory is full and needs to evict a page from RAM - * figure out which page to evict than evict that page - * page in the new page (done.) - */ - - //TODO: eventually change from equaling page to an actual id by establishing a proper hash table - uint32_t* id = (uint32_t*) page; - - int temp; - if ((temp = vm_swap_free_mapping(KERNEL_VAS, page, id)) < 0) - { - if (temp == VM_ERR_BADV) - { - os_printf("Virtual pointer passed was invalid [page_fault]"); - } - if (temp == VM_ERR_NOT_MAPPED) - { - os_printf( - "Virtual pointer was not mapped using set_mapping [page_fault]"); - } - return 0; - } - - uint8_t ssid = *((uint32_t*) page) & 0x000000FF; - uint32_t ss_entry = *((uint32_t*) page) & 0xFFFFFF00; - struct node *swap_area = pqueue_find(ssid); - // load memory back into RAM - swap_area->retrieve_func(page, &ss_entry); - - // find a free frame to map - void *pptr = vm_get_free_frame(); - // TODO: once hashtable is properly set change permission to proper value - int perm = VM_PERM_USER_RW; - if (vm_set_mapping(KERNEL_VAS, page, pptr, perm) < 0) - { - if (temp == VM_ERR_BADV) - { - os_printf("Virtual pointer passed was invalid [page_fault]"); - } - if (temp == VM_ERR_BADP) - { - os_printf("Physical pointer passed was invalid [page_fault]"); - } - if (temp == VM_ERR_MAPPED) - { - os_printf( - "The virtual pointer passed has already been mapped [page_fault]"); - } - return 0; - } - // Get level 2 page table - uint32_t *l2pt = (uint32_t*) VM_ENTRY_GET_L2( - (uint32_t) VM_L1_GET_ENTRY(vm_get_current_vas()->l1_pagetable, - page)); - - // confirm from @lkolby whether this will work for setting the page table - uint32_t *tmp = (uint32_t*) VM_L2_ENTRY(l2pt, page); - *tmp = (uint32_t*) page; - - return *((uint32_t*) pptr); -} - -//uint32_t* vm_scan_pages(void *page, uint32_t *ID); - diff --git a/kernel/src/memory/vm/swap_fs.c.old b/kernel/src/memory/vm/swap_fs.c.old deleted file mode 100644 index 74604d66..00000000 --- a/kernel/src/memory/vm/swap_fs.c.old +++ /dev/null @@ -1,161 +0,0 @@ -#include "file.h" -#include "bitvector.h" -#include "vm.h" -#include "klibc.h" -#include "swap_fs.h" - -char *generate_filename(uint8_t ssid) -{ - char *output; - if (ssid < 10) - { // single digit - char swapfile[9] = - { '/', 's', 'w', 'a', 'p', '0', '0', ssid + 48, 0 }; - output = swapfile; - } - else if (ssid < 100) - { // double digit - int tmp = ssid / 10; - char swapfile[9] = - { '/', 's', 'w', 'a', 'p', '0', tmp + 48, (ssid % 10) + 48, 0 }; - output = swapfile; - } - else - { // triple digit - int tmp = ssid / 10; - int tmp2 = ssid / 100; - char swapfile[9] = - { '/', 's', 'w', 'a', 'p', tmp2 + 48, tmp + 48, ssid + 48, 0 }; - output = swapfile; - } - return output; -} - -int32_t swapfs_init(int npages, uint8_t ssid) -{ - int fd; - int nbytes; - // Initialize the free bitmap -// free_bitvector = make_vector(npages); - bv_arr[ssid] = make_vector(npages); - - // making new files instead of a tree b/c the FS can't do it - char *swapfile = generate_filename(ssid); - - // The permissions parameter doesn't quite work right now (BUG?) - if (kcreate(swapfile, 'w', 1) < 0) - { - return -1; - } - - // For now, we have to fill the file with that much blank storage. - if ((fd = kopen(swapfile, 'w')) < 0) - { - return -1; - } - void *empty_page = kmalloc(BLOCK_SIZE); - - // seems useless to me...? - for (int i = 0; i < npages; i++) - { - if ((nbytes = kwrite(fd, empty_page, BLOCK_SIZE)) < 0) - { - return -1; - } - } - - kfree(empty_page); - kclose(fd); - - return nbytes * npages; // success -} - -int64_t swapfs_store(void *page, uint32_t *id, uint8_t ssid) -{ - int32_t fd; - char *swapfile; - int32_t b; - // Get the index to store the page into - *id = *((uint32_t*) page) & 0xFFFFFF00; - - if ((b = bv_isfree(*id, bv_arr[ssid])) <= 0) - { - if (b == -1) - { - os_printf("invalid index [swapfs_store]"); - } - else - { - os_printf("index not free [swapfs_store]"); - } - - return -1; - } - - // Error if invalid index - if (bv_set(*id, bv_arr[ssid]) < 0) - { - return -1; - } - - swapfile = generate_filename(ssid); - // Error if failed to open - if ((fd = kopen(swapfile, 'w')) < 0) - { - return -1; - } - - // Error if seeks beyond boundaries - if (kseek(fd, (*id) * BLOCK_SIZE) < 0) - { - return -1; - } - - if (kwrite(fd, page, BLOCK_SIZE) < 0) - { - return -1; - } - kclose(fd); - - return *id; // success -} - -int64_t swapfs_retreive(void *page, uint32_t *id, uint8_t ssid) -{ - int fd; - char *swapfile; - //checks if index is free - if (!bv_get(*id, bv_arr[ssid])) - { - return -1; - } - - swapfile = generate_filename(ssid); - - // not sure if I should make the index free here... - bv_lower(*id, bv_arr[ssid]); - - if ((fd = kopen(swapfile, 'r')) < 0) - { - return -1; - } - - kseek(fd, (*id) * BLOCK_SIZE); - kread(fd, page, BLOCK_SIZE); - kclose(fd); - - return 1; // success -} - -int32_t swapfs_disable(uint8_t ssid) -{ - char *swapfile; - bv_free(bv_arr[ssid]); - swapfile = generate_filename(ssid); - if (kdelete(swapfile, 0) < 0) - { - return -1; - } - - return 1; // success -} diff --git a/kernel/src/memory/vm/swap_pqueue.c.old b/kernel/src/memory/vm/swap_pqueue.c.old deleted file mode 100644 index d87f7f50..00000000 --- a/kernel/src/memory/vm/swap_pqueue.c.old +++ /dev/null @@ -1,158 +0,0 @@ -#include "stdint.h" -#include "swap_pqueue.h" -#include "swap_framework.h" -#include "klibc.h" - -void pqueue_init(struct swap_space *ss) -{ - head = (struct node*) kmalloc(sizeof(struct node)); - head->next = NULL; - head->e_head = ss->e_head; - head->lower_bits = ss->lower_bits; - head->priority = ss->priority; - head->store_func = ss->store_func; - head->retrieve_func = ss->retrieve_func; - path = head; - s = 1; -} - -void pqueue_push(struct swap_space *ss) -{ - struct node *restore = path; int count=1; - path = head; - while (count<=pqueue_size()) { - if (path->priority > ss->priority && count==1) { //set as new head - head = (struct node*) kmalloc(sizeof(struct node)); - head->next = path; - pqueue_set(head, ss); - path = restore; - break; - } - if (path->priority < ss->priority && path->next == NULL) { //set as new tail - path = restore; - path->next = (struct node*) kmalloc(sizeof(struct node)); - path = path->next; - pqueue_set(path, ss); - path->next = NULL; - break; - } - if (path->priority < ss->priority && count!=pqueue_size() && - (path->next)->priority > ss->priority) { //set in between nodes - struct node *temp = (struct node*) kmalloc(sizeof(struct node)); - pqueue_set(temp, ss); - temp->next = path->next; - path->next = temp; - path = restore; - break; - } - path = path->next; - count++; - } - s++; -} - -//set head to next node and delete previous node -//pops from front -void pqueue_pop_front() -{ - struct node *temp = head; - head = head->next; - kfree(temp); - s--; -} - -void pqueue_pop_back() -{ - kfree(path); - path = head; - while (path->next == NULL) { - path = path->next; - } - s--; -} - -void pqueue_pop_at(uint8_t ssid) -{ - struct node *temp = head; - int x; - for (x = 0; xlower_bits == ssid) { - break; - } - temp = temp->next; - } - if (x == 0) { - pqueue_pop_front(); - } else if (x == pqueue_size()-1) { - pqueue_pop_back(); - } else { - struct node *temp2 = head; - for (int y = 1; ynext; - } - temp2->next = temp->next; - kfree(temp); - } -} - -void pqueue_set(struct node *h, struct swap_space *ss){ - h->lower_bits = ss->lower_bits; - h->priority = ss->priority; - h->store_func = ss->store_func; - h->retrieve_func = ss->retrieve_func; - h->e_head = ss->e_head; -} - -struct node *pqueue_index(int i) -{ - if (i == 0) { - return head; - } - if (i == (pqueue_size()-1)) { - return path; - } - - struct node *restore = head; - int x; - for (x = 0; xnext; - } - - return restore; -} - -uint8_t pqueue_size() -{ - return s; -} - -// returns specified value from the head of list -void *pqueue_peek(int type) -{ - void *foo; - switch (type) { - case 0: - foo = &(head->lower_bits); - case 1: - foo = &(head->priority); - case 2: - foo = head->e_head; - } - return foo; -} - -struct node *pqueue_find(uint8_t ssid) -{ - struct node *temp = head; - - while (temp != NULL) { - if (temp->lower_bits == ssid) { - return temp; - } - temp = temp->next; - } - - return NULL; -} - - diff --git a/kernel/src/memory/vm/test/test_pagealloc2.c b/kernel/src/memory/vm/test/test_pagealloc2.c index 1ae48a27..0363a99e 100644 --- a/kernel/src/memory/vm/test/test_pagealloc2.c +++ b/kernel/src/memory/vm/test/test_pagealloc2.c @@ -1,6 +1,7 @@ #include -#include +#include #include +#include size_t listlength(struct MemorySliceInfo * start) { if (start == NULL) { @@ -19,86 +20,76 @@ TEST_CREATE(test_memoryinfo_size, { ASSERT_EQ(sizeof(struct MemorySliceInfo), 16); }) -TEST_CREATE(test_empty, { - ASSERT_NOT_NULL(pageallocator.unused); - ASSERT_EQ(listlength(pageallocator.unused),1278); - ASSERT_EQ(listlength(pageallocator.allocated), 2); - ASSERT_NULL(pageallocator.l2ptPartialFree); - ASSERT_NULL(pageallocator.pagePartialFree); -}) - TEST_CREATE(test_allocate_pt, { - struct L1PageTable * pt = pagealloc_allocate_l1_pagetable(); + size_t unused = listlength(physicalMemoryManager.unused); + size_t allocated = listlength(physicalMemoryManager.allocated); + + struct L1PageTable * pt = pmm_allocate_l1_pagetable(); // Just try to overwrite everything a few times so if something breaks we'll hopefully see in the next tests. memset(pt, 0, 1024 * 16); memset(pt, 1, 1024 * 16); + ASSERT_NOT_NULL(physicalMemoryManager.unused); + ASSERT_EQ(listlength(physicalMemoryManager.unused), unused - 1); + ASSERT_NOT_NULL(physicalMemoryManager.allocated); + ASSERT_EQ(listlength(physicalMemoryManager.allocated), allocated + 1); - ASSERT_NOT_NULL(pageallocator.unused); - ASSERT_EQ(listlength(pageallocator.unused), 1277); - ASSERT_NOT_NULL(pageallocator.allocated); - ASSERT_EQ(listlength(pageallocator.allocated), 3); - ASSERT_NULL(pageallocator.l2ptPartialFree); - ASSERT_NULL(pageallocator.pagePartialFree); - - pagealloc_free_l1_pagetable(pt); + pmm_free_l1_pagetable(pt); - ASSERT_EQ(listlength(pageallocator.unused), 1278); - ASSERT_EQ(listlength(pageallocator.allocated), 2); + ASSERT_EQ(listlength(physicalMemoryManager.unused), unused); + ASSERT_EQ(listlength(physicalMemoryManager.allocated), allocated); }) TEST_CREATE(test_allocate_many_pt, { - int total = listlength(pageallocator.unused); - int totalallocated = listlength(pageallocator.allocated); + size_t total = listlength(physicalMemoryManager.unused); + size_t totalallocated = listlength(physicalMemoryManager.allocated); - struct L1PageTable * pages[700]; + const size_t amount = 1026; - for (int i = 0; i < 700; i++) { + struct L1PageTable * pages[amount]; - pages[i] = pagealloc_allocate_l1_pagetable(); + for (int i = 0; i < amount; i++) { + pages[i] = pmm_allocate_l1_pagetable(); ASSERT_NOT_NULL(pages[i]); - ASSERT_EQ(listlength(pageallocator.unused), total - (i + 1u)); - ASSERT_EQ(listlength(pageallocator.allocated), totalallocated + i + 1); + ASSERT_EQ(listlength(physicalMemoryManager.unused), total - (i + 1u)); + ASSERT_EQ(listlength(physicalMemoryManager.allocated), totalallocated + i + 1); } - struct L1PageTable * pt = pagealloc_allocate_l1_pagetable(); + struct L1PageTable * pt = pmm_allocate_l1_pagetable(); - ASSERT_NOT_NULL(pageallocator.unused); - ASSERT_EQ(listlength(pageallocator.unused), 577); - ASSERT_NOT_NULL(pageallocator.allocated); + ASSERT_NOT_NULL(physicalMemoryManager.unused); + ASSERT_EQ(listlength(physicalMemoryManager.unused), total - (amount + 1)); + ASSERT_NOT_NULL(physicalMemoryManager.allocated); - ASSERT_EQ(listlength(pageallocator.allocated), 703); - ASSERT_NULL(pageallocator.l2ptPartialFree); - ASSERT_NULL(pageallocator.pagePartialFree); + ASSERT_EQ(listlength(physicalMemoryManager.allocated), totalallocated + (amount + 1)); - pagealloc_free_l1_pagetable(pt); + pmm_free_l1_pagetable(pt); - for (int i = 0; i < 700; i++) { - pagealloc_free_l1_pagetable(pages[i]); + + for (int i = 0; i < amount; i++) { + pmm_free_l1_pagetable(pages[i]); } - ASSERT_NOT_NULL(pageallocator.unused); - ASSERT_EQ(listlength(pageallocator.unused),1278); - ASSERT_EQ(listlength(pageallocator.allocated), 2); - ASSERT_NULL(pageallocator.l2ptPartialFree); - ASSERT_NULL(pageallocator.pagePartialFree); + ASSERT_NOT_NULL(physicalMemoryManager.unused); + ASSERT_EQ(listlength(physicalMemoryManager.unused), total); + ASSERT_EQ(listlength(physicalMemoryManager.allocated), totalallocated); }) // Test the magic :sparkles: TEST_CREATE(test_get_sliceinfo, { - struct L1PageTable * pt = pagealloc_allocate_l1_pagetable(); + struct L1PageTable * pt = pmm_allocate_l1_pagetable(); - struct MemorySliceInfo * info = pagealloc_get_sliceinfo_for_slice((union MemorySlice *)pt); + struct MemorySliceInfo * info = pmm_get_sliceinfo_for_slice((union MemorySlice *) pt); ASSERT_EQ(&info->slice->l1pt, pt); - pagealloc_free_l1_pagetable(pt); + pmm_free_l1_pagetable(pt); }) TEST_CREATE(test_doubly_linked_sliceinfo, { - struct MemorySliceInfo * curr = pageallocator.unused; + struct MemorySliceInfo * curr = physicalMemoryManager.unused; uint32_t length = listlength(curr); uint32_t i = 0; @@ -111,163 +102,10 @@ TEST_CREATE(test_doubly_linked_sliceinfo, { ASSERT_EQ(i, length-1); }) -TEST_CREATE(test_allocate_l2pt, { - // Save how many slices are allocated now - size_t totalallocated = listlength(pageallocator.allocated); - - // the l2ptPartialFree should start empty - ASSERT_NULL(pageallocator.l2ptPartialFree); - - struct L2PageTable * pt1 = pagealloc_allocate_l2_pagetable(); - // After one allocation, it shouldn't be empty anymore - ASSERT_NOT_NULL(pageallocator.l2ptPartialFree); - // But it's length should be only one - ASSERT_NULL(pageallocator.l2ptPartialFree->next); - // The #allocated should have stayed the same as this node goes on l2ptPartialFree - ASSERT_EQ(listlength(pageallocator.allocated), totalallocated); - - struct L2PageTable * pages[15]; - - for (int i = 0; i < 14; i++) { - pages[i] = pagealloc_allocate_l2_pagetable(); - ASSERT_NULL(pageallocator.l2ptPartialFree->next); - } - pages[14] = pagealloc_allocate_l2_pagetable(); - - ASSERT_NULL(pageallocator.l2ptPartialFree); - - ASSERT_EQ(totalallocated + 1u, listlength(pageallocator.allocated)); - - // Now as we allocate a 17th l1 pagetable, the #allocated should have grown by one - struct L2PageTable * pt17 = pagealloc_allocate_l2_pagetable(); - ASSERT_EQ(listlength(pageallocator.allocated), totalallocated + 1u); - // but l2ptPartialFree should now be of length one again - ASSERT_NOT_NULL(pageallocator.l2ptPartialFree); - ASSERT_NULL(pageallocator.l2ptPartialFree->next); - - ASSERT_EQ(pt1 + 1, pages[0]); +//TODO: test_allocate_page +//TODO: test_allocate_l2pt - // Assert pt2 comes after pt1 etc. - for (int i = 0; i < 14; i++) { - ASSERT_EQ(pages[i] + 1, pages[i+1]); - } - - pagealloc_free_l2_pagetable(pt17); - - for (int i = 0; i < 15; i++) { - pagealloc_free_l2_pagetable(pages[i]); - } - - pagealloc_free_l2_pagetable(pt1); - - - ASSERT_NOT_NULL(pageallocator.unused); - ASSERT_EQ(listlength(pageallocator.unused),1278); - ASSERT_EQ(listlength(pageallocator.allocated), 2); - ASSERT_NULL(pageallocator.l2ptPartialFree); - ASSERT_NULL(pageallocator.pagePartialFree); - - - for (int i = 0; i < 100; i++) { - struct L2PageTable * pages2[100]; - - // Allocate 100 l2pts - for (int i = 0; i < 100; i++) { - pages2[i] = pagealloc_allocate_l2_pagetable(); - } - - // Now free them in a very different order - for (int i = 0; i < 50; i++) { - pagealloc_free_l2_pagetable(pages2[i]); - pagealloc_free_l2_pagetable(pages2[99-i]); - } - - ASSERT_NOT_NULL(pageallocator.unused); - ASSERT_EQ(listlength(pageallocator.unused),1278); - ASSERT_EQ(listlength(pageallocator.allocated), 2); - ASSERT_NULL(pageallocator.l2ptPartialFree); - ASSERT_NULL(pageallocator.pagePartialFree); - } -}) - -TEST_CREATE(test_allocate_page, { - // Save how many slices are allocated now - size_t totalallocated = listlength(pageallocator.allocated); - - // the l2ptPartialFree should start empty - ASSERT_NULL(pageallocator.pagePartialFree); - - struct Page * p1 = pagealloc_allocate_page(); - // After one allocation, it shouldn't be empty anymore - ASSERT_NOT_NULL(pageallocator.pagePartialFree); - // But it's length should be only one - ASSERT_NULL(pageallocator.pagePartialFree->next); - // The #allocated should have stayed the same as this node goes on l2ptPartialFree - ASSERT_EQ(listlength(pageallocator.allocated), totalallocated); - - struct Page * pages[3]; - - for (int i = 0; i < 2; i++) { - pages[i] = pagealloc_allocate_page(); - ASSERT_NULL(pageallocator.pagePartialFree->next); - } - pages[2] = pagealloc_allocate_page(); - - ASSERT_NULL(pageallocator.pagePartialFree); - - ASSERT_EQ(totalallocated + 1u, listlength(pageallocator.allocated)); - - // Now as we allocate a 17th l1 pagetable, the #allocated should have grown by one - struct Page * p17 = pagealloc_allocate_page(); - ASSERT_EQ(listlength(pageallocator.allocated), totalallocated + 1u); - // but l2ptPartialFree should now be of length one again - ASSERT_NOT_NULL(pageallocator.pagePartialFree); - ASSERT_NULL(pageallocator.pagePartialFree->next); - - ASSERT_EQ(p1 + 1, pages[0]); - - // Assert pt2 comes after pt1 etc. - for (int i = 0; i < 2; i++) { - ASSERT_EQ(pages[i] + 1, pages[i+1]); - } - - pagealloc_free_page(p17); - - for (int i = 0; i < 3; i++) { - pagealloc_free_page(pages[i]); - } - - pagealloc_free_page(p1); - - - ASSERT_NOT_NULL(pageallocator.unused); - ASSERT_EQ(listlength(pageallocator.unused),1278); - ASSERT_EQ(listlength(pageallocator.allocated), 2); - ASSERT_NULL(pageallocator.l2ptPartialFree); - ASSERT_NULL(pageallocator.pagePartialFree); - - - for (int i = 0; i < 100; i++) { - struct Page * pages2[100]; - - // Allocate 100 l2pts - for (int i = 0; i < 100; i++) { - pages2[i] = pagealloc_allocate_page(); - } - - // Now free them in a very different order - for (int i = 0; i < 50; i++) { - pagealloc_free_page(pages2[i]); - pagealloc_free_page(pages2[99-i]); - } - - ASSERT_NOT_NULL(pageallocator.unused); - ASSERT_EQ(listlength(pageallocator.unused),1278); - ASSERT_EQ(listlength(pageallocator.allocated), 2); - ASSERT_NULL(pageallocator.l2ptPartialFree); - ASSERT_NULL(pageallocator.pagePartialFree); - } -}) +size_t first_free(uint16_t filled); TEST_CREATE(test_first_free, { ASSERT_EQ(first_free(0b000010), 0); diff --git a/kernel/src/memory/vm/vas2.c b/kernel/src/memory/vm/vas2.c index 32b3ccce..383ed78e 100644 --- a/kernel/src/memory/vm/vas2.c +++ b/kernel/src/memory/vm/vas2.c @@ -1,13 +1,13 @@ #include #include -#include +#include struct vas2 * create_vas() { struct vas2 * newvas = kmalloc(sizeof(struct vas2)); *newvas = (struct vas2) { .tlbDescriptor = request_tlb_descriptor(), - .l1PageTable = pagealloc_allocate_l1_pagetable(), + .l1PageTable = pmm_allocate_l1_pagetable(), }; return newvas; @@ -15,10 +15,10 @@ struct vas2 * create_vas() { void switch_to_vas(struct vas2 * vas) { - + } void free_vas() { - + } diff --git a/kernel/src/memory/vm/vm.c b/kernel/src/memory/vm/vm.c deleted file mode 100644 index 785efd16..00000000 --- a/kernel/src/memory/vm/vm.c +++ /dev/null @@ -1,451 +0,0 @@ -#include -#include -#include -#include - -#define CHECK_VPTR if ((unsigned int)vptr & (BLOCK_SIZE-1)) return VM_ERR_BADV; -#define CHECK_PPTR if ((unsigned int)pptr & (BLOCK_SIZE-1)) return VM_ERR_BADP; - -static const int perm_mapping[16] = { - 0, // 0000 Nothing - 5, // 0001 Privileged RO, nothing otherwise - 6, // 0010 User RO, privileged RO. - 6, // 0011 User RO, privileged RO. - 1, // 0100 Privileged RW, nothing otherwise - -1, // 0101 ??? - 2, // 0110 Privileged RW, user RO - -1, // 0111 ??? - 3, // 1000 User RW, privileged RW - -1, // 1001 ??? - -1, // 1010 ??? - -1, // 1011 ??? - 3, // 1100 User RW, privileged RW - -1, // 1101 ??? - -1, // 1110 ??? - -1, // 1111 ??? - }; - -static struct vas *vm_current_vas = (struct vas*) V_L1PTBASE; - -struct vm_free_list -{ - struct vm_free_list *next; -}; - -struct vm_free_list *vm_vas_free_list = 0x0; -struct vm_free_list *vm_l1pt_free_list = 0x0; -struct vm_free_list *vm_l2pt_free_list = 0x0; - -void vm_init() -{ - const int num_vas = 1024; - - // Initialize the VAS structures. We allocate enough for num_vas VASs. - struct vm_free_list * free_vas = (struct vm_free_list*) P_L1PTBASE; - kprintf("free_vas start location 0x%x\n", free_vas); - - // vm_vas_free_list = free_vas; - vm_vas_free_list = (struct vm_free_list*) ((void*) free_vas + V_L1PTBASE - P_L1PTBASE); - struct vm_free_list *last = 0x0; - while ((uint32_t) free_vas < P_L1PTBASE + sizeof(struct vas) * num_vas) - { - free_vas->next = 0x0; - if (last) - { - last->next = (struct vm_free_list*) ((void*) free_vas + V_L1PTBASE - P_L1PTBASE); - } - last = free_vas; - free_vas = (struct vm_free_list*) ((void*) free_vas + sizeof(struct vas)); - } - // FIXME: doesn't this overlap with the l1pt? - kprintf("free_vas end location 0x%x\n", free_vas); - - // Initialize the L1 page tables - struct vm_free_list * free_l1pt = (struct vm_free_list*) (P_L1PTBASE + sizeof(struct vas) * num_vas); - - kprintf("free_l1pt start location 0x%x\n", free_l1pt); - - vm_l1pt_free_list = (struct vm_free_list*) ((void*) free_l1pt + V_L1PTBASE - P_L1PTBASE); - - - last = 0x0; - while ((uint32_t) free_l1pt < P_L1PTBASE + (1 << 20) - ((1 << 20) >> 2)) - { - free_l1pt->next = 0x0; - if (last) - { - last->next = (struct vm_free_list*) ((void*) free_l1pt + V_L1PTBASE - P_L1PTBASE); - } - last = free_l1pt; - free_l1pt = (struct vm_free_list*) ((void*) free_l1pt + PAGE_TABLE_SIZE); - } - kprintf("free_l1pt end location 0x%x\n", free_l1pt); - - // Initialize the L2 coarse page tables - struct vm_free_list * free_l2pt = (struct vm_free_list*) (P_L1PTBASE + (1 << 19)); - - kprintf("free_l2pt location 0x%x\n", free_l2pt); - - - vm_l2pt_free_list = (struct vm_free_list*) ((void*) free_l2pt + V_L1PTBASE - P_L1PTBASE); - last = 0x0; - while ((uint32_t) free_l2pt < P_L1PTBASE + (1 << 20)) - { - free_l2pt->next = 0x0; - if (last) - { - last->next = (struct vm_free_list*) ((void*) free_l2pt + V_L1PTBASE - P_L1PTBASE); - } - last = free_l2pt; - free_l2pt = (struct vm_free_list*) ((void*) free_l2pt + L2_PAGE_TABLE_SIZE); - } - - kprintf("free_l2pt end location 0x%x\n", free_l2pt); - -} - -uint32_t *vm_alloc_coarse_page_table() -{ - // TODO: What if we run out? - uint32_t *vptr = (uint32_t*) vm_l2pt_free_list; - kprintf("Allocating l2 pagetable at 0x%x\n", vptr); - if (vptr == 0x0) - { - LOG("Could not allocate a coarse page table, bad things will happen soon.\n"); - return NULL; - } - vm_l2pt_free_list = ((struct vm_free_list*) vptr)->next; - memset((void*) vptr, 0, L2_PAGE_TABLE_SIZE); - return vptr; - -} - -uint32_t *vm_vtop(struct vas *vas, uint32_t *vptr) { - // Hack. Assume it's all linearly mapped, and vas == KERNEL_VAS - if (vas != KERNEL_VAS) { - kprintf("vas is not KERNEL_VAS in vm_vtop. :-(\n"); - panic(); - } - return (uint32_t*) ((void*) vptr - V_L1PTBASE + P_L1PTBASE); -} - -uint32_t *vm_ptov(struct vas *vas, uint32_t *vptr) { - // Hack. Assume it's all linearly mapped, and vas == KERNEL_VAS - if (vas != KERNEL_VAS) { - kprintf("vas is not KERNEL_VAS in vm_vtop. :-(\n"); - panic(); - } - return (uint32_t*) ((void*) vptr + V_L1PTBASE - P_L1PTBASE); -} - -struct vas *vm_get_current_vas() { - return vm_current_vas; -} - -void vm_use_kernel_vas() { - vm_enable_vas((struct vas*) V_L1PTBASE); -} - -int vm_allocate_page(struct vas *vas, void *vptr, int permission) { - CHECK_VPTR; - - // We have to save the current VAS and switch to the kernel VAS - struct vas *prev_vas = vm_current_vas; - vm_use_kernel_vas(); - - // TODO: Check if the vas already has a mapping there. - void *pptr = vm_get_free_frame(); - if (pptr == 0x0) - { - // We need to swap! (or something...) - vm_enable_vas(prev_vas); - return VM_ERR_UNKNOWN; // For now, just fail - } - - kprintf("mapping VA %x to PA %x\n", vptr, pptr); - - //LOG("Free frame is at: %X\n", pptr); - int retval = vm_set_mapping(vas, vptr, pptr, permission); - if (retval) - { - // Release the frame to prevent a memory leak - kprintf("vm_set_mapping returned %d for 0x%X\n", retval, vptr); - vm_release_frame(pptr); - vm_enable_vas(prev_vas); - return retval; - } - - vm_enable_vas(prev_vas); - return 0; -} - -void *vm_allocate_pages(struct vas *vas, void *vptr, uint32_t nbytes, int permission) { - int rc; - unsigned char *p = (unsigned char*) vptr; - while (p - (unsigned char*) vptr < nbytes) { - rc = vm_allocate_page(vas, p, permission); - if(rc != STATUS_OK) { - kprintf("Allocate page failed with code %i\n", rc); - kprintf("vptr: 0x%x", (uint32_t) p); - - panic(); - } - - p += BLOCK_SIZE; - } - return p; -} - - -int vm_free_page(struct vas *vas, void *vptr) { - CHECK_VPTR; - - // We have to save the current VAS - struct vas *prev_vas = vm_current_vas; - vm_use_kernel_vas(); - - // TODO: Check if it was actually allocated - uint32_t entry = VM_L1_GET_ENTRY(vas->l1_pagetable, vptr); - - // Okay, it's a 4KB page. We need to walk the l2 page table. - uint32_t *l2pt = vm_ptov(KERNEL_VAS, (uint32_t*) VM_ENTRY_GET_L2(entry)); - entry = VM_L2_ENTRY(l2pt, vptr); - vm_release_frame((void*) VM_L2ENTRY_GET_FRAME(entry)); - //LOG("Releasing frame %X, l2pt=%X\n", VM_L2ENTRY_GET_FRAME(entry), l2pt); - VM_L2_ENTRY(l2pt,vptr)= 0; - //vas->l1_pagetable[(unsigned int)vptr>>20] = 0; - - vm_enable_vas(prev_vas); - return 0; -} - -int vm_pin(struct vas *vas, void *vptr) { - // FIXME: unimplemented - return 0; -} - -int vm_unpin(struct vas *vas, void *vptr) { - // FIXME: unimplemented - return 0; -} - -int vm_set_mapping(struct vas *vas, void *vptr, void *pptr, int permission) { - CHECK_VPTR; - CHECK_PPTR; - int perm = perm_mapping[permission]; - if (perm == -1) - return VM_ERR_BADPERM; - - uint32_t cur_entry = vas->l1_pagetable[(unsigned int) vptr >> 20]; - if ((cur_entry & 3) == 2) { - return VM_ERR_MAPPED; - } - if ((cur_entry & 3) == 0) { - // We need to allocate a coarse page table - uint32_t *vptr_coarse_pt = vm_alloc_coarse_page_table(); - vas->l1_pagetable[(unsigned int) vptr >> 20] = (uint32_t) vm_vtop( - KERNEL_VAS, vptr_coarse_pt) | 1; - cur_entry = vas->l1_pagetable[(unsigned int) vptr >> 20]; - } - - uint32_t *l2_pagetable = vm_ptov(KERNEL_VAS, - (uint32_t*) VM_ENTRY_GET_L2(cur_entry)); - int l2_idx = ((unsigned int) vptr & 0x000FF000) >> 12; - if (l2_pagetable[l2_idx]) { - return VM_ERR_MAPPED; - } - - //perm &= ~(1<<10); // Clear AP[0] so we get an access exception. - //vas->l1_pagetable[(unsigned int)vptr>>20] = (unsigned int)pptr | (perm<<10) | 2; - // TODO: Permissions! - int lvl2_perm = perm; //perm_mapping[perm]; - int apx_bit = (lvl2_perm & 4) >> 2; - int ap_bits = lvl2_perm & 3; - l2_pagetable[l2_idx] = (unsigned int) pptr | (apx_bit << 9) | (ap_bits << 4) - | 2; - //os_printf("pptr: %X, idx=%d, l2pt=%X\n", pptr, l2_idx, l2_pagetable); - //os_printf("permission=%d lvl2_perm=%X apx=%X ap=%X\n", permission, lvl2_perm, apx_bit, ap_bits); - //l2_pagetable[l2_idx] = (unsigned int)pptr | (1<<4) | 2; - return 0; -} - -int vm_swap_free_mapping(struct vas *vas, void *vptr, uint32_t *ID) -{ - CHECK_VPTR; - // TODO: If this is a paged frame, then we need to throw an error - if ((vas->l1_pagetable[(unsigned int) vptr >> 20] & 3) == 2) - { - vas->l1_pagetable[(unsigned int) vptr >> 20] = 0; - } - else if ((vas->l1_pagetable[(unsigned int) vptr >> 20] & 3) == 1) - { - // We have to free the mapping in the L2 page table - uint32_t *l2pt = vm_ptov(KERNEL_VAS, - (uint32_t*) VM_ENTRY_GET_L2( - vas->l1_pagetable[(unsigned int )vptr >> 20])); - VM_L2_ENTRY(l2pt, vptr)= (uint32_t) ID; - } - return 0; -} - -int vm_free_mapping(struct vas *vas, void *vptr) -{ - CHECK_VPTR; - // TODO: If this is a paged frame, then we need to throw an error - if ((vas->l1_pagetable[(unsigned int) vptr >> 20] & 3) == 2) - { - vas->l1_pagetable[(unsigned int) vptr >> 20] = 0; - } - else if ((vas->l1_pagetable[(unsigned int) vptr >> 20] & 3) == 1) - { - // We have to free the mapping in the L2 page table - uint32_t *l2pt = vm_ptov(KERNEL_VAS, - (uint32_t*) VM_ENTRY_GET_L2( - vas->l1_pagetable[(unsigned int )vptr >> 20])); - VM_L2_ENTRY(l2pt, vptr)= 0; - } - return 0; -} - -// We're going to have to switch to the kernel's VAS, then copy it over. -int vm_map_shared_memory(struct vas *vas, void *this_ptr, struct vas *other_vas, - void *other_ptr, int permission) -{ - if ((unsigned int) this_ptr & (BLOCK_SIZE - 1)) - return VM_ERR_BADV; - if ((unsigned int) other_ptr & (BLOCK_SIZE - 1)) - return VM_ERR_BADP; - - struct vas *prev_vas = vm_current_vas; - vm_enable_vas(KERNEL_VAS); - - if ((vas->l1_pagetable[(unsigned int) this_ptr >> 20] & 3) == 2) - { - return VM_ERR_MAPPED; - } - if (!other_vas->l1_pagetable[(unsigned int) other_ptr >> 20]) - { - return VM_ERR_NOT_MAPPED; - } - if (!vas->l1_pagetable[(unsigned int) this_ptr >> 20]) - { - // We need to allocate a coarse page table... - uint32_t *vptr_coarse_pt = vm_alloc_coarse_page_table(); - vas->l1_pagetable[(unsigned int) this_ptr >> 20] = (uint32_t) vm_vtop( - KERNEL_VAS, vptr_coarse_pt) | 1; - //LOG("Allocated coarse page table.\n"); - //LOG("Should be zero: %X (%X)\n", vptr_coarse_pt[0], vptr_coarse_pt); - } - uint32_t *this_l2pt = vm_ptov(KERNEL_VAS, - (uint32_t*) VM_ENTRY_GET_L2( - vas->l1_pagetable[(unsigned int )this_ptr >> 20])); - if (VM_L2_ENTRY(this_l2pt, this_ptr)) - { - //LOG("Should be zero: %X (this_l2pt=%X, idx=%d)\n", VM_L2_ENTRY(this_l2pt, this_ptr), this_l2pt, ((unsigned int)this_ptr&0x000FF000)>>12); - return VM_ERR_MAPPED; - } - uint32_t *other_l2pt = vm_ptov(KERNEL_VAS, - (uint32_t*) VM_ENTRY_GET_L2( - other_vas->l1_pagetable[(unsigned int )other_ptr >> 20])); - if (!VM_L2_ENTRY(other_l2pt, other_ptr)) - { - return VM_ERR_NOT_MAPPED; - } - - int perm = perm_mapping[permission]; - if (perm == -1) - return VM_ERR_BADPERM; - - // Well, this was remarkably easy. - //unsigned int pptr = VM_ENTRY_GET_FRAME(other_vas->l1_pagetable[(unsigned int)other_ptr>>20]); - unsigned int pptr = VM_L2ENTRY_GET_FRAME( - VM_L2_ENTRY(other_l2pt, other_ptr)); - //os_printf("pptr: %X\n",pptr); - //perm &= ~(1<<10); // Clear AP[0] so we get an access exception. - //vas->l1_pagetable[(unsigned int)this_ptr>>20] = pptr | (perm<<10) | 2; - VM_L2_ENTRY(this_l2pt, this_ptr)= pptr | (1<<4) | 2; - LOG("%X\n", VM_L2_ENTRY(this_l2pt, this_ptr)); - - vm_enable_vas(prev_vas); - return 0; -} - -void vm_enable_vas(struct vas *vas) -{ - vm_current_vas = vas; - - // Clear the BTAC - // Performed by cleaning the caches, below - // asm volatile("mcr p15, 0, %[r], c7, c5, 6" : : [r] "r" (0x0)); - - // Flush the write caches - asm volatile("MCR p15, 0, %[r], c7, c10, 4" : : [r] "r" (0x0)); - // sync barrier - asm volatile("MCR p15, 0, %[r], c7, c10, 5" : : [r] "r" (0x0)); - // memory barrier - - //TTBR0 - asm volatile("mcr p15, 0, %[addr], c2, c0, 0" : : [addr] "r" (vas->l1_pagetable_phys)); - // Translation table 1 is currently ignored - - // Clean the caches (data & instruction) - asm volatile("mcr p15, 0, %[r], c7, c14, 0" : : [r] "r" (0x0)); -} - -struct vas *vm_new_vas() -{ - if (!vm_vas_free_list) { - return 0x0; - } - if (!vm_l1pt_free_list) { - return 0x0; - } - struct vas *p = (struct vas*) vm_vas_free_list; - vm_vas_free_list = vm_vas_free_list->next; - - kprintf("vm_l1pt_free_list=%X\n", vm_l1pt_free_list); - p->l1_pagetable = (uint32_t*) vm_l1pt_free_list; - vm_l1pt_free_list = vm_l1pt_free_list->next; - - p->l1_pagetable_phys = (unsigned int*) ((unsigned int) p->l1_pagetable - (V_L1PTBASE - P_L1PTBASE)); - - // Zero out the page table -// memset((unsigned int *)p->l1_pagetable, 0, PAGE_TABLE_SIZE); -// -// // Setup the static mappings... -// // The kernel (high & low addresses) -// //should be less than a MB -// p->l1_pagetable[P_KERNBASE >> 20] = 0 << 20 | 0x0400 | 2; -// -// //also map it to high memory at 0xf0000000 -// p->l1_pagetable[V_KERNBASE >> 20] = 0 << 20 | 0x0400 | 2; -// p->l1_pagetable[(V_KERNBASE + 0x100000) >> 20] = 0x100000 | 0x0400 | 2; -// -// // Kernel datastructures -// //temporarily map where it is until we copy it in VAS -// p->l1_pagetable[P_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; -// -// //1MB for static kernel data structures (stacks and l1 pt) -// p->l1_pagetable[V_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; -// -// // Our 1MB page to store VAS datastructures -// p->l1_pagetable[V_L1PTBASE >> 20] = P_L1PTBASE | 0x0400 | 2; -// -// // 2MB of peripheral registers (so we get the serial port et. al.) -// p->l1_pagetable[PERIPHBASE >> 20] = PERIPHBASE | 0x0400 | 2; -// p->l1_pagetable[(PERIPHBASE + 0x100000) >> 20] = (PERIPHBASE + 0x100000) | 0x0400 | 2; - - return p; -} - -int vm_free_vas(struct vas *vas) -{ - struct vm_free_list *n = (struct vm_free_list*) vas->l1_pagetable; - n->next = vm_l1pt_free_list; - vm_l1pt_free_list = n; - - n = (struct vm_free_list*) vas; - n->next = vm_vas_free_list; - vm_vas_free_list = n; - return 0; -} diff --git a/kernel/src/memory/vm/vm2.c b/kernel/src/memory/vm/vm2.c index a61e0714..f5d95aff 100644 --- a/kernel/src/memory/vm/vm2.c +++ b/kernel/src/memory/vm/vm2.c @@ -1,96 +1,176 @@ #include #include #include -#include #include -#include -#include +#include +#include +#include -struct L1PageTable * kernell1PageTable = (struct L1PageTable *) PhysicalL1PagetableLocation; -struct L1PageTable * virtualkernell1PageTable = (struct L1PageTable *) VirtualL1PagetableLocation; +struct L1PageTable * kernell1PageTable = (struct L1PageTable *) VirtualL1PagetableLocation; // NOLINT(cppcoreguidelines-interfaces-global-init) (defined in linker script) bool mmu_started = false; static inline size_t l1pt_index(size_t address) { return address >> 20u; } -void vm2_map_virtual_to_physical_l1(size_t virtual, size_t physical) { - if(mmu_started) { - // Outside users are not allowed to add entries to the pagetable - // after the mmu has been started. They can request a new frame with - // - panic(); - } +static inline uint8_t l2pt_index(size_t address) { + return (address & 0x000ff000u) >> 12u; +} - if (kernell1PageTable->entries[l1pt_index(virtual)].entry != 0){ - // The entry is already mapped - kprintf("Request for already mapped address denied"); - panic(); +static inline size_t l1pt_base_address(size_t address) { + // For l1 they are the same + return l1pt_index(address); +} + +static inline size_t l2pt_base_address(size_t address) { + return address >> 12u; +} +// TODO: More descriptive name +// Finds the location of an l2pt given an l1pt coarse entry. +static inline struct L2PageTable * l2pt_in_l1 (L1PagetableEntry * l1ptEntry){ + if(l1ptEntry->coarse.type == 1) { + return (struct L2PageTable *) PHYS2VIRT(l1ptEntry->coarse.base_address << 10u); + } else { + FATAL("Can't get L2 address from non-coarse L1 Entry"); } +} + +bool vm2_l1_map_physical_to_virtual(struct L1PageTable * pt, union L1PagetableEntry entry, size_t virtual, bool remap) { - L1PagetableEntry entry = { - .section.type = 2, // section - .section.bufferable = 0, - .section.cachable = 0, - .section.accessPermissions = 0b01, // Kernel r/w, user no access. - .section.TEX = 0, // Strongly ordered - .section.accessExtended = 0, // r/w access - .section.supersection = 0, - .section.nonSecure = 1, - .section.base_address = l1pt_index(physical), - }; + bool remapped = false; - kprintf("Mapping 1mb at virtual: 0x%x to physical: 0x%x\n", l1pt_index(virtual) << 20u, l1pt_index(physical)<<20u); + if (pt->entries[l1pt_index(virtual)].entry != 0) { + if (remap) { + remapped = true; + } else { + // The entry is already mapped + FATAL("Request for already mapped address denied"); + } + } kernell1PageTable->entries[l1pt_index(virtual)] = entry; + + return remapped; +} + +void vm2_flush_caches() { + //TODO: Only a subset of these instructions are necessary + asm volatile ( + "// invalidate caches\n" + "mcr p15, 0, %0, c7, c5, 0\n" + "// invalidate tlb\n" + "mcr p15, 0, %0, c8, c7, 0\n" + "// data sync barrier\n" + "mcr p15, 0, %0, c7,c10, 4\n" + + "mcr p15, 0, %0, c7, c10, 4\n" + "mcr p15, 0, %0, c7, c10, 5\n" + "mcr p15, 0, %0, c7, c14, 0\n" + :: "r"(0x0)); } -void vm2_map_nmegabytes_1to1(size_t address, size_t n) { - if(n == 0) { - panic(); +// Starts the actual MMU after this function we live in Virtual Memory +void vm2_start() { + size_t available_RAM; + + switch (get_hardwareinfo()->boardType) { + case RaspberryPiZero: + available_RAM = 512 * Mebibyte; + break; + case RaspBerryPiTwo: + available_RAM = 1 * Gibibyte; + break; + default: + // TODO: memory detection? Or just not bother. + kprintf("Board type unsupported by VM2\n"); + panic(); } - // Iterate over the address in 1 MiB chunks. - for (size_t newaddress = address; newaddress < (address + Mibibyte * n) ; newaddress += Mibibyte) { - vm2_map_virtual_to_physical_l1(newaddress, newaddress); + INFO("Using memory size 0x%x", available_RAM); + + /// Unmap the 1:1 mapped first megabyte which startup.s created to boot to a higher half kernel. + /// We don't need it anymore! +// kernell1PageTable->entries[0] = (L1PagetableEntry){0}; + + /// Map the entire gigabyte (or less on some boards, but never more) physical ram to virtual 2GB-3GB. + /// this includes the kernel, kernel stack, kernel pagetables, process pagetables, pmm etc. + for (size_t i = 0; i < (size_t)available_RAM; i += Mebibyte) { + vm2_l1_map_physical_to_virtual(kernell1PageTable, (union L1PagetableEntry) { + .section.type = 2, + .section.accessPermissions = 1, + .section.base_address = l1pt_base_address(i), + }, KERNEL_VIRTUAL_OFFSET + i, true); } + + pmm_init(KERNEL_PMM_BASE, KERNEL_VIRTUAL_OFFSET + available_RAM); + + + vm2_flush_caches(); + mmu_started = true; } -// Prepares the pagetable and add -void vm2_prepare() { - // Clear the pagetable - memset(kernell1PageTable, 0, sizeof(struct L1PageTable)); +void * vm2_allocate_kernel_page(struct L1PageTable * l1pt, size_t virtual, bool executable) { + L1PagetableEntry * l1Entry = &l1pt->entries[l1pt_index(virtual)]; + struct L2PageTable * l2 = NULL; + + switch (l1Entry->section.type ) { + case 0:; + // Allocate coarse/l2 pagetable + l2 = pmm_allocate_l2_pagetable(); + *l1Entry = (L1PagetableEntry) { + .coarse = { + .type = 1, + .base_address = ((size_t)VIRT2PHYS((size_t)l2)) >> 10u, + }, + }; + /** Fallthrough **/ + case 1:; + struct Page * page = pmm_allocate_page(); + // There already is a coarse pagetable + if(l2 == NULL) { + l2 = l2pt_in_l1(l1Entry); + } + union L2PagetableEntry * l2Entry = &l2->entries[l2pt_index(virtual)]; + + *l2Entry = (union L2PagetableEntry) { + .smallpage = { + .type = 2 + !executable, + .bufferable = 0, + .cachable = 0, + .accessPermissions = 1, + .accessExtended = 0, + .base_address = l2pt_base_address(((size_t)VIRT2PHYS(page))), + }, + }; + + return page; + default: + // This is a (super)section and we can't make it a coarse pagetable. Error. + return NULL; + } } +size_t vm2_map_peripheral(size_t physical, size_t n_mebibytes) { + static size_t mmio_current_top = KERNEL_MMIO_BASE; + mmio_current_top -= (n_mebibytes * Mebibyte); + for (size_t i = 0; i < n_mebibytes; i++) { -// Starts the actual MMU after this function we live in Virtual Memory -void vm2_start() { - // Temporary, TODO: new range - pagealloc_init(Gibibyte - 25 * Mibibyte, Gibibyte - 5 * Mibibyte); - - /// Identitymap the kernel and the stack. The kernel starts at 0x8000 but we already - /// start mapping at 0x0000 as this is the first address before 0x8000 that's megabyte - /// aligned. This has as a nice bonus that we also identitymap the L1 pagetable - /// which lives at L1PagetableLocation=0x4000, and the interrupt vectors at 0x0. - /// FIXME: We want to _eventually_ switch to a fully higher half kernel - for (size_t i = 0; i < (size_t)KERNEL_TOP; i += Mibibyte) { - vm2_map_nmegabytes_1to1(i, 1); - } + kernell1PageTable->entries[l1pt_index(mmio_current_top)] = (L1PagetableEntry){ + .section.type = 2, + .section.accessPermissions = 1, + .section.base_address = l1pt_base_address(physical), + }; - /// Map the kernel and the stack a second time to high virtual memory. Again this also - /// maps the l1 pagetable here and the interrupt vectors at 0x0. - for (size_t i = 0; i < (size_t)KERNEL_TOP; i += Mibibyte) { - vm2_map_virtual_to_physical_l1(KERNEL_VIRTUAL_START + i, i); + mmio_current_top += Mebibyte; + physical += Mebibyte; } - /// Map 1 megabyte for the kernel L2 pagetables. - vm2_map_virtual_to_physical_l1(VirtualL2PagetableLocation, PhysicalL2PagetableLocation); - kprintf("KERNEL_TOP: 0x%x, KERNEL_BASE: 0x%x\n", KERNEL_TOP, KERNEL_BASE); + mmio_current_top -= (n_mebibytes * Mebibyte); - mmu_started = true; + return mmio_current_top; } diff --git a/kernel/src/process/elf.c b/kernel/src/process/elf.c deleted file mode 100644 index 6c9eb500..00000000 --- a/kernel/src/process/elf.c +++ /dev/null @@ -1,259 +0,0 @@ -/* Worked on by Jeremy Wenzel, Kaelen Haag, and Sam Allen */ -#include -#include -#include - -unsigned char* filePointer; -unsigned char* startPointer; -//OVERHAUL TO MAKE EVERYTHING PASSED BY REFERENCE RATHER THAN VALUE. -//I THINK WE SHOULD JUST COMMENT OUT ALL THE SECTION HEADER STUFF BECAUSE IT'S NOT USED AND WILL BE A PAINTO MESS WITH. NEED TO MAKE PROGRAM HEADER ARRAY PASS BY VALUE AND NEED TO FIX get_value to take in refernce rather than value. DO TONIGHT OR TOMORROW - KAELEN - -/* Gets the value of the bytes on a big endian system */ -uint32_t do_big_endian(uint32_t size) -{ - uint32_t value = 0; - while (size > 0) - { - value = value << 8; - value = value + *filePointer; - filePointer++; - size--; - } - return value; -} - -/* Gets the value of the bytes on a little endian system */ -uint32_t do_little_endian(uint32_t size) -{ - uint32_t value = 0; - uint32_t num = 0; - int i = 0; - while (i < size) - { - num = *filePointer; - num = num << (8 * i); - value = value + num; - filePointer++; - i++; - } - return value; - -} - -/* Gets value of bytes given a size of bytes */ -//Make this pass by reference -uint32_t get_value(uint32_t size, Elf_Ehdr *h) -{ - if (h->e_ident[EI_DATA] == 1) - return do_little_endian(size); - else - return do_big_endian(size); -} - -/* Checks if the file is even an elf file */ -/* Returns 1 if elf file, -1 if not */ -int32_t isElf(Elf_Ehdr *h) -{ - // checks if elf file - char ELFMAG0 = get_value(1, h);// 0x7f - char ELFMAG1 = get_value(1, h);// 'E' - char ELFMAG2 = get_value(1, h);// 'L' - char ELFMAG3 = get_value(1, h);// 'F' - if (ELFMAG0 != 127 || ELFMAG1 != 'E' || ELFMAG2 != 'L' || ELFMAG3 != 'F') - return -1; - h->e_ident[EI_MAG0] = ELFMAG1; - h->e_ident[EI_MAG1] = ELFMAG2; - h->e_ident[EI_MAG2] = ELFMAG3; - return 1; -} - -/* Parses elf header of ELF file and places into ELF struct header */ -/* CRITICAL: It is important to initialize the elf header before - sending it into the function. Makes sure no data is lost */ -int32_t read_elf_header(Elf_Ehdr *h, unsigned char *pointer) -{ - filePointer = startPointer = pointer; - int32_t check = isElf(h); - if (check == -1) - { - return -1; - } - //os_printf("Size of char: %d\n", sizeof(char)); - //os_printf("Size of get_value(1, h): %d\n", sizeof((char)get_value(1, h))); - char temp = get_value(1, h); - //os_printf("Size of temp: %d\n", sizeof(temp)); - h->e_ident[EI_CLASS] = temp; // get_value(1, h); // get class - - temp = get_value(1, h); - h->e_ident[EI_DATA] = temp; //get_value(1, h); // endian - - temp = get_value(1, h); - h->e_ident[EI_VERSION] = temp; //get_value(1, h); // original version of ELF - - temp = get_value(1, h); - h->e_ident[EI_OSABI] = temp; //get_value(1, h); // Target operating system ABI - - temp = get_value(1, h); - h->e_ident[EI_ABIVERSION] = temp; //get_value(1, h); // Don't really know? - - int32_t skip = 0; // skips the padding - while (skip < 7) - { - get_value(1, h); - skip++; - } - Elf_Half half_temp = get_value(2, h); - h->e_type = half_temp; //get_value(2, h); // get type of file - - half_temp = get_value(2, h); - h->e_machine = half_temp; //get_value(2, h); // gets machine type (should be arm in our case) - - Elf_Word word_temp = get_value(4, h); - h->e_version = word_temp; //get_value(4, h); // version number (should be 1) - if (h->e_ident[EI_CLASS] == 1) // get entry point - { - word_temp = get_value(4, h); - h->e_entry = word_temp; //get_value(4, h); - } - else - h->e_entry = get_value(8, h); - - if (h->e_ident[EI_CLASS] == 1) // get program header offset - { - word_temp = get_value(4, h); - h->e_phoff = word_temp; //get_value(4, h); - } - else - h->e_phoff = get_value(8, h); - - if (h->e_ident[EI_CLASS] == 1) // get section header offset - { - word_temp = get_value(4, h); - h->e_shoff = word_temp; //get_value(4, h); - } - else - h->e_shoff = get_value(8, h); - - word_temp = get_value(4, h); - h->e_flags = word_temp; //get_value(4, h); // get flag number - - half_temp = get_value(2, h); - h->e_ehsize = half_temp; //get_value(2, h); // get elf header size - - half_temp = get_value(2, h); - h->e_phentsize = half_temp; //get_value(2, h); // get program header size - - half_temp = get_value(2, h); - h->e_phnum = half_temp; //get_value(2, h); // number of program headers - - half_temp = get_value(2, h); - h->e_shentsize = half_temp; //get_value(2, h); // section header size - - half_temp = get_value(2, h); - h->e_shnum = half_temp; //get_value(2, h); // number of section headers - - half_temp = get_value(2, h); - h->e_shstrndx = half_temp; //get_value(2, h); // section header string table index - - return 1; // return success -} - -void read_program_header_table(Elf_Ehdr *eh, Elf_Phdr ph[], - unsigned char *pointer) -{ - filePointer = startPointer = pointer; - filePointer = startPointer + eh->e_phoff; - int i = 0; - Elf_Word word_temp = 0; - while (i < eh->e_phnum) - { - word_temp = get_value(4, eh); - ph[i].p_type = word_temp; //get_value(4, eh); - ph[i].p_offset = get_value(4, eh); - ph[i].p_vaddr = get_value(4, eh); - ph[i].p_paddr = get_value(4, eh); - ph[i].p_filesz = get_value(4, eh); - ph[i].p_memsz = get_value(4, eh); - ph[i].p_flags = get_value(4, eh); - ph[i].p_align = get_value(4, eh); - i++; - } - -} - -/* Reads the section header table and places it into the the section header array */ -/* CRITICAL: The section header must be initalized with the correct size, - before put into the function */ -void read_section_header_table(Elf_Ehdr *eh, Elf_Shdr sh[], uint32_t *pointer) -{ - filePointer = startPointer = (unsigned char*) pointer; - int i = 0; - filePointer = startPointer + eh->e_shoff; - while (i < eh->e_shnum) - { - sh[i].sh_name = get_value(4, eh);// get name, which is index into string table - sh[i].sh_type = get_value(4, eh); // type of section header - sh[i].sh_flags = get_value(4, eh); // flags that partain to the header - sh[i].sh_addr = get_value(4, eh);// address of header (don't know much yet) - sh[i].sh_offset = get_value(4, eh); // offset from beginning of elf file - sh[i].sh_size = get_value(4, eh); // size of this section - sh[i].sh_link = get_value(4, eh); // link (don't know much yet) - sh[i].sh_info = get_value(4, eh); // info (don't know much yet) - sh[i].sh_addralign = get_value(4, eh);// address aligned (don't know much yet) - sh[i].sh_entsize = get_value(4, eh); - i++; - } -} - -/* Goes to the Section header that contains the section header string table */ -/* It then analyzes the table and puts them into each section header */ -/* This makes it easier to differentiate between sections when put into loader */ -void parse_section_header_names(Elf_Ehdr *eh, Elf_Shdr sh[], uint32_t *pointer) -{ - filePointer = startPointer = (unsigned char*) pointer; - filePointer = startPointer + sh[eh->e_shstrndx].sh_offset;// This pointer iterates through the section header - int i = 1; - - filePointer++; - while (i < eh->e_shnum) - { - if (strcmp(((char*) filePointer), ".symtab") == 0) - { // checks if symbol table - sh[i].sh_numname = SYMTAB; - } - else if (strcmp(((char*) filePointer), ".text") == 0) - { // checks if .text table - sh[i].sh_numname = TEXT; - } - else if (strcmp(((char*) filePointer), ".comment") == 0) - { // checks if comment table - sh[i].sh_numname = COMMENT; - } - else if (strcmp(((char*) filePointer), ".strtab") == 0) - { // checks if string table - sh[i].sh_numname = STRTAB; - } - else if (strcmp(((char*) filePointer), ".shstrtab") == 0) - { // checks if section header string table - sh[i].sh_numname = SHSTRTAB; - } - else if (strcmp(((char*) filePointer), ".rodata") == 0) - { // checks if read only data - sh[i].sh_numname = RODATA; - } - else if (strcmp(((char*) filePointer), ".data") == 0) - { // checks if initialized data - sh[i].sh_numname = DATA; - } - else if (strcmp(((char*) filePointer), ".bss") == 0) - { // checks if unitialized data - sh[i].sh_numname = BSS; - } - else - ; - while (*((char*) filePointer) != '\0')// move on to next sting in the list - filePointer++; - filePointer++; - i++; // move on to next item in section header table - } -} diff --git a/kernel/src/process/include/elf.h b/kernel/src/process/include/elf.h deleted file mode 100644 index aadd6e68..00000000 --- a/kernel/src/process/include/elf.h +++ /dev/null @@ -1,153 +0,0 @@ -/* Any confusion with what does what can be gotten from the - following website. It defines all the values - http://man7.org/linux/man-pages/man5/elf.5.html -*/ - -#ifndef _ELF_H_ -#define _ELF_H_ - -#include -#include - -typedef uint32_t Elf_Addr; // Program Address -typedef uint16_t Elf_Half; // 16 bit -typedef uint32_t Elf_Off; // File Offset -typedef int32_t Elf_Sword; // Signed 32 bit int -typedef uint32_t Elf_Word; // Unsigned 32 bit int -#define EI_NIDENT 16 - -/* Elf Header */ -/* Note: The ELF Header should begin the following header - EI_MAG0 = 0x7f - EI_MAG1 = 'E' - EI_MAG2 = 'L' - EI_MAG3 = 'F' -*/ - -/* Magic Numbers and preliminary info about file */ -#define EI_MAG0 0 // 0x7f -#define EI_MAG1 1 // 'E' -#define EI_MAG2 2 // 'L' -#define EI_MAG3 3 // 'F' -#define EI_CLASS 4 -#define EI_DATA 5 -#define EI_VERSION 6 -#define EI_OSABI 7 // Targeted operating system -#define EI_ABIVERSION 8 - -/* ELF Header Flags */ -#define EF_ARM_ABIMASK 0xFF000000 -#define EF_ARM_BE8 0x00800000 -#define EF_ARM_GCCMASK 0x00400FFF -#define EF_ARM_ABI_FLOAT_HARD 0x00000400 -#define EF_ARM_ABI_FLOAT_SOFT 0x00000200 - -/* Defines what type of file it is */ -#define no_file_type 0 -#define relocatable 1 -#define executable 2 -#define shared_obj 3 -#define core 4 - -/* Types of Program Headers */ -#define PT_NULL 0 // Indicates an unused program header -#define PT_LOAD 1 // Indicates that this program header describes a segment to be loaded from the file. -#define PT_DYNAMIC 2 // Indicates a segment where dynamic linking information can be found. -#define PT_INTERP 3 // Indicates a segment where the name of the program interpreter may be found. -#define PT_NOTE 4 // Indicates a segment holding note information. -#define PT_SHLIB 5 // A reserved program header type, defined but not specified by the ELF ABI. -#define PT_PHDR 6 // Indicates a segment where the program headers may be found. - -/* Program Flags */ -// 0: No access -// 1: Just execute -// 2: Write only -// 3: Write, execute only -// 4: Read only -// 5: Read, execute only -// 6: Read, write only -// 7: Read, Write, and Execute - -typedef enum {TEXT, RODATA, DATA, SYMTAB, STRTAB, SHSTRTAB, BSS, COMMENT} Section; - -typedef struct { - unsigned char e_ident[EI_NIDENT]; // How to interpret file - Elf_Half e_type; - Elf_Half e_machine; - Elf_Word e_version; - Elf_Addr e_entry; - Elf_Off e_phoff; - Elf_Off e_shoff; - Elf_Word e_flags; - Elf_Half e_ehsize; - Elf_Half e_phentsize; - Elf_Half e_phnum; - Elf_Half e_shentsize; - Elf_Half e_shnum; - Elf_Half e_shstrndx; -}Elf_Ehdr; - -/* Program header */ -typedef struct { - Elf_Word p_type; - Elf_Off p_offset; - Elf_Addr p_vaddr; - Elf_Addr p_paddr; - Elf_Word p_filesz; - Elf_Word p_memsz; - Elf_Word p_flags; - Elf_Word p_align; -}Elf_Phdr; - -/* Section header */ -typedef struct { - Elf_Word sh_name; - Elf_Word sh_type; - Elf_Word sh_flags; - Elf_Addr sh_addr; - Elf_Off sh_offset; - Section sh_numname; - Elf_Word sh_size; - Elf_Word sh_link; - Elf_Word sh_info; - Elf_Word sh_addralign; - Elf_Word sh_entsize; -}Elf_Shdr; - -/* Symbol Table */ -typedef struct { - Elf_Word st_name; - Elf_Addr st_value; - Elf_Word st_size; - unsigned char st_info; - unsigned char st_other; - Elf_Half st_shndx; -}Elf_Sym; - -/* Relocation without addend */ -typedef struct { - Elf_Addr r_offset; - Elf_Word r_info; -}Elf_Rel; - -/* Relocation with addend */ -typedef struct { - Elf_Addr r_offset; - Elf_Word r_info; - Elf_Sword r_addend; -}Elf_Rela; - -/* Dynmaic Section header */ -typedef struct { - Elf_Sword d_tag; - union { - Elf_Word d_val; - Elf_Addr d_ptr; - }d_un; -} Elf_Dyn; - -int read_elf_header(Elf_Ehdr *h, unsigned char *pointer); -void read_program_header_table(Elf_Ehdr *eh, Elf_Phdr ph[], unsigned char *pointer); -void read_section_header_table(Elf_Ehdr *eh, Elf_Shdr sh[], uint32_t *pointer); -void parse_section_header_names(Elf_Ehdr *eh, Elf_Shdr sh[], uint32_t *pointer); -#endif diff --git a/kernel/src/process/include/loader.h b/kernel/src/process/include/loader.h deleted file mode 100644 index e242155e..00000000 --- a/kernel/src/process/include/loader.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __loader_h -#define __loader_h -#include -#include - -#define USER_PROC_STACK_SIZE 0x100000 //1 MB -#define KERNEL_PROC_STACK_SIZE 0x1000 //4K -#define USER_PROC_HEAP_SIZE 4096 -#define PADDING 0x1000 - -Elf_Ehdr* load_file(pcb *, uint32_t *); //Needs to be of the type that's where ever our beginning of file is in mem - -#endif diff --git a/kernel/src/process/include/process.h b/kernel/src/process/include/process.h deleted file mode 100644 index 1073c5e1..00000000 --- a/kernel/src/process/include/process.h +++ /dev/null @@ -1,169 +0,0 @@ -#ifndef PROCESS_H -#define PROCESS_H -#include -#include -#include - -/* LOG: - 3/15: Initial skeleton and comments by Josh Guan. - 3/21: More research and comments by Faseeh Akhter and Josh Guan - 3/31: Further research and beginning implementation of process initialization and creation by Faseeh Akhter, Taylor Smith, Sean Villars - 4/2: Fixed mem_alloc and began initial pcb creation by Sean Villars, Faseeh Akhter, Josh Guan, Taylor Smith - 4/7: Fixed mem_alloc and fixed pcb allocation. added a few utility functions as well. Sean V, Faseeh A, Taylor Smith - 4/9: Added some more utility functions and changed process destroy. Sean V - 4/14: Worked on save process state. Sean V, Faseeh A, Taylor Smith - 4/15: Save state inline asm works, working on saving to pcb. Taylor s - 4/16: Load state with inline asm, Sean V, Faseeh A, Taylor Smith - ******************* - a work in progress - memory boundaries? - ******************** - - process struct outline - process id data - PID -- must be unique - User ID - Group ID - parent id ? - - processor state data - pc - CPU GPRs - CPU status word - SP, FP - - process control data - location of eimage on disk - location of user process kernel stack? - - process scheduling state - priority value? - amount of time running or suspended - EFLAGs - process structuring information - process's child process ID - other related processes via their IDs - IPC info* - process privileges* - accounting info - last run?, total CPU time accumulation - what are the bare essentials for a PCB - */ -typedef enum PROCESS_STATE -{ - PROCESS_NEW, PROCESS_READY, PROCESS_RUNNING, PROCESS_BLOCKED, PROCESS_DYING -} PROCESS_STATE; - -#define MAX_PROCESSES 32 - -#define P_STACK_BASE 0x9f000000 -#define PROC_LOCATION 0x9ff00000 -#define P_STACK_SIZE (BLOCK_SIZE) -#define P_STACK_TOP (P_STACK_BASE + P_STACK_SIZE) -#define HEAP_BASE 0x90000000 - - -typedef struct pcb { - //ID data - char* name; /* for debugging purposes */ - uint32_t PID; - uint32_t starting_address; - uint32_t process_number; // is this a mapping to actual executable image? or does it describe total number of processes? - uint32_t user_id; - uint32_t group_id; - uint32_t parent_id; - uint32_t (*function)(); - uint32_t has_executed; - struct vas* stored_vas; - uint32_t start; - uint32_t len; - //CPU state data - PROCESS_STATE current_state; - - /* - * r0-r3 are the argument and scratch registers; r0-r1 are also the result registers - * r4-r8 are callee-save registers - * r9 might be a callee-save register or not (on some variants of AAPCS it is a special register) - * r10-r11 are callee-save registers - * r12-r15 are special registers - * 37 REGISTERS IN TOTAL: 31 GPRs, 6 SRs - */ - - // WE ARE GOING TO TRY TO IMPLEMENT SETJMP/LONGJMP INSTEAD OF MANUALLY DEALING WITH THESE VALUES - // uint32_t PC; - // uint32_t SP; - // uint32_t CPSR; //current prog status register - // uint32_t SPSR; //saved prog status register when execption occurs - //unbanked register - uint32_t R0; - uint32_t R1; - uint32_t R2; - uint32_t R3; - uint32_t R4; - uint32_t R5; - uint32_t R6; - uint32_t R7; - - //banked registers - uint32_t R8; - uint32_t R9; - uint32_t R10; - uint32_t R11; - uint32_t R12; - uint32_t R13; //corresponds to the SP; do we need both? - uint32_t R14; - uint32_t R15; //corresponds to the PC; do we need both? - - //Control data - //int priority_value; - //uint32_t elapsed_time; - //uint32_t EFLAG; - //uint32_t* process_relations - //uint32_t total_cpu_time; - -//CPU state data - uint32_t SPSR; - uint32_t PC; - -//Control data - int priority_value; - uint32_t elapsed_time; - uint32_t EFLAG; - uint32_t* process_relations; - - uint32_t total_cpu_time; - - void* heap_p; - -} pcb; - -/* interface - processes can - be made (initialized) - be terminated - be duplicated - be suspended - be resumed - */ - -//input -//1) address of where the program code is in memory; elf and loader -//process -//do we n eed to create the stack and the heap? -//do we need to know where the data is? -//output -//create a corresponding pcb ds - -//Init process system -void process_init(); - -//Process API - start process from elf -pcb* process_create(const char *name); -int process_execute(pcb* pcb_p); -int process_destroy(pcb* pcb_p); - -//Execution functions -void process_load_state(pcb* pcb_p) __attribute__ ((noreturn)); -void process_save_state(pcb* pcb_p); - -#endif diff --git a/kernel/src/process/include/scheduler.h b/kernel/src/process/include/scheduler.h deleted file mode 100644 index a2f1e5d7..00000000 --- a/kernel/src/process/include/scheduler.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * scheduler.h - * - * Created on: Apr 16, 2015 - * Author: mwkurian - */ - -#include -#include -#include -#include -#include -#include - -#ifndef KERNEL_INCLUDE_SCHEDULER_H_ -#define KERNEL_INCLUDE_SCHEDULER_H_ - -typedef void (*sched_callback_handler)(uint32_t src_pid, uint32_t event, char * data, int chunk_length, int remain_length); - -typedef struct sched_task { - uint32_t parent_tid; - uint32_t tid; - uint32_t state; - uint32_t type; - int niceness; - void * task; - prq_node * node; - arrl_handle * children_tids; - sched_callback_handler cb_handler; - llist_handle * message_queue; -} sched_task; - -typedef struct sched_message_chunk { - uint32_t src_pid; - int chunk_length; - int remain_length; - uint32_t event; - char * data; -} sched_message_chunk; - -uint32_t sched_init(void); -void sched_start(void); -uint32_t sched_free(); -uint32_t sched_add_task(sched_task * task); -uint32_t sched_set_niceness(uint32_t pid, uint32_t niceness); -uint32_t shed_remove_task(uint32_t pid); -uint32_t sched_get_active_pid(); -void sched_waitpid(uint32_t pid); -sched_task* sched_create_task(uint32_t* file_p, int niceness); -sched_task* sched_create_task_from_kthread(kthread_handle * kthread, int niceness); -sched_task* sched_create_task_from_process(pcb * pcb_pointer, int niceness); -sched_task* sched_get_active_task(); -uint32_t sched_post_message(uint32_t dest_pid, uint32_t event, char * data, int len); -uint32_t sched_register_callback_handler(sched_callback_handler cb_handler); -uint32_t sched_deregister_callback_handler(); - -#endif /* KERNEL_INCLUDE_SCHEDULER_H_ */ diff --git a/kernel/src/process/include/signals.h.old b/kernel/src/process/include/signals.h.old deleted file mode 100644 index 8fd45baf..00000000 --- a/kernel/src/process/include/signals.h.old +++ /dev/null @@ -1,11 +0,0 @@ -//Contributors: Andrew Stepek, Michael Brennen, and Matthew Stromberg - -#include "stdint.h" -#include "include/mmap.h" -#include "include/process.h" - -typedef struct signal -{ - char * type; -} sig; - diff --git a/kernel/src/process/loader.c b/kernel/src/process/loader.c deleted file mode 100644 index 3a6640dd..00000000 --- a/kernel/src/process/loader.c +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include -#include -#include -#include -#include - -//Worked on by Kaelen Haag and Jeremy Wenzel -//We determine what the size of our process is going to be -//Determine the size of the segments that need to be loaded in (has p_type == PT_LOAD) -//Account for the other stuff we'll need (Stack, Heap, spacing) -os_size_t det_proc_size(Elf_Ehdr *h, Elf_Phdr ph[]) -{ - os_size_t process_size = 0; - int i = 0; - //Add up the size of all the necessary sections that - for (; i < (h->e_phnum); i++) - { - if (ph[i].p_type == PT_LOAD) - { - process_size += ph[i].p_memsz; - } - } - - process_size += USER_PROC_STACK_SIZE; - process_size += USER_PROC_HEAP_SIZE; //This is going to be the heap size (need to determine what this should be - - //Padding we want to be able to have some padding between certain sections of the program - //mainly the stack from the other parts - process_size += PADDING; - - return process_size; - -} - -//Probably want to return a memory address rather than nothing. -//Take a process control block and pointer to the start of an ELF file in memory. -Elf_Ehdr* load_file(pcb * pcb_p, uint32_t * file_pointer) -{ - Elf_Ehdr *h = (Elf_Ehdr *) kmalloc(sizeof(Elf_Ehdr)); // Get elf header - kprintf("elf header= %x\n", h); - int i = read_elf_header(h, (unsigned char *) file_pointer); - - if (i == -1) - { - kprintf("File is Not an ELF File. Exiting\n"); - return 0; - } - - if (h->e_phnum == 0) - { - kprintf("No Program headers in ELF file. Exiting\n"); - return 0; - } - - Elf_Phdr * ph = (Elf_Phdr *) kmalloc(h->e_phnum * sizeof(Elf_Phdr)); - Elf_Shdr * sh = (Elf_Shdr *) kmalloc(h->e_shnum * sizeof(Elf_Shdr)); - // FIXME: why is sh not used? - UNUSED(sh); - read_program_header_table(h, ph, (unsigned char *) file_pointer); - - //allocate pages for the read only segment - - //allocate pages for text section - - //assert(1 == 2 && "load_file"); - - //read_section_header_table(h, sh, (uint32_t*)file_pointer); - // /vm_enable_vas(pcb_p->stored_vas); - - //allocate_process_memory(pcb_p, h, ph, file_pointer); - - //vm_use_kernel_vas(); - return h; -} - diff --git a/kernel/src/process/process.c b/kernel/src/process/process.c deleted file mode 100644 index bd2765fd..00000000 --- a/kernel/src/process/process.c +++ /dev/null @@ -1,280 +0,0 @@ -#include -#include -#include -#include -#include -//#include -#include - -static pcb** pcb_table; -static bit_vector* pcb_map; - - -pcb* __process_create(); -void __process_elf_init(pcb* pcb_p, const char* name); -void __process_stack_init(pcb* pcb_p); -void __process_heap_init(pcb* pcb_p); - -void process_init() -{ - pcb_table = kmalloc(MAX_PROCESSES * sizeof(pcb*)); - pcb_map = make_vector(MAX_PROCESSES); -} - -pcb* process_create(const char *name) -{ - pcb* pcb_p = __process_create(); - if(!pcb_p) { - return NULL; - } - - __process_elf_init(pcb_p, name); - __process_stack_init(pcb_p); - __process_heap_init(pcb_p); - return pcb_p; -} - -int process_execute(pcb* pcb_p) -{ - //Copy the current process's program counter to the new process's return register - //The new process will use R14 to return to the parent function - asm("MOV %0, r15":"=r"(pcb_p->R14)::); - - pcb_p->current_state = PROCESS_RUNNING; - - vm_enable_vas(pcb_p->stored_vas); - process_load_state(pcb_p); - return 0; -} - -int process_destroy(pcb* pcb_p){ - bv_lower(pcb_p->PID, pcb_map); - kfree(pcb_p); - return 0; -} - -/*Spring 2015 course_os: Sathya Sankaran, Rakan Stanbouly, Jason Sim - - creates a process and initializes the PCB - @param file pointer to location in memory of file - @return pcb pointer upon success - @return 0 if there is no more room in pcb table */ -pcb* __process_create() -{ - int32_t pcb_index = bv_firstFree(pcb_map); - if (pcb_index < 0) { - return NULL; - } - pcb* pcb_p = (pcb*) kmalloc(sizeof(pcb)); - if (!pcb_p) { - return NULL; - } - //initialize PCB - pcb_p->stored_vas = vm_new_vas(); - pcb_p->PID = pcb_index; - //4-13-15: function pointer should point to common() of file pointer. - // TODO: Eventually should be able to pass parameters. Put them on the stack (argv/argc) - pcb_p->current_state = PROCESS_NEW; - pcb_p->has_executed = 0; - - pcb_table[pcb_index] = pcb_p; - bv_set(pcb_index, pcb_map); - return pcb_p; -} - -void __process_elf_init(pcb* pcb_p, const char* name) { - // TODO: depends on fs. did it not before? how did that work? fix fs? etc -// int fd = kopen(name, 'r'); -// uint32_t start = PROC_LOCATION; -// uint32_t len = 0; -// -// struct stats fstats; -// get_stats(name, &fstats); -// len = fstats.size; -// os_printf("LOADING PROCESS <<%s>>, start address %X\n", -// name, start, len); -// -// for (int i = 0; i < (len / BLOCK_SIZE) + 1; i++) -// { -// uint32_t *v = (uint32_t*) (start + (i * BLOCK_SIZE)); -// int x = vm_allocate_page(pcb_p->stored_vas, (void*) v, VM_PERM_USER_RW); -// assert(x == 0); -// vm_map_shared_memory(KERNEL_VAS, (void*) v, -// pcb_p->stored_vas,(void*) v, -// VM_PERM_USER_RW); -// } -// -// int* location = (int*) start; -// int counter = 0; -// while (counter < len) -// { -// kread(fd, location, 4); -// location += 1; -// counter += 4; -// } -// -// Elf_Ehdr* success = (Elf_Ehdr*) load_file(pcb_p, (uint32_t*) start); -// pcb_p->R15 = success->e_entry; -// for (int i = 0; i < (len / BLOCK_SIZE) + 1; i++) -// { -// uint32_t *v = (uint32_t *) (start + (i * BLOCK_SIZE)); -// vm_free_mapping(KERNEL_VAS, (void*) v); -// } -} - -/* - Allocated memory for the process stack - Moves arguments for argc, argv, envp, and auxp - into stack_top - - Points stack pointer to location where stack_top would begin - @param pointer to process control block - @param pcb* pcb_p - - */ -void __process_stack_init(pcb * pcb_p) { - int retval = 0; - for (int i = 0; i < (P_STACK_SIZE / BLOCK_SIZE); i++) - { - retval = vm_allocate_page(pcb_p->stored_vas, - (void*) (P_STACK_BASE + (i * BLOCK_SIZE)), VM_PERM_USER_RW); - if (retval) - { - kprintf("vm_allocate_page error code: %d\n", retval); - break; - } - else - { - kprintf( - "A page have been allocated for process stack at vptr: 0x%x\n", - (P_STACK_BASE + (i * BLOCK_SIZE))); - } - vm_map_shared_memory(KERNEL_VAS, - (void*) (P_STACK_BASE + (i * BLOCK_SIZE)), pcb_p->stored_vas, - (void*) (P_STACK_BASE + (i * BLOCK_SIZE)), VM_PERM_USER_RW); - } - - // Stick a NULL at STACK_TOP-sizeof(int*) - uint32_t *stack_top = (uint32_t*) P_STACK_TOP; - stack_top[-1] = 0; - stack_top[-2] = 0; - stack_top[-3] = 0; - stack_top[-4] = 0; - stack_top[-5] = P_STACK_BASE; - stack_top[-6] = 1; - - strcpy((char*) P_STACK_BASE, pcb_p->name); - - // We need to set sp (r13) to stack_top - 12 - pcb_p->R13 = P_STACK_TOP - 4 * 6; - for (int i = 0; i < (P_STACK_SIZE / BLOCK_SIZE); i++) - { - vm_free_mapping(KERNEL_VAS, (void*) (P_STACK_BASE + (i * BLOCK_SIZE))); - } -} - -void __process_heap_init(pcb* pcb_p) { - //from mem_alloc.c - init_process_heap(pcb_p->stored_vas); - kprintf("User Level Heap for Process PID %d initialized\n", pcb_p->PID); -} - -/* - Saves all of the Registers on the machine to the PCB - @param Process ID - @return 0 if failed - @return 1 for success - */ -void process_save_state(pcb* pcb_p) { - assert(pcb_p); - - asm("MOV %0, r0":"=r"(pcb_p->R0)::); - asm("MOV %0, r1":"=r"(pcb_p->R1)::); - asm("MOV %0, r2":"=r"(pcb_p->R2)::); - asm("MOV %0, r3":"=r"(pcb_p->R3)::); - asm("MOV %0, r4":"=r"(pcb_p->R4)::); - asm("MOV %0, r5":"=r"(pcb_p->R5)::); - asm("MOV %0, r6":"=r"(pcb_p->R6)::); - asm("MOV %0, r7":"=r"(pcb_p->R7)::); - asm("MOV %0, r8":"=r"(pcb_p->R8)::); - asm("MOV %0, r9":"=r"(pcb_p->R9)::); - asm("MOV %0, r10":"=r"(pcb_p->R10)::); - asm("MOV %0, r11":"=r"(pcb_p->R11)::); - asm("MOV %0, r12":"=r"(pcb_p->R12)::); - asm("MOV %0, r13":"=r"(pcb_p->R13)::); - asm("MOV %0, r14":"=r"(pcb_p->R14)::); - asm("MOV %0, r15":"=r"(pcb_p->R15)::); -} - -#define offsetof(st, m) __builtin_offsetof(st, m) - -__attribute((naked)) void process_load_state(pcb* pcb_p) -{ - asm volatile( - "mov ip, r0 \n\t" \ - "ldr r0, [ip, %0] \n\t " \ - "ldr r1, [ip, %1] \n\t " \ - "ldr r2, [ip, %3] \n\t " \ - "ldr r4, [ip, %4] \n\t " \ - "ldr r5, [ip, %5] \n\t " \ - "ldr r6, [ip, %6] \n\t " \ - "ldr r7, [ip, %7] \n\t " \ - "ldr r8, [ip, %8] \n\t " \ - "ldr r9, [ip, %9] \n\t " \ - "ldr r10, [ip, %10] \n\t " \ - "ldr r11, [ip, %11] \n\t " \ - "ldr r13, [ip, %12] \n\t " \ - "ldr r14, [ip, %13] \n\t " \ - "ldr ip, [ip, %14] \n\t " \ - "mcr p15, 0, r0, c8, c7, 0 \n\t" \ - "mov r15, ip \n\t" - :: "i" (offsetof(pcb, R0)), - "i" (offsetof(pcb, R1)), - "i" (offsetof(pcb, R2)), - "i" (offsetof(pcb, R3)), - "i" (offsetof(pcb, R4)), - "i" (offsetof(pcb, R5)), - "i" (offsetof(pcb, R6)), - "i" (offsetof(pcb, R7)), - "i" (offsetof(pcb, R8)), - "i" (offsetof(pcb, R9)), - "i" (offsetof(pcb, R10)), - "i" (offsetof(pcb, R11)), - "i" (offsetof(pcb, R13)), - "i" (offsetof(pcb, R14)), - "i" (offsetof(pcb, R15)) : - ); -} -/* - Loads registers using values in pcb - @param Process ID - */ -/* -void process_load_state(pcb* pcb_p) -{ - asm("MOV r0, %0"::"r"(pcb_p->R0):); - asm("MOV r1, %0"::"r"(pcb_p->R1):); - asm("MOV r2, %0"::"r"(pcb_p->R2):); - asm("MOV r3, %0"::"r"(pcb_p->R3):); - asm("MOV r4, %0"::"r"(pcb_p->R4):); - asm("MOV r5, %0"::"r"(pcb_p->R5):); - asm("MOV r6, %0"::"r"(pcb_p->R6):); - asm("MOV r7, %0"::"r"(pcb_p->R7):); - asm("MOV r8, %0"::"r"(pcb_p->R8):); - asm("MOV r9, %0"::"r"(pcb_p->R9):); - asm("MOV r10, %0"::"r"(pcb_p->R10):); - asm("MOV r12, %0"::"r"(pcb_p->R12):); - asm("MOV r13, %0"::"r"(pcb_p->R13):); - asm("MOV r14, %0"::"r"(pcb_p->R14):); - - // move pc to process stack - *((uint32_t*)(PROC_START+4)) = pcb_p->R15; - - vm_invalidate_tlb(); - - asm("MOV r12, %0":: "i" ((PROC_START+4)):); - asm("ldr r15, [r12]" :::); - - __builtin_unreachable(); -} -*/ diff --git a/kernel/src/process/scheduler.c b/kernel/src/process/scheduler.c deleted file mode 100644 index 163d22f6..00000000 --- a/kernel/src/process/scheduler.c +++ /dev/null @@ -1,512 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_TASKS 100 // in the future, cap will be removed -#define MAX_ACTIVE_TASKS 4 // in the future, will dynamically change based on load -#define MAX_NICENESS -20 -#define MIN_NICENESS 20 -#define TASK_STATE_FINISHED 3 // task has run by the scheduler and finished -#define TASK_STATE_INACTIVE 2 // task is in the wait queue (about to be executed) -#define TASK_STATE_ACTIVE 1 // task is part of the running tasks; it is being interleaved and executed atm -#define TASK_STATE_NONE 0 // task is just created (no real state) -#define SAFE_NICE(n) max(min(MAX_NICENESS, n), n) -#define KTHREAD 0 -#define PROCESS 1 - -#define AS_PROCESS(a) ((pcb*) a->task) -#define AS_KTHREAD(a) ((kthread_handle*) a->task) -#define IS_PROCESS(a) (a->type == PROCESS) -#define IS_KTHREAD(a) (a->type == KTHREAD) - -static char *last_err; -static prq_handle * inactive_tasks; -static prq_handle * active_tasks; -static sched_task * active_task; -static hmap_handle * all_tasks_map; - -static uint32_t sched_tid; - -// NOTE -// scheduler logic only. not tested - -// scheduler -// --------- -// round-robin timer-enabled scheduler that runs tasks in descending priority -// with the help of a heap-based priority queue - -// supported syscalls -// --------- -// create: create a process (not execute) -// exec: start a process which you created before -// waitpid: wait for a process (i.e. child) to finish -// kill: kill a process and its children processes -// -#define SCHEDULER_TIMER 0 - -void __sched_dispatch(void); - -void timer_handler(void *args) -{ - kprintf("scheduler received timer interrupt, need to switch tasks...\n"); -} - -void __sched_register_timer_irq(void) -{ -// register_handler(SCHEDULER_TIMER, timer_handler); -} - -void __sched_deregister_timer_irq() -{ -// unregister_handler(SCHEDULER_TIMER); -} - -void __sched_pause_timer_irq() -{ - // TODO: suspend the timer here -} - -void __sched_resume_timer_irq() -{ - // TODO: resume the timer here -} - -// get the current process id -uint32_t sched_get_active_tid() { - if (active_task) { - return active_task->tid; - } - - return (uint32_t) STATUS_FAIL; -} - -// Initialize the scheduler. Should be called by the kernel ONLY -uint32_t sched_init(void) { - ensure_kernel_vas(); - - sched_tid = 0; - - kprintf("Initializing scheduler\n"); - last_err = "No error"; - inactive_tasks = prq_create_fixed(MAX_TASKS); - active_tasks = prq_create_fixed(MAX_ACTIVE_TASKS); - active_task = 0; - - all_tasks_map = hmap_create(); - - __sched_register_timer_irq(); - - return STATUS_OK; -} - -// initial call that causes the scheduler to start -void sched_start(void) -{ - __sched_dispatch(); -} - -uint32_t sched_register_callback_handler(sched_callback_handler cb_handler) { - sched_task * task = hmap_get(all_tasks_map, sched_get_active_tid()); - task->cb_handler = cb_handler; - return STATUS_OK; -} - -uint32_t sched_deregister_callback_handler() { - sched_task * task = hmap_get(all_tasks_map, sched_get_active_tid()); - task->cb_handler = 0; - - return STATUS_OK; -} - -// Free the resources used the scheduler -uint32_t sched_free() { - ensure_kernel_vas(); - - // FIXME kill active tasks - - __sched_deregister_timer_irq(); - - prq_free(inactive_tasks); - prq_free(active_tasks); - - return STATUS_OK; -} - -// issue messages for the active task -void __sched_emit_messages(void) { - if (active_task->cb_handler) { - sched_message_chunk * chunk; - while ((chunk = llist_dequeue(active_task->message_queue)) != 0) { - active_task->cb_handler(chunk->src_pid, chunk->event, chunk->data, - chunk->chunk_length, chunk->remain_length); - if (chunk) { - kfree(chunk); - } - } - } -} - -sched_task* __sched_create_task(void * task_data, int niceness, uint32_t type) { - if (prq_count(inactive_tasks) >= MAX_TASKS) { - last_err = "Too many tasks"; - return (sched_task*) STATUS_FAIL; - } - - __sched_pause_timer_irq(); - - sched_task * task = (sched_task*) kmalloc(sizeof(sched_task)); - - niceness = SAFE_NICE(niceness); - - task->tid = ++sched_tid; - task->niceness = niceness; - task->task = task_data; - task->type = type; - task->state = TASK_STATE_NONE; - task->node = 0; - task->parent_tid = 0; - task->children_tids = arrl_create(); - task->cb_handler = 0; - - if (active_task) { - task->parent_tid = active_task->tid; - arrl_append(active_task->children_tids, (void*) task->tid); - } - - __sched_resume_timer_irq(); - - return task; - -} - -sched_task* sched_create_task_from_kthread(kthread_handle * kthread, - int niceness) { - return __sched_create_task(kthread, niceness, KTHREAD); -} - -sched_task* sched_create_task_from_process(pcb * pcb_pointer, int niceness) { - return __sched_create_task(pcb_pointer, niceness, PROCESS); -} - - -// Helper function used by the scheduler internally. It will traverse the parent/child -// list to find a subtask. -#if 0 -sched_task* __sched_find_subtask(sched_task * parent_task, uint32_t tid) { - if (parent_task && parent_task->tid == tid) { - return parent_task; - } - - int i = 0; - for (; i < arrl_count(parent_task->children_tids); i++) { - uint32_t child_tid = arrl_count(parent_task, i); - sched_task * child_task = hmap_get(all_tasks_map, child_tid); - if ((child_task = __sched_find_subtask(child_task, tid))) { - return child_task; - } - } - - return 0; -} -#endif - -// -// NOTE expecting access to kernel global vars -void sched_waittid(uint32_t tid) { - // FIXME: broken! - while (1) { - sched_task * task = (sched_task*) hmap_get(all_tasks_map, (unsigned long) tid); - if (task == 0 || task->state == TASK_STATE_FINISHED) { - break; - } - - //sleep(500); - } -} - -// contract -// -------- -// must disable timer_interrupt -uint32_t __sched_remove_task(sched_task * task) { - if (task == NULL) { - return (uint32_t) STATUS_FAIL; - } - - switch (task->state) { - case TASK_STATE_INACTIVE: { - __sched_pause_timer_irq(); - prq_remove(inactive_tasks, task->node); - prq_free_node(task->node); - __sched_resume_timer_irq(); - break; - } - case TASK_STATE_ACTIVE: { - __sched_pause_timer_irq(); - - task->state = TASK_STATE_FINISHED; - - if (IS_PROCESS(task)) { - process_destroy(AS_PROCESS(task)); - } else if (IS_KTHREAD(task)) { - // FIXME add later - } - - hmap_remove(all_tasks_map, task->tid); - prq_remove(active_tasks, task->node); - prq_free_node(task->node); - - int i = 0; - for (; i < arrl_count(task->children_tids); i++) { - // FIXME: this API does not exist anymore - // sched_remove_task(arrl_get(task->children_tids, i)); - } - - __sched_resume_timer_irq(); - break; - } - case TASK_STATE_FINISHED: { - // ignore - break; - } - } - - __sched_resume_timer_irq(); - - return task->state; -} - - -// essentially a kill process -uint32_t sched_remove_task(uint32_t tid) { - sched_task * task = (sched_task*) hmap_get(all_tasks_map, tid); - if (task) { - __sched_pause_timer_irq(); - uint32_t status = __sched_remove_task(task); - __sched_resume_timer_irq(); - return status; - } - - return STATUS_FAIL; -} - -void __sched_dispatch(void) { - // prevent interrupts while handling another interrupt - __sched_pause_timer_irq(); - - // use the kernel memory - vm_use_kernel_vas(); - - if (prq_count(active_tasks) < MAX_ACTIVE_TASKS) { - if (prq_count(inactive_tasks) > 0) { - prq_enqueue(active_tasks, prq_dequeue(inactive_tasks)); // add to active_tasks if the task - } - } - - if (prq_count(active_tasks) == 0) { - __sched_resume_timer_irq(); - return; - } - - sched_task * last_task; - - // check if there is active task - if (active_task) { - last_task = active_task; - } else { - prq_node * node = prq_peek(active_tasks); - last_task = (sched_task*) node->data; - } - - switch (last_task->state) { - case TASK_STATE_INACTIVE: { - active_task = last_task; - active_task->state = TASK_STATE_ACTIVE; - - if (IS_PROCESS(active_task)) { - __sched_resume_timer_irq(); - process_execute(AS_PROCESS(active_task)); - } else if (IS_KTHREAD(active_task)) { - AS_KTHREAD(active_task)->cb_handler(); - } - - __sched_pause_timer_irq(); - sched_remove_task(active_task->tid); - active_task = 0; - - // NOTE next interrupt will get the start the process - - break; - } - case TASK_STATE_ACTIVE: { - if (prq_count(active_tasks) > 1) { - prq_remove(active_tasks, active_task->node); - prq_enqueue(active_tasks, active_task->node); - sched_task * next_task = (sched_task*) prq_peek(active_tasks)->data; - - // old task - if (IS_PROCESS(active_task)) { - if (active_task == next_task) { - vm_enable_vas(AS_PROCESS(active_task)->stored_vas); - break; - } - - process_save_state(AS_PROCESS(last_task)); - } else if (IS_KTHREAD(active_task)) { - if (active_task == next_task) { - break; - } - - // FIXME: implement - // kthread_save_state(AS_KTHREAD(active_task)); - } - - active_task = next_task; - - // new task - if (IS_PROCESS(active_task)){ - vm_enable_vas(AS_PROCESS(active_task)->stored_vas); - __sched_emit_messages(); - process_load_state(AS_PROCESS(active_task)); // continue with the next process - } else if (IS_KTHREAD(active_task)) { - __sched_emit_messages(); - - // FIXME: implement - // kthread_load_state(AS_KTHREAD(active_task)); - } - } - break; - } - } - - __sched_resume_timer_irq(); -} - -// start process -uint32_t sched_add_task(sched_task * task) { - if (task) { - if (task->state != TASK_STATE_NONE) { - last_err = "Reusing task object not allowed"; - return (uint32_t) STATUS_FAIL; - } - - ensure_kernel_vas(); - - prq_node * new_node = (prq_node*) kmalloc(sizeof(prq_node)); - new_node->data = task; - new_node->priority = task->niceness; - - task->state = TASK_STATE_INACTIVE; - task->node = new_node; - prq_enqueue(inactive_tasks, new_node); - - hmap_put(all_tasks_map, active_task->tid, active_task); - - return active_task->tid; - } - - last_err = "Invalid sched_task pointer"; - return (uint32_t) STATUS_FAIL; -} - - -const char * sched_last_err() { - return last_err; -} - -uint32_t sched_set_niceness(uint32_t pid, uint32_t niceness) { - - sched_task * task; - - if (!(task = hmap_get(all_tasks_map, pid))) { - return STATUS_FAIL; - } - - __sched_pause_timer_irq(); - - prq_handle * tasks = NULL; - - switch (task->state) { - case TASK_STATE_ACTIVE: - tasks = active_tasks; - break; - case TASK_STATE_INACTIVE: - tasks = inactive_tasks; - break; - case TASK_STATE_FINISHED: - break; - } - - if (tasks != NULL) { - prq_remove(tasks, task->node); // remove the running task from queue - task->node->priority = SAFE_NICE(niceness); - prq_enqueue(tasks, task->node); // add it again to see if its position in the queue - - } - - __sched_resume_timer_irq(); - - return STATUS_OK; -} - -uint32_t sched_post_message(uint32_t dest_pid, uint32_t event, char * data, - int len) -{ - /*sched_task * dest_task; - - if (!(dest_task = hmap_get(&all_tasks_map, dest_pid))) { - return STATUS_FAIL; - } - __sched_pause_timer_irq(); - - vm_use_kernel_vas(); - - // create space on kernel stack - char data_cpy[512]; - while (len > 0) { - // get length to cpy - int cpy_len = MIN(len, 512); - // enable orignal struct - vm_enable_vas(active_task->pcb->stored_vas); - // copy to stack - os_memcpy(data, data_cpy, cpy_len); - // remaining bytes - len -= cpy_len; - // increment data pointer - data = (char*) (data + cpy_len / 4); - // get the dest_task - sched_task * dest_task = hmap_get(&all_tasks_map, dest_pid); - // switch to dest vas - vm_enable_vas(dest_task->pcb->stored_vas); - // copy from global kernel stack to process heap - char* task_mem_data_cpy = kmalloc(cpy_len); - os_memcpy(data_cpy, task_mem_data_cpy, cpy_len); - - vm_use_kernel_vas(); - - // FIXME create the message object and pass it in - // messages will be broken up into chunks since we have to - // copy into kernel stack first. - sched_message_chunk * chunk = kmalloc(sizeof(sched_message_chunk)); - chunk->data = task_mem_data_cpy; - chunk->chunk_length = cpy_len; - chunk->remain_length = len; - chunk->event = event; - chunk->src_pid = active_task ? active_task->pcb->PID : 0; - - llist_enqueue(dest_task->message_queue, chunk); - } - - if (active_task) { - vm_enable_vas(active_task->pcb->stored_vas); - } - - __sched_resume_timer_irq();*/ - - return STATUS_OK; -} diff --git a/kernel/src/process/signals.c.old b/kernel/src/process/signals.c.old deleted file mode 100644 index d2447631..00000000 --- a/kernel/src/process/signals.c.old +++ /dev/null @@ -1,20 +0,0 @@ -//Contributors: Andrew Stepek, Michael Brennen, and Matthew Stromberg - -/* - Signals - */ -/* - SIGKILL - SIGUSR - SIGTERM - */ - -#include -#include - -void signal_mask(char * type, int index, uint32_t PID) -{ - pcb* pcb_t = get_PCB(PID); - pcb_t.mask[index]->type = type; -} - diff --git a/kernel/src/test/generate_tests.sh b/kernel/src/test/generate_tests.sh index 333698bc..a4b38de3 100755 --- a/kernel/src/test/generate_tests.sh +++ b/kernel/src/test/generate_tests.sh @@ -17,6 +17,9 @@ echo " #include #include +#include + +size_t global_counter = 0; " >> "$DIR/test.c" diff --git a/kernel/src/test/include/test.h b/kernel/src/test/include/test.h index b9217b90..5f433d95 100644 --- a/kernel/src/test/include/test.h +++ b/kernel/src/test/include/test.h @@ -12,62 +12,66 @@ // Only compile test definitions if enabled #ifdef ENABLE_TESTS +size_t global_counter; + +#define DEBUG_COUNT kprintf("[DEBUG COUNT] %s:%i %i\n", __FILE__, __LINE__, global_counter++); + #ifdef MEM_DEBUG -#define TEST_CREATE(name, block) \ - int __internal_test_##name() { \ - heap_t * heap = mem_get_allocator(); \ - isize_t nbytes = heap->bytes_allocated; \ - block; \ - if (nbytes != (isize_t)heap->bytes_allocated) { \ - kprintf( \ - "FAILED (MEMORY LEAK: %i bytes) \n",\ - heap->bytes_allocated - nbytes \ - ); \ - return TEST_FAIL; \ - } \ - return TEST_PASS; \ - } \ - int test_##name() { \ - kprintf("Testing %s\n", #name); \ - int res = __internal_test_##name(); \ - if (res == TEST_PASS) { \ - kprintf("PASSED\n"); \ - return 1; \ - } else { \ - kprintf("FAILED\n"); \ - return 0; \ - } \ +#define TEST_CREATE(name, block) \ + int __internal_test_##name() { \ + heap_t * heap = mem_get_allocator(); \ + isize_t nbytes = heap->bytes_allocated; \ + block; \ + if (nbytes != (isize_t)heap->bytes_allocated) { \ + kprintf( \ + "\e[38;5;160mFAILED (MEMORY LEAK: %i bytes)\e[0m\n",\ + heap->bytes_allocated - nbytes \ + ); \ + return TEST_FAIL; \ + } \ + return TEST_PASS; \ + } \ + int test_##name() { \ + kprintf("\e[38;5;163m[TEST]\e[0m %s\n", #name); \ + int res = __internal_test_##name(); \ + if (res == TEST_PASS) { \ + kprintf("└─\e[92mPASSED\e[0m\n", #name); \ + return 1; \ + } else { \ + kprintf("└─\e[38;5;160mFAILED\e[0m\n", #name); \ + return 0; \ + } \ } #else -#define TEST_CREATE(name, block) \ - int __internal_test_##name() { \ - block; \ - return TEST_PASS; \ - } \ - int test_##name() { \ - kprintf("Testing %s\n", #name); \ - int res = __internal_test_##name(); \ - if (res == TEST_PASS) { \ - kprintf("PASSED\n"); \ - return 1; \ - } else { \ - kprintf("FAILED\n"); \ - return 0; \ - } \ +#define TEST_CREATE(name, block) \ + int __internal_test_##name() { \ + block; \ + return TEST_PASS; \ + } \ + int test_##name() { \ + kprintf("\e[38;5;163m[TEST]\e[0m %s\n", #name); \ + int res = __internal_test_##name(); \ + if (res == TEST_PASS) { \ + kprintf("└─\e[92mPASSED\e[0m\n"); \ + return 1; \ + } else { \ + kprintf("└─\e[38;5;160mFAILED\e[0m\n"); \ + return 0; \ + } \ } #endif #define PASS() return TEST_PASS #define FAIL() return TEST_FAIL -#define ASSERT(expr) do { if(!expr) { kprintf("failed assertion: %s at ASSERT(%s)\n", __FILE__, #expr); return TEST_FAIL; } } while(0) -#define ASSERT_EQ(l, r) do { if(l != r) { kprintf("failed assertion: %s at ASSERT_EQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) -#define ASSERT_GT(l, r) do { if(l <= r) { kprintf("failed assertion: %s at ASSERT_GT(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) -#define ASSERT_GTEQ(l, r) do { if(l < r) { kprintf("failed assertion: %s at ASSERT_GTEQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) -#define ASSERT_LT(l, r) do { if(l >= r) { kprintf("failed assertion: %s at ASSERT_LT(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) -#define ASSERT_LTEQ(l, r) do { if(l > r) { kprintf("failed assertion: %s at ASSERT_LTEQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) -#define ASSERT_NEQ(l, r) do { if(l == r) { kprintf("failed assertion: %s at ASSERT_NEQ(%s, %s)\n", __FILE__, #l, #r); return TEST_FAIL; } } while(0) -#define ASSERT_NOT_NULL(e) do { if(e == NULL) { kprintf("failed assertion: %s\n at ASSERT_NOT_NULL(%s)", __FILE__, #e); return TEST_FAIL; } } while(0) -#define ASSERT_NULL(e) do { if(e != NULL) { kprintf("failed assertion: %s\n at ASSERT_NULL(%s)", __FILE__, #e); return TEST_FAIL; } } while(0) +#define ASSERT(expr) do { if(!expr) { kprintf("failed assertion: %s:%i at ASSERT(%s)\n", __FILE__, __LINE__, #expr); return TEST_FAIL; } } while(0) +#define ASSERT_EQ(l, r) do { if(l != r) { kprintf("failed assertion: %s:%i at ASSERT_EQ(%s, %s)\n", __FILE__, __LINE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_GT(l, r) do { if(l <= r) { kprintf("failed assertion: %s:%i at ASSERT_GT(%s, %s)\n", __FILE__, __LINE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_GTEQ(l, r) do { if(l < r) { kprintf("failed assertion: %s:%i at ASSERT_GTEQ(%s, %s)\n", __FILE__, __LINE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_LT(l, r) do { if(l >= r) { kprintf("failed assertion: %s:%i at ASSERT_LT(%s, %s)\n", __FILE__, __LINE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_LTEQ(l, r) do { if(l > r) { kprintf("failed assertion: %s:%i at ASSERT_LTEQ(%s, %s)\n", __FILE__, __LINE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_NEQ(l, r) do { if(l == r) { kprintf("failed assertion: %s:%i at ASSERT_NEQ(%s, %s)\n", __FILE__, __LINE__, #l, #r); return TEST_FAIL; } } while(0) +#define ASSERT_NOT_NULL(e) do { if(e == NULL) { kprintf("failed assertion: %s:%i\n at ASSERT_NOT_NULL(%s)\n", __FILE__, __LINE__, #e); return TEST_FAIL; } } while(0) +#define ASSERT_NULL(e) do { if(e != NULL) { kprintf("failed assertion: %s:%i\n at ASSERT_NULL(%s)\n", __FILE__, __LINE__, #e); return TEST_FAIL; } } while(0) #else From 6e79bbc32ed0eac917b89cbdb6efceb9c62a3e5e Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Sun, 8 Mar 2020 15:05:49 +0100 Subject: [PATCH 041/104] Cleaned up source Co-authored-by: Victor Roest --- kernel/Makefile | 2 +- kernel/src/{memory => allocator}/allocator.c | 0 .../{memory => allocator}/include/allocator.h | 0 .../{memory => allocator}/include/mem_alloc.h | 0 kernel/src/{memory => allocator}/llist.c | 0 kernel/src/{memory => allocator}/mem_alloc.c | 1 - .../test/test_allocator.c | 0 kernel/src/common/include/argparse.h | 66 ------ kernel/src/common/include/interrupt.h | 1 + kernel/src/common/interrupt.c | 99 ++++----- kernel/src/common/start.c | 13 +- kernel/src/drivers/chipset/bcm2836/bcm2836.c | 2 +- kernel/src/drivers/chipset/bcm2836/timer.c | 2 +- kernel/src/klibc/include/klibc.h | 7 +- kernel/src/klibc/klibc.c | 2 +- kernel/src/memory/include/memory.h | 43 ---- kernel/src/memory/include/mmap.h | 38 ---- kernel/src/memory/mmap.c | 199 ----------------- kernel/src/memory/stacks.s | 52 ----- kernel/src/memory/vm/include/frame.h | 9 - kernel/src/memory/vm/include/swap_framework.h | 121 ----------- kernel/src/memory/vm/include/swap_fs.h | 51 ----- kernel/src/memory/vm/include/swap_pqueue.h | 82 ------- kernel/src/memory/vm/include/vm.h | 205 ------------------ kernel/src/memory/vm/test/test_vm.c | 105 --------- kernel/src/vm/README.md | 37 ++++ kernel/src/vm/include/mmio.h | 21 ++ kernel/src/{memory => }/vm/include/pmm.h | 0 .../vm/include/tlb_cache_id_allocator.h | 0 kernel/src/{memory => }/vm/include/vas2.h | 4 +- kernel/src/{memory => }/vm/include/vm2.h | 3 + kernel/src/{memory => }/vm/memory-layout.svg | 0 kernel/src/{memory => }/vm/pmm.c | 0 .../{memory => }/vm/test/test_pagealloc2.c | 0 kernel/src/{memory => }/vm/test/test_vm2.c | 0 .../{memory => }/vm/tlb_cache_id_allocator.c | 0 kernel/src/{memory => }/vm/vas2.c | 0 kernel/src/{memory => }/vm/vm2.c | 0 38 files changed, 118 insertions(+), 1047 deletions(-) rename kernel/src/{memory => allocator}/allocator.c (100%) rename kernel/src/{memory => allocator}/include/allocator.h (100%) rename kernel/src/{memory => allocator}/include/mem_alloc.h (100%) rename kernel/src/{memory => allocator}/llist.c (100%) rename kernel/src/{memory => allocator}/mem_alloc.c (99%) rename kernel/src/{memory => allocator}/test/test_allocator.c (100%) delete mode 100644 kernel/src/common/include/argparse.h delete mode 100644 kernel/src/memory/include/memory.h delete mode 100644 kernel/src/memory/include/mmap.h delete mode 100644 kernel/src/memory/mmap.c delete mode 100644 kernel/src/memory/stacks.s delete mode 100644 kernel/src/memory/vm/include/frame.h delete mode 100644 kernel/src/memory/vm/include/swap_framework.h delete mode 100644 kernel/src/memory/vm/include/swap_fs.h delete mode 100644 kernel/src/memory/vm/include/swap_pqueue.h delete mode 100644 kernel/src/memory/vm/include/vm.h delete mode 100644 kernel/src/memory/vm/test/test_vm.c create mode 100644 kernel/src/vm/README.md create mode 100644 kernel/src/vm/include/mmio.h rename kernel/src/{memory => }/vm/include/pmm.h (100%) rename kernel/src/{memory => }/vm/include/tlb_cache_id_allocator.h (100%) rename kernel/src/{memory => }/vm/include/vas2.h (80%) rename kernel/src/{memory => }/vm/include/vm2.h (99%) rename kernel/src/{memory => }/vm/memory-layout.svg (100%) rename kernel/src/{memory => }/vm/pmm.c (100%) rename kernel/src/{memory => }/vm/test/test_pagealloc2.c (100%) rename kernel/src/{memory => }/vm/test/test_vm2.c (100%) rename kernel/src/{memory => }/vm/tlb_cache_id_allocator.c (100%) rename kernel/src/{memory => }/vm/vas2.c (100%) rename kernel/src/{memory => }/vm/vm2.c (100%) diff --git a/kernel/Makefile b/kernel/Makefile index 9408c144..5cdacf31 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -9,7 +9,7 @@ CFLAGS += -pipe -std=gnu99 -ffreestanding -Wall -Werror -g -O0 -mcpu=arm1176jzf- # variables to define in the preprocessor. MEMORY = 1G -DEFINITIONS = MEM_DEBUG ENABLE_TESTS +DEFINITIONS = MEM_DEBUG #DEFINITIONS = MEM_DEBUG test: DEFINITIONS += ENABLE_TESTS # if we execute the test: rule, enable tests before recompiling KERNEL_PARAMS = root=/dev/ram mem=$(MEMORY) diff --git a/kernel/src/memory/allocator.c b/kernel/src/allocator/allocator.c similarity index 100% rename from kernel/src/memory/allocator.c rename to kernel/src/allocator/allocator.c diff --git a/kernel/src/memory/include/allocator.h b/kernel/src/allocator/include/allocator.h similarity index 100% rename from kernel/src/memory/include/allocator.h rename to kernel/src/allocator/include/allocator.h diff --git a/kernel/src/memory/include/mem_alloc.h b/kernel/src/allocator/include/mem_alloc.h similarity index 100% rename from kernel/src/memory/include/mem_alloc.h rename to kernel/src/allocator/include/mem_alloc.h diff --git a/kernel/src/memory/llist.c b/kernel/src/allocator/llist.c similarity index 100% rename from kernel/src/memory/llist.c rename to kernel/src/allocator/llist.c diff --git a/kernel/src/memory/mem_alloc.c b/kernel/src/allocator/mem_alloc.c similarity index 99% rename from kernel/src/memory/mem_alloc.c rename to kernel/src/allocator/mem_alloc.c index b5cb941f..614d7aa5 100644 --- a/kernel/src/memory/mem_alloc.c +++ b/kernel/src/allocator/mem_alloc.c @@ -1,7 +1,6 @@ #include "klibc.h" #include #include -#include #include #include #include diff --git a/kernel/src/memory/test/test_allocator.c b/kernel/src/allocator/test/test_allocator.c similarity index 100% rename from kernel/src/memory/test/test_allocator.c rename to kernel/src/allocator/test/test_allocator.c diff --git a/kernel/src/common/include/argparse.h b/kernel/src/common/include/argparse.h deleted file mode 100644 index 7225ebae..00000000 --- a/kernel/src/common/include/argparse.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef __ARGPARSE_H__ -#define __ARGPARSE_H__ - - - -#define ATAG_NONE 0x00000000 -#define ATAG_CORE 0x54410001 - -struct atag_core { - uint32_t flags; - uint32_t pagesize; - uint32_t rootdev; -}; - -#define ATAG_MEM 0x54410002 - -struct atag_mem { - uint32_t size; - uint32_t start; -}; - -#define ATAG_VIDEOTEXT 0x54410003 -#define ATAG_RAMDISK 0x54410004 -#define ATAG_INITRD2 0x54420005 -#define ATAG_SERIAL 0x54410006 -#define ATAG_REVISION 0x54410007 -#define ATAG_VIDEOLFB 0x54410008 -#define ATAG_CMDLINE 0x54410009 - -struct atag_cmdline { - char cmdline[1]; -}; - -struct atag_header { - uint32_t size; - uint32_t tag; -}; - -struct atag { - struct atag_header header; - union { - struct atag_core core; - struct atag_mem mem; - struct atag_cmdline cmdline; - } content; -}; - -static inline struct atag *atag_next_header(struct atag *t) -{ - return (struct atag*) ((uint32_t*)(t) + t->header.size); -} - -#define atag_iterator(tag, addr) struct atag* tag = (struct atag*) addr; tag->header.tag != ATAG_NONE; tag = atag_next_header(tag) - -void atag_print(struct atag *t); - -void argparse_process(uint32_t *p_bootargs); -void parse_arguments(int argc, char **argv); -int analyze_arguments(char **argv); -char* read_cmdline_tag(uint32_t *tag_base); -char** split_string(char *line, char **list); -int number_of_words(char *line); -int string_to_unsigned_int(char *input, int base); -int hex_value_of_character(char c); - -#endif diff --git a/kernel/src/common/include/interrupt.h b/kernel/src/common/include/interrupt.h index 21f024ad..b65b5f01 100644 --- a/kernel/src/common/include/interrupt.h +++ b/kernel/src/common/include/interrupt.h @@ -35,6 +35,7 @@ #define BRANCH_INSTRUCTION 0xe59ff018 // ldr pc, pc+offset (where offset is 0x20 bytes) // System Call Types +// TODO: maybe make enum? #define SYSCALL_CREATE 0 #define SYSCALL_SWITCH 1 #define SYSCALL_DELETE 2 diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index f1596936..dc92c7f2 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -1,11 +1,8 @@ #include -#include -#include -#include #include -#include #include #include +#include /* copy vector table from wherever QEMU loads the kernel to 0x00 */ void init_vector_table() { @@ -42,52 +39,44 @@ void init_vector_table() { } /* handlers */ -void reset_handler(void) -{ - kprintf("RESET HANDLER\n"); +void reset_handler(void) { + INFO("RESET HANDLER\n"); _Reset(); } -void __attribute__((interrupt("UNDEF"))) undef_instruction_handler(void) -{ - int spsr, lr; +void __attribute__((interrupt("UNDEF"))) undef_instruction_handler() { + size_t spsr, lr; asm volatile("mrs %0, spsr" : "=r"(spsr)); asm volatile("mov %0, lr" : "=r" (lr)); - int thumb = spsr & 0x20; - int pc = thumb ? lr - 0x2 : lr - 0x4; + size_t thumb = spsr & 0x20u; + size_t pc = thumb ? lr - 0x2u : lr - 0x4u; - if ((*(size_t *) pc) == UNDEFINED_INSTRUCTION_BYTES){ - kprintf("FATAL ERROR\n"); - panic(); - } - kprintf("UNDEFINED INSTRUCTION HANDLER\n"); + WARN("UNDEFINED INSTRUCTION HANDLER"); - int copro = (*(int*)pc & 0xf00000) >> 24; + size_t copro = (*(size_t *)pc & 0xf00000u) >> 24u; - if (spsr & 0x20) { - kprintf("THUMB mode\n"); + if (spsr & 0x20u) { + WARN("THUMB mode"); } else { - kprintf("ARM mode\n"); + WARN("ARM mode"); } - if (spsr & 0x1000000) { - kprintf("JAZELLE enabled\n"); + if (spsr & 0x1000000u) { + WARN("JAZELLE enabled"); } - kprintf("COPRO: %x\n", copro); - kprintf("violating instruction (at %x): %x\n", pc, *((int *) pc)); - if (pc >= V_KERNBASE && pc < V_KERNTOP) - { - kprintf("(instruction is in kernel address range)\n"); + WARN("COPRO: 0x%x", copro); + WARN("violating instruction (at 0x%x): 0x%x", pc, *((size_t *) pc)); + if (pc >= KERNEL_VIRTUAL_START && pc < KERNEL_VIRTUAL_END) { + WARN("(instruction is in kernel address range)"); } - panic(); + FATAL("UNDEFINED INSTRUCTION HANDLER"); } -long __attribute__((interrupt("SWI"))) software_interrupt_handler(void) -{ +long __attribute__((interrupt("SWI"))) software_interrupt_handler(void) { int callNumber = 0, r0 = 0, r1 = 0, r2 = 0, r3 = 0; asm volatile ("MOV %0, r7":"=r"(callNumber)::); @@ -188,15 +177,11 @@ long __attribute__((interrupt("SWI"))) software_interrupt_handler(void) } } -void __attribute__((interrupt("ABORT"))) prefetch_abort_handler(void) -{ - int lr; - +void __attribute__((interrupt("ABORT"))) prefetch_abort_handler(void) { + size_t lr; asm volatile("mov %0, lr" : "=r" (lr)); - kprintf("PREFETCH ABORT HANDLER, violating address: %x\n", (lr - 4)); - - panic(); + FATAL("PREFETCH ABORT HANDLER, violating address: 0x%x", (lr - 4u)); } void __attribute__((interrupt("ABORT"))) data_abort_handler(void) { @@ -207,20 +192,20 @@ void __attribute__((interrupt("ABORT"))) data_abort_handler(void) { asm volatile("mov %0, lr" : "=r" (lr)); int pc = lr - 8; - int far; + uint32_t far; asm volatile("mrc p15, 0, %0, c6, c0, 0" : "=r" (far)); - DEBUG("DATA ABORT HANDLER (Page Fault)"); - DEBUG("faulting address: 0x%x", far); + WARN("DATA ABORT HANDLER (Page Fault)"); + WARN("faulting address: 0x%x", far); if (far >= KERNEL_VIRTUAL_OFFSET) { - DEBUG("(address is in kernel address range)\n"); + DEBUG("(address is in kernel address range)"); } - DEBUG("violating instruction (at 0x%x): %x", pc, *((int *) pc)); + WARN("violating instruction (at 0x%x): 0x%x", pc, *((int *) pc)); // Get the Data Fault Status Register int dfsr; asm volatile("MRC p15, 0, %0, c5, c0, 0" : "=r" (dfsr)); - DEBUG("DFSR: 0x%x", dfsr); + WARN("DFSR: 0x%x", dfsr); #ifdef ENABLE_TESTS @@ -234,8 +219,9 @@ void reserved_handler(void) } // the attribute automatically saves and restores state +// TODO: We might not want that! (context switches etc) void __attribute__((interrupt("IRQ"))) irq_handler(void) { - kprintf("IRQ HANDLER\n"); + DEBUG("IRQ HANDLER"); return chipset.handle_irq(); // int * pendingregister = (int *) 0x40000060; @@ -260,7 +246,7 @@ void __attribute__((interrupt("IRQ"))) irq_handler(void) { } void __attribute__((interrupt("FIQ"))) fiq_handler(void) { - kprintf("FIQ HANDLER\n"); + DEBUG("FIQ HANDLER\n"); return chipset.handle_fiq(); // handle_irq_interrupt(interrupt_registers->fiq_control & 0x7f); @@ -283,7 +269,7 @@ void __attribute__((always_inline)) inline SemihostingCall(enum SemihostingSWI m /* enable IRQ and/or FIQ */ void enable_interrupt(InterruptType mask) { - kprintf("Enabling interrupts with mask %i\n", mask); + INFO("Enabling interrupts with mask %i", mask); // enable interrupt on the core switch (mask) { @@ -296,12 +282,15 @@ void enable_interrupt(InterruptType mask) { case BOTH: asm volatile("cpsie if"); break; + default: + /** should never happen **/ + return; } } /* disable IRQ and/or FIQ */ void disable_interrupt(InterruptType mask) { - kprintf("Disabling interrupts with mask %i\n", mask); + INFO("Disabling interrupts with mask %i", mask); // disable interrupts on the core switch (mask) { @@ -314,13 +303,16 @@ void disable_interrupt(InterruptType mask) { case BOTH: asm volatile("cpsid if"); break; + default: + /** should never happen **/ + return; } } /* disable IRQ and/or FIQ, but also return a copy of the CPSR */ int disable_interrupt_save(InterruptType mask) { - kprintf("Disabling interrupts (save) with mask %i\n", mask); + INFO("Disabling interrupts (save) with mask %i", mask); /* get a copy of the current process status register */ int cpsr; @@ -336,13 +328,16 @@ int disable_interrupt_save(InterruptType mask) { case BOTH: asm volatile("cpsid if"); break; + default: + /** should never happen **/ + return -1; } return cpsr; } /* return a full 32-bit copy of the current process status register */ -int get_proc_status() { - int cpsr; +size_t get_proc_status() { + size_t cpsr; asm volatile("mrs %0, cpsr" : "=r"(cpsr)); return cpsr; } @@ -350,6 +345,6 @@ int get_proc_status() { /* restore control status (interrupt, mode bits) of the cpsr */ /* (e.g. when we return from a handler, restore value from disable_interrupt_save */ -void restore_proc_status(int cpsr) { +void restore_proc_status(size_t cpsr) { asm volatile("msr cpsr_c, %0" : : "r"(cpsr)); } diff --git a/kernel/src/common/start.c b/kernel/src/common/start.c index edda33d2..4d1ae2f7 100644 --- a/kernel/src/common/start.c +++ b/kernel/src/common/start.c @@ -78,18 +78,7 @@ void start(uint32_t *p_bootargs) { // If we return, the tests failed. SemihostingCall(OSSpecific); #endif - kprintf("done parsing atag list\n"); - //init_kheap(31 * 0x100000); - //init_uheap(0x100000); - - //initialize pcb table and PID - /* init_all_processes(); */ - //print_process_state(0); - //run_process_tests(); - //print_PID(); - // init_q(); - //common(); // TODO: // * Mount vfs @@ -98,6 +87,6 @@ void start(uint32_t *p_bootargs) { asm volatile("cpsie i"); - kprintf("End of start method.\n"); + INFO("End of boot sequence.\n"); SLEEP; } diff --git a/kernel/src/drivers/chipset/bcm2836/bcm2836.c b/kernel/src/drivers/chipset/bcm2836/bcm2836.c index 93b3281b..91c000c1 100644 --- a/kernel/src/drivers/chipset/bcm2836/bcm2836.c +++ b/kernel/src/drivers/chipset/bcm2836/bcm2836.c @@ -1,7 +1,7 @@ // https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf #include #include -#include +#include #include #include #include diff --git a/kernel/src/drivers/chipset/bcm2836/timer.c b/kernel/src/drivers/chipset/bcm2836/timer.c index 06af7c4e..633231b8 100644 --- a/kernel/src/drivers/chipset/bcm2836/timer.c +++ b/kernel/src/drivers/chipset/bcm2836/timer.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include inline static uint32_t get_frequency() { diff --git a/kernel/src/klibc/include/klibc.h b/kernel/src/klibc/include/klibc.h index 4ae87d88..77bf1e9d 100644 --- a/kernel/src/klibc/include/klibc.h +++ b/kernel/src/klibc/include/klibc.h @@ -85,12 +85,9 @@ unsigned int rand(); #else #define INFO(...) #endif -//#define WARN(format, ...) kprintf("\e[38;5;208m[WARN] " format "\e[0m\n", ##__VA_ARGS__) +#define WARN(format, ...) kprintf("\e[38;5;208m[WARN] " format "\e[0m\n", ##__VA_ARGS__) + -// Defines an instruction that will raise an undefined instruction code on both ARM (and hopefully THUMB2) -#define UNDEFINED_INSTRUCTION_BYTES 0xF7F1A2F3 -#define STRINGIFY2(X) #X -#define STRINGIFY(X) STRINGIFY2(X) #define FATAL(format, ...) kprintf("\e[38;5;160m[FATAL] \e[38;5;208m%s:%i\e[38;5;160m " format "\e[0m\n", __FILE__, __LINE__, ##__VA_ARGS__); panic() //4-17-15: Initial panic * assert_fail functions added diff --git a/kernel/src/klibc/klibc.c b/kernel/src/klibc/klibc.c index 72a38bcd..d1ef3e75 100644 --- a/kernel/src/klibc/klibc.c +++ b/kernel/src/klibc/klibc.c @@ -71,7 +71,7 @@ void splash() { kprintf("\t██╔════╝██║ ██║██╔══██╗██╔════╝██╔════╝██╔═══██╗ ██╔═══██╗██╔════╝\n"); kprintf("\t██║ ██║ ██║██████╔╝███████╗█████╗ ██║ ██║ ██║ ██║███████╗\n"); kprintf("\t██║ ██║ ██║██╔══██╗╚════██║██╔══╝ ██║ ██║ ██║ ██║╚════██║\n"); - kprintf("\t╚██████╗╚██████╔╝██║ ██║███████║███████╗██████╔╝ ╚██████╔╝██████║\n\n"); + kprintf("\t╚██████╗╚██████╔╝██║ ██║███████║███████╗██████╔╝ ╚██████╔╝██████║\n\n\n"); } /*4-17-15: - Prakash diff --git a/kernel/src/memory/include/memory.h b/kernel/src/memory/include/memory.h deleted file mode 100644 index 35c191a3..00000000 --- a/kernel/src/memory/include/memory.h +++ /dev/null @@ -1,43 +0,0 @@ - -#include - - - -#define P_KERNBASE 0x00008000 -#define P_KERNTOP 0x00200000 -//Physical location of kernel. Defined in the linker script. -//const uint32_t P_KERNBASE; -//const uint32_t P_KERNTOP; - -//Virtual location of kernel -#define V_KERNBASE 0xf0000000 -#define V_KERNTOP 0xf0200000 - -//All static kernel data structures -//Total space=1MB, currently used=44kB -#define P_KDSBASE 0x07f00000 -#define P_L1PTBASE P_KERNTOP - -#define V_KDSBASE 0xfff00000 -#define V_L1PTBASE V_KERNTOP - -//#define PERIPHBASE 0x10000000 -#define PERIPHBASE 0x3F000000 -#define PERIPHTOP 0x20000000 - -#define PCIBASE 0x41000000 -#define PCITOP 0x70000000 - -//remapped physical memory for direct access -#define PMAPBASE 0xf0200000 -#define PMAPTOP 0xf7f00000 - -#define BCM2836BASE 0x40000000 -#define TIMERBASE BCM2836BASE + 0x40 - -// Region where we use 4K pages. -#define P_4K_BASE (P_L1PTBASE+0x200000) -#define P_4K_TOP (PMAPTOP - 0xf0000000) - -//High vectors are enabled by setting V bit in the control register -#define HIVECTABLE 0xffff0000 diff --git a/kernel/src/memory/include/mmap.h b/kernel/src/memory/include/mmap.h deleted file mode 100644 index 104c2890..00000000 --- a/kernel/src/memory/include/mmap.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Memory Mapped I/O addresses - */ - -#ifndef MMAP_H -#define MMAP_H - -#include - -#define mmio_read(address) (*((volatile uint32_t *)(address))) -#define mmio_write(address, value) mmio_write_internal((volatile uint32_t *)(address), (volatile uint32_t)(value)) - -// Do the mmio write in assembly to remove any chance of gcc optimizing the call away. *yes* even if it was marked volatile already. -// Hence the 4 hours it took us to make timer.c work...... -static inline void mmio_write_internal(volatile uint32_t * address, volatile uint32_t value ) { - asm volatile ( - "ldr r1, %1\n" - "str r1, %0\n" - :: - "m" (*address), - "m" (value) - ); -} - -void prepare_pagetable(); -void mmap(void *p_bootargs); -void request_identity_mapped_section(size_t start_address, size_t megabytes); - -#define CLOCK_ADDRESS (volatile uint32_t *const) 0x101e8000 /* RTC base address */ - -/* Physical Hardware Addresses */ -#define PERIPHERAL_BASE_PI (volatile uint32_t *const) 0x20000000 -#define PIC_ADDRESS_PI (volatile uint32_t *const) 0x2000B000 /* interrupt controller peripheral */ -//#define UART0_ADDRESS_PI (volatile uint32_t *const) 0x20201000 /* UART 0 base address */ -#define CLOCK_ADDRESS_PI (volatile uint32_t *const) 0x20003000 /* RTC base address */ -#define GPIO_ADDRESS_PI (volatile uint32_t *const) 0x20200000 - -#endif // MMAP_H diff --git a/kernel/src/memory/mmap.c b/kernel/src/memory/mmap.c deleted file mode 100644 index a0bab95b..00000000 --- a/kernel/src/memory/mmap.c +++ /dev/null @@ -1,199 +0,0 @@ -#include -#include -#include -#include -#include -#include - -/* - * APX AP Privileged Unprivileged - * 1 11 (0x8c00) = read-only read-only - * 1 01 (0x8400) = read-only no access - * 0 10 (0x0800) = read-write read-only - * 0 01 (0x0400) = read-write no-access - * See http://infocenter.arm.com/help/topic/com.arm.doc.ddi0333h/Caceaije.html - - * Bits 0 and 1 identify the table entry type - * 0 = translation fault - * 1 = course page table - * 2 = section or supersection - */ - -int vm_build_free_frame_list(void *start, void *end); - -volatile unsigned int * first_level_pt __attribute__((deprecated)) = (unsigned int *) (P_L1PTBASE + PAGE_TABLE_SIZE) ; -//extern struct vm_free_list *vm_vas_free_list; -//extern struct vm_free_list *vm_l1pt_free_list; -//extern struct vm_free_list *vm_l2pt_free_list; - -bool mmapped = false; - - -// Must be called before mmap and after vm.c -//void request_identity_mapped_section(size_t start_address, size_t megabytes) { -// -// if (mmapped) { -// // TODO: Technically possible if we were to flush the cache -// kprintf("Can only request identity mapping before mmap is called."); -// panic(); -// } -// kprintf("Identity mapping %i megabyte(s) at 0x%x\n", megabytes, start_address); -// -// for (unsigned int i = 0; i < megabytes; i++) { -//// first_level_pt[(start_address + (i * 0x100000)) >> 20] = ((start_address + (i *0x100000)) & 0xFFF00000) | 0x0400 | 2; -// } -//} - - -// 0x00000000 -// --- --- -// L1 off -void mmap(void *p_bootargs) { - - disable_interrupt(BOTH); - //stash register state on the stack - asm volatile("push {r0-r11}"); - - kprintf("Boot arguments location: %X\n", p_bootargs); - -// kprintf("first_level_pt=%X\n", first_level_pt); - -// for (int i = 0; i < PAGE_TABLE_SIZE >> 2; i++) { -// first_level_pt[i] = 0; -// } - - //temporarily map where it is until we copy it in VAS -// first_level_pt[P_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; - //first_level_pt[0x07f00000>>20] = first_level_pt[7F] = 0x07ffirst_level_pt=400000000 = 0x07f04010 - // 0x00004000 - // 0x00000010 - - //1MB for static kernel data structures (stacks and l1 pt) -// first_level_pt[V_KDSBASE >> 20] = P_KDSBASE | 0x0400 | 2; - //first_level_pt[0xfff00000>>20] = first_level_pt[0xfff] = 0x0x7f04010 - - //map the kernel where its currently loaded in the same location temporarily - //should be less than a MB -// first_level_pt[P_KERNBASE >> 20] = 0 << 20 | 0x0400 | 2; - - //also map it to high memory at 0xf0000000 (vpn = 3840) -// first_level_pt[V_KERNBASE >> 20] = 0 << 20 | 0x0400 | 2; -// first_level_pt[(V_KERNBASE + 0x100000) >> 20] = 0x100000 | 0x0400 | 2; // 0xf...; - - //map ~2MB of peripheral registers one-to-one -// first_level_pt[PERIPHBASE >> 20] = PERIPHBASE | 0x0400 | 2; // PERIPHBASE + 1 MiB -// first_level_pt[(PERIPHBASE + 0x100000) >> 20] = (PERIPHBASE + 0x100000) | 0x0400 | 2; -// first_level_pt[(PERIPHBASE + 0x200000) >> 20] = (PERIPHBASE + 0x200000) | 0x0400 | 2; -// first_level_pt[(0x20000000) >> 20] = (0x20000000) | 0x0400 | 2; -// -// first_level_pt[BCM2836BASE >> 20] = (BCM2836BASE & 0xFFF00000) | 0x0400 | 2; // TIMERBASE + 1 MiB -// first_level_pt[(PERIPHBASE) >> 20] = (PERIPHBASE + 0x300000) | 0x0400 | 2; - - - // TODO: re enable when we actually need it. 700mb seems a bit excessive though. - //map 752MB of PCI interface one-to-one -// unsigned int pci_bus_addr = PCIBASE; -// for (int i = (PCIBASE >> 20); i < (PCITOP >> 20); i++) { -// first_level_pt[i] = pci_bus_addr | 0x0400 | 2; -// pci_bus_addr += 0x100000; -// } -// request_identity_mapped_section(Gibibyte - 25 * Mebibyte, 20); - - // Quick coarse page table address - //unsigned int coarse_page_table_address = P_L1PTBASE + 2*PAGE_TABLE_SIZE; - //os_printf("coarse pt: 0x%X\n", coarse_page_table_address); - - //remap 62MB of physical memory after the kernel - // (KERNTOP to end of physical RAM (PMAPTOP)) - // This is where we allocate frames from. Except for the first one. -// unsigned int phys_addr = P_KERNTOP; - // +1 to skip L1PTBASE -// for (int i = (PMAPBASE >> 20); i < (PMAPTOP >> 20); i++) { -// first_level_pt[i] = phys_addr | 0x0400 | 2; -// phys_addr += 0x100000; -// } - - - // Fill in the coarse page table - // (TODO: How do we handle 64kB pages? Do they take up 16 entries?) - //os_memset((void*)coarse_page_table_address, 0, L2_PAGE_TABLE_SIZE); - // Set the first page to phys_addr - //*(unsigned int*)coarse_page_table_address = phys_addr | 0x20 | 2; - //os_printf("0x%X\n", *(unsigned int*)coarse_page_table_address); - -// first_level_pt[V_L1PTBASE >> 20] = P_L1PTBASE | 0x0400 | 2; - - // We have to empty out the first MB of that, so we can use it as an array of VASs - // The first slot is actually the kernel's VAS -// ((struct vas*) P_L1PTBASE)->l1_pagetable = (unsigned int*) (V_L1PTBASE + PAGE_TABLE_SIZE); //first_level_pt; -// ((struct vas*) P_L1PTBASE)->l1_pagetable_phys = first_level_pt; -// ((struct vas*) P_L1PTBASE)->next = 0x0; -// vm_vas_free_list = (struct vm_free_list*) ((void*) vm_vas_free_list + sizeof(struct vas)); -// vm_l1pt_free_list = (struct vm_free_list*) ((void*) vm_l1pt_free_list + PAGE_TABLE_SIZE); - -// unsigned int pt_addr = (unsigned int) first_level_pt; - - /*CONTROL REGISTER - * Enable MMU by setting 0 - * Alignment bit 1 - * D-cache bit 2 - * I-cache bit 12 - * V bit 13 (1=high vectors 0xffff0000) - * We disable high vectors, since low vectors work just fine. - */ - -// asm volatile ( -// // invalidate caches -// "mcr p15, 0, %[r], c7, c7, 0\n" -// // invalidate tlb -// "mcr p15, 0, %[r], c8, c7, 0\n" -// // data sync barrier -// "mcr p15, 0, %[r], c7,c10, 4\n" -// -// // set domains -// "mov r2, #0x01\n" -//// "ldr r2, =0x55555555\n" // [added] full r/w to everyone -// "mcr p15, 0, r2, c3, c0, 0\n" -// -// "mcr p15, 0, %[addr], c2, c0, 0\n" // Give the pagetable addr to the MMU -// "mcr p15, 0, %[addr], c2, c0, 1\n" -// -// "mrc p15, 0, r3, c1, c0, 0\n" // Read p15 -//// "mov r4, #0x1000 \n" -//// "add r4, #0x7 \n" -//// "orr r3, r4 \n" -// "orr r3, #0x800000\n" // Enable Armv6 bit -//// "orr r3, #0x1000\n" -// "orr r3, r3, #0x1\n" // Enable MMU bit -// "mcr p15, 0, r3, c1, c0, 0 \n" // Set p15 -// : -// : [addr] "r" (pt_addr), -// [r] "r" (0x0) -// ); - -// mmapped = true; - -// SemihostingCall(OSSpecific); - - // Build the free frame list -// vm_build_free_frame_list((void*) PMAPBASE + 0x100000, (void*) PMAPTOP); //(void*)PMAPBASE+(unsigned int)((PMAPTOP)-(PMAPBASE))); - - //restore register state - asm volatile("pop {r0-r11}"); - - // Except for r0, which is p_bootargs. stacks.s needs to know it. - asm volatile("mov r0, %[args]" : : [args] "r" (p_bootargs)); - - // asm volatile("cpsie if"); - asm volatile (".include \"src/memory/stacks.s\""); - -// void start2(uint32_t *p_bootargs); -// kprintf("Location of start2: 0x%x\n", &start2); -// //branch to proper kernel at start -//// asm volatile("bl start2"); -// -// void * oldstart2 = start2; -// void (*newstart2)(uint32_t *) = oldstart2 + V_KERNBASE; -// -// newstart2(p_bootargs); -} diff --git a/kernel/src/memory/stacks.s b/kernel/src/memory/stacks.s deleted file mode 100644 index 4bc9e933..00000000 --- a/kernel/src/memory/stacks.s +++ /dev/null @@ -1,52 +0,0 @@ -.equ stack_size, 0x1000 -.equ stack_base, 0xfffff000 - -.equ Mode_USR, 0x10 -.equ Mode_FIQ, 0x11 -.equ Mode_IRQ, 0x12 -.equ Mode_SVC, 0x13 -.equ Mode_MON, 0x16 -.equ Mode_ABT, 0x17 -.equ Mode_UND, 0x1B -.equ Mode_SYS, 0x1F - - MOV R1, R0 // R0 has p_bootargs, which we need to hang onto - LDR R0, =stack_base - MSR CPSR_c, #Mode_FIQ - MOV sp, R0 - SUB R0, R0, #stack_size - - MSR CPSR_c, #Mode_IRQ - MOV sp, R0 - SUB R0, R0, #stack_size - - MSR CPSR_c, #Mode_SVC - MOV sp, R0 - SUB R0, R0, #stack_size - - MSR CPSR_c, #Mode_MON - MOV sp, R0 - SUB R0, R0, #stack_size - - MSR CPSR_c, #Mode_ABT - MOV sp, R0 - SUB R0, R0, #stack_size - - MSR CPSR_c, #Mode_UND - MOV sp, R0 - SUB R0, R0, #stack_size - - MSR CPSR_c, #Mode_SYS - MOV sp, R0 - - MSR CPSR_c, #Mode_SVC - ADD fp, sp, #0 - - EOR R0, R0 - ADD R0, pc, #0xf0000000 - MOV pc, R0 - - EOR R0, R0 - ADD R0, lr, #0xf0000000 - MOV lr, R0 - MOV R0, R1 diff --git a/kernel/src/memory/vm/include/frame.h b/kernel/src/memory/vm/include/frame.h deleted file mode 100644 index 87f00fa5..00000000 --- a/kernel/src/memory/vm/include/frame.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __VM_FRAME_H -#define __VM_FRAME_H - -int vm_build_free_frame_list(void *start, void *end); -void *vm_get_free_frame(); -void vm_release_frame(void *p); -int vm_count_free_frames(); - -#endif diff --git a/kernel/src/memory/vm/include/swap_framework.h b/kernel/src/memory/vm/include/swap_framework.h deleted file mode 100644 index d8a6380b..00000000 --- a/kernel/src/memory/vm/include/swap_framework.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef __VM_SWAP_FRAMEWORK_H -#define __VM_SWAP_FRAMEWORK_H - -#include "../../../../old/include/klibc.h" -#include "stdint.h" - -// NOTE: SWAPPING CANNOT WORK UNTIL FILESYSTEMS CAN ALLOCATE MORE THAN 16 PAGES AT A TIME -/* Contributors: Noel Negusse and Jesse Thaden - * Last Update: 05/10/15 - */ - -/* Function: swap_framework - * Purpose: To present an API for swapping pages to various swap spaces - * so that pages may be stored independently of other related operations - * - * EXAMPLE OF VIRTUAL MEMORY ID/ADDRESS FROM SWAP SPACE - * _____________________________________________________________ - * || [24 bit] SWAP SPACE OFFSET |[8 bit] SWAP SPACE # || - * ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ - * * Total: 32 Bit Address - * therefore, there are 256 possible swap spaces possible - * w/ 2^12 page entries each (Assuming 4kB pages) - */ - -#define SWAP_SPACES (1<<8) -#define PAGE_ENTRIES (1<<12) // Assuming 4kB Pages right now -#define PAGE_SIZE (1<<12) // May carry an if statement later to account for different page sis -#define COMPRESSED_SIZE 10 // The size of compressing 16MiB of data - -typedef uint32_t *(*func)(void*, uint32_t*); - -struct swap_space { - struct swap_entry *e_head; // currently only used for LZ swap -// uint16_t pages_free; - uint8_t lower_bits; // swap space ID [8-bits] -// uint16_t flags; // swp_used (1000 or 1), swp_writeok (0010 or 2) or both (0011 or 3) - uint8_t priority; // lower is better - func store_func; - func retrieve_func; -}; // Total: 14 bytes - -struct swap_entry { - uint16_t e_flags; // PRIVILEGED_RO = 1, USER_RO = 2, PRIVILEGED_RW = 4, USER_RW = - uint16_t cmp_size; // size of compressed page - void *cmp_page; // virtual address pointer used for resolving page faults; NULL = unusedi -}; // Total: 8 bytes - -static struct swap_space *holder; -static os_size_t memory_count; - - -// Swap_init initializes swap framework -void swap_init(); -//void swap_init(os_size_t); To be implemented... [specifies global page size] - - -/* store_page will store a page to media - not main memory - storage, e.g. HDD - * from the page*. ID parameter passed will change to appropriate index (i.e. return value) - * void* page -> data to be paged - * os_size_t pagesize: The size of a page in bytes, i.e. 4096 b - * uint32_t* ID -> The page ID or address - * - * Returns: A pointer to a index value (from a bit vector) in memory - * OR returns a NULL/0 on failure - */ -uint32_t store_page(void*, uint32_t*); -uint32_t store_page_LZ(void*, uint32_t*); // All LZ functions not yet working... -// uint32_t *store_page(void*, os_size_t, uint32_t*); To be implemented... (will replace) -// uint32_t *store_pageLZ(void*, os_size_t, uint32_t*); diddo - - -/* retrieve_page will retrieve the page identified the ID pointer and - * will store it back into main memory (specified by the void *page pointer) - * - * Returns: NULL on failure or simply passes back ID on success - * NOTE: Page size was set by store_page - */ -uint32_t retrieve_page(void*, uint32_t*); -uint32_t retrieve_page_LZ(void*, uint32_t*); - - -/* Returns: The total stored memory in bytes by function store_page(void*, uint32_t*) */ -os_size_t sum_stored(); - - -/* vm_swap_page will store a page from main memory (specified by void *page) - * to a swap space either on disk or a compressed block in memory - * - * Returns: The ID pointer - bit vector index - of where the swap_space was stored and - * changes the ID pointer that value as well. Returns NULL on failure - */ -uint32_t vm_swapout_page(void*, uint32_t*); // store the page -uint32_t vm_swapin_page(void*, uint32_t*); // retrieve the page - - -/* vm_register/vm_deregister will activate/deactivate a swap space and set a priority - * accordingly to it. This allows the swap spaces use as well as increasing it's efficiency - * NOTE: deregister_swap_space will always deregister the lowest priority swap space first - * - * Returns: -1 or 1 whether the swap space registeration was a failure or success, respectively - */ -int vm_register_swap_space(func, func, int, int16_t); -void vm_deregister_swap_space(uint8_t); - - -/* Resolves the page fault and updates the corresponding page table - * - * Returns: 0 if the page_fault could not be resolved - * returns the new physical address of the loaded memory - */ -uint32_t vm_page_fault_handler(void*); - - -/* vm_scan_pages will scan through all pages for the corresponding page - * to the given page - * - * Returns: The address of matching swapped page - */ -//uint32_t* vm_scan_pages(void*); - -#endif diff --git a/kernel/src/memory/vm/include/swap_fs.h b/kernel/src/memory/vm/include/swap_fs.h deleted file mode 100644 index ddd64701..00000000 --- a/kernel/src/memory/vm/include/swap_fs.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef __VM_SWAP_FS_H -#define __VM_SWAP_FS_H - -#include "bitvector.h" -#include "swap_framework.h" - - -/* Last Update: 05/11/15 */ - - -bit_vector *bv_arr[SWAP_SPACES]; -// bit_vector *free_bitvector; - - -//helper function -char *generate_filename(uint8_t); - - -/* swapfs_init initializes swap file system framework for 'npages' number of pages - * - * Returns: -1 if failure, number of bytes written on success - */ -int32_t swapfs_init(int, uint8_t); - - -/* swapfs_store will store a page to media - not main memory - storage, e.g. HDD - * from the page* - * void* page -> data to be paged - * os_size_t pagesize: The size of a page in bytes, i.e. 4096 b - * uint32_t* ID -> The page ID or address - * - * Returns: The stored page's swap space ID, index OR -1 on failure - * NOTE: Relying on the changed id pointer is safer than using the output (unless - * for error checking) due to the int64_t type output - */ -int64_t swapfs_store(void*, uint32_t*, uint8_t); - - -/* swapfs_retrieve will retrieve the page identified by the ID pointer and - * will store it back into main memory (specified by the void *page pointer) - * - * Returns: -1 on failure and 1 on success - */ -int64_t swapfs_retrieve(void*, uint32_t*, uint8_t); - - -/* Returns: -1 if failure, 1 if success */ -int32_t swapfs_disable(uint8_t); - - -#endif diff --git a/kernel/src/memory/vm/include/swap_pqueue.h b/kernel/src/memory/vm/include/swap_pqueue.h deleted file mode 100644 index 3945070e..00000000 --- a/kernel/src/memory/vm/include/swap_pqueue.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef __VM_SWAP_PQUEUE_H -#define __VM_SWAP_PQUEUE_H - -#include "stdint.h" -#include "swap_framework.h" - - -/* Last Update: 05/10/15 */ - - -struct node{ - struct node *next; - struct swap_entry *e_head; - uint8_t lower_bits; // swap space ID [8-bits] -// uint16_t flags; // SWP_USED (1000 or 1), SWP_WRITEOK (0010 or 2) - uint8_t priority; // lower is better - func store_func; - func retrieve_func; -}; // Total: 16 bytes - -static struct node *head; -static struct node *path; //tail -static uint8_t s; - - -/* pqueue_init initializes the priority queue with a given - * swap_space type struct - */ -void pqueue_init(struct swap_space*); - - -/* pqueue_set does a deep copy of the value of the second - * struct to the front struct - */ -void pqueue_set(struct node*, struct swap_space*); - - -/* pqueue_push pushes the swap_space struct onto the proper - * index based on the priority found in the struct - */ -void pqueue_push(struct swap_space*); - - -/* pqueue_pop_front & pqueue_pop_back pops a node from the head/back of the - * pqueue_pop_front priority queue as well as freeing the given memory of the - * head/back - */ -void pqueue_pop_front(); -void pqueue_pop_back(); -void pqueue_pop_at(uint8_t); // Note: 'at' ssid not index - -/* pqueue_size returns the current size of the priority queue */ -uint8_t pqueue_size(); - - -/* pqueue_index finds the given index of the priority queue - * - * Returns: The struct of the given index in pqueue - * NOTE: THIS IS NOT THE SAME AS THE SWAP_SPACE STRUCT - */ -struct node *pqueue_index(int); - - -/* It 'peeks' at the head of the list for a specified value - * - * Returns: The specified value from the head of the list - * 0 - lower_bits - * 1 - priority - * 2 - e_head - */ -void *pqueue_peek(int); - - -/* pqueue_find finds the actual index of the swap space ID (lower_bit value) - * - * Returns: The found node specified or NULL if not found - * NOTE: THIS IS NOT THE SAME AS THE SWAP_SPACE STRUCT - */ -struct node *pqueue_find(uint8_t); - - -#endif diff --git a/kernel/src/memory/vm/include/vm.h b/kernel/src/memory/vm/include/vm.h deleted file mode 100644 index e3111c97..00000000 --- a/kernel/src/memory/vm/include/vm.h +++ /dev/null @@ -1,205 +0,0 @@ -#ifndef __VM_H -#define __VM_H - -#include -#include -#include -#include - -//#define BLOCK_SIZE (1<<20) -#define BLOCK_SIZE ((uint32_t)(1<<12)) - -#define PAGE_TABLE_SIZE (1<<14) -#define L2_PAGE_TABLE_SIZE (1<<12) - -struct vas { - // A pointer to the first level of the pagetable. - volatile unsigned int *l1_pagetable; - volatile unsigned int *l1_pagetable_phys; // The physical address to it - - // A pointer to the next VAS (it's a linked list) - struct vas *next; -}; - -#define VM_ERR_BADV -1 -#define VM_ERR_BADP -2 -#define VM_ERR_MAPPED -3 -#define VM_ERR_BADPERM -4 -#define VM_ERR_UNKNOWN -5 -#define VM_ERR_NOT_MAPPED -6 - -#define KERNEL_VAS ((struct vas*)V_L1PTBASE) - - -#define VM_L1_GET_ENTRY(table,vptr) table[((unsigned int)vptr)>>20] -#define VM_L1_SET_ENTRY(table,vptr,ent) (table[((unsigned int)vptr)>>20]=ent) -#define VM_ENTRY_GET_FRAME(x) ((x)&~((PAGE_TABLE_SIZE<<1) - 1)) -#define VM_ENTRY_GET_L2(x) ((x)&~0x1FF) -#define VM_L2_ENTRY(l2pt,vptr) ((uint32_t*)l2pt)[((unsigned int)vptr&0x000FF000)>>12] -#define VM_L2ENTRY_GET_FRAME(x) ((x)&0xFFFFF000) - -/** - * These permissions dictate who can access what pages. Note that you - * cannot combine these arbitrarily. For example: - * VM_PERM_PRIVILEGED_RO|VM_PERM_PRIVILEGED_RW - * makes no sense. If the user mode is granted a given permission, then the - * privileged mode is granted that permission as well, unless there is a - * confliction. Some examples: - * VM_PERM_USER_RO - * grants RO status to both user and privileged modes. - * - * VM_PERM_USER_RO|VM_PERM_PRIVILEGED_RW - * grants RO to the user, and RW to privileged modes. - * - * VM_PERM_USER_RW|VM_PERM_PRIVILEGED_RO - * doesn't make sense. USER_RW grants RW to both user and privileged, but - * PRIVILEGED_RO contradicts the USER_RW's implied grant. - * - * VM_ERR_BADPERM is returned if a bad permission is passed. Note that 0 - * is a valid permission, indicating that nobody may have access. - * - * (RO stands for Read-Only, RW for Read-Write) - */ -#define VM_PERM_PRIVILEGED_RO 1 -#define VM_PERM_USER_RO 2 -#define VM_PERM_PRIVILEGED_RW 4 -#define VM_PERM_USER_RW 8 - -void vm_init(); - -/** - * vm_allocate_page and vm_free_page allocate and free pages, and allow the - * VAS to access them at the given virtual address (vptr). - * Note that you cannot call free_page on a virtual address that was - * mapped using set_mapping. - * Return values: - * 0 - success - * VM_ERR_BADV - vptr was not a multiple of BLOCK_SIZE. - * VM_ERR_MAPPED - vptr is already mapped in this VAS. - * VM_ERR_BADPERM - permission is not valid (see above). - * - * free_page return values: - * 0 - success - * VM_ERR_BADV - vptr was not a multiple of BLOCK_SIZE. - * VM_ERR_MAPPED - vptr was mapped using set_mapping, not allocate_page. - * VM_ERR_NOT_MAPPED - vptr is not mapped in this VAS. - */ -int vm_allocate_page(struct vas *vas, void *vptr, int permission); -void *vm_allocate_pages(struct vas *vas, void *vptr, uint32_t nbytes, int permission); -int vm_free_page(struct vas *vas, void *vptr); - -/** - * vm_pin and vm_unpin currently do nothing. However, in the future, they will - * prevent pages from being swapped out of physical memory. - * Return values: - * 0 - Success. - */ -int vm_pin(struct vas *vas, void *vptr); -int vm_unpin(struct vas *vas, void *vptr); - -/** - * vm_set_mapping maps the given vptr to the given pptr. - * Return values: - * 0 - success - * VM_ERR_BADV - vptr was not a multiple of BLOCK_SIZE. - * VM_ERR_BADP - pptr was not a multiple of BLOCK_SIZE. - * VM_ERR_MAPPED - vptr is already mapped in this VAS. - * VM_ERR_BADPERM - permission is not valid. - * - * vm_free_mapping unmaps the vptr. Note that you may not call free_mapping - * on a virtual address that was allocated using allocate_page. - * Return values: - * 0 - success - * VM_ERR_BADV - vptr was not a multiple of BLOCK_SIZE. - * VM_ERR_NOT_MAPPED - vptr was not mapped using set_mapping. - */ -int vm_set_mapping(struct vas *vas, void *vptr, void *pptr, int permission); -int vm_free_mapping(struct vas *vas, void *vptr); - - -/* vm_swap_free_mapping is the spapping frameworks flavor on vm's vm_free_mapping - * It takes in an extra paramter that will be set to the L2 page entry (instead of 0) - * - Noel Negusse - * - * Returns: Same as vm_free_mapping - */ -int vm_swap_free_mapping(struct vas*, void*, uint32_t*); - - -/** - * Will make the memory that accessible to other_vas at other_ptr - * accessible to vas at this_ptr. - * It can then be unmapped from either using a typical vm_free_mapping - * or vm_free_page. The behavior of vm_free_mapping and vm_free_page - * will be made equivalent. - * For both, the behavior will be to free the frame if a frame was - * allocated (via vm_allocate_page) and the page is not shared. If the - * page is shared, then both will behave like vm_free_mapping. - * - * It is an error for other_ptr to point to an area not mapped in other_vas. - * - * For example, given vas1 and vas2: - * - * vm_allocate_page(vas2,0x10) - * vm_map_shared_memory(vas1, 0x20, vas2, 0x10) - * // Now vas1's 0x20 points to the same memory as vas2's 0x10 - * vm_free_page(vas2, 0x10) - * // Now vas1 is the sole owner of the memory at vas1's 0x20 - * vm_free_mapping(vas1, 0x20) - * // Now that frame has been freed - * - * All the pointers have to be a multiple of BLOCK_SIZE. - * - * Return values: - * 0 - success - * VM_ERR_BADV - this_ptr was not a multiple of BLOCK_SIZE. - * VM_ERR_BADP - other_ptr was not a multiple of BLOCK_SIZE. - * VM_ERR_NOT_MAPPED - other_ptr is not mapped in other_vas. - * VM_ERR_MAPPED - this_ptr is already mapped in vas. - * VM_ERR_BADPERM - permission is bad. - */ -int vm_map_shared_memory(struct vas *vas, void *this_ptr, struct vas *other_vas, void *other_ptr, int permission); - -/** - * This enabled the given VAS. - */ -void vm_enable_vas(struct vas *vas); - -/** - * Allocates a new VAS. - * - * Note that there is a limit of 4096 VASs in the system, including the - * kernel's VAS. - */ -struct vas *vm_new_vas(); -int vm_free_vas(struct vas *vas); - -/** - * Retrieves a reference to the currently running VAS. - */ -struct vas *vm_get_current_vas(); - -/** - * Switches to the kernel's VAS. - */ -void vm_use_kernel_vas(); - -static inline void ensure_kernel_vas() -{ - assert (vm_get_current_vas() == KERNEL_VAS && "Must run in kernel VAS!"); -} - -void vm_test(); - -static inline void vm_invalidate_tlb(void) -{ - // Invalidate the TLB - asm volatile("mcr p15, 0, %[r], c8, c5, 0" : : [r] "r" (0x0)); - asm volatile("mcr p15, 0, %[r], c8, c6, 0" : : [r] "r" (0x0)); - asm volatile("mcr p15, 0, %[r], c8, c7, 0" : : [r] "r" (0x0)); -} - -uint32_t *vm_vtop(struct vas *vas, uint32_t *vptr); -uint32_t *vm_ptov(struct vas *vas, uint32_t *vptr); - -#endif diff --git a/kernel/src/memory/vm/test/test_vm.c b/kernel/src/memory/vm/test/test_vm.c deleted file mode 100644 index 2a0f8bbd..00000000 --- a/kernel/src/memory/vm/test/test_vm.c +++ /dev/null @@ -1,105 +0,0 @@ -//#include -//#include "klibc.h" -//#include "memory.h" -//#include "vm.h" -// -//// TODO: This test has many LOG calls, we should try and looking at improving the logging capabilities -//TEST_CREATE(test_vm_1, { -// struct vas *vas1 = vm_new_vas(); -// LOG("Got new vas at 0x%X\n", vas1); -// -// // We're part of the kernel, which is already mapped into vas1. -// // But our stack isn't, so let's add that mapping. -// unsigned int mystack = (unsigned int) &vas1; -// mystack &= 0xFFF00000; // Round down to nearest MB -// LOG("Stack addr: 0x%X\n", mystack); -// LOG("Created page table w/ 0xFFF00000's entry = 0x%X\n", -// vas1->l1_pagetable[V_KDSBASE>>20]); -// -// vm_enable_vas(vas1); -// -// // Do we still have the stack? -// // FIXME Update constant as necessary -// #define STACK_ADDR 0xF020000C -// // Invalid stack -// ASSERT_EQ((unsigned int) vas1, STACK_ADDR); -// -// struct vas *vas2 = (struct vas*) V_L1PTBASE; -// INFO("%X (%X)\n", vas2, &vas2); -// INFO("%X\n", *((unsigned int* ) vas2)); -// INFO("%X\n", vas2->l1_pagetable); -// INFO("Entry: %x\n", -// vas1->l1_pagetable[(unsigned int ) vas2->l1_pagetable >> 20]); -// INFO("%X\n", vas2->l1_pagetable[0]); -// INFO("(deref: entry at 0x200000: 0x%X)\n", -// vas2->l1_pagetable[0x200000 >> 20]); -// -// // Test making a thing in this thing -// struct vas *vas3 = vm_new_vas(); -// vm_enable_vas(vas3); -// INFO("%X and %X and %X\n", vas1, vas2, vas3); -// -// // Test allocating frames... -// #define P3_BASE 0x24000000 -// int retval = vm_allocate_page(vas3, (void*) P3_BASE, VM_PERM_PRIVILEGED_RW); -// -// // vm_allocate_page fails -// ASSERT(!retval); -// -// int *p = (int*) 0xFFFFFFF0; -// p[0] = 1; -// -// ASSERT_EQ(p[0], 1); -// -// // Oh man! We should be able to write to there! -// p = (int*) P3_BASE; -// p[0] = 1; -// -// LOG("%x %x\n", &p, p); -// -// ASSERT_EQ(p[0], 1); -// -// // Test shared memory... -// LOG("Testing shared memory...\n"); -// int *p_3 = (int*) P3_BASE;//0x24000000; -// int *p_1 = (int*) 0x31000000; -// retval = vm_map_shared_memory(vas1, p_1, vas3, p_3, VM_PERM_PRIVILEGED_RW); -// LOG("map_shared_memory returned %d\n", retval); -// -// p_3[0] = 321; -// vm_enable_vas(vas1); -// ASSERT_EQ(p_1[0], 321); -// p_1[1] = 456; -// -// vm_enable_vas(vas3); -// ASSERT_EQ(p_3[1], 456); -// -// // Test allocating many frames... (this was commented but seems to work just fine) -// *p += BLOCK_SIZE; -// while (!vm_allocate_page(vas3, (void*) p, 0)) { -// //LOG("Allocated memory...\n"); -// p += BLOCK_SIZE; -// } -// -// p -= BLOCK_SIZE; -// kprintf("Highest frame allocated: 0x%X\n", p); -// -// while ((unsigned int) p > P3_BASE) { -// //LOG("Freed memory...\n"); -// vm_free_page(vas3, p); -// p -= BLOCK_SIZE; -// } -// -// // FIXME: This part of the test crashes the os, we should catch that in some way. -// // Test the data abort... -//// WARN("You should see a data abort...\n"); -//// int i = p[-1]; -//// LOG("%d\n", i); -// -// // Free the page! -// LOG("Freeing page at %X\n", p); -// vm_free_page(vas3, p); -// -// // Clean up & switch back to the kernel's VAS before we return. -// vm_enable_vas((struct vas*) KERNEL_VAS); -//}) diff --git a/kernel/src/vm/README.md b/kernel/src/vm/README.md new file mode 100644 index 00000000..7d0d0b31 --- /dev/null +++ b/kernel/src/vm/README.md @@ -0,0 +1,37 @@ + +# Virtual Memory + +## Description + +## Memory map + +### Physical + +| Address | Description | +| ---------- | ---------------------------------------------------------------------- | +| 0x0000000 | Interrupt Vector Table | +| 0x0004000 | Kernel L1 page table | +| 0x0008000 | Kernel start | +| ... | *Kernel* | +| ... | *Kernel* | +| KERNEL END | Physical Memory Manager starting point | +| ... | Physical Memory Manager | +| 0xXXXXXXXX | End of Physical memory (Device dependent, max 1GB) | + +### Virtual + +| Address | Description | +| ---------- | ---------------------------------------------------------------------- | +| 0x0000000 | Virtual Process Address Space | +| 0x8000000 | Interrupt Vector Table (remap of the first gigabyte of phys --> virt) | +| 0x8004000 | Kernel page table | +| 0x8008000 | Kernel start | +| ... | *Kernel* | +| ... | *Kernel* | +| KERNEL END | Location of the PMM in virtual address space | +| ... | (Virtual) Physical Memory Manager | +| 0xC000000 | Kernel heap start (growing up) | +| 0xFFFFFFF | MMIO mappings (growing down) | + +***Note:*** Both the MMIO mapping and kernel heap occupy the same gigabyte. +The sum of the two can't exceed 1 gigabyte and when the kernel heap grows to touch the MMIO top, the heap is full. diff --git a/kernel/src/vm/include/mmio.h b/kernel/src/vm/include/mmio.h new file mode 100644 index 00000000..3d446ac6 --- /dev/null +++ b/kernel/src/vm/include/mmio.h @@ -0,0 +1,21 @@ +#ifndef MMIO_H +#define MMIO_H + + +#define mmio_read(address) (*((volatile uint32_t *)(address))) +#define mmio_write(address, value) mmio_write_internal((volatile uint32_t *)(address), (volatile uint32_t)(value)) + +// Do the mmio write in assembly to remove any chance of gcc optimizing the call away. *yes* even if it was marked volatile already. +// Hence the 4 hours it took us to make timer.c work...... +static inline void mmio_write_internal(volatile uint32_t * address, volatile uint32_t value ) { + asm volatile ( + "ldr r1, %1\n" + "str r1, %0\n" + :: + "m" (*address), + "m" (value) + ); +} + +#endif + diff --git a/kernel/src/memory/vm/include/pmm.h b/kernel/src/vm/include/pmm.h similarity index 100% rename from kernel/src/memory/vm/include/pmm.h rename to kernel/src/vm/include/pmm.h diff --git a/kernel/src/memory/vm/include/tlb_cache_id_allocator.h b/kernel/src/vm/include/tlb_cache_id_allocator.h similarity index 100% rename from kernel/src/memory/vm/include/tlb_cache_id_allocator.h rename to kernel/src/vm/include/tlb_cache_id_allocator.h diff --git a/kernel/src/memory/vm/include/vas2.h b/kernel/src/vm/include/vas2.h similarity index 80% rename from kernel/src/memory/vm/include/vas2.h rename to kernel/src/vm/include/vas2.h index 7982774d..2356602d 100644 --- a/kernel/src/memory/vm/include/vas2.h +++ b/kernel/src/vm/include/vas2.h @@ -1,8 +1,8 @@ #ifndef VAS_2_H #define VAS_2_H -#include -#include +#include "vm2.h" +#include "tlb_cache_id_allocator.h" struct vas2 { diff --git a/kernel/src/memory/vm/include/vm2.h b/kernel/src/vm/include/vm2.h similarity index 99% rename from kernel/src/memory/vm/include/vm2.h rename to kernel/src/vm/include/vm2.h index 1333bd86..5e1bb231 100644 --- a/kernel/src/memory/vm/include/vm2.h +++ b/kernel/src/vm/include/vm2.h @@ -326,4 +326,7 @@ extern const size_t __KERNEL_VIRTUAL_OFFSET[]; #define PAGE_SIZE (4 * Kibibyte) + + + #endif diff --git a/kernel/src/memory/vm/memory-layout.svg b/kernel/src/vm/memory-layout.svg similarity index 100% rename from kernel/src/memory/vm/memory-layout.svg rename to kernel/src/vm/memory-layout.svg diff --git a/kernel/src/memory/vm/pmm.c b/kernel/src/vm/pmm.c similarity index 100% rename from kernel/src/memory/vm/pmm.c rename to kernel/src/vm/pmm.c diff --git a/kernel/src/memory/vm/test/test_pagealloc2.c b/kernel/src/vm/test/test_pagealloc2.c similarity index 100% rename from kernel/src/memory/vm/test/test_pagealloc2.c rename to kernel/src/vm/test/test_pagealloc2.c diff --git a/kernel/src/memory/vm/test/test_vm2.c b/kernel/src/vm/test/test_vm2.c similarity index 100% rename from kernel/src/memory/vm/test/test_vm2.c rename to kernel/src/vm/test/test_vm2.c diff --git a/kernel/src/memory/vm/tlb_cache_id_allocator.c b/kernel/src/vm/tlb_cache_id_allocator.c similarity index 100% rename from kernel/src/memory/vm/tlb_cache_id_allocator.c rename to kernel/src/vm/tlb_cache_id_allocator.c diff --git a/kernel/src/memory/vm/vas2.c b/kernel/src/vm/vas2.c similarity index 100% rename from kernel/src/memory/vm/vas2.c rename to kernel/src/vm/vas2.c diff --git a/kernel/src/memory/vm/vm2.c b/kernel/src/vm/vm2.c similarity index 100% rename from kernel/src/memory/vm/vm2.c rename to kernel/src/vm/vm2.c From 29c0a892a76ce5e8e1f788602a1e5b7182785a42 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Sun, 8 Mar 2020 16:52:47 +0100 Subject: [PATCH 042/104] enabled high interrupt vectors to enable higher-half interrupts Co-authored-by: Victor Roest --- .github/workflows/os_test.yml | 2 +- kernel/src/common/interrupt.c | 52 +++++++++++----------- kernel/src/common/startup.s | 6 +++ kernel/src/drivers/chipset/bcm2836/timer.c | 8 ++-- kernel/src/ds/u8_array_list.c | 6 ++- kernel/src/fs/path.c | 2 + kernel/src/fs/test/test_path.c | 1 + kernel/src/klibc/alloc.c | 8 +++- kernel/src/vm/README.md | 19 ++++---- kernel/src/vm/include/vm2.h | 6 ++- kernel/src/vm/vm2.c | 2 +- 11 files changed, 65 insertions(+), 47 deletions(-) diff --git a/.github/workflows/os_test.yml b/.github/workflows/os_test.yml index f38de978..4f0ed217 100644 --- a/.github/workflows/os_test.yml +++ b/.github/workflows/os_test.yml @@ -21,7 +21,7 @@ jobs: sudo apt-get install build-essential qemu-system-arm python3 wget texinfo zlib1g-dev -y - name: Install Toolchain - #if: steps.cache-toolchain.outputs.cache-hit != 'true' + if: steps.cache-toolchain.outputs.cache-hit != 'true' run: rm -rf toolchain/arm-none-eabi/ && make toolchain - name: Compile diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index dc92c7f2..dd5ce9b8 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -6,36 +6,36 @@ /* copy vector table from wherever QEMU loads the kernel to 0x00 */ void init_vector_table() { - /* This doesn't seem to work well with virtual memory; reverting - * to old method. - extern uint32_t vector_table_start, vector_table_end; - uint32_t *src = &vector_table_start; - uint32_t *dst = (uint32_t *) HIVECTABLE; - - while(src < &vector_table_end) - *dst++ = *src++; - */ + // allocate space for the IVR at the high vector location. + vm2_allocate_kernel_page(kernell1PageTable, HIGH_VECTOR_LOCATION, true); /* Primary Vector Table */ - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x0, BRANCH_INSTRUCTION); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x04, BRANCH_INSTRUCTION); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x08, BRANCH_INSTRUCTION); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x0C, BRANCH_INSTRUCTION); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x10, BRANCH_INSTRUCTION); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x14, BRANCH_INSTRUCTION); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x18, BRANCH_INSTRUCTION); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x1C, BRANCH_INSTRUCTION); + mmio_write(HIGH_VECTOR_LOCATION + 0x00, BRANCH_INSTRUCTION); + mmio_write(HIGH_VECTOR_LOCATION + 0x04, BRANCH_INSTRUCTION); + mmio_write(HIGH_VECTOR_LOCATION + 0x08, BRANCH_INSTRUCTION); + mmio_write(HIGH_VECTOR_LOCATION + 0x0C, BRANCH_INSTRUCTION); + mmio_write(HIGH_VECTOR_LOCATION + 0x10, BRANCH_INSTRUCTION); + mmio_write(HIGH_VECTOR_LOCATION + 0x14, BRANCH_INSTRUCTION); + mmio_write(HIGH_VECTOR_LOCATION + 0x18, BRANCH_INSTRUCTION); + mmio_write(HIGH_VECTOR_LOCATION + 0x1C, BRANCH_INSTRUCTION); /* Secondary Vector Table */ - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x20, &reset_handler); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x24, &undef_instruction_handler); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x28, &software_interrupt_handler); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x2C, &prefetch_abort_handler); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x30, &data_abort_handler); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x34, &reserved_handler); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x38, &irq_handler); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x3C, &fiq_handler); - + mmio_write(HIGH_VECTOR_LOCATION + 0x20, &reset_handler); + mmio_write(HIGH_VECTOR_LOCATION + 0x24, &undef_instruction_handler); + mmio_write(HIGH_VECTOR_LOCATION + 0x28, &software_interrupt_handler); + mmio_write(HIGH_VECTOR_LOCATION + 0x2C, &prefetch_abort_handler); + mmio_write(HIGH_VECTOR_LOCATION + 0x30, &data_abort_handler); + mmio_write(HIGH_VECTOR_LOCATION + 0x34, &reserved_handler); + mmio_write(HIGH_VECTOR_LOCATION + 0x38, &irq_handler); + mmio_write(HIGH_VECTOR_LOCATION + 0x3C, &fiq_handler); + + /// Enable high vectors (Vectors located at HIGH_VECTOR_LOCATION). + asm volatile ( + "mrc p15, 0, r1, c1, c0, 0 \n" // Read p15 + "orr r1, %0\n" // Enable High Vector bit + "mcr p15, 0, r1, c1, c0, 0\n" // Set p15 + :: "r" (1u << 13u) + ); } /* handlers */ diff --git a/kernel/src/common/startup.s b/kernel/src/common/startup.s index 88b2311a..59758767 100644 --- a/kernel/src/common/startup.s +++ b/kernel/src/common/startup.s @@ -8,6 +8,12 @@ _Reset: cmp r1, #0 bne loop + // Move the interrupt vector tables to 0x80000000 + ldr r0, =0xE000ED08 + ldr r1, =0x80000000 + str r1, [r0] + + ldr sp, =EARLY_KERNEL_STACK_TOP // Set the kernel/SVC stack push {r0-r11} diff --git a/kernel/src/drivers/chipset/bcm2836/timer.c b/kernel/src/drivers/chipset/bcm2836/timer.c index 633231b8..3b216929 100644 --- a/kernel/src/drivers/chipset/bcm2836/timer.c +++ b/kernel/src/drivers/chipset/bcm2836/timer.c @@ -41,14 +41,12 @@ void bcm2836_timer_init() { uint32_t freq = get_frequency(); - kprintf("control frequency: %i\n", freq); + TRACE("control frequency: %i", freq); // 1 (milli)second timer - write_interrupt_count_value(freq); - - kprintf("value: %i\n", read_interrupt_count_value()); - kprintf("value: %i\n", read_interrupt_count_value()); + write_interrupt_count_value(freq * 100); // when the register reaches the count value set above, interrupt. + // TODO: Enable timer // mmio_write(&bcm2836_registers_base->Core0TimersInterruptControl, VIRTUAL_NONSECURE_TIMER); // Enable timer interrupts. diff --git a/kernel/src/ds/u8_array_list.c b/kernel/src/ds/u8_array_list.c index b24f9b60..55bdc6e2 100644 --- a/kernel/src/ds/u8_array_list.c +++ b/kernel/src/ds/u8_array_list.c @@ -6,6 +6,7 @@ #include #include #include +#include U8ArrayList * u8a_create(uint32_t initial_cap) { U8ArrayList * list = kmalloc(sizeof(U8ArrayList)); @@ -39,7 +40,7 @@ void u8a_set(U8ArrayList * list, uint32_t index, uint8_t data) { uint32_t u8a_push(U8ArrayList * list, uint8_t data) { if(list->capacity == 0 || list->length >= list->capacity - 1) { - uint32_t new_size = max((list->capacity + (list->capacity >> 2)), list->capacity + 2); + uint32_t new_size = max((list->capacity + (list->capacity >> 2u)), list->capacity + 2); assert(new_size > list->capacity) @@ -47,6 +48,7 @@ uint32_t u8a_push(U8ArrayList * list, uint8_t data) { list->array = krealloc(list->array, list->capacity * sizeof(uint8_t)); } + list->array[list->length++] = data; return list->length; @@ -97,4 +99,4 @@ U8ArrayList * u8a_clone(U8ArrayList * arr) { } return newarr; -} \ No newline at end of file +} diff --git a/kernel/src/fs/path.c b/kernel/src/fs/path.c index 00b4cb2a..c7ad6739 100644 --- a/kernel/src/fs/path.c +++ b/kernel/src/fs/path.c @@ -5,6 +5,8 @@ #include #include +#include + const Path root = { .length = 1, diff --git a/kernel/src/fs/test/test_path.c b/kernel/src/fs/test/test_path.c index 23ea9128..1e52324c 100644 --- a/kernel/src/fs/test/test_path.c +++ b/kernel/src/fs/test/test_path.c @@ -71,6 +71,7 @@ TEST_CREATE(path_parent_test_4, { ASSERT(path_contents_equal(p1, p2)); path_free(p1); path_free(p2); + }) TEST_CREATE(path_parent_test_5, { diff --git a/kernel/src/klibc/alloc.c b/kernel/src/klibc/alloc.c index a9426e6a..00c7b9cc 100644 --- a/kernel/src/klibc/alloc.c +++ b/kernel/src/klibc/alloc.c @@ -33,13 +33,17 @@ uint32_t kmalloc_size(void* ptr) { // TODO: Implement in-place realloc if the next block is free. // Resize memory pointed to by ptr to new size void * krealloc(void *ptr, uint32_t newsize) { + if (ptr == NULL) { + TRACE("[MEM DEBUG] Realloc with nullptr"); + return kmalloc(newsize); + } + uint32_t oldsize = kmalloc_size(ptr); + if (newsize == 0) { kfree(ptr); return NULL; - } else if (ptr == NULL) { - return kmalloc(newsize); } else if (newsize <= oldsize) { return ptr; } else { diff --git a/kernel/src/vm/README.md b/kernel/src/vm/README.md index 7d0d0b31..50f1efe3 100644 --- a/kernel/src/vm/README.md +++ b/kernel/src/vm/README.md @@ -9,9 +9,9 @@ | Address | Description | | ---------- | ---------------------------------------------------------------------- | -| 0x0000000 | Interrupt Vector Table | -| 0x0004000 | Kernel L1 page table | -| 0x0008000 | Kernel start | +| 0x00000000 | Interrupt Vector Table | +| 0x00004000 | Kernel L1 page table | +| 0x00080000 | Kernel start | | ... | *Kernel* | | ... | *Kernel* | | KERNEL END | Physical Memory Manager starting point | @@ -22,16 +22,17 @@ | Address | Description | | ---------- | ---------------------------------------------------------------------- | -| 0x0000000 | Virtual Process Address Space | -| 0x8000000 | Interrupt Vector Table (remap of the first gigabyte of phys --> virt) | -| 0x8004000 | Kernel page table | -| 0x8008000 | Kernel start | +| 0x00000000 | Virtual Process Address Space | +| 0x80000000 | (start of) remap of physical 0x00000000-0x40000000 | +| 0x80004000 | Kernel page table | +| 0x80008000 | Kernel start | | ... | *Kernel* | | ... | *Kernel* | | KERNEL END | Location of the PMM in virtual address space | | ... | (Virtual) Physical Memory Manager | -| 0xC000000 | Kernel heap start (growing up) | -| 0xFFFFFFF | MMIO mappings (growing down) | +| 0xC0000000 | Kernel heap start (growing up) | +| 0xFFF00000 | MMIO mappings (growing down) | +| 0xFFFF0000 | High location of the vector table | ***Note:*** Both the MMIO mapping and kernel heap occupy the same gigabyte. The sum of the two can't exceed 1 gigabyte and when the kernel heap grows to touch the MMIO top, the heap is full. diff --git a/kernel/src/vm/include/vm2.h b/kernel/src/vm/include/vm2.h index 5e1bb231..296c66e0 100644 --- a/kernel/src/vm/include/vm2.h +++ b/kernel/src/vm/include/vm2.h @@ -310,8 +310,12 @@ extern const size_t __KERNEL_VIRTUAL_OFFSET[]; /// Location of the Kernel's Physical Memory Manager's Info structs. Can grow to a max of 16MiB when using 4GiB RAM. #define KERNEL_PMM_BASE KERNEL_VIRTUAL_END +// Location of the vector table in memory table. +// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/BABIFJFG.html +#define HIGH_VECTOR_LOCATION 0xFFFF0000 + /// From this address down, mmio devices are mapped in the kernel's virtual address space. -#define KERNEL_MMIO_BASE (4 * Gibibyte) +#define KERNEL_MMIO_BASE ((4 * Gibibyte) - (1 * Mebibyte)) /// Address space for the kernel heap, grows towards the mmio #define KERNEL_HEAP_BASE (3 * Gibibyte) diff --git a/kernel/src/vm/vm2.c b/kernel/src/vm/vm2.c index f5d95aff..5bbc5e46 100644 --- a/kernel/src/vm/vm2.c +++ b/kernel/src/vm/vm2.c @@ -91,7 +91,7 @@ void vm2_start() { /// Unmap the 1:1 mapped first megabyte which startup.s created to boot to a higher half kernel. /// We don't need it anymore! -// kernell1PageTable->entries[0] = (L1PagetableEntry){0}; + kernell1PageTable->entries[0] = (L1PagetableEntry){0}; /// Map the entire gigabyte (or less on some boards, but never more) physical ram to virtual 2GB-3GB. /// this includes the kernel, kernel stack, kernel pagetables, process pagetables, pmm etc. From 401470f240a93ffa6506ac52c585b819a54ed1d3 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Sun, 8 Mar 2020 16:52:47 +0100 Subject: [PATCH 043/104] enabled high interrupt vectors to enable higher-half interrupts Co-authored-by: Victor Roest --- .github/workflows/os_test.yml | 2 +- kernel/src/common/interrupt.c | 52 +++++++++++----------- kernel/src/common/startup.s | 6 +++ kernel/src/drivers/chipset/bcm2836/timer.c | 8 ++-- kernel/src/ds/u8_array_list.c | 6 ++- kernel/src/fs/path.c | 2 + kernel/src/fs/test/test_path.c | 1 + kernel/src/klibc/alloc.c | 8 +++- kernel/src/vm/README.md | 19 ++++---- kernel/src/vm/include/vm2.h | 6 ++- kernel/src/vm/vm2.c | 2 +- 11 files changed, 65 insertions(+), 47 deletions(-) diff --git a/.github/workflows/os_test.yml b/.github/workflows/os_test.yml index f38de978..4f0ed217 100644 --- a/.github/workflows/os_test.yml +++ b/.github/workflows/os_test.yml @@ -21,7 +21,7 @@ jobs: sudo apt-get install build-essential qemu-system-arm python3 wget texinfo zlib1g-dev -y - name: Install Toolchain - #if: steps.cache-toolchain.outputs.cache-hit != 'true' + if: steps.cache-toolchain.outputs.cache-hit != 'true' run: rm -rf toolchain/arm-none-eabi/ && make toolchain - name: Compile diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index dc92c7f2..dd5ce9b8 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -6,36 +6,36 @@ /* copy vector table from wherever QEMU loads the kernel to 0x00 */ void init_vector_table() { - /* This doesn't seem to work well with virtual memory; reverting - * to old method. - extern uint32_t vector_table_start, vector_table_end; - uint32_t *src = &vector_table_start; - uint32_t *dst = (uint32_t *) HIVECTABLE; - - while(src < &vector_table_end) - *dst++ = *src++; - */ + // allocate space for the IVR at the high vector location. + vm2_allocate_kernel_page(kernell1PageTable, HIGH_VECTOR_LOCATION, true); /* Primary Vector Table */ - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x0, BRANCH_INSTRUCTION); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x04, BRANCH_INSTRUCTION); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x08, BRANCH_INSTRUCTION); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x0C, BRANCH_INSTRUCTION); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x10, BRANCH_INSTRUCTION); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x14, BRANCH_INSTRUCTION); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x18, BRANCH_INSTRUCTION); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x1C, BRANCH_INSTRUCTION); + mmio_write(HIGH_VECTOR_LOCATION + 0x00, BRANCH_INSTRUCTION); + mmio_write(HIGH_VECTOR_LOCATION + 0x04, BRANCH_INSTRUCTION); + mmio_write(HIGH_VECTOR_LOCATION + 0x08, BRANCH_INSTRUCTION); + mmio_write(HIGH_VECTOR_LOCATION + 0x0C, BRANCH_INSTRUCTION); + mmio_write(HIGH_VECTOR_LOCATION + 0x10, BRANCH_INSTRUCTION); + mmio_write(HIGH_VECTOR_LOCATION + 0x14, BRANCH_INSTRUCTION); + mmio_write(HIGH_VECTOR_LOCATION + 0x18, BRANCH_INSTRUCTION); + mmio_write(HIGH_VECTOR_LOCATION + 0x1C, BRANCH_INSTRUCTION); /* Secondary Vector Table */ - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x20, &reset_handler); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x24, &undef_instruction_handler); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x28, &software_interrupt_handler); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x2C, &prefetch_abort_handler); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x30, &data_abort_handler); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x34, &reserved_handler); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x38, &irq_handler); - mmio_write(KERNEL_VIRTUAL_OFFSET + 0x3C, &fiq_handler); - + mmio_write(HIGH_VECTOR_LOCATION + 0x20, &reset_handler); + mmio_write(HIGH_VECTOR_LOCATION + 0x24, &undef_instruction_handler); + mmio_write(HIGH_VECTOR_LOCATION + 0x28, &software_interrupt_handler); + mmio_write(HIGH_VECTOR_LOCATION + 0x2C, &prefetch_abort_handler); + mmio_write(HIGH_VECTOR_LOCATION + 0x30, &data_abort_handler); + mmio_write(HIGH_VECTOR_LOCATION + 0x34, &reserved_handler); + mmio_write(HIGH_VECTOR_LOCATION + 0x38, &irq_handler); + mmio_write(HIGH_VECTOR_LOCATION + 0x3C, &fiq_handler); + + /// Enable high vectors (Vectors located at HIGH_VECTOR_LOCATION). + asm volatile ( + "mrc p15, 0, r1, c1, c0, 0 \n" // Read p15 + "orr r1, %0\n" // Enable High Vector bit + "mcr p15, 0, r1, c1, c0, 0\n" // Set p15 + :: "r" (1u << 13u) + ); } /* handlers */ diff --git a/kernel/src/common/startup.s b/kernel/src/common/startup.s index 88b2311a..59758767 100644 --- a/kernel/src/common/startup.s +++ b/kernel/src/common/startup.s @@ -8,6 +8,12 @@ _Reset: cmp r1, #0 bne loop + // Move the interrupt vector tables to 0x80000000 + ldr r0, =0xE000ED08 + ldr r1, =0x80000000 + str r1, [r0] + + ldr sp, =EARLY_KERNEL_STACK_TOP // Set the kernel/SVC stack push {r0-r11} diff --git a/kernel/src/drivers/chipset/bcm2836/timer.c b/kernel/src/drivers/chipset/bcm2836/timer.c index 633231b8..3b216929 100644 --- a/kernel/src/drivers/chipset/bcm2836/timer.c +++ b/kernel/src/drivers/chipset/bcm2836/timer.c @@ -41,14 +41,12 @@ void bcm2836_timer_init() { uint32_t freq = get_frequency(); - kprintf("control frequency: %i\n", freq); + TRACE("control frequency: %i", freq); // 1 (milli)second timer - write_interrupt_count_value(freq); - - kprintf("value: %i\n", read_interrupt_count_value()); - kprintf("value: %i\n", read_interrupt_count_value()); + write_interrupt_count_value(freq * 100); // when the register reaches the count value set above, interrupt. + // TODO: Enable timer // mmio_write(&bcm2836_registers_base->Core0TimersInterruptControl, VIRTUAL_NONSECURE_TIMER); // Enable timer interrupts. diff --git a/kernel/src/ds/u8_array_list.c b/kernel/src/ds/u8_array_list.c index b24f9b60..55bdc6e2 100644 --- a/kernel/src/ds/u8_array_list.c +++ b/kernel/src/ds/u8_array_list.c @@ -6,6 +6,7 @@ #include #include #include +#include U8ArrayList * u8a_create(uint32_t initial_cap) { U8ArrayList * list = kmalloc(sizeof(U8ArrayList)); @@ -39,7 +40,7 @@ void u8a_set(U8ArrayList * list, uint32_t index, uint8_t data) { uint32_t u8a_push(U8ArrayList * list, uint8_t data) { if(list->capacity == 0 || list->length >= list->capacity - 1) { - uint32_t new_size = max((list->capacity + (list->capacity >> 2)), list->capacity + 2); + uint32_t new_size = max((list->capacity + (list->capacity >> 2u)), list->capacity + 2); assert(new_size > list->capacity) @@ -47,6 +48,7 @@ uint32_t u8a_push(U8ArrayList * list, uint8_t data) { list->array = krealloc(list->array, list->capacity * sizeof(uint8_t)); } + list->array[list->length++] = data; return list->length; @@ -97,4 +99,4 @@ U8ArrayList * u8a_clone(U8ArrayList * arr) { } return newarr; -} \ No newline at end of file +} diff --git a/kernel/src/fs/path.c b/kernel/src/fs/path.c index 00b4cb2a..c7ad6739 100644 --- a/kernel/src/fs/path.c +++ b/kernel/src/fs/path.c @@ -5,6 +5,8 @@ #include #include +#include + const Path root = { .length = 1, diff --git a/kernel/src/fs/test/test_path.c b/kernel/src/fs/test/test_path.c index 23ea9128..1e52324c 100644 --- a/kernel/src/fs/test/test_path.c +++ b/kernel/src/fs/test/test_path.c @@ -71,6 +71,7 @@ TEST_CREATE(path_parent_test_4, { ASSERT(path_contents_equal(p1, p2)); path_free(p1); path_free(p2); + }) TEST_CREATE(path_parent_test_5, { diff --git a/kernel/src/klibc/alloc.c b/kernel/src/klibc/alloc.c index a9426e6a..00c7b9cc 100644 --- a/kernel/src/klibc/alloc.c +++ b/kernel/src/klibc/alloc.c @@ -33,13 +33,17 @@ uint32_t kmalloc_size(void* ptr) { // TODO: Implement in-place realloc if the next block is free. // Resize memory pointed to by ptr to new size void * krealloc(void *ptr, uint32_t newsize) { + if (ptr == NULL) { + TRACE("[MEM DEBUG] Realloc with nullptr"); + return kmalloc(newsize); + } + uint32_t oldsize = kmalloc_size(ptr); + if (newsize == 0) { kfree(ptr); return NULL; - } else if (ptr == NULL) { - return kmalloc(newsize); } else if (newsize <= oldsize) { return ptr; } else { diff --git a/kernel/src/vm/README.md b/kernel/src/vm/README.md index 7d0d0b31..50f1efe3 100644 --- a/kernel/src/vm/README.md +++ b/kernel/src/vm/README.md @@ -9,9 +9,9 @@ | Address | Description | | ---------- | ---------------------------------------------------------------------- | -| 0x0000000 | Interrupt Vector Table | -| 0x0004000 | Kernel L1 page table | -| 0x0008000 | Kernel start | +| 0x00000000 | Interrupt Vector Table | +| 0x00004000 | Kernel L1 page table | +| 0x00080000 | Kernel start | | ... | *Kernel* | | ... | *Kernel* | | KERNEL END | Physical Memory Manager starting point | @@ -22,16 +22,17 @@ | Address | Description | | ---------- | ---------------------------------------------------------------------- | -| 0x0000000 | Virtual Process Address Space | -| 0x8000000 | Interrupt Vector Table (remap of the first gigabyte of phys --> virt) | -| 0x8004000 | Kernel page table | -| 0x8008000 | Kernel start | +| 0x00000000 | Virtual Process Address Space | +| 0x80000000 | (start of) remap of physical 0x00000000-0x40000000 | +| 0x80004000 | Kernel page table | +| 0x80008000 | Kernel start | | ... | *Kernel* | | ... | *Kernel* | | KERNEL END | Location of the PMM in virtual address space | | ... | (Virtual) Physical Memory Manager | -| 0xC000000 | Kernel heap start (growing up) | -| 0xFFFFFFF | MMIO mappings (growing down) | +| 0xC0000000 | Kernel heap start (growing up) | +| 0xFFF00000 | MMIO mappings (growing down) | +| 0xFFFF0000 | High location of the vector table | ***Note:*** Both the MMIO mapping and kernel heap occupy the same gigabyte. The sum of the two can't exceed 1 gigabyte and when the kernel heap grows to touch the MMIO top, the heap is full. diff --git a/kernel/src/vm/include/vm2.h b/kernel/src/vm/include/vm2.h index 5e1bb231..296c66e0 100644 --- a/kernel/src/vm/include/vm2.h +++ b/kernel/src/vm/include/vm2.h @@ -310,8 +310,12 @@ extern const size_t __KERNEL_VIRTUAL_OFFSET[]; /// Location of the Kernel's Physical Memory Manager's Info structs. Can grow to a max of 16MiB when using 4GiB RAM. #define KERNEL_PMM_BASE KERNEL_VIRTUAL_END +// Location of the vector table in memory table. +// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/BABIFJFG.html +#define HIGH_VECTOR_LOCATION 0xFFFF0000 + /// From this address down, mmio devices are mapped in the kernel's virtual address space. -#define KERNEL_MMIO_BASE (4 * Gibibyte) +#define KERNEL_MMIO_BASE ((4 * Gibibyte) - (1 * Mebibyte)) /// Address space for the kernel heap, grows towards the mmio #define KERNEL_HEAP_BASE (3 * Gibibyte) diff --git a/kernel/src/vm/vm2.c b/kernel/src/vm/vm2.c index f5d95aff..5bbc5e46 100644 --- a/kernel/src/vm/vm2.c +++ b/kernel/src/vm/vm2.c @@ -91,7 +91,7 @@ void vm2_start() { /// Unmap the 1:1 mapped first megabyte which startup.s created to boot to a higher half kernel. /// We don't need it anymore! -// kernell1PageTable->entries[0] = (L1PagetableEntry){0}; + kernell1PageTable->entries[0] = (L1PagetableEntry){0}; /// Map the entire gigabyte (or less on some boards, but never more) physical ram to virtual 2GB-3GB. /// this includes the kernel, kernel stack, kernel pagetables, process pagetables, pmm etc. From 29253eb92d210ae1d66fd3583f86bf0d597e7b68 Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Sun, 8 Mar 2020 17:30:33 +0100 Subject: [PATCH 044/104] Disable toolchain cache, to see if it fixs CI --- .github/workflows/os_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/os_test.yml b/.github/workflows/os_test.yml index 4f0ed217..9b0ce153 100644 --- a/.github/workflows/os_test.yml +++ b/.github/workflows/os_test.yml @@ -21,7 +21,7 @@ jobs: sudo apt-get install build-essential qemu-system-arm python3 wget texinfo zlib1g-dev -y - name: Install Toolchain - if: steps.cache-toolchain.outputs.cache-hit != 'true' +# if: steps.cache-toolchain.outputs.cache-hit != 'true' run: rm -rf toolchain/arm-none-eabi/ && make toolchain - name: Compile From be99ff816c00fabd6edfdea9e04e6fadf38fd2b9 Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Sun, 8 Mar 2020 18:21:46 +0100 Subject: [PATCH 045/104] Added tlb_cache_id_allocator tests and comments --- .github/workflows/os_test.yml | 2 +- kernel/src/klibc/alloc.c | 5 +- .../src/vm/include/tlb_cache_id_allocator.h | 33 +- kernel/src/vm/memory-layout.svg | 652 ------------------ kernel/src/vm/pmm.c | 2 - kernel/src/vm/test/test_tlb_id.c | 39 ++ kernel/src/vm/tlb_cache_id_allocator.c | 17 +- 7 files changed, 80 insertions(+), 670 deletions(-) delete mode 100644 kernel/src/vm/memory-layout.svg create mode 100644 kernel/src/vm/test/test_tlb_id.c diff --git a/.github/workflows/os_test.yml b/.github/workflows/os_test.yml index 9b0ce153..4f0ed217 100644 --- a/.github/workflows/os_test.yml +++ b/.github/workflows/os_test.yml @@ -21,7 +21,7 @@ jobs: sudo apt-get install build-essential qemu-system-arm python3 wget texinfo zlib1g-dev -y - name: Install Toolchain -# if: steps.cache-toolchain.outputs.cache-hit != 'true' + if: steps.cache-toolchain.outputs.cache-hit != 'true' run: rm -rf toolchain/arm-none-eabi/ && make toolchain - name: Compile diff --git a/kernel/src/klibc/alloc.c b/kernel/src/klibc/alloc.c index 00c7b9cc..c664e5f3 100644 --- a/kernel/src/klibc/alloc.c +++ b/kernel/src/klibc/alloc.c @@ -34,7 +34,10 @@ uint32_t kmalloc_size(void* ptr) { // Resize memory pointed to by ptr to new size void * krealloc(void *ptr, uint32_t newsize) { if (ptr == NULL) { - TRACE("[MEM DEBUG] Realloc with nullptr"); + #if MEM_DEBUG + TRACE("[MEM DEBUG] Realloc with nullptr"); + #endif + return kmalloc(newsize); } diff --git a/kernel/src/vm/include/tlb_cache_id_allocator.h b/kernel/src/vm/include/tlb_cache_id_allocator.h index e1d28256..afee33df 100644 --- a/kernel/src/vm/include/tlb_cache_id_allocator.h +++ b/kernel/src/vm/include/tlb_cache_id_allocator.h @@ -10,19 +10,34 @@ /// * tlb_descriptor: A pair of above two numbers. struct TLBDescriptor { - uint32_t tlb_cache_id; - uint32_t cache_iteration; + uint8_t tlb_cache_id; + uint8_t cache_iteration; }; +/// Is set to true whenever all tlb_cache_ids are used up. +bool tlb_everything_allocated; + +/** + * Requests a tlb_descriptor. + * + * + * Allocates you a new tlb_id, + * if [tlb_everything_allocated] is true you should flush caches. + * If [tlb_everything_allocated] is false, you don't have to flush caches. + * @returns a TLBDescriptor + */ struct TLBDescriptor request_tlb_descriptor(); -/// Updates the current tlb_descriptor you have. -/// If it was able to, it gives you the same tlb_cache_id that you already had. -/// Then it returns false. -/// -/// If all of those were allocated it updates your id and returns true. -/// When this function returns true, flush the caches. -bool get_and_update(struct TLBDescriptor* desc); +/** + * Updates and checks a tlb_descriptor. + * + * It checks if your saved cache_iteration corresponds with the current one. + * If it doesn't it will update both, and return true. + * If it does it won't update and return false. + * @param desc the tlb_descriptor to check. + * @returns whether you should flush caches or not. + */ +bool check_and_update(struct TLBDescriptor* desc); #endif diff --git a/kernel/src/vm/memory-layout.svg b/kernel/src/vm/memory-layout.svg deleted file mode 100644 index a6b75dc4..00000000 --- a/kernel/src/vm/memory-layout.svg +++ /dev/null @@ -1,652 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - Physical Memory - - Kernel - 0x0 - 0x10000 - 0x200000 - - L1PTBASE - 0x300000 - - 0x7F00000 - VirtualMemoryFrames(128MB) - KDS - 0x7FFFFFF - (Interrupt Vectors) - Virtual Memory (Reserved) - - - Kernel - 0x10000 - 0x200000 - - 0x7F00000 - KDS - 0x7FFFFFF - (Interrupt Vectors) - - L1PTBASE - 0xF0200000 - - 0xF0300000 - - Kernel - - 0xF0000000 - - 0xFFF00000 - KDS - 0xFFFFFFFF - Peripherals - - - 0x10000000 - 0x10200000 - - diff --git a/kernel/src/vm/pmm.c b/kernel/src/vm/pmm.c index 0da0666c..834163e4 100644 --- a/kernel/src/vm/pmm.c +++ b/kernel/src/vm/pmm.c @@ -1,8 +1,6 @@ #include #include #include -#include -#include /// Private functions // Returns the index of the first zero from the LSB diff --git a/kernel/src/vm/test/test_tlb_id.c b/kernel/src/vm/test/test_tlb_id.c new file mode 100644 index 00000000..fc35575e --- /dev/null +++ b/kernel/src/vm/test/test_tlb_id.c @@ -0,0 +1,39 @@ +#include +#include + +TEST_CREATE(tlb_simple, { + struct TLBDescriptor desc = request_tlb_descriptor(); + + uint32_t id = desc.tlb_cache_id; + uint32_t iteration = desc.cache_iteration; + + if(check_and_update(&desc)) { + ASSERT_NEQ(iteration, desc.cache_iteration); + } else { + ASSERT_EQ(iteration, desc.cache_iteration); + } + + ASSERT_EQ(id, desc.tlb_cache_id); +}) + +TEST_CREATE(tlb_intensive, { + // This tests asserts the properties of the TLBDescriptor in an extensive way, + // to ensure at least 1 overflow takes place + for(size_t i = 0; i < 666; i++) { + struct TLBDescriptor desc = request_tlb_descriptor(); + + uint32_t id = desc.tlb_cache_id; + uint32_t iteration = desc.cache_iteration; + + if(check_and_update(&desc)) { + ASSERT_NEQ(iteration, desc.cache_iteration); + } else { + ASSERT_EQ(iteration, desc.cache_iteration); + } + + ASSERT_EQ(id, desc.tlb_cache_id); + } + + // Everything should have definitely been allocated by now. + ASSERT(tlb_everything_allocated); +}) diff --git a/kernel/src/vm/tlb_cache_id_allocator.c b/kernel/src/vm/tlb_cache_id_allocator.c index d86eee13..b67d6db2 100644 --- a/kernel/src/vm/tlb_cache_id_allocator.c +++ b/kernel/src/vm/tlb_cache_id_allocator.c @@ -3,11 +3,18 @@ #include uint8_t curr = 0; -uint32_t allocated_ids[256] = {0}; +uint8_t allocated_ids[256] = {0}; +bool tlb_everything_allocated = false; + +// TODO: Ensure atomicity struct TLBDescriptor request_tlb_descriptor() { - uint32_t cache_iteration = ++(allocated_ids[curr]); - uint32_t tlb_cache_id = curr++; + uint8_t cache_iteration = ++(allocated_ids[curr]); + uint8_t tlb_cache_id = curr++; + + if(tlb_cache_id == 255) { + tlb_everything_allocated = true; + } struct TLBDescriptor res = (struct TLBDescriptor) { .cache_iteration = cache_iteration, @@ -17,8 +24,8 @@ struct TLBDescriptor request_tlb_descriptor() { return res; } - -bool get_and_update(struct TLBDescriptor* desc) { +// TODO: Ensure atomicity +bool check_and_update(struct TLBDescriptor* desc) { if(desc->cache_iteration != allocated_ids[desc->tlb_cache_id]) { desc->cache_iteration = ++(allocated_ids[desc->tlb_cache_id]); return true; From 82c027eb569195d851b44ffd82cbdb6ce3b85206 Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Sun, 8 Mar 2020 19:33:35 +0100 Subject: [PATCH 046/104] Added Semihosting call to exit with an arbitrary exit code, this should make panic exit codes more obvious. --- kernel/src/common/include/interrupt.h | 12 +++++++----- kernel/src/common/interrupt.c | 23 +++++++++++++++++++++++ kernel/src/klibc/klibc.c | 6 +++--- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/kernel/src/common/include/interrupt.h b/kernel/src/common/include/interrupt.h index b65b5f01..9c9fb7ad 100644 --- a/kernel/src/common/include/interrupt.h +++ b/kernel/src/common/include/interrupt.h @@ -81,17 +81,19 @@ enum SemihostingSWI { BreakPoint = 0x20020, WatchPoint = 0x20021, StepComplete = 0x20022, - RunTimeErrorUnknown = 0x20023, - InternalError = 0x20024, - UserInterruption = 0x20025, + RunTimeErrorUnknown = 0x20023, // Qemu exits with 1 + InternalError = 0x20024, // Qemu exits with 1 + UserInterruption = 0x20025, // Qemu exits with 1 ApplicationExit = 0x20026, // Qemu exits with 0 - StackOverflow = 0x20027, - DivisionByZero = 0x20028, + StackOverflow = 0x20027, // Qemu exits with 1 + DivisionByZero = 0x20028, // Qemu exits with 1 OSSpecific = 0x20029, // Qemu exits with 1 }; void SemihostingCall(enum SemihostingSWI mode); +void SemihostingOSExit(int code) __attribute__ ((noreturn));; + typedef enum { IRQ, // (this is bit 0x8 on the CPSR) FIQ, // (this is bit 0x4 on the CPSR) diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index dd5ce9b8..409f459f 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -267,6 +267,29 @@ void __attribute__((always_inline)) inline SemihostingCall(enum SemihostingSWI m ); } + +/// Uses the ExtendedExit Semihosting call +/// ARM Docs: https://developer.arm.com/docs/100863/0200/semihosting-operations/sys_exit_extended-0x20 +void __attribute__((always_inline)) inline SemihostingOSExit(int code) { + struct { + uint32_t field1; + uint32_t field2; + } parameters; + + parameters.field1 = ApplicationExit; + parameters.field2 = code; + + asm volatile ( + "MOV r0, #0x20\n" + "mov r1, %[in0]\n" + "svc 0x00123456\n" + :: + [in0] "r" (¶meters) + ); + + __builtin_unreachable(); +} + /* enable IRQ and/or FIQ */ void enable_interrupt(InterruptType mask) { INFO("Enabling interrupts with mask %i", mask); diff --git a/kernel/src/klibc/klibc.c b/kernel/src/klibc/klibc.c index d1ef3e75..9e7296db 100644 --- a/kernel/src/klibc/klibc.c +++ b/kernel/src/klibc/klibc.c @@ -51,10 +51,10 @@ void panic() { kprintf("|_ ((_)((_|()\\ )\\ ) /((_) (_)) )(_)) )\\ |(_) )\\ \n"); kprintf("| |/ (_)) ((_)_(_/((_))| | | _ ((_)_ _(_/((_)((_) \n"); kprintf(" ' Date: Mon, 9 Mar 2020 10:23:37 +0100 Subject: [PATCH 047/104] hopefully fixed CI by building qemu ourselves Co-authored-by: Victor Roest --- .github/workflows/os_test.yml | 13 ++++++++++++- Makefile | 8 +++++++- config.mk | 4 +--- kernel/Makefile | 2 +- kernel/src/common/include/interrupt.h | 2 +- kernel/src/common/interrupt.c | 10 ++-------- kernel/src/common/start.c | 5 ++--- kernel/src/klibc/klibc.c | 4 ++-- qemu/build.sh | 4 ++-- 9 files changed, 30 insertions(+), 22 deletions(-) diff --git a/.github/workflows/os_test.yml b/.github/workflows/os_test.yml index 4f0ed217..87714358 100644 --- a/.github/workflows/os_test.yml +++ b/.github/workflows/os_test.yml @@ -15,15 +15,26 @@ jobs: path: toolchain key: toolchain + - name: Cache Qemu + id: cache-qemu + uses: actions/cache@v1 + with: + path: toolchain + key: toolchain + - name: Install Dependencies run: | sudo apt-get update && sudo apt-get install build-essential qemu-system-arm python3 wget texinfo zlib1g-dev -y - - name: Install Toolchain + - name: Build Toolchain if: steps.cache-toolchain.outputs.cache-hit != 'true' run: rm -rf toolchain/arm-none-eabi/ && make toolchain + - name: Build Qemu + if: steps.cache-qemu.outputs.cache-hit != 'true' + run: rm -rf qemu/qemu* && make qemu + - name: Compile run: make build diff --git a/Makefile b/Makefile index 486eb04e..05ead509 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,15 @@ -all: toolchain kernel +all: requirements kernel toolchain: cd ./toolchain && ./build.sh .PHONY: toolchain +qemu: + cd ./qemu && ./build.sh +.PHONY: qemu + +requirements: toolchain qemu + libc: $(MAKE) -C user/libc diff --git a/config.mk b/config.mk index 1cb1f7d0..0ff9e2e6 100644 --- a/config.mk +++ b/config.mk @@ -3,9 +3,7 @@ TOOLCHAIN_DIR=toolchain BARE_METAL_TUPLE=arm-none-eabi BARE_METAL_TARGET:=$(BARE_METAL_TUPLE) -QEMU=qemu-system-arm - -UBOOT_VERSION=2014.10 +QEMU=./qemu/qemu/bin/qemu-system-arm #CFLAGS = -mcpu=arm1136j-s CFLAGS = -mcpu=arm1176jz-s diff --git a/kernel/Makefile b/kernel/Makefile index 5cdacf31..414b16a1 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -26,8 +26,8 @@ CC:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gcc AS:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-as LD:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gcc OBJCOPY:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-objcopy -MKIMAGE:=$(CURDIR)/../u-boot/u-boot-$(UBOOT_VERSION)/tools/mkimage GDB:=$(TOOLCHAIN_PATH)/$(BARE_METAL_TUPLE)-gdb +QEMU := $(CURDIR)/../${QEMU} DIRS = $(shell find $(SOURCEDIR)/ -type d -print) C_SOURCE_FILES := $(foreach dir,$(DIRS),$(wildcard $(dir)/*.c)) $(TEST_MAIN_FILE) diff --git a/kernel/src/common/include/interrupt.h b/kernel/src/common/include/interrupt.h index 9c9fb7ad..75286816 100644 --- a/kernel/src/common/include/interrupt.h +++ b/kernel/src/common/include/interrupt.h @@ -92,7 +92,7 @@ enum SemihostingSWI { void SemihostingCall(enum SemihostingSWI mode); -void SemihostingOSExit(int code) __attribute__ ((noreturn));; +void SemihostingOSExit(uint8_t code) __attribute__ ((noreturn));; typedef enum { IRQ, // (this is bit 0x8 on the CPSR) diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index 409f459f..8861cc13 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -270,14 +270,8 @@ void __attribute__((always_inline)) inline SemihostingCall(enum SemihostingSWI m /// Uses the ExtendedExit Semihosting call /// ARM Docs: https://developer.arm.com/docs/100863/0200/semihosting-operations/sys_exit_extended-0x20 -void __attribute__((always_inline)) inline SemihostingOSExit(int code) { - struct { - uint32_t field1; - uint32_t field2; - } parameters; - - parameters.field1 = ApplicationExit; - parameters.field2 = code; +void __attribute__((always_inline)) inline SemihostingOSExit(uint8_t code) { + struct {uint32_t f1; uint32_t f2;} parameters = {ApplicationExit, code }; asm volatile ( "MOV r0, #0x20\n" diff --git a/kernel/src/common/start.c b/kernel/src/common/start.c index 4d1ae2f7..4421288a 100644 --- a/kernel/src/common/start.c +++ b/kernel/src/common/start.c @@ -58,14 +58,13 @@ void start(uint32_t *p_bootargs) { // After this point kmalloc and kfree can be used for dynamic memory management. init_heap(); - + // Splash screen splash(); - // Turn on interrupts enable_interrupt(BOTH); - // Call the chipset again to do post-interrupt-enable initialization + // Call the chipset again to do any initialization after enabling interrupts and the heap. chipset.late_init(); diff --git a/kernel/src/klibc/klibc.c b/kernel/src/klibc/klibc.c index 9e7296db..9f3d49c2 100644 --- a/kernel/src/klibc/klibc.c +++ b/kernel/src/klibc/klibc.c @@ -41,9 +41,9 @@ * panic() added - Currrently states the panic and stalls the machine */ -void panic() { +void inline panic() { disable_interrupt(BOTH); - kprintf("Kernel panic!\n"); + WARN("Kernel panic!\n"); kprintf("\n ) ( \n"); kprintf(" ( /( ( )\\ ) \n"); kprintf(" )\\()) ( ( ( )\\ (()/( ) ( \n"); diff --git a/qemu/build.sh b/qemu/build.sh index a9cce93b..e0e9543c 100755 --- a/qemu/build.sh +++ b/qemu/build.sh @@ -1,8 +1,8 @@ #!/bin/bash -QEMU_VERSION=2.4.1 +QEMU_VERSION=4.2.0 -qemu-system-arm --version || { +{ if [ ! -e qemu-${QEMU_VERSION}.tar.bz2 ]; then wget http://wiki.qemu-project.org/download/qemu-${QEMU_VERSION}.tar.bz2 From 7e0ea6fa4a50b9efc1888150fb796f9fdb843d90 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Mon, 9 Mar 2020 10:30:46 +0100 Subject: [PATCH 048/104] fixed ci script Co-authored-by: Victor Roest --- .github/workflows/os_test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/os_test.yml b/.github/workflows/os_test.yml index 87714358..8c442586 100644 --- a/.github/workflows/os_test.yml +++ b/.github/workflows/os_test.yml @@ -19,8 +19,8 @@ jobs: id: cache-qemu uses: actions/cache@v1 with: - path: toolchain - key: toolchain + path: qemu/qemu + key: qemu - name: Install Dependencies run: | From 51fcf51d32e424be6fc29f8d27b504183284d37a Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Mon, 9 Mar 2020 11:59:37 +0100 Subject: [PATCH 049/104] Fixed heap init and randomized test order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jonathan Dönszelmann --- .github/workflows/os_test.yml | 2 +- a.s | 1 - generate_static_l1pt.c | 237 ------------------------------ kernel/Makefile | 2 +- kernel/src/allocator/mem_alloc.c | 13 +- kernel/src/common/interrupt.c | 2 +- kernel/src/fs/test/test_path.c | 1 + kernel/src/test/generate_tests.sh | 2 +- kernel/src/vm/include/vm2.h | 7 +- kernel/src/vm/vm2.c | 20 ++- qemu/build.sh | 6 +- 11 files changed, 37 insertions(+), 256 deletions(-) delete mode 100644 a.s delete mode 100644 generate_static_l1pt.c diff --git a/.github/workflows/os_test.yml b/.github/workflows/os_test.yml index 8c442586..ddca8668 100644 --- a/.github/workflows/os_test.yml +++ b/.github/workflows/os_test.yml @@ -25,7 +25,7 @@ jobs: - name: Install Dependencies run: | sudo apt-get update && - sudo apt-get install build-essential qemu-system-arm python3 wget texinfo zlib1g-dev -y + sudo apt-get install build-essential python3 wget texinfo zlib1g-dev -y - name: Build Toolchain if: steps.cache-toolchain.outputs.cache-hit != 'true' diff --git a/a.s b/a.s deleted file mode 100644 index 612027f7..00000000 --- a/a.s +++ /dev/null @@ -1 +0,0 @@ -ldr pc, [pc, #0x20] diff --git a/generate_static_l1pt.c b/generate_static_l1pt.c deleted file mode 100644 index 46fbd18d..00000000 --- a/generate_static_l1pt.c +++ /dev/null @@ -1,237 +0,0 @@ -/// This code helped generate the data section of startup.s by printing out an entire l1pt -#include -#include -#include - -#define pt_size 0x1000 - -uint32_t pt[pt_size] = {0}; - -#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c" -#define BYTE_TO_BINARY(byte) \ - (byte & 0x80000000 ? '1' : '0'), \ - (byte & 0x40000000 ? '1' : '0'), \ - (byte & 0x20000000 ? '1' : '0'), \ - (byte & 0x10000000 ? '1' : '0'), \ - (byte & 0x08000000 ? '1' : '0'), \ - (byte & 0x04000000 ? '1' : '0'), \ - (byte & 0x02000000 ? '1' : '0'), \ - (byte & 0x01000000 ? '1' : '0'), \ - (byte & 0x00800000 ? '1' : '0'), \ - (byte & 0x00400000 ? '1' : '0'), \ - (byte & 0x00200000 ? '1' : '0'), \ - (byte & 0x00100000 ? '1' : '0'), \ - (byte & 0x00080000 ? '1' : '0'), \ - (byte & 0x00040000 ? '1' : '0'), \ - (byte & 0x00020000 ? '1' : '0'), \ - (byte & 0x00010000 ? '1' : '0'), \ - (byte & 0x00008000 ? '1' : '0'), \ - (byte & 0x00004000 ? '1' : '0'), \ - (byte & 0x00002000 ? '1' : '0'), \ - (byte & 0x00001000 ? '1' : '0'), \ - (byte & 0x00000800 ? '1' : '0'), \ - (byte & 0x00000400 ? '1' : '0'), \ - (byte & 0x00000200 ? '1' : '0'), \ - (byte & 0x00000100 ? '1' : '0'), \ - (byte & 0x00000080 ? '1' : '0'), \ - (byte & 0x00000040 ? '1' : '0'), \ - (byte & 0x00000020 ? '1' : '0'), \ - (byte & 0x00000010 ? '1' : '0'), \ - (byte & 0x00000008 ? '1' : '0'), \ - (byte & 0x00000004 ? '1' : '0'), \ - (byte & 0x00000002 ? '1' : '0'), \ - (byte & 0x00000001 ? '1' : '0') - - - -/// A L1PagetableEntry is an entry in the top level pagetable. -/// There is only one L1 pagetable and it is always located at address 0x4000. -/// Relevant manual section: http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf -/// * 6.1 -/// * 6.5 (memory access control) -/// * 6.11.1 (entry layout) -/// * 6.13 (control registers) -/// * 6.10 (page faults and aborts) -typedef union L1PagetableEntry{ - uint32_t entry; - struct { - /// This 2 bit field gives what type of entry this is. - /// 00 for invalid pages (pagefault) - /// 01 for coarse pages (64kb). - /// 10 for sections and supersections. (see bit 18) - /// 11 for invalid pages (pagefault) - /// Note that for supersections you have to repeat this entry 16x to fill up all 1mb entries that would lie within it, - /// and the first of these 16 entries must be on a 16-word boundary - uint32_t type: 2; - - /// Should be zero - uint32_t sbz1: 1; - - /// Non-secure bit. This is used by the security extensions (TrustZone). - uint32_t nonSecure: 1; - - /// Should be zero - uint32_t sbz2: 1; - - /// Domain. This is used by the security extensions (TrustZone). - uint32_t domain: 4; - - /// (P) ECC bit (some processors support this but the ARM1176 does *NOT*) - uint32_t ECC: 1; - - /// Top 22 bits of the base address. Points to a L2 pagetable. - /// formula: - /// base_address = (address >> 10); - uint32_t base_address: 22; - - } coarse; - - struct { - /// This 2 bit field gives what type of entry this is. - /// 00 for invalid pages (pagefault) - /// 01 for coarse pages (64kb). - /// 10 for sections and supersections. (see bit 18) - /// 11 for invalid pages (pagefault) - /// Note that for supersections you have to repeat this entry 16x to fill up all 1mb entries that would lie within it, - /// and the first of these 16 entries must be on a 16-word boundary - uint32_t type: 2; - - /// If set, this page is bufferable - uint32_t bufferable: 1; - - /// If set, this page is cachable - uint32_t cachable: 1; - - /// Should be zero - uint32_t sbz2: 1; - - /// Domain. This is used by the security extensions (TrustZone). - uint32_t domain: 4; - - /// (P) ECC bit (some processors support this but the ARM1176 does *NOT*) - uint32_t ECC: 1; - - /// Access permissions - /// accessExtended = 0: - /// Kernel: User: - /// 00 No access No access (Recommended) - /// 01 Read/Write No access - /// 10 Read/Write Read only - /// 11 Read/Write Read/Write - /// accessExtended = 1: - /// 00 Reserved Reserved - /// 01 Read only No access - /// 10 Read only Read only - /// 11 Read only Read only - uint32_t accessPermissions: 2; - - /// Type Extension - /// TEX C B Description Memory type Sharable - /// 000 0 0 Strongly ordered Strongly ordered yes - /// 000 0 1 Shared device Device yes - /// 000 1 0 Outer and Inner Write-Through,No Allocate on Write Normal Page sharable if S bit is set - /// 000 1 1 Outer and Inner Write-Back,No Allocate on Write Normal Page sharable if S bit is set - /// 001 0 0 Outer and Inner Noncacheable Normal Page sharable if S bit is set - /// 001 0 1 Reserved - /// 001 1 0 Reserved - /// 001 1 1 Outer and Inner Write-Back, Allocate on Write Normal Page sharable if S bit is set - /// 010 0 0 Non shared device Device no - /// 010 0 1 Reserved - /// 010 1 X Reserved - /// 011 X X Reserved - /// 1BB A A Cached Memory Normal Page sharable if S bit is set - /// BB = Outer policy - /// AA = Inner policy - /// - /// BB *or* AA bits: - /// 00 Non-cachable - /// 01 Write-back cached, write allocate - /// 10 Write-through cached, no allocate on write - /// 11 Write-back cached, no allocate on write - /// - /// For more info (and there is a lot more!), see table 6-4 in the ARM1176jzf-s - /// [reference manual](http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf) - uint32_t TEX: 3; - - /// Access extended bit. See `accessPermissions` - uint32_t accessExtended: 1; - - /// Marks the page sharable (see TEX). Also named S-bit - uint32_t sharable: 1; - - /// Not Global (ng). Determines how this is marked in the TLB. - uint32_t notglobal: 1; - - /// Supersection identifier is '1' if this entry is a supersection, is '0' if this is a normal section - uint32_t supersection: 1; - - /// Non-secure bit. This is used by the security extensions (TrustZone). - uint32_t nonSecure: 1; - - /// Top 12 bits of the base address. Pointer to the first byte in a 1mb-large block. - /// If this entry refers to a supersection, the lower 4 bits Should Be Zero. - /// The top 8 bits now refer to a 16mb-large block - /// - /// formulae: - /// section_base_address = (address >> 20); - /// supersection_base_address = (address >> 24); - uint32_t base_address: 12; - } section; -} L1PagetableEntry; - - -static inline uint32_t address_to_index(uint32_t address) { - return address >> 20u; -} - -void map_virtual_to_physical(uint32_t virtual, L1PagetableEntry entry) { - - - if (pt[address_to_index(virtual)] != 0){ - // The entry is already mapped - printf("Request for already mapped address denied"); - exit(-1); - } - - - pt[address_to_index(virtual)] = entry.entry; -} - -int main() { - const int virtual_offset = 0xC0000000; - - uint32_t address = 0x00000000; - - // identitymap the first page - map_virtual_to_physical(address, (L1PagetableEntry) { - .section.type=2, - .section.accessPermissions = 1, //rw kernel - .section.base_address = address_to_index(address) - }); - - - map_virtual_to_physical(address + virtual_offset, (L1PagetableEntry) { - .section.type=2, - .section.accessPermissions = 1, //rw kernel - .section.base_address = address_to_index(address) - }); - - - int numzeros = 0; - for (uint32_t i = 0; i < pt_size; i++) { - if (pt[i] == 0) { - numzeros += 4; - } else { - if (numzeros != 0) { - printf(".skip 0x%x\n", numzeros); - } - numzeros = 0; - printf(".long 0b"BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(pt[i])); - } - } - - if (numzeros > 0) { - printf(".skip 0x%x\n", numzeros); - } -} - diff --git a/kernel/Makefile b/kernel/Makefile index 414b16a1..acffda10 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -9,7 +9,7 @@ CFLAGS += -pipe -std=gnu99 -ffreestanding -Wall -Werror -g -O0 -mcpu=arm1176jzf- # variables to define in the preprocessor. MEMORY = 1G -DEFINITIONS = MEM_DEBUG +DEFINITIONS = MEM_DEBUG ENABLE_TESTS #DEFINITIONS = MEM_DEBUG test: DEFINITIONS += ENABLE_TESTS # if we execute the test: rule, enable tests before recompiling KERNEL_PARAMS = root=/dev/ram mem=$(MEMORY) diff --git a/kernel/src/allocator/mem_alloc.c b/kernel/src/allocator/mem_alloc.c index 614d7aa5..92c181d1 100644 --- a/kernel/src/allocator/mem_alloc.c +++ b/kernel/src/allocator/mem_alloc.c @@ -1,9 +1,8 @@ -#include "klibc.h" +#include #include #include #include #include -#include heap_t * allocator; size_t heap_end; @@ -24,10 +23,10 @@ size_t heap_end; */ void init_heap() { - size_t heap_end = KERNEL_HEAP_BASE; + heap_end = KERNEL_HEAP_BASE; // Allocate space for the heap_t struct. is too large but at least big enough. - void * ret = vm2_allocate_kernel_page(kernell1PageTable, KERNEL_HEAP_BASE, false); + void * ret = vm2_allocate_kernel_page(kernell1PageTable, KERNEL_HEAP_BASE, false, 0); if (ret == NULL) { FATAL("Couldn't allocate page for the kernel heap"); } @@ -38,6 +37,7 @@ void init_heap() { heap_end += sizeof(heap_t); + for(int i = 0; i < BIN_COUNT; i++) { heap->bins[i] = (bin_t *) heap_end; memset(heap->bins[0], 0, sizeof(bin_t)); @@ -47,10 +47,11 @@ void init_heap() { assert(KERNEL_HEAP_BASE + sizeof(heap_t) + BIN_COUNT * sizeof(bin_t) == heap_end); // current heap end. + heap_end = ALIGN(heap_end, PAGE_SIZE); size_t heap_start = heap_end; - while(heap_end < (heap_start + HEAP_INIT_SIZE + PAGE_SIZE)) { - if (vm2_allocate_kernel_page(kernell1PageTable, heap_end, false) == NULL) { + while(heap_end < (heap_start + HEAP_INIT_SIZE)) { + if (vm2_allocate_kernel_page(kernell1PageTable, heap_end, false, 0) == NULL) { FATAL("Allocation of the kernel heap went wrong!"); } diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index 8861cc13..9880caf5 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -7,7 +7,7 @@ /* copy vector table from wherever QEMU loads the kernel to 0x00 */ void init_vector_table() { // allocate space for the IVR at the high vector location. - vm2_allocate_kernel_page(kernell1PageTable, HIGH_VECTOR_LOCATION, true); + vm2_allocate_kernel_page(kernell1PageTable, HIGH_VECTOR_LOCATION, true, false); /* Primary Vector Table */ mmio_write(HIGH_VECTOR_LOCATION + 0x00, BRANCH_INSTRUCTION); diff --git a/kernel/src/fs/test/test_path.c b/kernel/src/fs/test/test_path.c index 1e52324c..b3876fa5 100644 --- a/kernel/src/fs/test/test_path.c +++ b/kernel/src/fs/test/test_path.c @@ -166,6 +166,7 @@ TEST_CREATE(path_clone_test, { Path * p2 = path_clone(p1); ASSERT(path_contents_equal(p1, p2)); + path_free(p1); path_free(p2); }) diff --git a/kernel/src/test/generate_tests.sh b/kernel/src/test/generate_tests.sh index a4b38de3..d4c75fa8 100755 --- a/kernel/src/test/generate_tests.sh +++ b/kernel/src/test/generate_tests.sh @@ -24,7 +24,7 @@ size_t global_counter = 0; " >> "$DIR/test.c" #TESTFNS=$(grep -hr --include "*.c" -oP "(?<=TEST_CREATE\()(.*)(?=,)") -TESTFNS=$(grep -hr --include "*.c" -vP "^\s*\/\/.+" | grep -oP "(?<=TEST_CREATE\()(.*)(?=,)") +TESTFNS=$(grep -hr --include "*.c" -vP "^\s*\/\/.+" | grep -oP "(?<=TEST_CREATE\()(.*)(?=,)" | sort -R) for FNNAME in $TESTFNS do diff --git a/kernel/src/vm/include/vm2.h b/kernel/src/vm/include/vm2.h index 296c66e0..667e34a6 100644 --- a/kernel/src/vm/include/vm2.h +++ b/kernel/src/vm/include/vm2.h @@ -284,7 +284,7 @@ size_t vm2_map_peripheral(size_t physical, size_t n_mebibytes); /// or null if unsuccesfull. The physical location of this page is determined by the pmm. /// Since this allocates a 4kb page, it has to go through l2 pagetables. It will create the right /// l2 pagetables as it needs. You can make the allocated page executable with the last parameter. -void * vm2_allocate_kernel_page(struct L1PageTable * l1pt, size_t virtual, bool executable); +void *vm2_allocate_kernel_page(struct L1PageTable *l1pt, size_t virtual, bool executable, bool remap); /// Should be called after updating a pagetable. void vm2_flush_caches(); @@ -330,7 +330,8 @@ extern const size_t __KERNEL_VIRTUAL_OFFSET[]; #define PAGE_SIZE (4 * Kibibyte) - - +// aligns an address to the *next* boundary of size n. +// only works where n is a power of 2 +#define ALIGN(address, n) ((((size_t)(address) + (size_t)(n) - 1) & ~((size_t)(n) - 1))); #endif diff --git a/kernel/src/vm/vm2.c b/kernel/src/vm/vm2.c index 5bbc5e46..28427c8a 100644 --- a/kernel/src/vm/vm2.c +++ b/kernel/src/vm/vm2.c @@ -4,7 +4,6 @@ #include #include #include -#include struct L1PageTable * kernell1PageTable = (struct L1PageTable *) VirtualL1PagetableLocation; // NOLINT(cppcoreguidelines-interfaces-global-init) (defined in linker script) bool mmu_started = false; @@ -43,6 +42,7 @@ bool vm2_l1_map_physical_to_virtual(struct L1PageTable * pt, union L1PagetableEn if (pt->entries[l1pt_index(virtual)].entry != 0) { if (remap) { remapped = true; + TRACE("[MEM DEBUG] Remapping l1 page located at 0x%x", virtual); } else { // The entry is already mapped FATAL("Request for already mapped address denied"); @@ -51,10 +51,16 @@ bool vm2_l1_map_physical_to_virtual(struct L1PageTable * pt, union L1PagetableEn kernell1PageTable->entries[l1pt_index(virtual)] = entry; + if (remap) { + // TODO: partial flush + vm2_flush_caches(); + } + return remapped; } void vm2_flush_caches() { + TRACE("[MEM DEBUG] Flushing caches"); //TODO: Only a subset of these instructions are necessary asm volatile ( "// invalidate caches\n" @@ -110,7 +116,7 @@ void vm2_start() { mmu_started = true; } -void * vm2_allocate_kernel_page(struct L1PageTable * l1pt, size_t virtual, bool executable) { +void *vm2_allocate_kernel_page(struct L1PageTable *l1pt, size_t virtual, bool executable, bool remap) { L1PagetableEntry * l1Entry = &l1pt->entries[l1pt_index(virtual)]; struct L2PageTable * l2 = NULL; @@ -133,6 +139,12 @@ void * vm2_allocate_kernel_page(struct L1PageTable * l1pt, size_t virtual, bool } union L2PagetableEntry * l2Entry = &l2->entries[l2pt_index(virtual)]; + if (l2Entry->entry != 0 && !remap) { + FATAL("Overwriting entry in l2pt : 0x%x", virtual); + } else if (l2Entry->entry != 0 && remap) { + TRACE("[MEM DEBUG] Remapping l2 page located at 0x%x", virtual); + } + *l2Entry = (union L2PagetableEntry) { .smallpage = { .type = 2 + !executable, @@ -144,6 +156,10 @@ void * vm2_allocate_kernel_page(struct L1PageTable * l1pt, size_t virtual, bool }, }; + if(remap) { + vm2_flush_caches(); + } + return page; default: // This is a (super)section and we can't make it a coarse pagetable. Error. diff --git a/qemu/build.sh b/qemu/build.sh index e0e9543c..a4261a1b 100755 --- a/qemu/build.sh +++ b/qemu/build.sh @@ -3,14 +3,14 @@ QEMU_VERSION=4.2.0 { + if [ ! -e qemu-${QEMU_VERSION}.tar.bz2 ]; then - if [ ! -e qemu-${QEMU_VERSION}.tar.bz2 ]; then wget http://wiki.qemu-project.org/download/qemu-${QEMU_VERSION}.tar.bz2 fi - if [ ! -d qemu-${QEMU_VERSION} ]; then + if [ ! -d qemu-${QEMU_VERSION} ]; then tar xvf qemu-${QEMU_VERSION}.tar.bz2 fi - cd qemu-${QEMU_VERSION}; ./configure --prefix="$(pwd)/../qemu" --target-list=arm-softmmu && make all install + cd qemu-${QEMU_VERSION} || exit 1; ./configure --prefix="$(pwd)/../qemu" --target-list=arm-softmmu && make all install } From 96c485c58b12a15fec7377863f032b7b41fdb4ce Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Mon, 9 Mar 2020 12:41:15 +0100 Subject: [PATCH 050/104] Cleanup codebase * Resolved easy TODOs where possible * Converted `panic` calls to `FATAL` (for better logging) * Resolved some code analysis issues CLion flagged --- kernel/Makefile | 3 +-- kernel/src/allocator/llist.c | 1 + kernel/src/common/hardwareinfo.c | 2 +- kernel/src/common/interrupt.c | 4 ++-- kernel/src/drivers/chipset/bcm2836/bcm2836.c | 22 +------------------ .../drivers/chipset/bcm2836/include/bcm2836.h | 22 +++++++++---------- kernel/src/drivers/chipset/chipset.c | 6 ++--- kernel/src/ds/include/vp_singly_linked_list.h | 2 +- kernel/src/ds/qstr.c | 2 +- kernel/src/ds/vp_array_list.c | 4 ++-- kernel/src/fs/path.c | 3 +-- kernel/src/klibc/include/klibc.h | 5 ----- kernel/src/klibc/klibc.c | 8 ++----- kernel/src/test/generate_tests.sh | 2 +- kernel/src/vm/vm2.c | 3 +-- 15 files changed, 28 insertions(+), 61 deletions(-) diff --git a/kernel/Makefile b/kernel/Makefile index acffda10..a4349027 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -9,8 +9,7 @@ CFLAGS += -pipe -std=gnu99 -ffreestanding -Wall -Werror -g -O0 -mcpu=arm1176jzf- # variables to define in the preprocessor. MEMORY = 1G -DEFINITIONS = MEM_DEBUG ENABLE_TESTS -#DEFINITIONS = MEM_DEBUG +DEFINITIONS = MEM_DEBUG test: DEFINITIONS += ENABLE_TESTS # if we execute the test: rule, enable tests before recompiling KERNEL_PARAMS = root=/dev/ram mem=$(MEMORY) SOURCEDIR = src diff --git a/kernel/src/allocator/llist.c b/kernel/src/allocator/llist.c index 75ee5b72..d396a71b 100644 --- a/kernel/src/allocator/llist.c +++ b/kernel/src/allocator/llist.c @@ -21,6 +21,7 @@ void add_node(bin_t *bin, node_t* node) { } if (current == NULL) { // we reached the end of the list + // FIXME: previous could be null previous->next = node; node->prev = previous; } diff --git a/kernel/src/common/hardwareinfo.c b/kernel/src/common/hardwareinfo.c index dc1f7cb6..c5606929 100644 --- a/kernel/src/common/hardwareinfo.c +++ b/kernel/src/common/hardwareinfo.c @@ -18,7 +18,7 @@ BoardType detect_boardtype() { case 0xC07: return RaspBerryPiTwo; // bcm2836 default: - panic(); + FATAL("Unknown boardtype"); } } diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index 9880caf5..35088b00 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -209,13 +209,13 @@ void __attribute__((interrupt("ABORT"))) data_abort_handler(void) { #ifdef ENABLE_TESTS - panic(); + FATAL("Data abort is disallowed in tests"); #endif } void reserved_handler(void) { - kprintf("RESERVED HANDLER\n"); + INFO("RESERVED HANDLER\n"); } // the attribute automatically saves and restores state diff --git a/kernel/src/drivers/chipset/bcm2836/bcm2836.c b/kernel/src/drivers/chipset/bcm2836/bcm2836.c index 91c000c1..c6951b04 100644 --- a/kernel/src/drivers/chipset/bcm2836/bcm2836.c +++ b/kernel/src/drivers/chipset/bcm2836/bcm2836.c @@ -30,9 +30,7 @@ void bcm2836_late_init() { void bcm2836_irq_handler() { volatile uint32_t pending = bcm2836_registers_base->Core0IRQSource; - - - kprintf("interrupt: 0x%x", pending); + TRACE("interrupt: 0x%x", pending); } void bcm2836_fiq_handler() { @@ -54,22 +52,4 @@ void bcm2836_init() { bcm2836_peripheral_base = vm2_map_peripheral(BCM2836_PERIPHERALS_PHYSICAL_BASE, 4); bcm2836_uart_init(); - -// // Mapping memory used by bcm2836 peripherals -// // TEMP (vm1): -// request_identity_mapped_section(BCM2836_peripheral_base, 4); -// -// -// vm2_map_peripheral() -// // TODO: remove vm1 code and leave only this vm2 call -// vm2_map_nmegabytes_1to1(BCM2836_PERIPHERALS_PHYSICAL_BASE, 4); -// vm2_map_peripheral() -// -// -// // Map control registers -// // TEMP (vm1): -// request_identity_mapped_section((size_t)bcm2836_registers_base, 1); -// -// // TODO: remove vm1 code and leave only this vm2 call -// vm2_map_nmegabytes_1to1((size_t)bcm2836_registers_base, 1); } diff --git a/kernel/src/drivers/chipset/bcm2836/include/bcm2836.h b/kernel/src/drivers/chipset/bcm2836/include/bcm2836.h index de1c7e1b..40b19655 100644 --- a/kernel/src/drivers/chipset/bcm2836/include/bcm2836.h +++ b/kernel/src/drivers/chipset/bcm2836/include/bcm2836.h @@ -80,24 +80,24 @@ enum InterruptSource { PHYSICAL_SECURE_TIMER = (1u << 0u), // nCNTPNSIRQ : Non-secure physical timer event - PHYSICAL_NONSECURE_TIMER = (1u << 1), + PHYSICAL_NONSECURE_TIMER = (1u << 1u), // nCNTHPIRQ: Physical Timer for use in Hypervisor mode. - PHYSICAL_HYPERVISOR_TIMER = (1 << 2), + PHYSICAL_HYPERVISOR_TIMER = (1u << 2u), // nCNTVIRQ: Virtual Timer for use in Non-secure PL1 modes. - VIRTUAL_NONSECURE_TIMER = (1 << 3), + VIRTUAL_NONSECURE_TIMER = (1u << 3u), - MAILBOX_0 = (1 << 4), - MAILBOX_1 = (1 << 5), - MAILBOX_2 = (1 << 6), - MAILBOX_3 = (1 << 7), + MAILBOX_0 = (1u << 4u), + MAILBOX_1 = (1u << 5u), + MAILBOX_2 = (1u << 6u), + MAILBOX_3 = (1u << 7u), - GPU = (1 << 8), - PMU = (1 << 9), + GPU = (1u << 8u), + PMU = (1u << 9u), - AXI = (1 << 10), - LOCAL_TIMER = (1 << 11), + AXI = (1u << 10u), + LOCAL_TIMER = (1u << 11u), }; void bcm2836_init(); diff --git a/kernel/src/drivers/chipset/chipset.c b/kernel/src/drivers/chipset/chipset.c index 0125852d..f0c9fe49 100644 --- a/kernel/src/drivers/chipset/chipset.c +++ b/kernel/src/drivers/chipset/chipset.c @@ -23,15 +23,13 @@ void init_chipset() { bcm2836_init(); break; default: { - kprintf("Board type not supported for interrupts \n"); - panic(); + FATAL("Board type not supported for interrupts \n"); } } for (size_t i = 0; i < sizeof(ChipsetInterface) / sizeof(uint32_t); i++) { if (((uint32_t **) &chipset)[i] == NULL) { - kprintf("Chipset did not satisfy the required interface. Missing field %i\n", i); - panic(); + FATAL("Chipset did not satisfy the required interface. Missing field %i\n", i); } } } diff --git a/kernel/src/ds/include/vp_singly_linked_list.h b/kernel/src/ds/include/vp_singly_linked_list.h index e5917141..13d966ff 100644 --- a/kernel/src/ds/include/vp_singly_linked_list.h +++ b/kernel/src/ds/include/vp_singly_linked_list.h @@ -38,5 +38,5 @@ bool vpsll_contains(VPSinglyLinkedList * lst, void * value, CompareFunc compf); size_t vpsll_length(VPSinglyLinkedList * lst); -#define VPSLL_FOREACH(lst, i) for (VPSinglyLinkedListIterator i = vpslli_create(lst); !vpslli_empty(i); vpslli_next(&i)) +#define VPSLL_FOREACH(lst, i) for (VPSinglyLinkedListIterator i = vpslli_create(lst); !vpslli_empty(i); vpslli_next(&(i))) #endif \ No newline at end of file diff --git a/kernel/src/ds/qstr.c b/kernel/src/ds/qstr.c index 369c39f3..fa1fb62a 100644 --- a/kernel/src/ds/qstr.c +++ b/kernel/src/ds/qstr.c @@ -46,7 +46,7 @@ static inline bool __eq(Qstr * left, Qstr * right, bool fake) { bool equal = true; char c; while ((c = *(leftstr++)) != '\0') { - hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + hash = ((hash << 5u) + hash) + c; /* hash * 33 + c */ if (equal && c != (*rightstr++)) { equal = false; diff --git a/kernel/src/ds/vp_array_list.c b/kernel/src/ds/vp_array_list.c index 8422b523..52410ae3 100644 --- a/kernel/src/ds/vp_array_list.c +++ b/kernel/src/ds/vp_array_list.c @@ -44,7 +44,7 @@ uint32_t vpa_push(VPArrayList * list, void * data) { list->array[list->length++] = data; if(list->length >= list->capacity) { - uint32_t new_size = max((list->capacity + (list->capacity >> 2)), list->capacity + 2); + uint32_t new_size = max((list->capacity + (list->capacity >> 2u)), list->capacity + 2); assert(new_size > list->capacity) @@ -89,4 +89,4 @@ void vpa_resize(VPArrayList * list, uint32_t new_size, FreeFunc freeFunc) { list->array = krealloc(list->array, new_size); } -void * vpa_remove(VPArrayList * list, size_t index); \ No newline at end of file +void * vpa_remove(VPArrayList * list, size_t index); diff --git a/kernel/src/fs/path.c b/kernel/src/fs/path.c index c7ad6739..af102587 100644 --- a/kernel/src/fs/path.c +++ b/kernel/src/fs/path.c @@ -51,8 +51,7 @@ struct DirEntry *path_get_direntry(struct Vfs *vfs, Path *path, enum VfsErr *err pathpointer = path->array + 1; } else { - kprintf("Inode lookup only supports absolute path right now."); - panic(); + FATAL("Inode lookup only supports absolute path right now."); curr = NULL; pathpointer = path->array; } diff --git a/kernel/src/klibc/include/klibc.h b/kernel/src/klibc/include/klibc.h index 77bf1e9d..c758a3c5 100644 --- a/kernel/src/klibc/include/klibc.h +++ b/kernel/src/klibc/include/klibc.h @@ -36,11 +36,6 @@ #define SLEEP for(;;) #endif -// TODO: previously in global_defs -#define STATUS_OK 0 -#define STATUS_FAIL -1 -// END TODO - typedef unsigned int os_size_t; diff --git a/kernel/src/klibc/klibc.c b/kernel/src/klibc/klibc.c index 9f3d49c2..364c6947 100644 --- a/kernel/src/klibc/klibc.c +++ b/kernel/src/klibc/klibc.c @@ -37,10 +37,7 @@ #define HIGHS (ONES * (UCHAR_MAX/2+1)) #define HASZERO(x) (((x)-ONES) & (~(x)) & HIGHS) -/*4-17-15: - Prakash - * panic() added - - Currrently states the panic and stalls the machine - */ +// Currrently states the panic and stalls the machine or exits iff run within qemu with semihosting enabled. void inline panic() { disable_interrupt(BOTH); WARN("Kernel panic!\n"); @@ -79,8 +76,7 @@ void splash() { - This is a helper function for the assert() macro */ int _assert_fail(char *_file, unsigned int _line, char *_func) { - kprintf("ASSERT FAILURE: %s:%u: %s\n", _file, _line, _func); - panic(); + FATAL("ASSERT FAILURE: %s:%u: %s\n", _file, _line, _func); return 1; } diff --git a/kernel/src/test/generate_tests.sh b/kernel/src/test/generate_tests.sh index d4c75fa8..53ad8564 100755 --- a/kernel/src/test/generate_tests.sh +++ b/kernel/src/test/generate_tests.sh @@ -43,7 +43,7 @@ done # shellcheck disable=SC2028 echo " - kprintf(\"TESTS COMPLETE. Passed %i tests\n\", "$len"); + kprintf(\"TESTS COMPLETE. Passed %i tests\n\", $len); SemihostingCall(ApplicationExit); } #endif diff --git a/kernel/src/vm/vm2.c b/kernel/src/vm/vm2.c index 28427c8a..68b63938 100644 --- a/kernel/src/vm/vm2.c +++ b/kernel/src/vm/vm2.c @@ -89,8 +89,7 @@ void vm2_start() { break; default: // TODO: memory detection? Or just not bother. - kprintf("Board type unsupported by VM2\n"); - panic(); + FATAL("Board type unsupported by VM2\n"); } INFO("Using memory size 0x%x", available_RAM); From cfa2050d9d6eaa2d8ba6a6aaff54b9cb07214924 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Mon, 9 Mar 2020 15:07:45 +0100 Subject: [PATCH 051/104] added fatals in interrupt.c for invalid interrupt mask --- .github/workflows/os_test.yml | 2 +- kernel/Makefile | 2 +- kernel/src/allocator/allocator.c | 1 + kernel/src/allocator/mem_alloc.c | 9 ++++++--- kernel/src/common/interrupt.c | 8 ++++---- kernel/src/fs/test/test_path.c | 1 + kernel/src/test/generate_tests.sh | 2 +- kernel/src/vm/include/vm2.h | 7 ++++--- kernel/src/vm/vm2.c | 19 +++++++++++++++++-- 9 files changed, 36 insertions(+), 15 deletions(-) diff --git a/.github/workflows/os_test.yml b/.github/workflows/os_test.yml index 8c442586..ddca8668 100644 --- a/.github/workflows/os_test.yml +++ b/.github/workflows/os_test.yml @@ -25,7 +25,7 @@ jobs: - name: Install Dependencies run: | sudo apt-get update && - sudo apt-get install build-essential qemu-system-arm python3 wget texinfo zlib1g-dev -y + sudo apt-get install build-essential python3 wget texinfo zlib1g-dev -y - name: Build Toolchain if: steps.cache-toolchain.outputs.cache-hit != 'true' diff --git a/kernel/Makefile b/kernel/Makefile index 414b16a1..acffda10 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -9,7 +9,7 @@ CFLAGS += -pipe -std=gnu99 -ffreestanding -Wall -Werror -g -O0 -mcpu=arm1176jzf- # variables to define in the preprocessor. MEMORY = 1G -DEFINITIONS = MEM_DEBUG +DEFINITIONS = MEM_DEBUG ENABLE_TESTS #DEFINITIONS = MEM_DEBUG test: DEFINITIONS += ENABLE_TESTS # if we execute the test: rule, enable tests before recompiling KERNEL_PARAMS = root=/dev/ram mem=$(MEMORY) diff --git a/kernel/src/allocator/allocator.c b/kernel/src/allocator/allocator.c index 1d41d34b..525b1b5e 100644 --- a/kernel/src/allocator/allocator.c +++ b/kernel/src/allocator/allocator.c @@ -3,6 +3,7 @@ #include #include +#include int offset = sizeof(uint32_t) * 2; uint32_t overhead = sizeof(footer_t) + sizeof(node_t); diff --git a/kernel/src/allocator/mem_alloc.c b/kernel/src/allocator/mem_alloc.c index 614d7aa5..8bf44168 100644 --- a/kernel/src/allocator/mem_alloc.c +++ b/kernel/src/allocator/mem_alloc.c @@ -4,6 +4,7 @@ #include #include #include +#include heap_t * allocator; size_t heap_end; @@ -27,7 +28,7 @@ void init_heap() { size_t heap_end = KERNEL_HEAP_BASE; // Allocate space for the heap_t struct. is too large but at least big enough. - void * ret = vm2_allocate_kernel_page(kernell1PageTable, KERNEL_HEAP_BASE, false); + void * ret = vm2_allocate_kernel_page(kernell1PageTable, KERNEL_HEAP_BASE, false, 0); if (ret == NULL) { FATAL("Couldn't allocate page for the kernel heap"); } @@ -38,6 +39,7 @@ void init_heap() { heap_end += sizeof(heap_t); + for(int i = 0; i < BIN_COUNT; i++) { heap->bins[i] = (bin_t *) heap_end; memset(heap->bins[0], 0, sizeof(bin_t)); @@ -47,10 +49,11 @@ void init_heap() { assert(KERNEL_HEAP_BASE + sizeof(heap_t) + BIN_COUNT * sizeof(bin_t) == heap_end); // current heap end. + heap_end = ALIGN(heap_end, PAGE_SIZE); size_t heap_start = heap_end; - while(heap_end < (heap_start + HEAP_INIT_SIZE + PAGE_SIZE)) { - if (vm2_allocate_kernel_page(kernell1PageTable, heap_end, false) == NULL) { + while(heap_end < (heap_start + HEAP_INIT_SIZE)) { + if (vm2_allocate_kernel_page(kernell1PageTable, heap_end, false, 0) == NULL) { FATAL("Allocation of the kernel heap went wrong!"); } diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index 8861cc13..7501d8f5 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -7,7 +7,7 @@ /* copy vector table from wherever QEMU loads the kernel to 0x00 */ void init_vector_table() { // allocate space for the IVR at the high vector location. - vm2_allocate_kernel_page(kernell1PageTable, HIGH_VECTOR_LOCATION, true); + vm2_allocate_kernel_page(kernell1PageTable, HIGH_VECTOR_LOCATION, true, 0); /* Primary Vector Table */ mmio_write(HIGH_VECTOR_LOCATION + 0x00, BRANCH_INSTRUCTION); @@ -301,7 +301,7 @@ void enable_interrupt(InterruptType mask) { break; default: /** should never happen **/ - return; + FATAL("invalid interrupt mask"); } } @@ -322,7 +322,7 @@ void disable_interrupt(InterruptType mask) { break; default: /** should never happen **/ - return; + FATAL("invalid interrupt mask"); } } @@ -347,7 +347,7 @@ int disable_interrupt_save(InterruptType mask) { break; default: /** should never happen **/ - return -1; + FATAL("invalid interrupt mask"); } return cpsr; } diff --git a/kernel/src/fs/test/test_path.c b/kernel/src/fs/test/test_path.c index 1e52324c..b3876fa5 100644 --- a/kernel/src/fs/test/test_path.c +++ b/kernel/src/fs/test/test_path.c @@ -166,6 +166,7 @@ TEST_CREATE(path_clone_test, { Path * p2 = path_clone(p1); ASSERT(path_contents_equal(p1, p2)); + path_free(p1); path_free(p2); }) diff --git a/kernel/src/test/generate_tests.sh b/kernel/src/test/generate_tests.sh index a4b38de3..d4c75fa8 100755 --- a/kernel/src/test/generate_tests.sh +++ b/kernel/src/test/generate_tests.sh @@ -24,7 +24,7 @@ size_t global_counter = 0; " >> "$DIR/test.c" #TESTFNS=$(grep -hr --include "*.c" -oP "(?<=TEST_CREATE\()(.*)(?=,)") -TESTFNS=$(grep -hr --include "*.c" -vP "^\s*\/\/.+" | grep -oP "(?<=TEST_CREATE\()(.*)(?=,)") +TESTFNS=$(grep -hr --include "*.c" -vP "^\s*\/\/.+" | grep -oP "(?<=TEST_CREATE\()(.*)(?=,)" | sort -R) for FNNAME in $TESTFNS do diff --git a/kernel/src/vm/include/vm2.h b/kernel/src/vm/include/vm2.h index 296c66e0..667e34a6 100644 --- a/kernel/src/vm/include/vm2.h +++ b/kernel/src/vm/include/vm2.h @@ -284,7 +284,7 @@ size_t vm2_map_peripheral(size_t physical, size_t n_mebibytes); /// or null if unsuccesfull. The physical location of this page is determined by the pmm. /// Since this allocates a 4kb page, it has to go through l2 pagetables. It will create the right /// l2 pagetables as it needs. You can make the allocated page executable with the last parameter. -void * vm2_allocate_kernel_page(struct L1PageTable * l1pt, size_t virtual, bool executable); +void *vm2_allocate_kernel_page(struct L1PageTable *l1pt, size_t virtual, bool executable, bool remap); /// Should be called after updating a pagetable. void vm2_flush_caches(); @@ -330,7 +330,8 @@ extern const size_t __KERNEL_VIRTUAL_OFFSET[]; #define PAGE_SIZE (4 * Kibibyte) - - +// aligns an address to the *next* boundary of size n. +// only works where n is a power of 2 +#define ALIGN(address, n) ((((size_t)(address) + (size_t)(n) - 1) & ~((size_t)(n) - 1))); #endif diff --git a/kernel/src/vm/vm2.c b/kernel/src/vm/vm2.c index 5bbc5e46..101b813f 100644 --- a/kernel/src/vm/vm2.c +++ b/kernel/src/vm/vm2.c @@ -4,7 +4,6 @@ #include #include #include -#include struct L1PageTable * kernell1PageTable = (struct L1PageTable *) VirtualL1PagetableLocation; // NOLINT(cppcoreguidelines-interfaces-global-init) (defined in linker script) bool mmu_started = false; @@ -43,6 +42,7 @@ bool vm2_l1_map_physical_to_virtual(struct L1PageTable * pt, union L1PagetableEn if (pt->entries[l1pt_index(virtual)].entry != 0) { if (remap) { remapped = true; + TRACE("[MEM DEBUG] Remapping l1 page located at 0x%x", virtual); } else { // The entry is already mapped FATAL("Request for already mapped address denied"); @@ -51,6 +51,11 @@ bool vm2_l1_map_physical_to_virtual(struct L1PageTable * pt, union L1PagetableEn kernell1PageTable->entries[l1pt_index(virtual)] = entry; + if (remap) { + // TODO: partial flush + vm2_flush_caches(); + } + return remapped; } @@ -110,7 +115,7 @@ void vm2_start() { mmu_started = true; } -void * vm2_allocate_kernel_page(struct L1PageTable * l1pt, size_t virtual, bool executable) { +void *vm2_allocate_kernel_page(struct L1PageTable *l1pt, size_t virtual, bool executable, bool remap) { L1PagetableEntry * l1Entry = &l1pt->entries[l1pt_index(virtual)]; struct L2PageTable * l2 = NULL; @@ -133,6 +138,12 @@ void * vm2_allocate_kernel_page(struct L1PageTable * l1pt, size_t virtual, bool } union L2PagetableEntry * l2Entry = &l2->entries[l2pt_index(virtual)]; + if (l2Entry->entry != 0 && !remap) { + FATAL("Overwriting entry in l2pt : 0x%x", virtual); + } else if (l2Entry->entry != 0 && remap) { + TRACE("[MEM DEBUG] Remapping l2 page located at 0x%x", virtual); + } + *l2Entry = (union L2PagetableEntry) { .smallpage = { .type = 2 + !executable, @@ -144,6 +155,10 @@ void * vm2_allocate_kernel_page(struct L1PageTable * l1pt, size_t virtual, bool }, }; + if(remap) { + vm2_flush_caches(); + } + return page; default: // This is a (super)section and we can't make it a coarse pagetable. Error. From 9a9e99e358bd416a1413b2fa5ac8f7e96fe93b57 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Mon, 9 Mar 2020 15:14:21 +0100 Subject: [PATCH 052/104] added runconfigs to git --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2754487d..c2ace989 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,4 @@ uboot-commands.ubt NOTES /server.PID -!/.idea/ \ No newline at end of file +!/.idea/runConfigurations From 53c4be61d288993d10a195ec67bbad896556ba87 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Mon, 9 Mar 2020 15:20:30 +0100 Subject: [PATCH 053/104] renamed l1_in_l2 to find_l2pt --- kernel/src/vm/vm2.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kernel/src/vm/vm2.c b/kernel/src/vm/vm2.c index 68b63938..3e517ef5 100644 --- a/kernel/src/vm/vm2.c +++ b/kernel/src/vm/vm2.c @@ -25,9 +25,8 @@ static inline size_t l2pt_base_address(size_t address) { return address >> 12u; } -// TODO: More descriptive name // Finds the location of an l2pt given an l1pt coarse entry. -static inline struct L2PageTable * l2pt_in_l1 (L1PagetableEntry * l1ptEntry){ +static inline struct L2PageTable * find_l2pt (L1PagetableEntry * l1ptEntry){ if(l1ptEntry->coarse.type == 1) { return (struct L2PageTable *) PHYS2VIRT(l1ptEntry->coarse.base_address << 10u); } else { @@ -134,7 +133,7 @@ void *vm2_allocate_kernel_page(struct L1PageTable *l1pt, size_t virtual, bool ex struct Page * page = pmm_allocate_page(); // There already is a coarse pagetable if(l2 == NULL) { - l2 = l2pt_in_l1(l1Entry); + l2 = find_l2pt(l1Entry); } union L2PagetableEntry * l2Entry = &l2->entries[l2pt_index(virtual)]; From 3ffb2464f875f3941413d7ad39ba8af069b9fa39 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Mon, 9 Mar 2020 15:59:05 +0100 Subject: [PATCH 054/104] changed fatals to warns in interrupt.c --- kernel/src/common/interrupt.c | 6 +++--- kernel/src/vm/vas2.c | 8 ++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index 719f1444..90d934ab 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -301,7 +301,7 @@ void enable_interrupt(InterruptType mask) { break; default: /** should never happen **/ - FATAL("invalid interrupt mask"); + WARN("invalid interrupt mask"); } } @@ -322,7 +322,7 @@ void disable_interrupt(InterruptType mask) { break; default: /** should never happen **/ - FATAL("invalid interrupt mask"); + WARN("invalid interrupt mask"); } } @@ -347,7 +347,7 @@ int disable_interrupt_save(InterruptType mask) { break; default: /** should never happen **/ - FATAL("invalid interrupt mask"); + WARN("invalid interrupt mask"); } return cpsr; } diff --git a/kernel/src/vm/vas2.c b/kernel/src/vm/vas2.c index 383ed78e..4cb678f6 100644 --- a/kernel/src/vm/vas2.c +++ b/kernel/src/vm/vas2.c @@ -14,11 +14,7 @@ struct vas2 * create_vas() { } -void switch_to_vas(struct vas2 * vas) { +void switch_to_vas(struct vas2 * vas) {} -} - -void free_vas() { - -} +void free_vas() {} From 27bbc83aa0509a876b26881dedde0c2070983e6c Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Mon, 9 Mar 2020 22:11:02 +0100 Subject: [PATCH 055/104] Added vscode run config --- .vscode/launch.json | 17 +++++++++++++++++ .vscode/tasks.json | 24 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..68d29747 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "gdb", + "request": "attach", + "gdbpath": "${workspaceFolder}/toolchain/arm-none-eabi/bin/arm-none-eabi-gdb", + "name": "Debug", + "executable": "${workspaceFolder}/kernel/build/kernel.sym", + "target": ":1234", + "remote": true, + "cwd": "${workspaceRoot}", + // "preLaunchTask": "run_debug", + "valuesFormatting": "prettyPrinters" + }, + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..52d93342 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,24 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "make test", + "detail": "Runs the course_os test suite", + "type": "shell", + "command": "make test", + "problemMatcher": "$gcc", + "group": { + "kind": "test", + "isDefault": true + } + }, + { + "label": "run_debug", + "detail": "Runs qemu with gdbserver", + "type": "shell", + "command": "make -C kernel debug", + } + ] +} From 8aecf6a8de00c110262f554a7607319dcce25359 Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Tue, 10 Mar 2020 09:16:17 +0100 Subject: [PATCH 056/104] Cleaned up gitignore --- .gitignore | 52 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index c2ace989..779026fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,50 +1,62 @@ -#these were not originally apart of the repo -- appeared after build -/kernel/kernel.bin -/kernel/flash.bin -/kernel/boot-commands -/kernel/card.sd -/kernel/src/test/test.c -/toolchain/target/ -/u-boot/u-boot-* +# Build files +kernel/kernel.bin +kernel/flash.bin +kernel/boot-commands +kernel/card.sd +kernel/src/test/test.c + +# Toolchain dir, but not the build script +/toolchain/ +!/toolchain/build.sh + +# Qemu dir, again without its buildscript /qemu/ !/qemu/build.sh + +# Generic build dirs build/ /cmake-build-*/ + +# Generated docs /html/ /latex/ /course_os_docs.pdf +# Editor specific .settings/ .cproject .project /.idea/ +!/.idea/runConfigurations /.vscode/ +*~ +*.swp +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +*.un~ +Session.vim +.netrwhist -#always exclude these from being pushed +# CCLS files +.ccls-cache/ +compile_commands.json + +# Binary files *.o *.img *.map *.elf *.bin -*~ -*.swp /user/hello/hello /user/hello/hello1 /user/hello/hello2 /user/libc/libc.a -[._]*.s[a-w][a-z] -[._]s[a-w][a-z] -*.un~ -Session.vim -.netrwhist - +# Floobits (CLion collabrative editing plugin) .floo .flooignore -uboot-commands.ubt - +# Misc NOTES /server.PID -!/.idea/runConfigurations From 79ed90d2f5ec75f553713c2bd56c1d0a52d95030 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Tue, 10 Mar 2020 10:48:14 +0100 Subject: [PATCH 057/104] updated vas2.c. Has to be tested with a scheduler but is pretty complete Co-authored-by: Victor Roest --- kernel/Makefile | 7 +- kernel/src/allocator/llist.c | 11 +-- kernel/src/allocator/mem_alloc.c | 34 +++++---- kernel/src/common/interrupt.c | 5 +- kernel/src/common/startup.s | 7 +- kernel/src/ds/include/vp_singly_linked_list.h | 2 +- kernel/src/ds/qstr.c | 2 +- kernel/src/klibc/include/klibc.h | 6 +- kernel/src/klibc/printf.c | 1 + ..._cache_id_allocator.c => asid_allocator.c} | 23 ++++-- ..._cache_id_allocator.h => asid_allocator.h} | 16 +++-- kernel/src/vm/include/pmm.h | 3 - kernel/src/vm/include/vas2.h | 28 ++++++-- kernel/src/vm/include/vm2.h | 41 ++++++++++- kernel/src/vm/pmm.c | 14 +++- kernel/src/vm/test/test_tlb_id.c | 10 +-- kernel/src/vm/vas2.c | 44 +++++++++++- kernel/src/vm/vm2.c | 72 ++++++++++++++++--- 18 files changed, 254 insertions(+), 72 deletions(-) rename kernel/src/vm/{tlb_cache_id_allocator.c => asid_allocator.c} (54%) rename kernel/src/vm/include/{tlb_cache_id_allocator.h => asid_allocator.h} (73%) diff --git a/kernel/Makefile b/kernel/Makefile index a4349027..b30a950b 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -17,6 +17,7 @@ BUILDDIR = build # every directory named `include` will have it's contents autoincluded INCLUDEDIR = include TEST_MAIN_FILE = $(SOURCEDIR)/test/test.c +CPU = cortex-a7 # =================== End Configuration =================== @@ -48,17 +49,17 @@ build_pi: $(BUILDDIR)/kernelPi.img | builddir test: build | builddir #${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -semihosting -kernel build/flash.bin -append "-load 0x410000 0x14000" - ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M raspi2 -cpu arm1176 -nographic -append "-load 0x410000 0x14000" -semihosting + ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M raspi2 -cpu $(CPU) -nographic -append "-load 0x410000 0x14000" -semihosting run: build | builddir # nographic to turn off the gui # monitor none to disable stdio monitoring so # serial stdio works #${QEMU} -M versatilepb -cpu arm1176 -sd $(BUILDDIR)/card.sd -m $(MEMORY) -nographic -semihosting -monitor none -serial stdio -kernel build/flash.bin -append "-load 0x410000 0x14000" - ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M raspi2 -cpu arm1176 -nographic -append "-load 0x410000 0x14000" -semihosting + ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M raspi2 -cpu $(CPU) -nographic -append "-load 0x410000 0x14000" -semihosting debug: build | builddir - ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M raspi2 -cpu arm1176 -nographic -append "-load 0x410000 0x14000" -semihosting -S -s + ${QEMU} -kernel $(BUILDDIR)/kernel.elf -m $(MEMORY) -serial stdio -monitor none -M raspi2 -cpu $(CPU) -nographic -append "-load 0x410000 0x14000" -semihosting -S -s start_debug: build | builddir $(GDB) -ex "target remote localhost:1234" -ex "symbol-file $(BUILDDIR)/kernel.sym" diff --git a/kernel/src/allocator/llist.c b/kernel/src/allocator/llist.c index d396a71b..2f0360c1 100644 --- a/kernel/src/allocator/llist.c +++ b/kernel/src/allocator/llist.c @@ -21,19 +21,20 @@ void add_node(bin_t *bin, node_t* node) { } if (current == NULL) { // we reached the end of the list - // FIXME: previous could be null + if(previous == NULL) { + FATAL("BUG: previous shouldn't be null, this is probably a bug!"); + } + previous->next = node; node->prev = previous; - } - else { + } else { if (previous != NULL) { // middle of list, connect all links! node->next = current; previous->next = node; node->prev = previous; current->prev = node; - } - else { // head is the only element + } else { // head is the only element node->next = bin->head; bin->head->prev = node; bin->head = node; diff --git a/kernel/src/allocator/mem_alloc.c b/kernel/src/allocator/mem_alloc.c index 1d217309..8ec22972 100644 --- a/kernel/src/allocator/mem_alloc.c +++ b/kernel/src/allocator/mem_alloc.c @@ -1,4 +1,4 @@ -#include "klibc.h" +#include #include #include #include @@ -6,26 +6,16 @@ heap_t * allocator; size_t heap_end; -/* - * The kernel heap is organized in blocks. Each block has a header and a - * footer each a 4 byte integer, at the beginning and end of the block. - * The header and footer both specify the size of the block in question. - * Used blocks are indicated by the heap header and the heap footer being - * negative. - * - * To allocate a block, we start at the first block and walk through each - * one, finding the first free block large enough to support a header, - * footer, and the size requested. - * - * To free a block, we do a bunch of merging stuff to check to see if we - * should merge with the blocks on the left or right of us, respectively. - */ - +/// Initializes the heap by asking for HEAP_INIT_SIZE of pages, and putting the heap datastructure there. +/// After the heap is initialized [kmalloc] and related functions can be used. void init_heap() { heap_end = KERNEL_HEAP_BASE; // Allocate space for the heap_t struct. is too large but at least big enough. - void * ret = vm2_allocate_kernel_page(kernell1PageTable, KERNEL_HEAP_BASE, false, 0); + void * ret = vm2_allocate_page(kernell1PageTable, KERNEL_HEAP_BASE, false, (struct PagePermission) { + .access = KernelRW, + .executable = false + }, NULL); if (ret == NULL) { FATAL("Couldn't allocate page for the kernel heap"); } @@ -50,7 +40,10 @@ void init_heap() { size_t heap_start = heap_end; while(heap_end < (heap_start + HEAP_INIT_SIZE)) { - if (vm2_allocate_kernel_page(kernell1PageTable, heap_end, false, 0) == NULL) { + if (vm2_allocate_page(kernell1PageTable, heap_end, false, (struct PagePermission) { + .access = KernelRW, + .executable = false + }, NULL) == NULL) { FATAL("Allocation of the kernel heap went wrong!"); } @@ -65,22 +58,27 @@ void init_heap() { INFO("Heap successfully initialized."); } +/// Internal wrapper around heap_alloc. Should only be indirectly used through kmalloc/krealloc/kcalloc/kfree void *allocate(uint32_t size) { return heap_alloc(allocator, size); } +/// Internal wrapper around heap_free. Should only be indirectly used through kmalloc/krealloc/kcalloc/kfree void deallocate(void *ptr) { return heap_free(allocator, ptr); } +/// Internal function to get the size of an allocation. Should only be indirectly used through kmalloc/krealloc/kcalloc/kfree uint32_t allocation_size(void* ptr) { return get_alloc_size(ptr); } +/// Internal function to get the global allocator. Should only be indirectly used through kmalloc/krealloc/kcalloc/kfree heap_t * mem_get_allocator(){ return allocator; } +/// Internal function to get the size of the heap. Should only be indirectly used through kmalloc/krealloc/kcalloc/kfree uint32_t mem_get_heap_size(){ return allocator->end - allocator->start; } diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index 90d934ab..7b9aba7a 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -7,7 +7,10 @@ /* copy vector table from wherever QEMU loads the kernel to 0x00 */ void init_vector_table() { // allocate space for the IVR at the high vector location. - vm2_allocate_kernel_page(kernell1PageTable, HIGH_VECTOR_LOCATION, true, false); + vm2_allocate_page(kernell1PageTable, HIGH_VECTOR_LOCATION, false, (struct PagePermission) { + .access = KernelRW, + .executable = true + }, NULL); /* Primary Vector Table */ mmio_write(HIGH_VECTOR_LOCATION + 0x00, BRANCH_INSTRUCTION); diff --git a/kernel/src/common/startup.s b/kernel/src/common/startup.s index 59758767..b9b5b9a4 100644 --- a/kernel/src/common/startup.s +++ b/kernel/src/common/startup.s @@ -50,8 +50,11 @@ _Reset: ldr r0, =0x4000 // Give the pagetable addr to the MMU - mcr p15, 0, r0, c2, c0, 0 - mcr p15, 0, r0, c2, c0, 1 + mcr p15, 0, r0, c2, c0, 0 // Table 0 + mcr p15, 0, r0, c2, c0, 1 // Table 1 + + eor r0, r0, r0 // Zero r0 + mcr p15, 0, r0, c2, c0, 2 // Enable page walks on both page tables. mrc p15, 0, r3, c1, c0, 0 orr r3, #0x800000 diff --git a/kernel/src/ds/include/vp_singly_linked_list.h b/kernel/src/ds/include/vp_singly_linked_list.h index 13d966ff..2fb42658 100644 --- a/kernel/src/ds/include/vp_singly_linked_list.h +++ b/kernel/src/ds/include/vp_singly_linked_list.h @@ -39,4 +39,4 @@ bool vpsll_contains(VPSinglyLinkedList * lst, void * value, CompareFunc compf); size_t vpsll_length(VPSinglyLinkedList * lst); #define VPSLL_FOREACH(lst, i) for (VPSinglyLinkedListIterator i = vpslli_create(lst); !vpslli_empty(i); vpslli_next(&(i))) -#endif \ No newline at end of file +#endif diff --git a/kernel/src/ds/qstr.c b/kernel/src/ds/qstr.c index fa1fb62a..34d0a073 100644 --- a/kernel/src/ds/qstr.c +++ b/kernel/src/ds/qstr.c @@ -27,7 +27,7 @@ void qstr_free(Qstr* qstr) { static inline bool __eq(Qstr * left, Qstr * right, bool fake) { // Hash function from http://www.cse.yorku.ca/~oz/hash.html (djb2) char * rightstr; - if(!fake){ + if(!fake) { if (left->hash != 0 && right->hash != 0 && left->hash != right->hash) { return false; } diff --git a/kernel/src/klibc/include/klibc.h b/kernel/src/klibc/include/klibc.h index c758a3c5..f49f3ded 100644 --- a/kernel/src/klibc/include/klibc.h +++ b/kernel/src/klibc/include/klibc.h @@ -80,7 +80,11 @@ unsigned int rand(); #else #define INFO(...) #endif -#define WARN(format, ...) kprintf("\e[38;5;208m[WARN] " format "\e[0m\n", ##__VA_ARGS__) +#if ENABLE_TESTS +#define WARN(format, ...) kprintf("\e[38;5;208m[WARN] \e[38;5;208m%s:%i\e[38;5;208m" format "\e[0m\n", __FILE__, __LINE__, ##__VA_ARGS__); panic() +#else +#define WARN(format, ...) kprintf("\e[38;5;208m[WARN] " format "\e[0m\n", ##__VA_ARGS__) +#endif #define FATAL(format, ...) kprintf("\e[38;5;160m[FATAL] \e[38;5;208m%s:%i\e[38;5;160m " format "\e[0m\n", __FILE__, __LINE__, ##__VA_ARGS__); panic() diff --git a/kernel/src/klibc/printf.c b/kernel/src/klibc/printf.c index c80826bd..31ac76b4 100644 --- a/kernel/src/klibc/printf.c +++ b/kernel/src/klibc/printf.c @@ -71,6 +71,7 @@ int print_int(char *buf, int buflen, int val, int base, int is_unsigned, } // args must already have been started +// TODO: properly stop at buflen. Otherwise there is a buffer overflow. int os_vsnprintf(char *buf, int buflen, const char *str_buf, va_list args) { if (buflen == 0) return 0; diff --git a/kernel/src/vm/tlb_cache_id_allocator.c b/kernel/src/vm/asid_allocator.c similarity index 54% rename from kernel/src/vm/tlb_cache_id_allocator.c rename to kernel/src/vm/asid_allocator.c index b67d6db2..78f77bd4 100644 --- a/kernel/src/vm/tlb_cache_id_allocator.c +++ b/kernel/src/vm/asid_allocator.c @@ -1,6 +1,7 @@ -#include +#include #include #include +#include uint8_t curr = 0; uint8_t allocated_ids[256] = {0}; @@ -8,7 +9,7 @@ uint8_t allocated_ids[256] = {0}; bool tlb_everything_allocated = false; // TODO: Ensure atomicity -struct TLBDescriptor request_tlb_descriptor() { +struct ASIDDescriptor asid_request_descriptor() { uint8_t cache_iteration = ++(allocated_ids[curr]); uint8_t tlb_cache_id = curr++; @@ -16,7 +17,7 @@ struct TLBDescriptor request_tlb_descriptor() { tlb_everything_allocated = true; } - struct TLBDescriptor res = (struct TLBDescriptor) { + struct ASIDDescriptor res = (struct ASIDDescriptor) { .cache_iteration = cache_iteration, .tlb_cache_id = tlb_cache_id, }; @@ -25,7 +26,7 @@ struct TLBDescriptor request_tlb_descriptor() { } // TODO: Ensure atomicity -bool check_and_update(struct TLBDescriptor* desc) { +bool asid_check_and_update(struct ASIDDescriptor* desc) { if(desc->cache_iteration != allocated_ids[desc->tlb_cache_id]) { desc->cache_iteration = ++(allocated_ids[desc->tlb_cache_id]); return true; @@ -33,3 +34,17 @@ bool check_and_update(struct TLBDescriptor* desc) { return false; } + +void asid_set(uint8_t id) { + + DATA_SYNC_BARRIER() + + asm volatile ( + "mrc p15, 0, r1, c13, c0, 1 \n" // Read Context ID (c13) register to R1 + "and r1, r1, #0xffffff00\n" + "orr r1, %0, r1\n" + "mcr p15, 0, r1, c13, c0, 1\n" // Write it back with the ASID set + ::"r"(id) + : "r1" + ); +} diff --git a/kernel/src/vm/include/tlb_cache_id_allocator.h b/kernel/src/vm/include/asid_allocator.h similarity index 73% rename from kernel/src/vm/include/tlb_cache_id_allocator.h rename to kernel/src/vm/include/asid_allocator.h index afee33df..0cb1723a 100644 --- a/kernel/src/vm/include/tlb_cache_id_allocator.h +++ b/kernel/src/vm/include/asid_allocator.h @@ -5,11 +5,11 @@ #include /// Terminology -/// * tlb_cache_id: Hardware process id used for the pagetable cache. +/// * asid: Hardware process id used for the pagetable cache. /// * cache_iteration: Which iteration of the cache we are on, determines if we should flush the cache on a process switch or not. -/// * tlb_descriptor: A pair of above two numbers. +/// * asid_descriptor: A pair of above two numbers. -struct TLBDescriptor { +struct ASIDDescriptor { uint8_t tlb_cache_id; uint8_t cache_iteration; }; @@ -26,7 +26,7 @@ bool tlb_everything_allocated; * If [tlb_everything_allocated] is false, you don't have to flush caches. * @returns a TLBDescriptor */ -struct TLBDescriptor request_tlb_descriptor(); +struct ASIDDescriptor asid_request_descriptor(); /** * Updates and checks a tlb_descriptor. @@ -37,7 +37,11 @@ struct TLBDescriptor request_tlb_descriptor(); * @param desc the tlb_descriptor to check. * @returns whether you should flush caches or not. */ -bool check_and_update(struct TLBDescriptor* desc); - +bool asid_check_and_update(struct ASIDDescriptor* desc); +/** + * Sets a specific ASID for the current core. + * @param id the ASID to set. + */ +void asid_set(uint8_t id); #endif diff --git a/kernel/src/vm/include/pmm.h b/kernel/src/vm/include/pmm.h index 33368e63..d9dde209 100644 --- a/kernel/src/vm/include/pmm.h +++ b/kernel/src/vm/include/pmm.h @@ -41,7 +41,6 @@ // TODO: Excluded regions. (for mmio for example) // TODO: detect memory size. -#define PMM_TOP 0x10000000 // 256 MiB and less than all Peripheral bases #ifndef PMM_H #define PMM_H @@ -131,6 +130,4 @@ void pmm_free_l2_pagetable(struct L2PageTable * pt); struct Page * pmm_allocate_page(); void pmm_free_page(struct Page * p); - - #endif diff --git a/kernel/src/vm/include/vas2.h b/kernel/src/vm/include/vas2.h index 2356602d..20e0e338 100644 --- a/kernel/src/vm/include/vas2.h +++ b/kernel/src/vm/include/vas2.h @@ -1,15 +1,33 @@ #ifndef VAS_2_H #define VAS_2_H -#include "vm2.h" -#include "tlb_cache_id_allocator.h" +#include +#include +#include +#define VAS2_INITIAL_PAGE_LIST_CAPACITY 10 struct vas2 { - struct TLBDescriptor tlbDescriptor; + struct ASIDDescriptor tlbDescriptor; struct L1PageTable * l1PageTable; - // TODO: Do we want to store L2Tables to make freeing VASes faster? - }; + VPArrayList * l2tables; + VPArrayList * pages; +}; +/// Creates a new virtual address spce for a process. +struct vas2 * create_vas(); + +/// Used in context switching. Sets up the mmu for a process to run. +void switch_to_vas(struct vas2 * vas); + +/// Freeing a vas clears all pagetables and pages associated with it. +/// It essentially frees all the memory a process has. +void free_vas(struct vas2 * vas); + +/// Creates a new page starting at the first page boundary below address. +/// This page is thus the page around the address. The address does not have to be +/// page boundary aligned. The new page is added to the vas and made executable if requested. +void allocate_page(struct vas2 * vas, size_t address, bool executable); + #endif diff --git a/kernel/src/vm/include/vm2.h b/kernel/src/vm/include/vm2.h index 667e34a6..bf78180f 100644 --- a/kernel/src/vm/include/vm2.h +++ b/kernel/src/vm/include/vm2.h @@ -6,6 +6,21 @@ #include +/// Permissions for mapping a page +enum Access { + KernelRO, // kernel ro, user no access + KernelRW, // kernel r/w, user no access + + // Everything below this are accessible for the kernel and the user. + UserRO, // kernel r/w, user ro + UserRW, // kernel r/w user r/w +}; + +struct PagePermission { + enum Access access; + bool executable; +}; + /// A L1PagetableEntry is an entry in the top level pagetable. /// There is only one L1 pagetable and it is always located at address 0x4000. /// Relevant manual section: http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf @@ -14,7 +29,7 @@ /// * 6.11.1 (entry layout) /// * 6.13 (control registers) /// * 6.10 (page faults and aborts) -typedef union L1PagetableEntry{ +typedef union L1PagetableEntry { uint32_t entry; /// A coarse l1pt entry means an l1pt entry that points to an l2pt. /// The other possibility is a (super)section, where the l1pt maps a @@ -284,12 +299,19 @@ size_t vm2_map_peripheral(size_t physical, size_t n_mebibytes); /// or null if unsuccesfull. The physical location of this page is determined by the pmm. /// Since this allocates a 4kb page, it has to go through l2 pagetables. It will create the right /// l2 pagetables as it needs. You can make the allocated page executable with the last parameter. -void *vm2_allocate_kernel_page(struct L1PageTable *l1pt, size_t virtual, bool executable, bool remap); +void *vm2_allocate_page(struct L1PageTable *l1pt, size_t virtual, bool remap, struct PagePermission perms, + struct L2PageTable **created_l2pt); /// Should be called after updating a pagetable. void vm2_flush_caches(); -/// +/// Flushes the caches associated with an ASID. +void vm2_flush_caches_of_ASID(uint8_t id); + +/// Enables a given l1 pagetable on the MMU. +void vm2_set_current_pagetable(struct L1PageTable * l1); + +/// The kernel's L1 Pagetable. struct L1PageTable * kernell1PageTable; /// From the `kernel.ld` linker file. These are not arrays but this is how you refer to the pointers by the linker script. @@ -309,6 +331,11 @@ extern const size_t __KERNEL_VIRTUAL_OFFSET[]; /// Location of the Kernel's Physical Memory Manager's Info structs. Can grow to a max of 16MiB when using 4GiB RAM. #define KERNEL_PMM_BASE KERNEL_VIRTUAL_END +// TODO: This changes per chipset and we either need to detect that or +// TODO: (the actual solution) support excluded regions in the pmm +// If we write above this range (0x3f000000) on a bcm2836 we enter the peripheral +// DMA region and are thus setting all kinds of registers. This kills qemu :) +#define PMM_TOP (KERNEL_VIRTUAL_OFFSET + 0x3f000000) // Location of the vector table in memory table. // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/BABIFJFG.html @@ -330,8 +357,16 @@ extern const size_t __KERNEL_VIRTUAL_OFFSET[]; #define PAGE_SIZE (4 * Kibibyte) + +// general purpose useful macros + // aligns an address to the *next* boundary of size n. // only works where n is a power of 2 #define ALIGN(address, n) ((((size_t)(address) + (size_t)(n) - 1) & ~((size_t)(n) - 1))); +/// The purpose of the Data Synchronization Barrier operation is to ensure that +/// all outstanding explicit memory transactions complete before any following instructions begin. +/// This ensures that data in memory is up to date before the processor executes any more instructions. +#define DATA_SYNC_BARRIER() asm volatile ("eor r0, r0, r0\nmcr p15, 0, r0, c7, c10, 4"); + #endif diff --git a/kernel/src/vm/pmm.c b/kernel/src/vm/pmm.c index 834163e4..2e608eed 100644 --- a/kernel/src/vm/pmm.c +++ b/kernel/src/vm/pmm.c @@ -1,6 +1,7 @@ #include #include #include +#include /// Private functions // Returns the index of the first zero from the LSB @@ -143,7 +144,6 @@ void pmm_free_l1_pagetable(struct L1PageTable * pt) { // Since it's the first thing on the unused list, make prev null. sliceinfo->prev = NULL; - } struct L1PageTable * pmm_allocate_l1_pagetable() { @@ -161,6 +161,8 @@ struct L1PageTable * pmm_allocate_l1_pagetable() { // Put it on the allocated stack push_to_ll(&physicalMemoryManager.allocated, sliceinfo); + memset(&sliceinfo->slice->l1pt, 0, sizeof(struct L1PageTable)); + return &sliceinfo->slice->l1pt; } @@ -186,6 +188,7 @@ struct L2PageTable * pmm_allocate_l2_pagetable() { push_to_ll(&physicalMemoryManager.allocated, sliceinfo); } + memset(newl2pt, 0, sizeof(struct L2PageTable)); return newl2pt; } else { struct MemorySliceInfo * sliceinfo = pop_from_ll(&physicalMemoryManager.unused); @@ -197,7 +200,9 @@ struct L2PageTable * pmm_allocate_l2_pagetable() { // Put it on the partially allocated list push_to_ll(&physicalMemoryManager.l2ptPartialFree, sliceinfo); - return &sliceinfo->slice->l2pt[0]; + struct L2PageTable * newl2pt = &sliceinfo->slice->l2pt[0]; + memset(newl2pt, 0, sizeof(struct L2PageTable)); + return newl2pt; } } @@ -224,6 +229,7 @@ struct Page * pmm_allocate_page() { push_to_ll(&physicalMemoryManager.allocated, sliceinfo); } + memset(newpage, 0, sizeof(struct Page)); return newpage; } else { struct MemorySliceInfo * sliceinfo = pop_from_ll(&physicalMemoryManager.unused); @@ -235,7 +241,9 @@ struct Page * pmm_allocate_page() { // Put it on the partially allocated list push_to_ll(&physicalMemoryManager.pagePartialFree, sliceinfo); - return &sliceinfo->slice->page[0]; + struct Page * newpage = &sliceinfo->slice->page[0]; + memset(newpage, 0, sizeof(struct Page)); + return newpage; } } diff --git a/kernel/src/vm/test/test_tlb_id.c b/kernel/src/vm/test/test_tlb_id.c index fc35575e..e103d5f4 100644 --- a/kernel/src/vm/test/test_tlb_id.c +++ b/kernel/src/vm/test/test_tlb_id.c @@ -1,13 +1,13 @@ -#include +#include #include TEST_CREATE(tlb_simple, { - struct TLBDescriptor desc = request_tlb_descriptor(); + struct ASIDDescriptor desc = asid_request_descriptor(); uint32_t id = desc.tlb_cache_id; uint32_t iteration = desc.cache_iteration; - if(check_and_update(&desc)) { + if(asid_check_and_update(&desc)) { ASSERT_NEQ(iteration, desc.cache_iteration); } else { ASSERT_EQ(iteration, desc.cache_iteration); @@ -20,12 +20,12 @@ TEST_CREATE(tlb_intensive, { // This tests asserts the properties of the TLBDescriptor in an extensive way, // to ensure at least 1 overflow takes place for(size_t i = 0; i < 666; i++) { - struct TLBDescriptor desc = request_tlb_descriptor(); + struct ASIDDescriptor desc = asid_request_descriptor(); uint32_t id = desc.tlb_cache_id; uint32_t iteration = desc.cache_iteration; - if(check_and_update(&desc)) { + if(asid_check_and_update(&desc)) { ASSERT_NEQ(iteration, desc.cache_iteration); } else { ASSERT_EQ(iteration, desc.cache_iteration); diff --git a/kernel/src/vm/vas2.c b/kernel/src/vm/vas2.c index 4cb678f6..d006efdc 100644 --- a/kernel/src/vm/vas2.c +++ b/kernel/src/vm/vas2.c @@ -1,20 +1,58 @@ #include #include +#include #include +/// FIXME: +/// WARNING: This code is untested, and quite hard to even make tests for. +/// This should just be used in a scheduler to see if it works. + struct vas2 * create_vas() { struct vas2 * newvas = kmalloc(sizeof(struct vas2)); *newvas = (struct vas2) { - .tlbDescriptor = request_tlb_descriptor(), + .tlbDescriptor = asid_request_descriptor(), .l1PageTable = pmm_allocate_l1_pagetable(), + .l2tables = vpa_create(VAS2_INITIAL_PAGE_LIST_CAPACITY), + .pages = vpa_create(VAS2_INITIAL_PAGE_LIST_CAPACITY), }; + // Copy the upper half of the kernelPageTable to any other page table. + memcpy(newvas->l1PageTable, &kernell1PageTable->entries[0x800], sizeof(struct L1PageTable) / 2); + return newvas; } +void switch_to_vas(struct vas2 * vas) { + if(asid_check_and_update(&vas->tlbDescriptor)) { + vm2_flush_caches_of_ASID(vas->tlbDescriptor.tlb_cache_id); + } + + asid_set(vas->tlbDescriptor.tlb_cache_id); -void switch_to_vas(struct vas2 * vas) {} + vm2_set_current_pagetable(vas->l1PageTable); +} -void free_vas() {} +void free_vas(struct vas2 * vas) { + vpa_free(vas->l2tables, (FreeFunc) pmm_free_l2_pagetable); + vpa_free(vas->pages, (FreeFunc) pmm_free_page); + pmm_free_l1_pagetable(vas->l1PageTable); + kfree(vas); +} +void allocate_page(struct vas2 * vas, size_t address, bool executable) { + struct PagePermission perms = (struct PagePermission) { + .executable = executable, + .access = UserRW, + }; + + struct L2PageTable * l2pt = NULL; + + void * page = vm2_allocate_page(vas->l1PageTable, address, false, perms, &l2pt); + + if (l2pt != NULL) { + vpa_push(vas->l2tables, l2pt); + } + + vpa_push(vas->pages, page); +} diff --git a/kernel/src/vm/vm2.c b/kernel/src/vm/vm2.c index 3e517ef5..48f3aeda 100644 --- a/kernel/src/vm/vm2.c +++ b/kernel/src/vm/vm2.c @@ -75,6 +75,20 @@ void vm2_flush_caches() { :: "r"(0x0)); } +// http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf#page=219 +void vm2_flush_caches_of_ASID(uint8_t id) { + asm volatile ( + "mcr p15, 0, %0, c8, c7, 2" // Invalidate TLB Entry on ASID Match + :: "r" (id)); +} + +void vm2_set_current_pagetable(struct L1PageTable * l1) { + // FIXME: Determine if we want split tables or a single one + // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf#page=360 + asm volatile ("MCR p15, 0, %0, c2, c0, 0\n" // Set Translation base address 0 + "MCR p15, 0, %0, c2, c0, 1" :: "r" (l1)); // Set Translation base address 1 +} + // Starts the actual MMU after this function we live in Virtual Memory void vm2_start() { size_t available_RAM; @@ -107,14 +121,15 @@ void vm2_start() { }, KERNEL_VIRTUAL_OFFSET + i, true); } - pmm_init(KERNEL_PMM_BASE, KERNEL_VIRTUAL_OFFSET + available_RAM); + pmm_init(KERNEL_PMM_BASE, PMM_TOP); vm2_flush_caches(); mmu_started = true; } -void *vm2_allocate_kernel_page(struct L1PageTable *l1pt, size_t virtual, bool executable, bool remap) { +void *vm2_allocate_page(struct L1PageTable *l1pt, size_t virtual, bool remap, struct PagePermission perms, + struct L2PageTable **created_l2pt) { L1PagetableEntry * l1Entry = &l1pt->entries[l1pt_index(virtual)]; struct L2PageTable * l2 = NULL; @@ -128,6 +143,12 @@ void *vm2_allocate_kernel_page(struct L1PageTable *l1pt, size_t virtual, bool ex .base_address = ((size_t)VIRT2PHYS((size_t)l2)) >> 10u, }, }; + + // Return the allocated l2pt + if(created_l2pt != NULL){ + *created_l2pt = l2; + } + /** Fallthrough **/ case 1:; struct Page * page = pmm_allocate_page(); @@ -143,13 +164,45 @@ void *vm2_allocate_kernel_page(struct L1PageTable *l1pt, size_t virtual, bool ex TRACE("[MEM DEBUG] Remapping l2 page located at 0x%x", virtual); } + // Set up perms correctly + int accessPerms = 0; + int accessExtended = 0; + bool global = false; + + switch (perms.access) { + case KernelRW: + accessPerms = 0b01; + accessExtended = 0; + global = true; + break; + case KernelRO: + accessPerms = 0b01; + accessExtended = 1; + global = true; + break; + case UserRO: + accessPerms = 0b10; + accessExtended = 0; + global = false; + break; + case UserRW: + accessPerms = 0b11; + accessExtended = 0; + global = false; + break; + default: + WARN("[MEM DEBUG] No access permissions specified, falling back to No access "); + break; + } + *l2Entry = (union L2PagetableEntry) { .smallpage = { - .type = 2 + !executable, + .type = 2 + !perms.executable, .bufferable = 0, .cachable = 0, - .accessPermissions = 1, - .accessExtended = 0, + .notglobal = !global, + .accessPermissions = accessPerms, + .accessExtended = accessExtended, .base_address = l2pt_base_address(((size_t)VIRT2PHYS(page))), }, }; @@ -158,9 +211,15 @@ void *vm2_allocate_kernel_page(struct L1PageTable *l1pt, size_t virtual, bool ex vm2_flush_caches(); } + // make sure that if we didn't allocate a new pt, we set created_l2pt it to null + if(created_l2pt != NULL && *created_l2pt != NULL){ + *created_l2pt = NULL; + } + return page; default: // This is a (super)section and we can't make it a coarse pagetable. Error. + WARN("[MEM DEBUG] L1 Entry is a section or super section, can't map a page there"); return NULL; } } @@ -186,6 +245,3 @@ size_t vm2_map_peripheral(size_t physical, size_t n_mebibytes) { return mmio_current_top; } - - - From b91078e7e5006fc8c2049409e5a2c25dc7dd6ebd Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Tue, 10 Mar 2020 13:13:45 +0100 Subject: [PATCH 058/104] Switched to a memory model where the Process pagetable is separate from the OS pagetable. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This saves 8KiB (!) per process. It also makes caching more efficient. Co-authored-by: Jonathan Dönszelmann --- kernel/linker/kernel.ld | 8 ++++---- kernel/src/allocator/allocator.c | 2 +- kernel/src/allocator/mem_alloc.c | 2 +- kernel/src/common/interrupt.c | 6 +++--- kernel/src/common/startup.s | 9 +++------ kernel/src/klibc/klibc.c | 4 ++-- kernel/src/vm/include/pmm.h | 27 +++++++++++++++------------ kernel/src/vm/include/vm2.h | 4 ++-- kernel/src/vm/pmm.c | 21 ++++++++------------- kernel/src/vm/vas2.c | 5 +---- kernel/src/vm/vm2.c | 10 +++++----- 11 files changed, 45 insertions(+), 53 deletions(-) diff --git a/kernel/linker/kernel.ld b/kernel/linker/kernel.ld index 75f4d626..6c487f28 100644 --- a/kernel/linker/kernel.ld +++ b/kernel/linker/kernel.ld @@ -18,17 +18,17 @@ SECTIONS __KERNEL_BASE = .; .text : AT(ADDR(.text) - __KERNEL_VIRTUAL_OFFSET) { - *(EXCLUDE_FILE (*/boot.o */stacks.o) .text) + *(EXCLUDE_FILE (*/startup.o */stacks.o) .text) *(.rodata*) } .data : AT(ADDR(.data) - __KERNEL_VIRTUAL_OFFSET){ - *(EXCLUDE_FILE (*/boot.o */stacks.o) .data) + *(EXCLUDE_FILE (*/startup.o) .data) } .bss : AT(ADDR(.bss) - __KERNEL_VIRTUAL_OFFSET) { - *(EXCLUDE_FILE (*/boot.o */stacks.o) COMMON) - *(EXCLUDE_FILE (*/boot.o) .bss) + *(EXCLUDE_FILE (*/startup.o) COMMON) + *(EXCLUDE_FILE (*/startup.o) .bss) } /*make kernel top megabyte aligned*/ diff --git a/kernel/src/allocator/allocator.c b/kernel/src/allocator/allocator.c index 525b1b5e..cc0a745e 100644 --- a/kernel/src/allocator/allocator.c +++ b/kernel/src/allocator/allocator.c @@ -180,7 +180,7 @@ void heap_free(heap_t *heap, void *p) { // these are left here to implement contraction / expansion uint32_t expand(heap_t *heap, uint32_t sz) { - TRACE("[MEM DEBUG] Trying to expand"); + WARN("[MEM DEBUG] Trying to expand"); return 0; // fail for now } diff --git a/kernel/src/allocator/mem_alloc.c b/kernel/src/allocator/mem_alloc.c index 8ec22972..5f85ea3a 100644 --- a/kernel/src/allocator/mem_alloc.c +++ b/kernel/src/allocator/mem_alloc.c @@ -39,7 +39,7 @@ void init_heap() { heap_end = ALIGN(heap_end, PAGE_SIZE); size_t heap_start = heap_end; - while(heap_end < (heap_start + HEAP_INIT_SIZE)) { + while(heap_end < (heap_start + HEAP_INIT_SIZE + PAGE_SIZE)) { if (vm2_allocate_page(kernell1PageTable, heap_end, false, (struct PagePermission) { .access = KernelRW, .executable = false diff --git a/kernel/src/common/interrupt.c b/kernel/src/common/interrupt.c index 7b9aba7a..a8c08c0d 100644 --- a/kernel/src/common/interrupt.c +++ b/kernel/src/common/interrupt.c @@ -211,9 +211,9 @@ void __attribute__((interrupt("ABORT"))) data_abort_handler(void) { WARN("DFSR: 0x%x", dfsr); - #ifdef ENABLE_TESTS - FATAL("Data abort is disallowed in tests"); - #endif +#ifdef ENABLE_TESTS + FATAL("Data abort is disallowed in tests"); +#endif } void reserved_handler(void) diff --git a/kernel/src/common/startup.s b/kernel/src/common/startup.s index b9b5b9a4..cda9f810 100644 --- a/kernel/src/common/startup.s +++ b/kernel/src/common/startup.s @@ -8,12 +8,6 @@ _Reset: cmp r1, #0 bne loop - // Move the interrupt vector tables to 0x80000000 - ldr r0, =0xE000ED08 - ldr r1, =0x80000000 - str r1, [r0] - - ldr sp, =EARLY_KERNEL_STACK_TOP // Set the kernel/SVC stack push {r0-r11} @@ -53,7 +47,10 @@ _Reset: mcr p15, 0, r0, c2, c0, 0 // Table 0 mcr p15, 0, r0, c2, c0, 1 // Table 1 + // infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf#page=193 + // Set up that we use half sized page tables (one for kernel one for userspace) eor r0, r0, r0 // Zero r0 + ADD r0, #1 // Set N to 1 meaning we are using pagetables of 8KiB in size. mcr p15, 0, r0, c2, c0, 2 // Enable page walks on both page tables. mrc p15, 0, r3, c1, c0, 0 diff --git a/kernel/src/klibc/klibc.c b/kernel/src/klibc/klibc.c index 364c6947..2d966a2c 100644 --- a/kernel/src/klibc/klibc.c +++ b/kernel/src/klibc/klibc.c @@ -57,14 +57,14 @@ void inline panic() { void splash() { // kprintf("\n\n"); -// kprintf("\t ██████╗ ██████╗ ██╗ ██╗██████╗ ███████╗███████╗ ██████╗ ███████╗\n"); +// kprintf("\t ██████╗ ██████╗ ██╗ ██╗██████╗ ███████╗███████╗ ██████╗ ██████╗\n"); // kprintf("\t██╔════╝██╔═══██╗██║ ██║██╔══██╗██╔════╝██╔════╝██╔═══██╗██╔════╝\n"); // kprintf("\t██║ ██║ ██║██║ ██║██████╔╝███████╗█████╗ ██║ ██║███████╗\n"); // kprintf("\t██║ ██║ ██║██║ ██║██╔══██╗╚════██║██╔══╝ ██║ ██║╚════██║\n"); // kprintf("\t╚██████╗╚██████╔╝╚██████╔╝██║ ██║███████║███████╗╚██████╔╝██████║\n\n"); // kprintf("\n\n"); - kprintf("\t ██████╗██╗ ██╗██████╗ ███████╗███████╗██████╗ ██████╗ ███████╗\n"); + kprintf("\t ██████╗██╗ ██╗██████╗ ███████╗███████╗██████╗ ██████╗ ██████╗\n"); kprintf("\t██╔════╝██║ ██║██╔══██╗██╔════╝██╔════╝██╔═══██╗ ██╔═══██╗██╔════╝\n"); kprintf("\t██║ ██║ ██║██████╔╝███████╗█████╗ ██║ ██║ ██║ ██║███████╗\n"); kprintf("\t██║ ██║ ██║██╔══██╗╚════██║██╔══╝ ██║ ██║ ██║ ██║╚════██║\n"); diff --git a/kernel/src/vm/include/pmm.h b/kernel/src/vm/include/pmm.h index d9dde209..e0c1dd66 100644 --- a/kernel/src/vm/include/pmm.h +++ b/kernel/src/vm/include/pmm.h @@ -50,8 +50,6 @@ #include "vm2.h" -#define SLICEINFO_PER_SLICE 1024 - /// The type of a 16kib Slice enum MemoryType { L1PageTable, @@ -72,9 +70,9 @@ struct MemorySliceInfo { uint32_t entry; struct { enum MemoryType type: 2; - uint32_t filled: 16; + uint32_t filled: 8; /// Filler bits - uint32_t unused: 14; + uint32_t unused: 22; }; }; @@ -84,16 +82,21 @@ struct MemorySliceInfo { union MemorySlice * slice; }; -/// A Memory slice of 16KB, that's also 16kb aligned. -/// A slice of 16kb can fit one of three things: -/// * 4 physical pages of 4kb -/// * 1 l1 pagetable of 16kb -/// * 16 l2 pagetabke of 1kb -/// * 682 (rounded down) MemorySliceInfo structs indexing other pages + +#define SLICEINFO_PER_SLICE 512 +#define L2TABLES_PER_SLICE 8 +#define PAGES_PER_SLICE 2 + +/// A Memory slice of 8KB, that's also 8kb aligned. +/// A slice of 8kb can fit one of three things: +/// * 2 physical pages of 4kb +/// * 1 l1 pagetable of 8kb +/// * 8 l2 pagetabke of 1kb +/// * 512 MemorySliceInfo structs indexing other pages union MemorySlice { struct L1PageTable l1pt; - struct Page page[4]; - struct L2PageTable l2pt[16]; + struct Page page[PAGES_PER_SLICE]; + struct L2PageTable l2pt[L2TABLES_PER_SLICE]; // The sliceinfo array (bucketinfo) that contains the information of all Memoryslices in the next bucket. struct MemorySliceInfo bucketinfo[SLICEINFO_PER_SLICE]; }; diff --git a/kernel/src/vm/include/vm2.h b/kernel/src/vm/include/vm2.h index bf78180f..f0b17834 100644 --- a/kernel/src/vm/include/vm2.h +++ b/kernel/src/vm/include/vm2.h @@ -272,7 +272,7 @@ typedef union L2PagetableEntry{ /// The representation of an L1Pagetable struct L1PageTable { - L1PagetableEntry entries[0x1000]; + L1PagetableEntry entries[0x800]; }; /// The representation of an L1Pagetable @@ -309,7 +309,7 @@ void vm2_flush_caches(); void vm2_flush_caches_of_ASID(uint8_t id); /// Enables a given l1 pagetable on the MMU. -void vm2_set_current_pagetable(struct L1PageTable * l1); +void vm2_set_user_pagetable(struct L1PageTable * l1); /// The kernel's L1 Pagetable. struct L1PageTable * kernell1PageTable; diff --git a/kernel/src/vm/pmm.c b/kernel/src/vm/pmm.c index 2e608eed..023adfc8 100644 --- a/kernel/src/vm/pmm.c +++ b/kernel/src/vm/pmm.c @@ -105,12 +105,7 @@ struct MemorySliceInfo * pmm_get_sliceinfo_for_slice(union MemorySlice * slice) // slice for a bucket sits in the *last* slice of the previous bucket. // However, for the first bucket, the bucketinfo slice is actually the // *first* slice in the bucket - size_t correction; - if (bucketindex == 0) { - correction = 0; - } else { - correction = 1; - } + size_t correction = bucketindex == 0 ? 0 : 1; // Multiply by blocksize again (NOTE: this is so we round down! The division and multiplication DO NOT CANCEL OUT) // Subtract two as the bucket is actually the last page of the previous bucket. @@ -161,6 +156,7 @@ struct L1PageTable * pmm_allocate_l1_pagetable() { // Put it on the allocated stack push_to_ll(&physicalMemoryManager.allocated, sliceinfo); + // Pre-zero the L1PageTable memset(&sliceinfo->slice->l1pt, 0, sizeof(struct L1PageTable)); return &sliceinfo->slice->l1pt; @@ -179,7 +175,7 @@ struct L2PageTable * pmm_allocate_l2_pagetable() { sliceinfo->filled |= (1u << index); // If it is filled - if(sliceinfo->filled == 0xffff) { + if(sliceinfo->filled == 0xff) { // Remove from the partial free list // We can ignore the return value here as we already got it. pop_from_ll(&physicalMemoryManager.l2ptPartialFree); @@ -219,8 +215,8 @@ struct Page * pmm_allocate_page() { sliceinfo->filled |= (1u << index); - // If it is filled - if(sliceinfo->filled == 0xf) { + // If it is filled (2 pages) + if(sliceinfo->filled == 0b11) { // Remove from the partial free list // We can ignore the return value here as we already got it. pop_from_ll(&physicalMemoryManager.pagePartialFree); @@ -251,7 +247,7 @@ void pmm_free_page(struct Page * p) { // works cuz rounding (we think, might just work because random luck) struct MemorySliceInfo * info = pmm_get_sliceinfo_for_slice((union MemorySlice *) p); - if (info->filled == 0xf) { + if (info->filled == 0b11) { remove_element_ll(&physicalMemoryManager.allocated, info); } else { remove_element_ll(&physicalMemoryManager.pagePartialFree, info); @@ -265,7 +261,7 @@ void pmm_free_page(struct Page * p) { info->filled &= ~(1u << index_in_slice); // if there was only one l2pt in this slice, put it on unallocated - if(info->filled == 00) { + if(info->filled == 0x0) { push_to_ll(&physicalMemoryManager.unused, info); } else { push_to_ll(&physicalMemoryManager.pagePartialFree, info); @@ -276,7 +272,7 @@ void pmm_free_l2_pagetable(struct L2PageTable * pt) { // works cuz rounding (we think, might just work because random luck) struct MemorySliceInfo * info = pmm_get_sliceinfo_for_slice((union MemorySlice *) pt); - if (info->filled == 0xffff) { + if (info->filled == 0xff) { remove_element_ll(&physicalMemoryManager.allocated, info); } else { remove_element_ll(&physicalMemoryManager.l2ptPartialFree, info); @@ -297,7 +293,6 @@ void pmm_free_l2_pagetable(struct L2PageTable * pt) { } } - void push_to_ll(struct MemorySliceInfo ** head, struct MemorySliceInfo * entry) { if (*head != NULL) { (*head)->prev = entry; diff --git a/kernel/src/vm/vas2.c b/kernel/src/vm/vas2.c index d006efdc..d313109c 100644 --- a/kernel/src/vm/vas2.c +++ b/kernel/src/vm/vas2.c @@ -17,9 +17,6 @@ struct vas2 * create_vas() { .pages = vpa_create(VAS2_INITIAL_PAGE_LIST_CAPACITY), }; - // Copy the upper half of the kernelPageTable to any other page table. - memcpy(newvas->l1PageTable, &kernell1PageTable->entries[0x800], sizeof(struct L1PageTable) / 2); - return newvas; } @@ -30,7 +27,7 @@ void switch_to_vas(struct vas2 * vas) { asid_set(vas->tlbDescriptor.tlb_cache_id); - vm2_set_current_pagetable(vas->l1PageTable); + vm2_set_user_pagetable(vas->l1PageTable); } void free_vas(struct vas2 * vas) { diff --git a/kernel/src/vm/vm2.c b/kernel/src/vm/vm2.c index 48f3aeda..d5b6a510 100644 --- a/kernel/src/vm/vm2.c +++ b/kernel/src/vm/vm2.c @@ -50,7 +50,7 @@ bool vm2_l1_map_physical_to_virtual(struct L1PageTable * pt, union L1PagetableEn kernell1PageTable->entries[l1pt_index(virtual)] = entry; - if (remap) { + if (remap && remapped) { // TODO: partial flush vm2_flush_caches(); } @@ -82,11 +82,9 @@ void vm2_flush_caches_of_ASID(uint8_t id) { :: "r" (id)); } -void vm2_set_current_pagetable(struct L1PageTable * l1) { - // FIXME: Determine if we want split tables or a single one +void vm2_set_user_pagetable(struct L1PageTable * l1) { // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf#page=360 - asm volatile ("MCR p15, 0, %0, c2, c0, 0\n" // Set Translation base address 0 - "MCR p15, 0, %0, c2, c0, 1" :: "r" (l1)); // Set Translation base address 1 + asm volatile ("MCR p15, 0, %0, c2, c0, 0\n" :: "r" (l1)); // Set Translation base address 0 } // Starts the actual MMU after this function we live in Virtual Memory @@ -123,8 +121,10 @@ void vm2_start() { pmm_init(KERNEL_PMM_BASE, PMM_TOP); + vm2_set_user_pagetable(NULL); vm2_flush_caches(); + mmu_started = true; } From 5cdd28d306be2097be3d1cbb350b809c492b4070 Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Tue, 10 Mar 2020 13:51:33 +0100 Subject: [PATCH 059/104] Removed outdated TODO --- kernel/src/vm/pmm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/src/vm/pmm.c b/kernel/src/vm/pmm.c index 023adfc8..af5ad713 100644 --- a/kernel/src/vm/pmm.c +++ b/kernel/src/vm/pmm.c @@ -88,8 +88,6 @@ struct MemorySliceInfo * pmm_new_sliceinfo_slice() { struct MemorySliceInfo * pmm_get_sliceinfo_for_slice(union MemorySlice * slice) { - // TODO: think about changing SLICEINFO_PER_SLICE to 512 instead of 682. This adds quite some memory overhead - // TODO: but makes the division and multiplication below a lot faster. (or even unnecessary as it can be replaced with a single logical AND) const int bucketsize = (SLICEINFO_PER_SLICE * sizeof(union MemorySlice)); // Take the address of the slice and determine in which bucket it falls. From ccdfcc1977ec8a606613ec8df705027c05ed3ad0 Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Tue, 10 Mar 2020 14:37:10 +0100 Subject: [PATCH 060/104] Added more docs And removed some unused header files. --- kernel/src/common/hardwareinfo.c | 1 + kernel/src/common/start.c | 6 +- kernel/src/common/startup.s | 1 + kernel/src/ds/bpf/HashMap.c | 2 +- kernel/src/ds/bpf/include/HashMap.h | 1 + kernel/src/ds/include/array_list.h | 34 ------- kernel/src/ds/include/bin_tree.h | 36 ------- kernel/src/ds/include/bitvector.h | 42 --------- kernel/src/ds/include/hash_map.h | 30 ------ kernel/src/ds/include/linked_list.h | 44 --------- kernel/src/ds/include/qstr.h | 3 +- kernel/src/ds/include/ring_buffer.h | 38 -------- kernel/src/ds/include/vp_singly_linked_list.h | 2 + kernel/src/vm/asid_allocator.c | 6 +- kernel/src/vm/include/asid_allocator.h | 18 +++- kernel/src/vm/include/pmm.h | 93 +++++++++++++++---- kernel/src/vm/include/vm2.h | 43 +++++---- .../vm/test/{test_tlb_id.c => test_asid.c} | 8 +- kernel/src/vm/test/test_pagealloc2.c | 8 +- kernel/src/vm/vas2.c | 4 +- 20 files changed, 144 insertions(+), 276 deletions(-) delete mode 100644 kernel/src/ds/include/array_list.h delete mode 100644 kernel/src/ds/include/bin_tree.h delete mode 100644 kernel/src/ds/include/bitvector.h delete mode 100644 kernel/src/ds/include/hash_map.h delete mode 100644 kernel/src/ds/include/linked_list.h delete mode 100644 kernel/src/ds/include/ring_buffer.h rename kernel/src/vm/test/{test_tlb_id.c => test_asid.c} (85%) diff --git a/kernel/src/common/hardwareinfo.c b/kernel/src/common/hardwareinfo.c index c5606929..bc8b999f 100644 --- a/kernel/src/common/hardwareinfo.c +++ b/kernel/src/common/hardwareinfo.c @@ -23,6 +23,7 @@ BoardType detect_boardtype() { } // TODO: detect hardware info. +// Such as: CPU and RAM. void init_hardwareinfo() { hardware_info = (HardwareInfo){ .cpuType = ARM1176, diff --git a/kernel/src/common/start.c b/kernel/src/common/start.c index 4421288a..84bdbc20 100644 --- a/kernel/src/common/start.c +++ b/kernel/src/common/start.c @@ -25,8 +25,9 @@ #include #include -// This start is what u-boot calls. It's just a wrapper around setting up the -// virtual memory for the kernel. +/// Entrypoint for the C part of the kernel. +/// This function is called by the assembly located in [startup.s]. +/// The MMU has already been initialized here but only the first MiB of the kernel has been mapped. void start(uint32_t *p_bootargs) { // Before this point, all code has to be hardware independent. @@ -47,6 +48,7 @@ void start(uint32_t *p_bootargs) { // Even though we already enabled the mmu in startup.s to // create a higher half kernel. The pagetable created there // was temporary and has to be replaced here. + // This will actually map the whole kernel in memory and initialize the physicalMemoryManager. INFO("Initializing the physical and virtual memory managers."); vm2_start(); diff --git a/kernel/src/common/startup.s b/kernel/src/common/startup.s index cda9f810..9ef54384 100644 --- a/kernel/src/common/startup.s +++ b/kernel/src/common/startup.s @@ -1,6 +1,7 @@ .global _Reset +// Actual entrypoint of the Kernel. _Reset: // Disable other cores mrc p15, #0, r1, c0, c0, #5 diff --git a/kernel/src/ds/bpf/HashMap.c b/kernel/src/ds/bpf/HashMap.c index 8881e6b4..0329490b 100644 --- a/kernel/src/ds/bpf/HashMap.c +++ b/kernel/src/ds/bpf/HashMap.c @@ -4,7 +4,7 @@ * Generic non-thread safe hash map implementation. * * Copyright (c) 2019 Facebook - * Copyright (c) 2020 Jonathan Dönszelmann and Victor Roest + * Copyright (c) 2020 Jonathan Dönszelmann and Victor Roest (Changed for use in course_os) */ diff --git a/kernel/src/ds/bpf/include/HashMap.h b/kernel/src/ds/bpf/include/HashMap.h index 906006d8..cc249566 100644 --- a/kernel/src/ds/bpf/include/HashMap.h +++ b/kernel/src/ds/bpf/include/HashMap.h @@ -4,6 +4,7 @@ * Generic non-thread safe hash map implementation. * * Copyright (c) 2019 Facebook + * Copyright (c) 2020 Jonathan Dönszelmann and Victor Roest (Changed for integration in course_os) */ #ifndef __LIBBPF_HASHMAP_H #define __LIBBPF_HASHMAP_H diff --git a/kernel/src/ds/include/array_list.h b/kernel/src/ds/include/array_list.h deleted file mode 100644 index c99afb46..00000000 --- a/kernel/src/ds/include/array_list.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * array_list.h - * - * Created on: Apr 21, 2015 - * Author: namaz89 - */ - -#ifndef KERNEL_INCLUDE_ARRAY_LIST_H_ -#define KERNEL_INCLUDE_ARRAY_LIST_H_ - -#include -#include - -#define DEFAULT_BUCKET_SIZE 20 - -typedef struct arrl_handle arrl_handle; - -struct arrl_handle { - llist_handle * linked_list; - int bucket_size; - int size; - int capacity; -} __attribute__((deprecated)); // The implementation is faulty. - -arrl_handle* arrl_create(); -arrl_handle* arrl_create_fixed(uint32_t bucket_size); -void arrl_append(arrl_handle* arrl, void* elem); -void arrl_remove(arrl_handle* arrl, void* elem); -void arrl_remove_all(arrl_handle* arrl, void* elem); -uint32_t arrl_contains(arrl_handle* arrl, void* elem); -uint32_t arrl_index_of(arrl_handle* arrl, void* elem); -uint32_t arrl_count(arrl_handle* arrl); - -#endif /* KERNEL_INCLUDE_ARRAY_LIST_H_ */ diff --git a/kernel/src/ds/include/bin_tree.h b/kernel/src/ds/include/bin_tree.h deleted file mode 100644 index 7827df5c..00000000 --- a/kernel/src/ds/include/bin_tree.h +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************** - * bin_tree.h - * - * Author: Brandon Olivier // any collaborators, please add name - * - * Date: 19 April 2014 - * - * Purpose: Provide basis for b-trees for addresses - * - ********************************************************************/ - -#ifndef __b_tree_ -#define __b_tree_ - -typedef struct tree tree; -typedef struct node node; - -struct tree -{ - node *root; - int size; - int depth; -}; - -struct node -{ - node *left; - node *right; - void *address; -}; - -tree* init_tree(); -void llist_insert(tree* t, void *d); -void delete(tree *t, node *n); - -#endif diff --git a/kernel/src/ds/include/bitvector.h b/kernel/src/ds/include/bitvector.h deleted file mode 100644 index 6f5314b6..00000000 --- a/kernel/src/ds/include/bitvector.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef BITVECTOR_H_ -#define BITVECTOR_H_ - -#include "stdint.h" - -typedef struct bit_vector { - uint32_t length; - uint32_t *vector; - uint32_t actualLength; -} bit_vector; - -/* creates butvector of "size" number of bits */ -bit_vector *make_vector(uint32_t size); - -/* gets the value of bit number "index" */ -int32_t bv_get(uint32_t index, bit_vector* bit_vec); - -/* flips the bit number "index" */ -int32_t bv_toggle(uint32_t index, bit_vector* bit_vec); - -/* sets the value of bit number "index" to 1 (meaning taken) */ -int32_t bv_set(uint32_t index, bit_vector* bit_vec); - -/* sets the value of bit number "index" to 0 (meaning free) */ -int32_t bv_lower(uint32_t index, bit_vector* bit_vec); - -/* returns the first free index (first 0 in the vector) */ -int32_t bv_firstFree(bit_vector* bit_vec); - -/* frees the memory used by the vector */ -int32_t bv_free(bit_vector* bit_vec); - -/* returns whether the given index is free - Noel*/ -int32_t bv_isfree(uint32_t index, bit_vector* bit_vec); - -/* transfer a bit_vector to disk */ -int32_t bv_serialize(bit_vector* bit_vec, uint32_t start_block, uint32_t end_block); - -/* transfer a bit_vector from disk */ -int32_t bv_unserialize(bit_vector* bit_vec, uint32_t start_block, uint32_t end_block); - -#endif diff --git a/kernel/src/ds/include/hash_map.h b/kernel/src/ds/include/hash_map.h deleted file mode 100644 index f55b8a0b..00000000 --- a/kernel/src/ds/include/hash_map.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * hash_map.h - * - * Created on: Apr 18, 2015 - * Author: mwkurian - */ - -#ifndef KERNEL_INCLUDE_HASH_MAP_H_ -#define KERNEL_INCLUDE_HASH_MAP_H_ - -typedef struct { - void* data; - int flags; - long key; -} hmap_entry; - -typedef struct hmap_handle { - hmap_entry* table; - long size, count; -} hmap_handle; - -hmap_handle* hmap_create(); -hmap_handle* hmap_create_fixed(int startsize); -void* hmap_get(hmap_handle* hmap, unsigned long key); -void hmap_put(hmap_handle* hmap, unsigned long key, const void* data); -void* hmap_remove(hmap_handle* hmap, unsigned long key); -long hmap_count(hmap_handle* hash); -void hmap_free(hmap_handle* hash); - -#endif /* KERNEL_INCLUDE_HASH_MAP_H_ */ diff --git a/kernel/src/ds/include/linked_list.h b/kernel/src/ds/include/linked_list.h deleted file mode 100644 index 913cc18a..00000000 --- a/kernel/src/ds/include/linked_list.h +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************** - * linked_list.h - * - * Author: Brandon Olivier // any collaborators, please add name - * - * Date: 14 April 2014 - * - * Purpose: Provide linked lists for CourseOS - * This header provides function skeletons - * for linked_list.c - * - ********************************************************************/ - -#ifndef __llist_h -#define __llist_h - -typedef struct llist_node llist_node; - -struct llist_node { - llist_node *next; - void *data; -}; - -typedef struct { - llist_node *head; - llist_node *tail; - int count; -} llist_handle; - -/* prepend (because of speed) to the list. */ -llist_handle* llist_create(void *data); -llist_node* create_node(void *data); -void llist_free(llist_handle *l); -void llist_free_node(llist_node *node); -void llist_insert(llist_handle *l, void *data, int index); -void llist_enqueue(llist_handle *l, void *data); -void* llist_dequeue(llist_handle *l); -void llist_remove_at(llist_handle *l, int index); -void* llist_get_by_index(llist_handle *l, int index); -llist_node* llist_get_node(llist_handle *l, int index); -void llist_set_data(llist_node *l, void *data); -int llist_count(llist_handle *l); - -#endif diff --git a/kernel/src/ds/include/qstr.h b/kernel/src/ds/include/qstr.h index 40e7cdc4..52ac9bd6 100644 --- a/kernel/src/ds/include/qstr.h +++ b/kernel/src/ds/include/qstr.h @@ -10,7 +10,6 @@ // data is always a null. Therefore a pointer to a Qstr is *always* also a valid null // terminated string. - typedef struct Qstr { char * data; size_t length; @@ -35,4 +34,4 @@ bool qstr_eq_null_terminated(Qstr * left, char * right); // Hash the qstring void qstr_hash(Qstr * q); -#endif \ No newline at end of file +#endif diff --git a/kernel/src/ds/include/ring_buffer.h b/kernel/src/ds/include/ring_buffer.h deleted file mode 100644 index 7687d580..00000000 --- a/kernel/src/ds/include/ring_buffer.h +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************** - * ring_buffer.h - * - * Author: Brandon Olivier // any collaborators, please add name - * - * Date: 14 April 2014 - * - * Purpose: Provide ring buffer for CourseOS - * Data gets PUT in at the head index - * and it is GET at the tail index - * - ********************************************************************/ -#include "mem_alloc.h" - -typedef struct rb_node rb_node; -typedef struct ring_buffer ring_buffer; - -struct rb_node -{ - rb_node *next; - rb_node *prev; - void *data; -}; - -struct ring_buffer -{ - rb_node *head; - rb_node *tail; - int size; - int size_limit; -}; -ring_buffer* create(int size); -void free_ring_buffer(ring_buffer *r); - -int put(ring_buffer *r, void *data); -rb_node* get(ring_buffer *r); -void clear(ring_buffer *r); -ring_buffer* increase_size(ring_buffer *r, int by); // as in increase by x diff --git a/kernel/src/ds/include/vp_singly_linked_list.h b/kernel/src/ds/include/vp_singly_linked_list.h index 2fb42658..cdc1812e 100644 --- a/kernel/src/ds/include/vp_singly_linked_list.h +++ b/kernel/src/ds/include/vp_singly_linked_list.h @@ -4,6 +4,8 @@ #include +//TODO: Docs + struct VPSinglyLinkedListLink { struct VPSinglyLinkedListLink * next; void * data; diff --git a/kernel/src/vm/asid_allocator.c b/kernel/src/vm/asid_allocator.c index 78f77bd4..6ab1cd75 100644 --- a/kernel/src/vm/asid_allocator.c +++ b/kernel/src/vm/asid_allocator.c @@ -19,7 +19,7 @@ struct ASIDDescriptor asid_request_descriptor() { struct ASIDDescriptor res = (struct ASIDDescriptor) { .cache_iteration = cache_iteration, - .tlb_cache_id = tlb_cache_id, + .asid = tlb_cache_id, }; return res; @@ -27,8 +27,8 @@ struct ASIDDescriptor asid_request_descriptor() { // TODO: Ensure atomicity bool asid_check_and_update(struct ASIDDescriptor* desc) { - if(desc->cache_iteration != allocated_ids[desc->tlb_cache_id]) { - desc->cache_iteration = ++(allocated_ids[desc->tlb_cache_id]); + if(desc->cache_iteration != allocated_ids[desc->asid]) { + desc->cache_iteration = ++(allocated_ids[desc->asid]); return true; } diff --git a/kernel/src/vm/include/asid_allocator.h b/kernel/src/vm/include/asid_allocator.h index 0cb1723a..c674fb70 100644 --- a/kernel/src/vm/include/asid_allocator.h +++ b/kernel/src/vm/include/asid_allocator.h @@ -4,13 +4,28 @@ #include #include +/// We have made a special allocator to keep track of all the ASIDs used and to determine if we would need to flush +/// the caches upon a context switch. This should greatly reduce the amount of cache flushes needed and optimizes +/// the usage of ASIDs. +/// +/// Designed by: +/// Victor Roest +/// +/// Implemented by: +/// Jonathan Donszelmann +/// Victor Roest + + /// Terminology /// * asid: Hardware process id used for the pagetable cache. /// * cache_iteration: Which iteration of the cache we are on, determines if we should flush the cache on a process switch or not. /// * asid_descriptor: A pair of above two numbers. +/// Each ASID Descriptor has 2 fields: +/// asid: the actual ASID used for this process. +/// cache_iteration: On which iteration of the cache we are (used to determine if a cache flush is needed). struct ASIDDescriptor { - uint8_t tlb_cache_id; + uint8_t asid; uint8_t cache_iteration; }; @@ -44,4 +59,5 @@ bool asid_check_and_update(struct ASIDDescriptor* desc); * @param id the ASID to set. */ void asid_set(uint8_t id); + #endif diff --git a/kernel/src/vm/include/pmm.h b/kernel/src/vm/include/pmm.h index e0c1dd66..8bad407a 100644 --- a/kernel/src/vm/include/pmm.h +++ b/kernel/src/vm/include/pmm.h @@ -5,10 +5,10 @@ /// ## Description /// /// It can allocate pages of sizes: -/// * 16kb (L1 pagetables) -/// * 1kb (L2 pagetables) -/// * 4kb (Normal data pages) -/// All pages are aligned to their own size (i.e. The 16kb pages are 16k algined) +/// * 8KiB (L1 pagetables) +/// * 1KiB (L2 pagetables) +/// * 4KiB (Normal data pages) +/// All pages are aligned to their own size (i.e. The 8KiB pages are 8K algined) /// /// It stores all datastructures it uses in the same pages it allocates, /// and can therefore be used without any existing allocator allocating it's space. @@ -19,7 +19,7 @@ /// /// ## Overhead /// Since this allocator also has to store some datastructures in itself, it obviously has some overhead. -/// This overhead is 16kb for every 682 pages of size 16kb allocated. For 64 bit systems this ovehead would be larger. +/// This overhead is 16kb for every 512 pages of size 16kb allocated. For 64 bit systems this ovehead would be larger. /// /// ## Time complexity /// All operations performed on this allocator are O(1). They are in no way dependent on the size of memory. @@ -35,9 +35,6 @@ /// * bucket A piece of memory that can be referred to by a single 16kb page full of sliceinfo structs. /// The size of a bucket is therefore 16kb * 682b which is just over 10.5 megabytes /// * bucketinfo A slice containing an array of sliceinfo structs describing the contents of a bucket. -/// -/// The 1024 byte constant you might see popping up refers to the maximum number of 16 byte sliceinfo structs -/// can fit in a single 16kb slice. // TODO: Excluded regions. (for mmio for example) // TODO: detect memory size. @@ -50,7 +47,7 @@ #include "vm2.h" -/// The type of a 16kib Slice +/// The type of an 8KiB Slice enum MemoryType { L1PageTable, L2PageTable, @@ -58,34 +55,44 @@ enum MemoryType { BucketInfo, }; +/// A page with 4KiB of data. struct Page { uint8_t data[4096]; }; - +// Early definition so we can have the cyclic dependency between MemorySliceInfo and MemorySlice. union MemorySlice; +/// A MemorySliceInfo contains all information for describing an 8KiB Slice of memory. +/// These are allocated inside so-called BucketInfo Slices. struct MemorySliceInfo { union { uint32_t entry; struct { + /// The type of the memory this SliceInfo is describing. enum MemoryType type: 2; + + /// To determine how full this slice is if it describes a list of structures of less than 8KiB. + /// This is a BitVector where 1 means allocated and 0 means free. uint32_t filled: 8; - /// Filler bits + + /// Unused bits uint32_t unused: 22; }; }; + /// Pointers used to build a linked list of SliceInfos struct MemorySliceInfo * next; struct MemorySliceInfo * prev; + /// Pointer to the actual memory this SliceInfo is describing. union MemorySlice * slice; }; -#define SLICEINFO_PER_SLICE 512 -#define L2TABLES_PER_SLICE 8 -#define PAGES_PER_SLICE 2 +#define SLICEINFO_PER_SLICE 512 // sizeof(union MemorySlice) / sizeof(struct MemorySliceInfo) +#define L2TABLES_PER_SLICE 8 // sizeof(union MemorySlice) / sizeof(struct L2PageTable) +#define PAGES_PER_SLICE 2 // sizeof(union MemorySlice) / sizeof(struct Page) /// A Memory slice of 8KB, that's also 8kb aligned. /// A slice of 8kb can fit one of three things: @@ -101,13 +108,13 @@ union MemorySlice { struct MemorySliceInfo bucketinfo[SLICEINFO_PER_SLICE]; }; - +/// The main data struct for the PhysicalMemoryManager (PMM). This struct gets created when calling [pmm_init]. struct PhysicalMemoryManager { /// Two linked lists of unused and allocated slices, referred to by their SliceInfos. struct MemorySliceInfo * unused; struct MemorySliceInfo * allocated; - /// The partially allocated entries, these either exist or don't (NULL). + /// The partially allocated entries, these can be linked lists or NULL. struct MemorySliceInfo * l2ptPartialFree; struct MemorySliceInfo * pagePartialFree; @@ -120,17 +127,69 @@ struct PhysicalMemoryManager { struct PhysicalMemoryManager physicalMemoryManager; // Allocator specific operations + +/** + * Initializes the PMM over the specified memory region. + * + * This functions will also set the global [physicalMemoryManager] variable. + * + * @param start of the memory region to be managed by the PMM + * @param end of the memory region to be managed by the pmm + */ void pmm_init(size_t start, size_t end); + +/** + * Allocates a new MemorySliceInfo inside the PMM. + * For internal use only. + * @return a pointer to the allocated slice. + */ struct MemorySliceInfo * pmm_new_sliceinfo_slice(); + +/** + * This function uses pointer arithmetic to determine the associated [MemorySliceInfo] for a [MemorySlice]. + * Despite the fact that we store the allocated pages in a linked list this function is O(1) due to aforementioned, + * pointer arithmetic. + * @param slice The slice to get the sliceinfo for. + * @return The [MemorySliceInfo] pointer for the given [MemorySlice]. + */ struct MemorySliceInfo * pmm_get_sliceinfo_for_slice(union MemorySlice * slice); -// Element operations +/** + * Allocates an L1Pagetable. + * @return A pointer to said pagetable. + */ struct L1PageTable * pmm_allocate_l1_pagetable(); + +/** + * Frees an L1Pagetable. + * @param pt The [struct L1PageTable] to free. + */ void pmm_free_l1_pagetable(struct L1PageTable * pt); + +/** + * Allocates an L1Pagetable. + * @return A pointer to said pagetable. + */ struct L2PageTable * pmm_allocate_l2_pagetable(); + +/** + * Frees an L2Pagetable. + * @param pt The [struct L2PageTable] to free. + */ void pmm_free_l2_pagetable(struct L2PageTable * pt); + +/** + * Allocates a single 4KiB page. + * This is the function you want to use if you just want an area of memory. + * @return a pointer to the allocated [struct Page] + */ struct Page * pmm_allocate_page(); + +/** + * Frees a single 4KiB Page. + * @param p The [struct Page] to free. + */ void pmm_free_page(struct Page * p); #endif diff --git a/kernel/src/vm/include/vm2.h b/kernel/src/vm/include/vm2.h index f0b17834..51b3e052 100644 --- a/kernel/src/vm/include/vm2.h +++ b/kernel/src/vm/include/vm2.h @@ -8,21 +8,21 @@ /// Permissions for mapping a page enum Access { - KernelRO, // kernel ro, user no access - KernelRW, // kernel r/w, user no access + KernelRO, // kernel ro, user no access + KernelRW, // kernel rw, user no access - // Everything below this are accessible for the kernel and the user. - UserRO, // kernel r/w, user ro - UserRW, // kernel r/w user r/w + // Everything below this is accessible for the kernel and the user. + + UserRO, // kernel rw, user ro + UserRW, // kernel rw, user rw }; struct PagePermission { - enum Access access; - bool executable; + enum Access access; // Access permissions for this page as specified above + bool executable; // If the Page should be executable or not }; /// A L1PagetableEntry is an entry in the top level pagetable. -/// There is only one L1 pagetable and it is always located at address 0x4000. /// Relevant manual section: http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf /// * 6.1 /// * 6.5 (memory access control) @@ -159,7 +159,10 @@ typedef union L1PagetableEntry { } section; } L1PagetableEntry; -/// +/// An L2PagetableEntry is an entry inside the L2Pagetable. +/// A single entry can address 4KiB of memory. +/// You shouldn't need to make any entries manually as you can use the [vm2_allocate_page] function to allocate space +/// for you. typedef union L2PagetableEntry{ uint32_t entry; struct { @@ -280,8 +283,7 @@ struct L2PageTable { L2PagetableEntry entries[0x100]; }; -/// Should be called early, initiliazes everything vm2 needs -/// Actually enables the MMU and switches the kernel to higher half +/// Should be called early, initializes everything vm2 needs void vm2_start(); /// Takes an L1PageTableEntry containing a physical address (in .*.base_address) and maps it to a physical addres. @@ -295,10 +297,12 @@ bool vm2_l1_map_physical_to_virtual(struct L1PageTable * pt, union L1PagetableEn /// same n megabytes in which some mmio is located. Returns the virtual address. size_t vm2_map_peripheral(size_t physical, size_t n_mebibytes); -/// Maps a new 4kb page with kernel permissions at a virtual address. Returns a reference to this page -/// or null if unsuccesfull. The physical location of this page is determined by the pmm. -/// Since this allocates a 4kb page, it has to go through l2 pagetables. It will create the right -/// l2 pagetables as it needs. You can make the allocated page executable with the last parameter. +/// Maps a new 4KiB page with kernel permissions at a virtual address. Returns a reference to this page +/// or NULL if unsuccessful. The physical location of this page is determined by the [PMM](pmm.c). +/// Since this allocates a 4KiB page, it has to go through L2Pagetables. It will create the right +/// L2 pagetables as it needs. You can make the allocated page executable with the second to last parameter. +/// If you want to keep track of your allocated L2Pagetables you can pass a double pointer to `created_l2pt` +/// And the function will return the pointer to the allocated L2Pagetable in there (or NULL if no allocation happened). void *vm2_allocate_page(struct L1PageTable *l1pt, size_t virtual, bool remap, struct PagePermission perms, struct L2PageTable **created_l2pt); @@ -357,11 +361,12 @@ extern const size_t __KERNEL_VIRTUAL_OFFSET[]; #define PAGE_SIZE (4 * Kibibyte) +/* + * general purpose useful macros + */ -// general purpose useful macros - -// aligns an address to the *next* boundary of size n. -// only works where n is a power of 2 +/// aligns an address to the *next* boundary of size n. +/// only works where n is a power of 2 #define ALIGN(address, n) ((((size_t)(address) + (size_t)(n) - 1) & ~((size_t)(n) - 1))); /// The purpose of the Data Synchronization Barrier operation is to ensure that diff --git a/kernel/src/vm/test/test_tlb_id.c b/kernel/src/vm/test/test_asid.c similarity index 85% rename from kernel/src/vm/test/test_tlb_id.c rename to kernel/src/vm/test/test_asid.c index e103d5f4..2972a75e 100644 --- a/kernel/src/vm/test/test_tlb_id.c +++ b/kernel/src/vm/test/test_asid.c @@ -4,7 +4,7 @@ TEST_CREATE(tlb_simple, { struct ASIDDescriptor desc = asid_request_descriptor(); - uint32_t id = desc.tlb_cache_id; + uint32_t id = desc.asid; uint32_t iteration = desc.cache_iteration; if(asid_check_and_update(&desc)) { @@ -13,7 +13,7 @@ TEST_CREATE(tlb_simple, { ASSERT_EQ(iteration, desc.cache_iteration); } - ASSERT_EQ(id, desc.tlb_cache_id); + ASSERT_EQ(id, desc.asid); }) TEST_CREATE(tlb_intensive, { @@ -22,7 +22,7 @@ TEST_CREATE(tlb_intensive, { for(size_t i = 0; i < 666; i++) { struct ASIDDescriptor desc = asid_request_descriptor(); - uint32_t id = desc.tlb_cache_id; + uint32_t id = desc.asid; uint32_t iteration = desc.cache_iteration; if(asid_check_and_update(&desc)) { @@ -31,7 +31,7 @@ TEST_CREATE(tlb_intensive, { ASSERT_EQ(iteration, desc.cache_iteration); } - ASSERT_EQ(id, desc.tlb_cache_id); + ASSERT_EQ(id, desc.asid); } // Everything should have definitely been allocated by now. diff --git a/kernel/src/vm/test/test_pagealloc2.c b/kernel/src/vm/test/test_pagealloc2.c index 0363a99e..2eaee074 100644 --- a/kernel/src/vm/test/test_pagealloc2.c +++ b/kernel/src/vm/test/test_pagealloc2.c @@ -3,6 +3,7 @@ #include #include +// Warning: This method is O(n) and is thus quite slow on long lists. size_t listlength(struct MemorySliceInfo * start) { if (start == NULL) { return 0; @@ -16,8 +17,13 @@ size_t listlength(struct MemorySliceInfo * start) { return count; } -TEST_CREATE(test_memoryinfo_size, { +TEST_CREATE(test_pmm_constants, { ASSERT_EQ(sizeof(struct MemorySliceInfo), 16); + ASSERT_EQ(sizeof(union MemorySlice) / sizeof(struct MemorySliceInfo), SLICEINFO_PER_SLICE); + ASSERT_EQ(sizeof(union MemorySlice) / sizeof(struct L1PageTable), 1); + ASSERT_EQ(sizeof(union MemorySlice) / sizeof(struct L2PageTable), L2TABLES_PER_SLICE); + ASSERT_EQ(sizeof(union MemorySlice) / sizeof(struct Page), PAGES_PER_SLICE); + ASSERT_EQ(sizeof(struct Page), PAGE_SIZE); }) TEST_CREATE(test_allocate_pt, { diff --git a/kernel/src/vm/vas2.c b/kernel/src/vm/vas2.c index d313109c..9948ec93 100644 --- a/kernel/src/vm/vas2.c +++ b/kernel/src/vm/vas2.c @@ -22,10 +22,10 @@ struct vas2 * create_vas() { void switch_to_vas(struct vas2 * vas) { if(asid_check_and_update(&vas->tlbDescriptor)) { - vm2_flush_caches_of_ASID(vas->tlbDescriptor.tlb_cache_id); + vm2_flush_caches_of_ASID(vas->tlbDescriptor.asid); } - asid_set(vas->tlbDescriptor.tlb_cache_id); + asid_set(vas->tlbDescriptor.asid); vm2_set_user_pagetable(vas->l1PageTable); } From 473f75cede3e0add43c422257be39e5328bf7f54 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Tue, 10 Mar 2020 16:16:51 +0100 Subject: [PATCH 061/104] Added debug runconfig --- .idea/runConfigurations/debug.xml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .idea/runConfigurations/debug.xml diff --git a/.idea/runConfigurations/debug.xml b/.idea/runConfigurations/debug.xml new file mode 100644 index 00000000..b7959806 --- /dev/null +++ b/.idea/runConfigurations/debug.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file From 1c86ba3fbf69af95e893b6213c4a653f15e2a634 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Tue, 10 Mar 2020 17:45:51 +0100 Subject: [PATCH 062/104] Updated readme --- README.md | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1478faef..f469e2cb 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,67 @@ -course_os -========= +![course_os test suite](https://github.com/rellermeyer/course_os/workflows/course_os%20test%20suite/badge.svg) -CS 439 course OS +# Course OS + +This is a 'toy' kernel created by students from multiple universities. +Currently it is mainly developed by students of the TU Delft. +It is targeted to run on the raspberry pi zero, b+ and 2. + +# Building + +## Toolchain +To build the c toolchain for arm, and qemu version 4.20, run +``` +make requirements +``` +from the root project directory. We build qemu from source as this gives us better support +for attaching debuggers. Any up to date version of `qemu-system-arm` should work and if you already have this installed +through your package manager, just running +``` +make toolchain +``` +should be sufficient. + +## Running + +After you built the toolchain, the kernel can be ran with +``` +make run +``` +from the root project directory, or from the `kernel` directory. + +## Running tests + +To test the entire kernel, run + +``` +make test +``` +from the root project directory, or from the `kernel` directory. + + +## Debugging + +To debug the kernel, you have to perform two steps. First you have to build and start the kernel with +``` +make debug +``` + +from the `kernel` directory. This prepares qemu so it waits for a debugger to be attached. + +now, if you have `clion` you can run the supplied run configuration called `debug` which attaches a debugger, loads the sourcemap and runs the kernel. Now you can create breakpoints from within clion. + +If however you don't have `clion`, or want to use gdb from a terminal, one can run the following command: +```bash +gdb -ex "target remote localhost:1234" -ex "symbol-file kernel/build/kernel.sym" +``` + +# Editors + +## Opening the project in clion + +To open this project in clion, you can simply create a new `c` project with the supplied `CMakeLists.txt` file. This file can *not* be used to actually run the kernel but it does give clion the right instructions to make code completion etc. work. + +# Copyright Copyright (c) 2015, All rights reserved. From a3c4b3b41a0711de2dab4710d11ddd7c553910b1 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Tue, 10 Mar 2020 17:50:16 +0100 Subject: [PATCH 063/104] added cross compiler text --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f469e2cb..dd00da9f 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,14 @@ It is targeted to run on the raspberry pi zero, b+ and 2. # Building ## Toolchain -To build the c toolchain for arm, and qemu version 4.20, run + +To build and run the project, you will need a cross compiler. Since the kernel is made to run on ARM, the compiler has to output ARM instructions. + +To build the c toolchain for ARM, and `qemu-system-arm` version 4.20, run ``` make requirements ``` -from the root project directory. We build qemu from source as this gives us better support +from the root project directory. We build `qemu-system-arm` from source as this gives us better support for attaching debuggers. Any up to date version of `qemu-system-arm` should work and if you already have this installed through your package manager, just running ``` @@ -61,6 +64,8 @@ gdb -ex "target remote localhost:1234" -ex "symbol-file kernel/build/kernel.sym" To open this project in clion, you can simply create a new `c` project with the supplied `CMakeLists.txt` file. This file can *not* be used to actually run the kernel but it does give clion the right instructions to make code completion etc. work. + + # Copyright Copyright (c) 2015, From 72823e003f34f12a13b8cb2c57993b03d29909e4 Mon Sep 17 00:00:00 2001 From: Victor Date: Tue, 10 Mar 2020 18:01:02 +0100 Subject: [PATCH 064/104] Update README.md --- README.md | 53 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index dd00da9f..7f53bb10 100644 --- a/README.md +++ b/README.md @@ -4,39 +4,38 @@ This is a 'toy' kernel created by students from multiple universities. Currently it is mainly developed by students of the TU Delft. -It is targeted to run on the raspberry pi zero, b+ and 2. +It is targeted to run on the raspberry pi zero, b+ and 2. # Building ## Toolchain - To build and run the project, you will need a cross compiler. Since the kernel is made to run on ARM, the compiler has to output ARM instructions. To build the c toolchain for ARM, and `qemu-system-arm` version 4.20, run -``` +```bash make requirements -``` +``` from the root project directory. We build `qemu-system-arm` from source as this gives us better support for attaching debuggers. Any up to date version of `qemu-system-arm` should work and if you already have this installed -through your package manager, just running -``` +through your package manager, just running +```bash make toolchain ``` should be sufficient. ## Running -After you built the toolchain, the kernel can be ran with -``` +After you built the toolchain, the kernel can be ran with: +```bash make run -``` +``` from the root project directory, or from the `kernel` directory. ## Running tests -To test the entire kernel, run +To run the test suite for the kernel, execute: -``` +```bash make test ``` from the root project directory, or from the `kernel` directory. @@ -45,24 +44,44 @@ from the root project directory, or from the `kernel` directory. ## Debugging To debug the kernel, you have to perform two steps. First you have to build and start the kernel with -``` +```bash make debug ``` from the `kernel` directory. This prepares qemu so it waits for a debugger to be attached. -now, if you have `clion` you can run the supplied run configuration called `debug` which attaches a debugger, loads the sourcemap and runs the kernel. Now you can create breakpoints from within clion. +now, if you have CLion or VSCode you can run the supplied run configuration called `debug` which attaches a debugger, loads the sourcemap and runs the kernel. Now you can create breakpoints from within your IDE. -If however you don't have `clion`, or want to use gdb from a terminal, one can run the following command: +If however you don't have either of those IDEs, or want to use gdb from a terminal, one can run the following command: ```bash gdb -ex "target remote localhost:1234" -ex "symbol-file kernel/build/kernel.sym" ``` - + # Editors -## Opening the project in clion +## CLion + +To open this project in CLion, you can simply create a new `c` project with the supplied `CMakeLists.txt` file. This file can *not* be used to actually run the kernel but it does give clion the right instructions to make code completion etc. work. + +## Vim + CCLS + +To generate the required `compile_commands.json` so that CCLS correctly index the project. You have to do the following: + +First, generate the file using cmake: +```bash +cmake -H. -BDebug -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=YES +``` +Then, copy the file to the root folder: +```bash +cp Debug/compile_commands.json . +``` + +Afterwards you can remove the `Debug` folder with: +```bash +rm -rf Debug +``` -To open this project in clion, you can simply create a new `c` project with the supplied `CMakeLists.txt` file. This file can *not* be used to actually run the kernel but it does give clion the right instructions to make code completion etc. work. +Now Vim and CCLS will correctly know how to index the project. From ae8e991439b10be1d0193579120a523df970a9f4 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Tue, 10 Mar 2020 18:18:50 +0100 Subject: [PATCH 065/104] added kernel and test readmes --- README.md | 6 +++++ kernel/README.md | 24 +++++++++++++++++ kernel/src/test/README.md | 55 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 kernel/README.md create mode 100644 kernel/src/test/README.md diff --git a/README.md b/README.md index dd00da9f..8384864c 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ It is targeted to run on the raspberry pi zero, b+ and 2. # Building +[Build parameters](kernel/README.md) + ## Toolchain To build and run the project, you will need a cross compiler. Since the kernel is made to run on ARM, the compiler has to output ARM instructions. @@ -58,6 +60,10 @@ If however you don't have `clion`, or want to use gdb from a terminal, one can r gdb -ex "target remote localhost:1234" -ex "symbol-file kernel/build/kernel.sym" ``` +# Creating test + +To create tests for the kernel, please read [this](kernel/src/test/README.md) file. + # Editors ## Opening the project in clion diff --git a/kernel/README.md b/kernel/README.md new file mode 100644 index 00000000..a2433cb1 --- /dev/null +++ b/kernel/README.md @@ -0,0 +1,24 @@ +# Running the kernel + +The [makefile](Makefile) in this directory contains a number of configuration options. + +| Configuration opion | description | +| --- | --- | +| CFLAGS | Flags given to the c compiler | +| MEMORY | The amount of memory given to qemu. Until memory detection works, must be `1G` | +| DEFINITIONS | These are variables given to the c preprocessor. Options for these are listed below. | +| KERNEL_PARAMS | Currently not supported and outdated | +| SOURCEDIR | The name of the directory containing the sourcecode. | +| BUILDDIR | The name of the directory containing object files and binaries | +| INCLUDEDIR | Any directory in SOURCEDIR with this name, will be globally included in every c file. This means they can be included with `#include ` instead of `#include "something.h"`. | +| TEST_MAIN_FILE | The name of the file generated to contain all [tests](src/test/README.md). | +| CPU | The cpu type emulated by qemu. Supported cpu types are the `arm1176` and `cortex-a7`| + + +## Definitions + +| Definition | Action | +| --- | --- | +| ENABLE_TESTS | With this definition enabled, tests are compiled into the kernel | +| MEM_DEBUG | Every kernel heap memory allocation (kmalloc, kfree) will be logged at TRACE level. Tests will be checked for memory leaks. | +| LOG_LEVEL | Number between 1 and 4 describing the log level of the kernel. 1 means only `WARN` logs. 2 means also `INFO` logs. 3 means also `DEBUG` logs and 4 means also `TRACE` logs. \ No newline at end of file diff --git a/kernel/src/test/README.md b/kernel/src/test/README.md new file mode 100644 index 00000000..38691668 --- /dev/null +++ b/kernel/src/test/README.md @@ -0,0 +1,55 @@ +# Course OS Testing framework + +This directory is a custom-build testing framework by [Jonathan Dönszelmann](https://github.com/jonay2000/) and [Victor Roest](https://github.com/nullx76/). +To run tests, run + +```bash +make test +``` + + +## Creating tests. + +To create a new test, you can use the `TEST_CREATE` macro. It takes two arguments, a test name (which must be globally unique) and a block of code. +An example test would be + +```c +#include + +TEST_CREATE(test_one_plus_one, { + ASSERT_EQ(1 + 1, 2); +}) + +``` + +Tests created like this will be automatically detected and compiled into a file `src/test/test.c` which will then be compiled by gcc into the kernel. +Tests can be created in any file in any subdirectory of the src file. Tests will be randomized in order, and you cannot depend on the order in which tests are executed. +This has been done deliberately since we have had many problems with accidentally depending on this. + +When the MEM_DEBUG definition is given in the makefile (default for tests), the testing framework will record the allocator's number of bytes allocated before the test. If this number is not equal after the test, the test will fail. +When running with ENABLE_TESTS on, WARN macros will report file and line number, and DATA_ABORT handlers will panic and fail the test. + +## Assert macros + +There are a number of assertion macros included in `test.h`. + +They are listed here: + +| Macro name | usage | +| --- | --- | +| PASS() | Will immediately return and pass the test | +| FAIL() | Will immediately return and fail the test | +| ASSERT(expr) | Will fail the test if `expr` evaluates to zero/false | +| ASSERT_EQ(l, r) | Will fail the test if `l != r` | +| ASSERT_GT(l, r) | Will fail the test if `!(l >= r)` | +| ASSERT_GTEQ(l, r) | Will fail the test if `!(l > r)` | +| ASSERT_GT(l, r) | Will fail the test if `!(l >= r)` | +| ASSERT_LT(l, r) | Will fail the test if `!(l < r)` | +| ASSERT_LTEQ(l, r) | Will fail the test if `!(l <= r)` | +| ASSERT_NEQ(l, r) | Will fail the test if `l == r` | +| ASSERT_NOT_NULL(expr) | Will fail the test if `expr` evaluates to NULL | +| ASSERT_NULL(expr) | Will fail the test if `expr` doesn't evaluates to NULL | + + + + From 42e08e7d2b6b6cb065c6e723564b89fa471dd712 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Tue, 10 Mar 2020 18:22:36 +0100 Subject: [PATCH 066/104] added s to creating tests --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 91169af7..14438d39 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ If however you don't have either of those IDEs, or want to use gdb from a termin gdb -ex "target remote localhost:1234" -ex "symbol-file kernel/build/kernel.sym" ``` -# Creating test +# Creating tests To create tests for the kernel, please read [this](kernel/src/test/README.md) file. From f63f820d830f9ade872e0dae462ca792ef44dbb5 Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Wed, 11 Mar 2020 13:59:10 +0100 Subject: [PATCH 067/104] Started on finishing up refactor --- .vscode/settings.json | 4 +-- kernel/.gdbinit | 3 -- kernel/Makefile | 3 +- kernel/debug.sh | 1 - kernel/offset.sh | 7 ----- kernel/pi_light.c | 50 -------------------------------- kernel/src/klibc/include/klibc.h | 22 +++++++++++--- kernel/src/vm/README.md | 19 +++++++++++- 8 files changed, 38 insertions(+), 71 deletions(-) delete mode 100644 kernel/.gdbinit delete mode 100755 kernel/debug.sh delete mode 100755 kernel/offset.sh delete mode 100644 kernel/pi_light.c diff --git a/.vscode/settings.json b/.vscode/settings.json index 4a1c636a..2ee84431 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,5 @@ { "files.associations": { - "string.h": "c", - "stdint.h": "c", - "stdio.h": "c" + "*.h": "c" } } diff --git a/kernel/.gdbinit b/kernel/.gdbinit deleted file mode 100644 index 04a23b5e..00000000 --- a/kernel/.gdbinit +++ /dev/null @@ -1,3 +0,0 @@ -add-symbol-file kernel.elf 0x00010000 -add-symbol-file kernel.elf 0xf0000000 -target remote localhost:1234 diff --git a/kernel/Makefile b/kernel/Makefile index b30a950b..8e95a837 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -9,9 +9,8 @@ CFLAGS += -pipe -std=gnu99 -ffreestanding -Wall -Werror -g -O0 -mcpu=arm1176jzf- # variables to define in the preprocessor. MEMORY = 1G -DEFINITIONS = MEM_DEBUG +DEFINITIONS = MEM_DEBUG LOG_LEVEL=1 test: DEFINITIONS += ENABLE_TESTS # if we execute the test: rule, enable tests before recompiling -KERNEL_PARAMS = root=/dev/ram mem=$(MEMORY) SOURCEDIR = src BUILDDIR = build # every directory named `include` will have it's contents autoincluded diff --git a/kernel/debug.sh b/kernel/debug.sh deleted file mode 100755 index 638978e2..00000000 --- a/kernel/debug.sh +++ /dev/null @@ -1 +0,0 @@ -../toolchain/arm-none-eabi/bin/arm-none-eabi-gdb diff --git a/kernel/offset.sh b/kernel/offset.sh deleted file mode 100755 index e1dc9889..00000000 --- a/kernel/offset.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -if [ "$(uname)" == "Darwin" ]; then - printf "bootm 0x%X\n" $(($(stat -f%z "../u-boot/u-boot-$1/u-boot.bin") + 65536)) -else - printf "bootm 0x%X\n" $(($(stat -c%s "../u-boot/u-boot-$1/u-boot.bin") + 65536)) -fi diff --git a/kernel/pi_light.c b/kernel/pi_light.c deleted file mode 100644 index fb0b11e0..00000000 --- a/kernel/pi_light.c +++ /dev/null @@ -1,50 +0,0 @@ - -#include "mmap.h" -#include "src/klibc//include/stdint.h" -#include "pi_light.h" - -//#define GPIO_BASE 0x20200000 -//#define LED_PIN 16 - -volatile unsigned int* gpio; -void set_up_LED() -{ - //Initialize the LED - gpio = (unsigned int*) GPIO_BASE; - gpio[1] |= (1 << 18); -} -void light_on() -{ - gpio[10] = (1 << LED_PIN); -} -void light_off() -{ - gpio[7] = (1 << LED_PIN); -} -void on_off() -{ - light_on(); - for (int i = 0; i < 250000; ++i) - { - } - light_off(); - for (int i = 0; i < 250000; ++i) - { - } -} -void LED_alternate() -{ - - for (int i = 0; i < 20; ++i) - { - on_off(); - } -} -void LED_alternate2(int numFlash) -{ - //Flash the ACT LED numFlash number of times - for (int i = 0; i < numFlash; ++i) - { - on_off(); - } -} diff --git a/kernel/src/klibc/include/klibc.h b/kernel/src/klibc/include/klibc.h index f49f3ded..93300f78 100644 --- a/kernel/src/klibc/include/klibc.h +++ b/kernel/src/klibc/include/klibc.h @@ -62,23 +62,37 @@ uint32_t kmcheck(); unsigned int rand(); -#define LOG_LEVEL 4 +#define UNUSED1(z) (void)(z) +#define UNUSED2(y,z) UNUSED1(y),UNUSED1(z) +#define UNUSED3(x,y,z) UNUSED1(x),UNUSED2(y,z) +#define UNUSED4(b,x,y,z) UNUSED2(b,x),UNUSED2(y,z) +#define UNUSED5(a,b,x,y,z) UNUSED2(a,b),UNUSED3(x,y,z) + +#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5, N,...) N +#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1) + +#define ALL_UNUSED_IMPL_(nargs) UNUSED ## nargs +#define ALL_UNUSED_IMPL(nargs) ALL_UNUSED_IMPL_(nargs) +#define ALL_UNUSED(...) ALL_UNUSED_IMPL( VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__ ) + + +/// Log level is defined in the Makefile #if LOG_LEVEL > 3 #define TRACE(format, ...) kprintf("\e[90m[TRACE] " format "\e[0m\n", ##__VA_ARGS__) #else -#define TRACE(...) +#define TRACE(...) ALL_UNUSED(__VA_ARGS__) #endif #if LOG_LEVEL > 2 #define DEBUG(format, ...) kprintf("[DEBUG] \e[92m%s:%i\e[0m " format "\n", __FILE__, __LINE__, ##__VA_ARGS__) #else -#define DEBUG(...) +#define DEBUG(...) ALL_UNUSED(__VA_ARGS__) #endif #if LOG_LEVEL > 1 #define INFO(format, ...) kprintf("\e[96m[INFO]\e[0m " format "\n", ##__VA_ARGS__) #else -#define INFO(...) +#define INFO(...) ALL_UNUSED(__VA_ARGS__) #endif #if ENABLE_TESTS #define WARN(format, ...) kprintf("\e[38;5;208m[WARN] \e[38;5;208m%s:%i\e[38;5;208m" format "\e[0m\n", __FILE__, __LINE__, ##__VA_ARGS__); panic() diff --git a/kernel/src/vm/README.md b/kernel/src/vm/README.md index 50f1efe3..2f9b14d3 100644 --- a/kernel/src/vm/README.md +++ b/kernel/src/vm/README.md @@ -1,7 +1,24 @@ - # Virtual Memory ## Description +The virtual memory implemention consists of the following parts: +* [ASID Allocator](include/asid_allocator.h) +* [Physical Memory Manager (PMM)](include/pmm.h) +* [Virtual Address Space Manager (VAS)](include/vas2.h) +* [Generic Virtual Memory Manager (VM)](include/vm2.h) + + +The entry point for the virtual memory functionality is the [vm2_start()](vm2.c#L91) method. +It will first map all the physical to the 2 to 3GB region (only the first MiB of this was mapped by [startup.s](../common/startup.s)). +Afterwards it will remove the identity mapping done by that same file. After that is done the kernel is fully higher half. + +After mapping the physical memory it will initialize the PMM with the range of memory available, using the [pmm_int()](pmm.c#L17) function. +This function will then use the address space provided to build op all the structures needed for +physical page allocation. A general overview of how this is done and the methods available can be +found in its [header](include/pmm.h). + +And finally after the PMM has been initialized it will clear the pointer to the user pagetable (which was temporarily set). + ## Memory map From 7f8ff993b1dab975498cb377125c3cfa96bcc74a Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Wed, 11 Mar 2020 14:03:16 +0100 Subject: [PATCH 068/104] Finished up init blurb --- kernel/src/vm/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/src/vm/README.md b/kernel/src/vm/README.md index 2f9b14d3..4924193a 100644 --- a/kernel/src/vm/README.md +++ b/kernel/src/vm/README.md @@ -7,7 +7,7 @@ The virtual memory implemention consists of the following parts: * [Virtual Address Space Manager (VAS)](include/vas2.h) * [Generic Virtual Memory Manager (VM)](include/vm2.h) - +### Initialization The entry point for the virtual memory functionality is the [vm2_start()](vm2.c#L91) method. It will first map all the physical to the 2 to 3GB region (only the first MiB of this was mapped by [startup.s](../common/startup.s)). Afterwards it will remove the identity mapping done by that same file. After that is done the kernel is fully higher half. @@ -17,8 +17,8 @@ This function will then use the address space provided to build op all the struc physical page allocation. A general overview of how this is done and the methods available can be found in its [header](include/pmm.h). -And finally after the PMM has been initialized it will clear the pointer to the user pagetable (which was temporarily set). - +And finally after the PMM has been initialized it will clear the pointer to the user pagetable (which was temporarily set); +flush the caches and return. ## Memory map From b381485348696ebaaa32b5cb0c5f0869719b827c Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Wed, 11 Mar 2020 14:33:30 +0100 Subject: [PATCH 069/104] Copy of Final Really Final This time refactor (42).txt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jonathan Dönszelmann --- .gitignore | 1 + Doxyfile | 2538 +++++++++++++++++ README.md | 19 +- doxygen_styles/LICENSE | 24 + doxygen_styles/custom.css | 338 +++ doxygen_styles/custom_dark_theme.css | 425 +++ doxygen_styles/html_footer.html | 18 + doxygen_styles/html_header.html | 55 + kernel/Makefile | 2 +- kernel/src/common/include/interrupt.h | 22 +- kernel/src/common/start.c | 18 - .../drivers/chipset/bcm2835/include/bcm2835.h | 5 +- kernel/src/ds/include/u8_array_list.h | 4 - kernel/src/ds/include/vp_array_list.h | 3 +- kernel/src/ds/u8_array_list.c | 3 - kernel/src/ds/vp_array_list.c | 3 - 16 files changed, 3426 insertions(+), 52 deletions(-) create mode 100644 Doxyfile create mode 100644 doxygen_styles/LICENSE create mode 100644 doxygen_styles/custom.css create mode 100644 doxygen_styles/custom_dark_theme.css create mode 100644 doxygen_styles/html_footer.html create mode 100644 doxygen_styles/html_header.html diff --git a/.gitignore b/.gitignore index 779026fe..5d13af8b 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ build/ /cmake-build-*/ # Generated docs +/docs/ /html/ /latex/ /course_os_docs.pdf diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 00000000..79283e15 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,2538 @@ +# Doxyfile 1.8.15 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "Course OS" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Giving everyone a piece of the pi" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = YES + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = YES + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = kernel/src/ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = YES + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is +# Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 4 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = YES + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = YES + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = YES + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# The default value is: NO. + +WARN_NO_PARAMDOC = YES + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = README.md kernel/src/ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.s \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = README.md + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = docs + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = "doxygen_styles/html_header.html" + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = "doxygen_styles/html_footer.html" + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = "doxygen_styles/custom.css" \ + "doxygen_styles/custom_dark_theme.css" + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via Javascript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have Javascript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = YES + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: https://developer.apple.com/xcode/), introduced with OSX +# 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 350 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/ + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , / + + + + + + diff --git a/doxygen_styles/html_header.html b/doxygen_styles/html_header.html new file mode 100644 index 00000000..7588e63b --- /dev/null +++ b/doxygen_styles/html_header.html @@ -0,0 +1,55 @@ + + + + + + + + $projectname: $title + $title + + + + $treeview + $search + $mathjax + + $extrastylesheet + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + +
+
$projectname +  $projectnumber +
+
$projectbrief
+
+
$projectbrief
+
$searchbox
+
+ + \ No newline at end of file diff --git a/kernel/Makefile b/kernel/Makefile index 8e95a837..863793d9 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -9,7 +9,7 @@ CFLAGS += -pipe -std=gnu99 -ffreestanding -Wall -Werror -g -O0 -mcpu=arm1176jzf- # variables to define in the preprocessor. MEMORY = 1G -DEFINITIONS = MEM_DEBUG LOG_LEVEL=1 +DEFINITIONS = MEM_DEBUG LOG_LEVEL=4 test: DEFINITIONS += ENABLE_TESTS # if we execute the test: rule, enable tests before recompiling SOURCEDIR = src BUILDDIR = build diff --git a/kernel/src/common/include/interrupt.h b/kernel/src/common/include/interrupt.h index 75286816..a091c88f 100644 --- a/kernel/src/common/include/interrupt.h +++ b/kernel/src/common/include/interrupt.h @@ -8,15 +8,17 @@ * * A bit of background: * - The ARM architecture has 7 modes of operation: - * + USR - user mode - * + FIQ - processing "fast" interrupts - * + IRQ - processing "normal" interrupts - * + SVC - proctected mode for OS - * + UND - processing an undefined instruction exception - * + SYS - also protecteed mode for OS --if anyone wants to clarify, feel free-- - * These modes can be entered or exited by modifying the CPSR (status register) + * + USR - User mode + * + FIQ - processing "fast" interrupts + * + IRQ - processing "normal" interrupts + * + SVC - Supervisor/Kernel mode + * + UND - processing an undefined instruction exception + * + SYS - Privileged mode but retains the registers of the user mode, used for handling interrupts in a faster way. + * These modes can be entered or exited by modifying the CPSR (status register) * - * exceptions (e.g. software interrupts, system calls, etc.), Interrupts (IRQ, FIQ) + * All modes have their own stack which can be found in [stacks.s](stacks.s] + * + * Exceptions (e.g. software interrupts, system calls, etc.), Interrupts (IRQ, FIQ) * trigger the core to switch to an appropriate mode and the pc to jump to a * preset address (somewhere in the vector table) for a branch instruction to the * proper handler. @@ -95,8 +97,8 @@ void SemihostingCall(enum SemihostingSWI mode); void SemihostingOSExit(uint8_t code) __attribute__ ((noreturn));; typedef enum { - IRQ, // (this is bit 0x8 on the CPSR) - FIQ, // (this is bit 0x4 on the CPSR) + IRQ, // (this is bit 0x8 on the CPSR) + FIQ, // (this is bit 0x4 on the CPSR) BOTH } InterruptType; diff --git a/kernel/src/common/start.c b/kernel/src/common/start.c index 84bdbc20..462cc1d3 100644 --- a/kernel/src/common/start.c +++ b/kernel/src/common/start.c @@ -1,21 +1,3 @@ -/* - * A bit of background: - * - The ARM architecture has 7 modes of operation: - * + USR - user mode - * + FIQ - processing "fast" interrupts - * + IRQ - processing "normal" interrupts - * + SVC - proctected mode for OS - * + UND - processing an undefined instruction exception - * + SYS - also protecteed mode for OS --if anyone wants to clarify, feel free-- - * - * - These modes can be entered or exited by modifying the CPSR (status register), first 5 bits - * + 0b10000 = user mode - * + 0b10001 = FIQ (fast interrupt) mode - * + 0b10010 = IRQ (normal interrupt) mode - * + 0b10011 = SVC (supervisor, or, OS) mode - * (others...) - */ - #include #include #include diff --git a/kernel/src/drivers/chipset/bcm2835/include/bcm2835.h b/kernel/src/drivers/chipset/bcm2835/include/bcm2835.h index fd40910d..35a61b75 100644 --- a/kernel/src/drivers/chipset/bcm2835/include/bcm2835.h +++ b/kernel/src/drivers/chipset/bcm2835/include/bcm2835.h @@ -1,4 +1,3 @@ - - - +// TODO: Implement. +// We want to have bcm2835 for being able to boot on an actual Pi Zero/B+ diff --git a/kernel/src/ds/include/u8_array_list.h b/kernel/src/ds/include/u8_array_list.h index cef4f64d..85a02a01 100644 --- a/kernel/src/ds/include/u8_array_list.h +++ b/kernel/src/ds/include/u8_array_list.h @@ -1,7 +1,3 @@ -// -// Created by victor on 2/21/20. -// - #ifndef U8ARRAY_LIST_H #define U8ARRAY_LIST_H diff --git a/kernel/src/ds/include/vp_array_list.h b/kernel/src/ds/include/vp_array_list.h index fbe9b3a4..227ebdb2 100644 --- a/kernel/src/ds/include/vp_array_list.h +++ b/kernel/src/ds/include/vp_array_list.h @@ -32,4 +32,5 @@ void vpa_resize(VPArrayList * list, uint32_t new_size, FreeFunc freeFunc); void * vpa_remove(VPArrayList * list, size_t index); -#endif \ No newline at end of file +#endif + diff --git a/kernel/src/ds/u8_array_list.c b/kernel/src/ds/u8_array_list.c index 55bdc6e2..66fe3720 100644 --- a/kernel/src/ds/u8_array_list.c +++ b/kernel/src/ds/u8_array_list.c @@ -1,6 +1,3 @@ -// -// Created by victor on 2/21/20. -// #include #include #include diff --git a/kernel/src/ds/vp_array_list.c b/kernel/src/ds/vp_array_list.c index 52410ae3..fe311fc3 100644 --- a/kernel/src/ds/vp_array_list.c +++ b/kernel/src/ds/vp_array_list.c @@ -1,6 +1,3 @@ -// -// Created by victor on 2/21/20. -// #include #include #include From 3cf6f1e73787eb91758cbe06286a6ee0a3a2bd0c Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Wed, 11 Mar 2020 14:43:00 +0100 Subject: [PATCH 070/104] makes header files show up as c files in stead of cpp --- .gitattributes | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..4f37515b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,10 @@ +# Sources +*.c text diff=c +*.cc text diff=cpp +*.cxx text diff=cpp +*.cpp text diff=cpp +*.c++ text diff=cpp +*.hpp text diff=cpp +*.h text diff=c +*.h++ text diff=cpp +*.hh text diff=cpp From 9c2c771b979454d28a5192928048b9a9ebd77084 Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Wed, 11 Mar 2020 14:44:03 +0100 Subject: [PATCH 071/104] remove cpp stuff --- .gitattributes | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.gitattributes b/.gitattributes index 4f37515b..90d0c6d5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,10 +1,3 @@ # Sources *.c text diff=c -*.cc text diff=cpp -*.cxx text diff=cpp -*.cpp text diff=cpp -*.c++ text diff=cpp -*.hpp text diff=cpp *.h text diff=c -*.h++ text diff=cpp -*.hh text diff=cpp From 081d2576cdcc5b1abbd3750cfcfa4710becaaa6e Mon Sep 17 00:00:00 2001 From: jonay2000 Date: Wed, 11 Mar 2020 15:44:11 +0100 Subject: [PATCH 072/104] remove doxyfile --- doxyfile | 2303 ------------------------------------------------------ 1 file changed, 2303 deletions(-) delete mode 100644 doxyfile diff --git a/doxyfile b/doxyfile deleted file mode 100644 index 706263ce..00000000 --- a/doxyfile +++ /dev/null @@ -1,2303 +0,0 @@ -# Doxyfile 1.8.6 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. -# -# All text after a double hash (##) is considered a comment and is placed in -# front of the TAG it is preceding. -# -# All text after a single hash (#) is considered a comment and will be ignored. -# The format is: -# TAG = value [value, ...] -# For lists, items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (\" \"). - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all text -# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv -# for the list of possible encodings. -# The default value is: UTF-8. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by -# double-quotes, unless you are using Doxywizard) that should identify the -# project for which the documentation is generated. This name is used in the -# title of most generated pages and in a few other places. -# The default value is: My Project. - -PROJECT_NAME = "Course OS" - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. This -# could be handy for archiving the generated documentation or if some version -# control system is used. - -PROJECT_NUMBER = - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer a -# quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = "Giving everyone a piece of the pi" - -# With the PROJECT_LOGO tag one can specify an logo or icon that is included in -# the documentation. The maximum height of the logo should not exceed 55 pixels -# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo -# to the output directory. - -PROJECT_LOGO = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path -# into which the generated documentation will be written. If a relative path is -# entered, it will be relative to the location where doxygen was started. If -# left blank the current directory will be used. - -OUTPUT_DIRECTORY = - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this -# option can be useful when feeding doxygen a huge amount of source files, where -# putting all generated files in the same directory would otherwise causes -# performance problems for the file system. -# The default value is: NO. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. -# The default value is: English. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member -# descriptions after the members that are listed in the file and class -# documentation (similar to Javadoc). Set to NO to disable this. -# The default value is: YES. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief -# description of a member or function before the detailed description -# -# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. -# The default value is: YES. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator that is -# used to form the text in various listings. Each string in this list, if found -# as the leading text of the brief description, will be stripped from the text -# and the result, after processing the whole list, is used as the annotated -# text. Otherwise, the brief description is used as-is. If left blank, the -# following values are used ($name is automatically replaced with the name of -# the entity):The $name class, The $name widget, The $name file, is, provides, -# specifies, contains, represents, a, an and the. - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# doxygen will generate a detailed section even if there is only a brief -# description. -# The default value is: NO. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. -# The default value is: NO. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path -# before files name in the file list and in the header files. If set to NO the -# shortest path that makes the file name unique will be used -# The default value is: YES. - -FULL_PATH_NAMES = YES - -# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. -# Stripping is only done if one of the specified strings matches the left-hand -# part of the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the path to -# strip. -# -# Note that you can specify absolute paths here, but also relative paths, which -# will be relative from the directory where doxygen is started. -# This tag requires that the tag FULL_PATH_NAMES is set to YES. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the -# path mentioned in the documentation of a class, which tells the reader which -# header file to include in order to use a class. If left blank only the name of -# the header file containing the class definition is used. Otherwise one should -# specify the list of include paths that are normally passed to the compiler -# using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but -# less readable) file names. This can be useful is your file systems doesn't -# support long names like on DOS, Mac, or CD-ROM. -# The default value is: NO. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the -# first line (until the first dot) of a Javadoc-style comment as the brief -# description. If set to NO, the Javadoc-style will behave just like regular Qt- -# style comments (thus requiring an explicit @brief command for a brief -# description.) -# The default value is: NO. - -JAVADOC_AUTOBRIEF = NO - -# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first -# line (until the first dot) of a Qt-style comment as the brief description. If -# set to NO, the Qt-style will behave just like regular Qt-style comments (thus -# requiring an explicit \brief command for a brief description.) -# The default value is: NO. - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a -# multi-line C++ special comment block (i.e. a block of //! or /// comments) as -# a brief description. This used to be the default behavior. The new default is -# to treat a multi-line C++ comment block as a detailed description. Set this -# tag to YES if you prefer the old behavior instead. -# -# Note that setting this tag to YES also means that rational rose comments are -# not recognized any more. -# The default value is: NO. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the -# documentation from any documented member that it re-implements. -# The default value is: YES. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a -# new page for each member. If set to NO, the documentation of a member will be -# part of the file/class/namespace that contains it. -# The default value is: NO. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen -# uses this value to replace tabs by spaces in code fragments. -# Minimum value: 1, maximum value: 16, default value: 4. - -TAB_SIZE = 4 - -# This tag can be used to specify a number of aliases that act as commands in -# the documentation. An alias has the form: -# name=value -# For example adding -# "sideeffect=@par Side Effects:\n" -# will allow you to put the command \sideeffect (or @sideeffect) in the -# documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines. - -ALIASES = - -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources -# only. Doxygen will then generate output that is more tailored for C. For -# instance, some of the names that are used will be different. The list of all -# members will be omitted, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or -# Python sources only. Doxygen will then generate output that is more tailored -# for that language. For instance, namespaces will be presented as packages, -# qualified scopes will look different, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources. Doxygen will then generate output that is tailored for Fortran. -# The default value is: NO. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for VHDL. -# The default value is: NO. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given -# extension. Doxygen has a built-in mapping, but you can override or extend it -# using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. -# -# Note For files without extension you can use no_extension as a placeholder. -# -# Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments -# according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you can -# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in -# case of backward compatibilities issues. -# The default value is: YES. - -MARKDOWN_SUPPORT = YES - -# When enabled doxygen tries to link words that correspond to documented -# classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by by putting a % sign in front of the word -# or globally by setting AUTOLINK_SUPPORT to NO. -# The default value is: YES. - -AUTOLINK_SUPPORT = YES - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should set this -# tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. -# The default value is: NO. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. -# The default value is: NO. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen -# will parse them like normal C++ but will assume all classes use public instead -# of private inheritance when no explicit protection keyword is present. -# The default value is: NO. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate -# getter and setter methods for a property. Setting this option to YES will make -# doxygen to replace the get and set methods by a property in the documentation. -# This will only work if the methods are indeed getting or setting a simple -# type. If this is not the case, or you want to show the methods anyway, you -# should set this option to NO. -# The default value is: YES. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. -# The default value is: NO. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES to allow class member groups of the same type -# (for instance a group of public functions) to be put as a subgroup of that -# type (e.g. under the Public Functions section). Set it to NO to prevent -# subgrouping. Alternatively, this can be done per class using the -# \nosubgrouping command. -# The default value is: YES. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions -# are shown inside the group in which they are included (e.g. using \ingroup) -# instead of on a separate page (for HTML and Man pages) or section (for LaTeX -# and RTF). -# -# Note that this feature does not work in combination with -# SEPARATE_MEMBER_PAGES. -# The default value is: NO. - -INLINE_GROUPED_CLASSES = NO - -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions -# with only public data fields or simple typedef fields will be shown inline in -# the documentation of the scope in which they are defined (i.e. file, -# namespace, or group documentation), provided this scope is documented. If set -# to NO, structs, classes, and unions are shown on a separate page (for HTML and -# Man pages) or section (for LaTeX and RTF). -# The default value is: NO. - -INLINE_SIMPLE_STRUCTS = NO - -# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or -# enum is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically be -# useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. -# The default value is: NO. - -TYPEDEF_HIDES_STRUCT = NO - -# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This -# cache is used to resolve symbols given their name and scope. Since this can be -# an expensive process and often the same symbol appears multiple times in the -# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small -# doxygen will become slower. If the cache is too large, memory is wasted. The -# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range -# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 -# symbols. At the end of a run doxygen will report the cache usage and suggest -# the optimal cache size from a speed point of view. -# Minimum value: 0, maximum value: 9, default value: 0. - -LOOKUP_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. Private -# class members and static file members will be hidden unless the -# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. -# Note: This will also disable the warnings about undocumented members that are -# normally produced when WARNINGS is set to YES. -# The default value is: NO. - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will -# be included in the documentation. -# The default value is: NO. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal -# scope will be included in the documentation. -# The default value is: NO. - -EXTRACT_PACKAGE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file will be -# included in the documentation. -# The default value is: NO. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO -# only classes defined in header files are included. Does not have any effect -# for Java sources. -# The default value is: YES. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local methods, -# which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO only methods in the interface are -# included. -# The default value is: NO. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base name of -# the file that contains the anonymous namespace. By default anonymous namespace -# are hidden. -# The default value is: NO. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all -# undocumented members inside documented classes or files. If set to NO these -# members will be included in the various overviews, but no documentation -# section is generated. This option has no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. If set -# to NO these classes will be included in the various overviews. This option has -# no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO these declarations will be -# included in the documentation. -# The default value is: NO. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO these -# blocks will be appended to the function's detailed documentation block. -# The default value is: NO. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation that is typed after a -# \internal command is included. If the tag is set to NO then the documentation -# will be excluded. Set it to YES to include the internal documentation. -# The default value is: NO. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. -# The default value is: system dependent. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES the -# scope will be hidden. -# The default value is: NO. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of -# the files that are included by a file in the documentation of that file. -# The default value is: YES. - -SHOW_INCLUDE_FILES = YES - -# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each -# grouped member an include statement to the documentation, telling the reader -# which file to include in order to use the member. -# The default value is: NO. - -SHOW_GROUPED_MEMB_INC = NO - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include -# files with double quotes in the documentation rather than with sharp brackets. -# The default value is: NO. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the -# documentation for inline members. -# The default value is: YES. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the -# (detailed) documentation of file and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. -# The default value is: YES. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief -# descriptions of file, namespace and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. Note that -# this will also influence the order of the classes in the class list. -# The default value is: NO. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the -# (brief and detailed) documentation of class members so that constructors and -# destructors are listed first. If set to NO the constructors will appear in the -# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. -# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief -# member documentation. -# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting -# detailed member documentation. -# The default value is: NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy -# of group names into alphabetical order. If set to NO the group names will -# appear in their defined order. -# The default value is: NO. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by -# fully-qualified names, including namespaces. If set to NO, the class list will -# be sorted only by class name, not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the alphabetical -# list. -# The default value is: NO. - -SORT_BY_SCOPE_NAME = NO - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper -# type resolution of all parameters of a function it will reject a match between -# the prototype and the implementation of a member function even if there is -# only one candidate or it is obvious which candidate to choose by doing a -# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still -# accept a match between prototype and implementation in such cases. -# The default value is: NO. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the -# todo list. This list is created by putting \todo commands in the -# documentation. -# The default value is: YES. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the -# test list. This list is created by putting \test commands in the -# documentation. -# The default value is: YES. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug -# list. This list is created by putting \bug commands in the documentation. -# The default value is: YES. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) -# the deprecated list. This list is created by putting \deprecated commands in -# the documentation. -# The default value is: YES. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional documentation -# sections, marked by \if ... \endif and \cond -# ... \endcond blocks. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the -# initial value of a variable or macro / define can have for it to appear in the -# documentation. If the initializer consists of more lines than specified here -# it will be hidden. Use a value of 0 to hide initializers completely. The -# appearance of the value of individual variables and macros / defines can be -# controlled using \showinitializer or \hideinitializer command in the -# documentation regardless of this setting. -# Minimum value: 0, maximum value: 10000, default value: 30. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES the list -# will mention the files that were used to generate the documentation. -# The default value is: YES. - -SHOW_USED_FILES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This -# will remove the Files entry from the Quick Index and from the Folder Tree View -# (if specified). -# The default value is: YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces -# page. This will remove the Namespaces entry from the Quick Index and from the -# Folder Tree View (if specified). -# The default value is: YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command command input-file, where command is the value of the -# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided -# by doxygen. Whatever the program writes to standard output is used as the file -# version. For an example see the documentation. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. You can -# optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. -# -# Note that if you run doxygen from a directory containing a file called -# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE -# tag is left empty. - -LAYOUT_FILE = - -# The CITE_BIB_FILES tag can be used to specify one or more bib files containing -# the reference definitions. This must be a list of .bib files. The .bib -# extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. -# For LaTeX the style of the bibliography can be controlled using -# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the -# search path. Do not use file names with spaces, bibtex cannot handle them. See -# also \cite for info how to create references. - -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# Configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated to -# standard output by doxygen. If QUIET is set to YES this implies that the -# messages are off. -# The default value is: NO. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES -# this implies that the warnings are on. -# -# Tip: Turn warnings on while writing the documentation. -# The default value is: YES. - -WARNINGS = YES - -# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate -# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag -# will automatically be disabled. -# The default value is: YES. - -WARN_IF_UNDOCUMENTED = YES - -# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. -# The default value is: YES. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that -# are documented, but have no documentation for their parameters or return -# value. If set to NO doxygen will only warn about wrong or incomplete parameter -# documentation, but not about the absence of documentation. -# The default value is: NO. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that doxygen -# can produce. The string should contain the $file, $line, and $text tags, which -# will be replaced by the file and line number from which the warning originated -# and the warning text. Optionally the format may contain $version, which will -# be replaced by the version of the file (if it could be obtained via -# FILE_VERSION_FILTER) -# The default value is: $file:$line: $text. - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning and error -# messages should be written. If left blank the output is written to standard -# error (stderr). - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# Configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag is used to specify the files and/or directories that contain -# documented source files. You may enter file names like myfile.cpp or -# directories like /usr/src/myproject. Separate the files or directories with -# spaces. -# Note: If this tag is empty the current directory is searched. - -INPUT = - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses -# libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of -# possible encodings. -# The default value is: UTF-8. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank the -# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, -# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, -# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, -# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, -# *.qsf, *.as and *.js. - -FILE_PATTERNS = - -# The RECURSIVE tag can be used to specify whether or not subdirectories should -# be searched for input files as well. -# The default value is: NO. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should be -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. -# -# Note that relative paths are relative to the directory from which doxygen is -# run. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. -# The default value is: NO. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories for example use the pattern */test/* - -EXCLUDE_PATTERNS = */u-boot/* */toolchain/* */qemu/* - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or directories -# that contain example code fragments that are included (see the \include -# command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank all -# files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude commands -# irrespective of the value of the RECURSIVE tag. -# The default value is: NO. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or directories -# that contain images that are to be included in the documentation (see the -# \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command: -# -# -# -# where is the value of the INPUT_FILTER tag, and is the -# name of an input file. Doxygen will then use the output that the filter -# program writes to standard output. If FILTER_PATTERNS is specified, this tag -# will be ignored. -# -# Note that the filter must not add or remove lines; it is applied before the -# code is scanned, but not when the output code is generated. If lines are added -# or removed, the anchors will not be placed correctly. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: pattern=filter -# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how -# filters are used. If the FILTER_PATTERNS tag is empty or if none of the -# patterns match the file name, INPUT_FILTER is applied. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER ) will also be used to filter the input files that are used for -# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). -# The default value is: NO. - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and -# it is also possible to disable source filtering for a specific pattern using -# *.ext= (so without naming a filter). -# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. - -FILTER_SOURCE_PATTERNS = - -# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that -# is part of the input, its contents will be placed on the main page -# (index.html). This can be useful if you have a project on for instance GitHub -# and want to reuse the introduction page also for the doxygen output. - -USE_MDFILE_AS_MAINPAGE = - -#--------------------------------------------------------------------------- -# Configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will be -# generated. Documented entities will be cross-referenced with these sources. -# -# Note: To get rid of all source code in the generated output, make sure that -# also VERBATIM_HEADERS is set to NO. -# The default value is: NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. -# The default value is: NO. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any -# special comment blocks from generated source code fragments. Normal C, C++ and -# Fortran comments will always remain visible. -# The default value is: YES. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. -# The default value is: NO. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES then for each documented function -# all documented entities called/used by that function will be listed. -# The default value is: NO. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES, then the hyperlinks from functions in REFERENCES_RELATION and -# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will -# link to the documentation. -# The default value is: YES. - -REFERENCES_LINK_SOURCE = YES - -# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the -# source code will show a tooltip with additional information such as prototype, -# brief description and links to the definition and documentation. Since this -# will make the HTML file larger and loading of large files a bit slower, you -# can opt to disable this feature. -# The default value is: YES. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -SOURCE_TOOLTIPS = YES - -# If the USE_HTAGS tag is set to YES then the references to source code will -# point to the HTML generated by the htags(1) tool instead of doxygen built-in -# source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version -# 4.8.6 or higher. -# -# To use it do the following: -# - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file -# - Make sure the INPUT points to the root of the source tree -# - Run doxygen as normal -# -# Doxygen will invoke htags (and that will in turn invoke gtags), so these -# tools must be available from the command line (i.e. in the search path). -# -# The result: instead of the source browser generated by doxygen, the links to -# source code will now point to the output of htags. -# The default value is: NO. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a -# verbatim copy of the header file for each class for which an include is -# specified. Set to NO to disable this. -# See also: Section \class. -# The default value is: YES. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# Configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all -# compounds will be generated. Enable this if the project contains a lot of -# classes, structs, unions or interfaces. -# The default value is: YES. - -ALPHABETICAL_INDEX = YES - -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output -# The default value is: YES. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a -# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of -# it. -# The default directory is: html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each -# generated HTML page (for example: .htm, .php, .asp). -# The default value is: .html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a user-defined HTML header file for -# each generated HTML page. If the tag is left blank doxygen will generate a -# standard header. -# -# To get valid HTML the header file that includes any scripts and style sheets -# that doxygen needs, which is dependent on the configuration options used (e.g. -# the setting GENERATE_TREEVIEW). It is highly recommended to start with a -# default header using -# doxygen -w html new_header.html new_footer.html new_stylesheet.css -# YourConfigFile -# and then modify the file new_header.html. See also section "Doxygen usage" -# for information on how to generate the default header that doxygen normally -# uses. -# Note: The header is subject to change so you typically have to regenerate the -# default header when upgrading to a newer version of doxygen. For a description -# of the possible markers and block names see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each -# generated HTML page. If the tag is left blank doxygen will generate a standard -# footer. See HTML_HEADER for more information on how to generate a default -# footer and what special commands can be used inside the footer. See also -# section "Doxygen usage" for information on how to generate the default footer -# that doxygen normally uses. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style -# sheet that is used by each HTML page. It can be used to fine-tune the look of -# the HTML output. If left blank doxygen will generate a default style sheet. -# See also section "Doxygen usage" for information on how to generate the style -# sheet that doxygen normally uses. -# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as -# it is more robust and this tag (HTML_STYLESHEET) will in the future become -# obsolete. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_STYLESHEET = - -# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- -# defined cascading style sheet that is included after the standard style sheets -# created by doxygen. Using this option one can overrule certain style aspects. -# This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. -# Doxygen will copy the style sheet file to the output directory. For an example -# see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_STYLESHEET = - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that the -# files will be copied as-is; there are no commands or markers available. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the stylesheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value -# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 -# purple, and 360 is red again. -# Minimum value: 0, maximum value: 359, default value: 220. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A -# value of 255 will produce the most vivid colors. -# Minimum value: 0, maximum value: 255, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_SAT = 100 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the -# luminance component of the colors in the HTML output. Values below 100 -# gradually make the output lighter, whereas values above 100 make the output -# darker. The value divided by 100 is the actual gamma applied, so 80 represents -# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not -# change the gamma. -# Minimum value: 40, maximum value: 240, default value: 80. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_GAMMA = 80 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_DYNAMIC_SECTIONS = NO - -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries -# shown in the various tree structured indices initially; the user can expand -# and collapse entries dynamically later on. Doxygen will expand the tree to -# such a level that at most the specified number of entries are visible (unless -# a fully collapsed tree already exceeds this amount). So setting the number of -# entries 1 will produce a full collapsed tree by default. 0 is a special value -# representing an infinite number of entries and will result in a full expanded -# tree by default. -# Minimum value: 0, maximum value: 9999, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_INDEX_NUM_ENTRIES = 100 - -# If the GENERATE_DOCSET tag is set to YES, additional index files will be -# generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with -# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_DOCSET = NO - -# This tag determines the name of the docset feed. A documentation feed provides -# an umbrella under which multiple documentation sets from a single provider -# (such as a company or product suite) can be grouped. -# The default value is: Doxygen generated docs. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# This tag specifies a string that should uniquely identify the documentation -# set bundle. This should be a reverse domain-name style string, e.g. -# com.mycompany.MyDocSet. Doxygen will append .docset to the name. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. -# The default value is: org.doxygen.Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. -# The default value is: Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three -# additional HTML index files: index.hhp, index.hhc, and index.hhk. The -# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. -# -# The HTML Help Workshop contains a compiler that can convert all HTML output -# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML -# files are now used as the Windows 98 help format, and will replace the old -# Windows help format (.hlp) on all Windows platforms in the future. Compressed -# HTML files also contain an index, a table of contents, and you can search for -# words in the documentation. The HTML workshop also contains a viewer for -# compressed HTML files. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_HTMLHELP = NO - -# The CHM_FILE tag can be used to specify the file name of the resulting .chm -# file. You can add a path in front of the file if the result should not be -# written to the html output directory. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_FILE = - -# The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler ( hhc.exe). If non-empty -# doxygen will try to run the HTML help compiler on the generated index.hhp. -# The file has to be specified with full path. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -HHC_LOCATION = - -# The GENERATE_CHI flag controls if a separate .chi index file is generated ( -# YES) or that it should be included in the master .chm file ( NO). -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -GENERATE_CHI = NO - -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) -# and project file content. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_INDEX_ENCODING = - -# The BINARY_TOC flag controls whether a binary table of contents is generated ( -# YES) or a normal table of contents ( NO) in the .chm file. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members to -# the table of contents of the HTML help documentation and to the tree view. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that -# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help -# (.qch) of the generated HTML documentation. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify -# the file name of the resulting .qch file. The path specified is relative to -# the HTML output folder. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help -# Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt -# Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- -# folders). -# The default value is: doc. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_VIRTUAL_FOLDER = doc - -# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom -# filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_SECT_FILTER_ATTRS = - -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be -# generated, together with the HTML files, they form an Eclipse help plugin. To -# install this plugin and make it available under the help contents menu in -# Eclipse, the contents of the directory containing the HTML and XML files needs -# to be copied into the plugins directory of eclipse. The name of the directory -# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. -# After copying Eclipse needs to be restarted before the help appears. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the Eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have this -# name. Each documentation set should have its own identifier. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# If you want full control over the layout of the generated HTML pages it might -# be necessary to disable the index and replace it with your own. The -# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top -# of each HTML page. A value of NO enables the index and the value YES disables -# it. Since the tabs in the index contain the same information as the navigation -# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -DISABLE_INDEX = NO - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. If the tag -# value is set to YES, a side panel will be generated containing a tree-like -# index structure (just like the one that is generated for HTML Help). For this -# to work a browser that supports JavaScript, DHTML, CSS and frames is required -# (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_TREEVIEW = NO - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that -# doxygen will group on one line in the generated HTML documentation. -# -# Note that a value of 0 will completely suppress the enum values from appearing -# in the overview section. -# Minimum value: 0, maximum value: 20, default value: 4. -# This tag requires that the tag GENERATE_HTML is set to YES. - -ENUM_VALUES_PER_LINE = 4 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used -# to set the initial width (in pixels) of the frame in which the tree is shown. -# Minimum value: 0, maximum value: 1500, default value: 250. -# This tag requires that the tag GENERATE_HTML is set to YES. - -TREEVIEW_WIDTH = 250 - -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to -# external symbols imported via tag files in a separate window. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -EXT_LINKS_IN_WINDOW = NO - -# Use this tag to change the font size of LaTeX formulas included as images in -# the HTML documentation. When you change the font size after a successful -# doxygen run you need to manually remove any form_*.png images from the HTML -# output directory to force them to be regenerated. -# Minimum value: 8, maximum value: 50, default value: 10. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering -# instead of using prerendered bitmaps. Use this if you do not have LaTeX -# installed or if you want to formulas look prettier in the HTML output. When -# enabled you may also need to install MathJax separately and configure the path -# to it using the MATHJAX_RELPATH option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -USE_MATHJAX = NO - -# When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. -# Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. -# The default value is: HTML-CSS. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_FORMAT = HTML-CSS - -# When MathJax is enabled you need to specify the location relative to the HTML -# output directory using the MATHJAX_RELPATH option. The destination directory -# should contain the MathJax.js script. For instance, if the mathjax directory -# is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax -# Content Delivery Network so you can quickly see the result without installing -# MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest - -# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax -# extension names that should be enabled during MathJax rendering. For example -# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_EXTENSIONS = - -# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces -# of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an -# example see the documentation. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_CODEFILE = - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box for -# the HTML output. The underlying search engine uses javascript and DHTML and -# should work on any modern browser. Note that when using HTML help -# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) -# there is already a search function so this one should typically be disabled. -# For large projects the javascript based search engine can be slow, then -# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to -# search using the keyboard; to jump to the search box use + S -# (what the is depends on the OS and browser, but it is typically -# , /