From d6548b2d7e69c614e8a95fe951a0331addf09dc9 Mon Sep 17 00:00:00 2001 From: JusticeLeee Date: Mon, 30 May 2022 21:17:05 +0800 Subject: [PATCH] Sync lab5 to lab7 // Don't need VA in this lab --- lab5/kernel/src/exception.c | 6 + lab7/README.md | 25 + lab7/bootloader/Makefile | 48 + lab7/bootloader/bootloader.elf | Bin 0 -> 3128 bytes lab7/bootloader/bootloader.img | Bin 0 -> 1105 bytes lab7/bootloader/include/mini_uart.h | 9 + lab7/bootloader/include/mm.h | 17 + lab7/bootloader/include/peripherals/base.h | 6 + lab7/bootloader/include/peripherals/gpio.h | 12 + .../include/peripherals/mini_uart.h | 18 + lab7/bootloader/include/shell.h | 26 + lab7/bootloader/include/stdint.h | 18 + lab7/bootloader/include/str_tool.h | 24 + lab7/bootloader/include/utils.h | 8 + lab7/bootloader/link.ld | 13 + lab7/bootloader/main.c | 31 + lab7/bootloader/mini_uart.c | 47 + lab7/bootloader/mm.S | 6 + lab7/bootloader/start.S | 38 + lab7/bootloader/stdint.c | 21 + lab7/bootloader/str_tool.c | 23 + lab7/bootloader/utils.S | 15 + lab7/bootloader/utils/mini_uart.c | 47 + lab7/bootloader/utils/mm.S | 6 + lab7/bootloader/utils/stdint.c | 21 + lab7/bootloader/utils/str_tool.c | 23 + lab7/bootloader/utils/utils.S | 15 + lab7/config.txt | 4 + lab7/kernel/Makefile | 49 + lab7/kernel/gdb_file | 2 + lab7/kernel/include/alloc.h | 42 + lab7/kernel/include/cpio.h | 28 + lab7/kernel/include/delays.h | 29 + lab7/kernel/include/dtb.h | 38 + lab7/kernel/include/exception.h | 12 + lab7/kernel/include/gpio.h | 45 + lab7/kernel/include/math.h | 6 + lab7/kernel/include/mbox.h | 51 + lab7/kernel/include/power.h | 27 + lab7/kernel/include/printf.h | 117 +++ lab7/kernel/include/shell.h | 32 + lab7/kernel/include/string.h | 6 + lab7/kernel/include/thread.h | 73 ++ lab7/kernel/include/timer.h | 25 + lab7/kernel/include/uart.h | 60 ++ lab7/kernel/include/utils.h | 15 + lab7/kernel/src/alloc.c | 446 +++++++++ lab7/kernel/src/cpio.c | 86 ++ lab7/kernel/src/delays.c | 81 ++ lab7/kernel/src/dtb.c | 252 +++++ lab7/kernel/src/exception.S | 127 +++ lab7/kernel/src/exception.c | 111 +++ lab7/kernel/src/linker.ld | 44 + lab7/kernel/src/main.c | 29 + lab7/kernel/src/math.c | 9 + lab7/kernel/src/mbox.c | 62 ++ lab7/kernel/src/power.c | 83 ++ lab7/kernel/src/printf.c | 921 ++++++++++++++++++ lab7/kernel/src/shell.c | 237 +++++ lab7/kernel/src/start.S | 85 ++ lab7/kernel/src/string.c | 76 ++ lab7/kernel/src/thread.S | 26 + lab7/kernel/src/thread.c | 272 ++++++ lab7/kernel/src/timer.c | 146 +++ lab7/kernel/src/uart.c | 213 ++++ lab7/kernel/src/utils.S | 9 + lab7/kernel/src/utils.c | 71 ++ lab7/make.sh | 9 + lab7/qemu_run.sh | 4 + lab7/run.sh | 4 + lab7/script/send_file.py | 42 + lab7/user/Makefile | 32 + lab7/user/src/argv_test.c | 17 + lab7/user/src/fork_test.c | 46 + lab7/user/src/linker.ld | 17 + lab7/user/src/my_test.c | 12 + lab7/user/src/my_test2.c | 12 + lab7/user/src/start.S | 49 + lab7/user/src/start.h | 54 + lab7/user/src/svc_test.c | 7 + lab7/user/src/user_program.S | 11 + 81 files changed, 4886 insertions(+) create mode 100644 lab7/README.md create mode 100644 lab7/bootloader/Makefile create mode 100755 lab7/bootloader/bootloader.elf create mode 100755 lab7/bootloader/bootloader.img create mode 100644 lab7/bootloader/include/mini_uart.h create mode 100644 lab7/bootloader/include/mm.h create mode 100644 lab7/bootloader/include/peripherals/base.h create mode 100644 lab7/bootloader/include/peripherals/gpio.h create mode 100644 lab7/bootloader/include/peripherals/mini_uart.h create mode 100644 lab7/bootloader/include/shell.h create mode 100644 lab7/bootloader/include/stdint.h create mode 100644 lab7/bootloader/include/str_tool.h create mode 100644 lab7/bootloader/include/utils.h create mode 100644 lab7/bootloader/link.ld create mode 100644 lab7/bootloader/main.c create mode 100644 lab7/bootloader/mini_uart.c create mode 100644 lab7/bootloader/mm.S create mode 100644 lab7/bootloader/start.S create mode 100644 lab7/bootloader/stdint.c create mode 100644 lab7/bootloader/str_tool.c create mode 100644 lab7/bootloader/utils.S create mode 100644 lab7/bootloader/utils/mini_uart.c create mode 100644 lab7/bootloader/utils/mm.S create mode 100644 lab7/bootloader/utils/stdint.c create mode 100644 lab7/bootloader/utils/str_tool.c create mode 100644 lab7/bootloader/utils/utils.S create mode 100644 lab7/config.txt create mode 100644 lab7/kernel/Makefile create mode 100644 lab7/kernel/gdb_file create mode 100644 lab7/kernel/include/alloc.h create mode 100644 lab7/kernel/include/cpio.h create mode 100644 lab7/kernel/include/delays.h create mode 100644 lab7/kernel/include/dtb.h create mode 100644 lab7/kernel/include/exception.h create mode 100644 lab7/kernel/include/gpio.h create mode 100644 lab7/kernel/include/math.h create mode 100644 lab7/kernel/include/mbox.h create mode 100644 lab7/kernel/include/power.h create mode 100644 lab7/kernel/include/printf.h create mode 100644 lab7/kernel/include/shell.h create mode 100644 lab7/kernel/include/string.h create mode 100644 lab7/kernel/include/thread.h create mode 100644 lab7/kernel/include/timer.h create mode 100644 lab7/kernel/include/uart.h create mode 100644 lab7/kernel/include/utils.h create mode 100644 lab7/kernel/src/alloc.c create mode 100644 lab7/kernel/src/cpio.c create mode 100644 lab7/kernel/src/delays.c create mode 100644 lab7/kernel/src/dtb.c create mode 100644 lab7/kernel/src/exception.S create mode 100644 lab7/kernel/src/exception.c create mode 100644 lab7/kernel/src/linker.ld create mode 100644 lab7/kernel/src/main.c create mode 100644 lab7/kernel/src/math.c create mode 100644 lab7/kernel/src/mbox.c create mode 100644 lab7/kernel/src/power.c create mode 100644 lab7/kernel/src/printf.c create mode 100644 lab7/kernel/src/shell.c create mode 100644 lab7/kernel/src/start.S create mode 100644 lab7/kernel/src/string.c create mode 100644 lab7/kernel/src/thread.S create mode 100644 lab7/kernel/src/thread.c create mode 100644 lab7/kernel/src/timer.c create mode 100644 lab7/kernel/src/uart.c create mode 100644 lab7/kernel/src/utils.S create mode 100644 lab7/kernel/src/utils.c create mode 100755 lab7/make.sh create mode 100755 lab7/qemu_run.sh create mode 100755 lab7/run.sh create mode 100644 lab7/script/send_file.py create mode 100644 lab7/user/Makefile create mode 100644 lab7/user/src/argv_test.c create mode 100644 lab7/user/src/fork_test.c create mode 100644 lab7/user/src/linker.ld create mode 100644 lab7/user/src/my_test.c create mode 100644 lab7/user/src/my_test2.c create mode 100644 lab7/user/src/start.S create mode 100644 lab7/user/src/start.h create mode 100644 lab7/user/src/svc_test.c create mode 100644 lab7/user/src/user_program.S diff --git a/lab5/kernel/src/exception.c b/lab5/kernel/src/exception.c index 8ab024a2d..3addfcadb 100644 --- a/lab5/kernel/src/exception.c +++ b/lab5/kernel/src/exception.c @@ -38,6 +38,7 @@ void sync_handler_lowerEL_64(uint64_t sp) { uint32_t ec = (esr_el1 >> 26) & 0x3f; // printf("EC: %x\n", ec); if (ec == 0b010101) { // SVC instruction + // printf("pid = %d, ",get_current()->pid); uint64_t iss; asm volatile("mov %0, x8" : "=r"(iss)); // printf("syscall number: %d\n", iss); @@ -47,6 +48,7 @@ void sync_handler_lowerEL_64(uint64_t sp) { uint32_t pid = get_current()->pid; trap_frame->x[0] = pid; } else if (iss == 1) { // uartread + // printf("[read]\n"); disable_uart_interrupt(); enable_interrupt(); char *str = (char *)(trap_frame->x[0]); @@ -54,6 +56,7 @@ void sync_handler_lowerEL_64(uint64_t sp) { size = uart_gets(str, size); trap_frame->x[0] = size; } else if (iss == 2) { // uartwrite + // printf("[write]\n"); char *str = (char *)(trap_frame->x[0]); trap_frame->x[0] = uart_write(str,trap_frame->x[1]); } else if (iss == 3) { // exec @@ -61,10 +64,12 @@ void sync_handler_lowerEL_64(uint64_t sp) { const char **argv = (const char **)trap_frame->x[1]; exec(program_name, argv); } else if (iss == 4) { // fork + // printf("[fork]\n"); fork(sp); } else if (iss == 5) { // exit exit(); } else if (iss == 6) { // mbox_call + // printf("[mbox_call]\n"); trap_frame->x[0] = mbox_call(trap_frame->x[0],(unsigned int *)trap_frame->x[1]); } else if (iss == 7) { // kill kill((int)trap_frame->x[0]); @@ -72,6 +77,7 @@ void sync_handler_lowerEL_64(uint64_t sp) { } } + void irq_handler_currentEL_ELx() { // printf("====irq_handler_currentEL_ELx=====\n"); diff --git a/lab7/README.md b/lab7/README.md new file mode 100644 index 000000000..78ddcba99 --- /dev/null +++ b/lab7/README.md @@ -0,0 +1,25 @@ +# osc2022 +## Author + +| 學號 | GitHub 帳號 | 姓名 | Email | +| --- | ----------- | --- | --- | +|`309554042`| `JusticeLeee` | `李政毅` | franklp97531@gmail.com | + +## How to build + +```bash +./make.sh +``` +## How to run + +```bash +make run +``` +## How to burn it into pi3 +```bash +./rus.sh # write kernel to rpi3 through uart +sudo screen /dev/ttyUSB0 115200 +``` +## Note + +copy some string.h source for use strcmp \ No newline at end of file diff --git a/lab7/bootloader/Makefile b/lab7/bootloader/Makefile new file mode 100644 index 000000000..cff2e3c2a --- /dev/null +++ b/lab7/bootloader/Makefile @@ -0,0 +1,48 @@ +# +# Copyright (C) 2018 bzt (bztsrc@github) +# +# 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. +# +# + +CFILE = $(wildcard *.c) +ASMFILE = $(wildcard *.S) +OBJS = $(CFILE:.c=_c.o) +OBJS += $(ASMFILE:.S=_s.o) +CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -fno-stack-protector -Iinclude -Iinclude + +all: kernel8.img + +%_s.o: %.S + aarch64-elf-gcc $(CFLAGS) -c $< -o $@ + +%_c.o: %.c + aarch64-elf-gcc $(CFLAGS) -c $< -o $@ + +kernel8.img: $(OBJS) + aarch64-elf-ld -nostdlib -nostartfiles $(OBJS) -T link.ld -o bootloader.elf + aarch64-elf-objcopy -O binary bootloader.elf bootloader.img + +clean: + rm kernel8.elf *.o >/dev/null 2>/dev/null || true + +run: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -serial null -serial stdio diff --git a/lab7/bootloader/bootloader.elf b/lab7/bootloader/bootloader.elf new file mode 100755 index 0000000000000000000000000000000000000000..74f2d52e74c0b45dde8b2fac1e450e2516639968 GIT binary patch literal 3128 zcmbtWU2GIp6h1SvmS4^GM={X2vvf5=%vxxnTb_mjV*I6LRT53M`&YWA+wJa7$wEoG z#1f&zgq0>3eV_!1w2w+6KAsVg`ggqYf-Fg7H<`X9%X`FxG%*oaZZn893V@^0Qd(kimtZP4J8kKREZgd` zCUU|q6})ko_NYWNV}{{Ajq!Cw8uitY+e6Ysi70rAXyPcWGN4V@4bb#IhOtT`&sFl0 z`x?5J==;Bkh79H1&#%CSRON~R4v|}As4%TmOI7L^wGynyN9m&y1yz@1`7uhbgTHn_ zYE|EnT3f(jeyEeuB~QLhtQ$knOUoAb4Zzwc+%abn><%{pDR9Hq-^9{#QDEJ$6 zTkDT}Jm8`Nk#x);*Mufh@DORubo<~>b;z?8c{-4z4mCaPl3Jq}x72DMo`voAQTklj z2!`R$k0ISNf}GonI=q;>g>@>3=|evwQ6u&$y%zOg#WhN2B;Z4DK@E(bA!=-QZ$F?J zMzEb+FLNA)@@@9GB-44kljE*%WdZN;xc8uTVjxF_%SyiOCRG+>#Qa^USTC;}|9D4U z`Xod&SyJTD>q}0p?r>4M#eHh^AD!{Q;k%x|rF+IELL3^aJH~nN0*+IAWkIUQw@J69 z0AuC8uSd!X6{c3u%n8(7edDvgN=o(Udw7R(?6E3|2HM#7(r{)gN$dN7XWQh0gqrhJ z*mv;v0UN^@XKqNMk4%1AU|Cq!GrtSt>Xn1VJPj7T@KtE{0&9TfdFDmo=a&u^+2?tz zZz#WPuoxEp+wf`m-27YYKRQ?(_gehj?1Mip_^-p~xU8RAq0N;0E}eS`dpNu9-O|Vj z#H+#k<~o?W9U2d<$qeHiT~lh-6Y81Ty>*1^Vf~i*dfqqaS?j@>XMLloCsWT_);$l* z&hOm!DV$+^#m#w~jb9AoWcyQE0N>%Jh5U=wd*XV*DWRL+kekw{QRm$=RA|8aWBnny z`dGGt3jNQ}q(xe#V#lyA&~%;5_2$v5o6_*MUbKQ8cq zgOB?UO(NBSKPT`;2Yy!IyBzptf$wqP&A{(hzg=gigWvKHz9ubPua$T4K3n+WeSQ`3 zC7Q!k_}tz^e^8y%j=YhF@Q0O!btWFduW_6Q+&>Sjr{2Lo0KOY5t99Uc;8nnni28fr zb32UAd}o{wfHS{G)Nh~vlLEK*VH!TS)97yOXU>s#1USdB_d#be+85}I*NgZXgJ>7g z8NVZ2`=&97_ANT&7sNR^VxmMp3*0_Gy98bmxP4Au6!=Y8Ua!wl=br+1?*FGIzIa_z z0$=p~X7zAJ4`ux+3YkOl@r${y%ig(8-l1k|zj%Ce3jhKQTrOtQ`MTAh%=EiwWfUAopdngv~ z3hyU`MoNwtiSI=u@@Mxa^>74M&set89_jI%PX0_P7S_Y$hlc#oR5BUwwoe2$^nbK9 z(DE&4{iSgr>-^aNk(%R5wf`HL$&K$n*5m)gZ1#P9LFg(4ZX2h59VQr41i?NR-wC}c zaN9WbeoSzF`#ZCFw%(bax!mSkyLM~FdY0_`!t(yqqTBhO6lDB&&ekp<%kTtR*)p?F XJFg9JefHXIjBQ!yo92TUJN5qpgRnv9 literal 0 HcmV?d00001 diff --git a/lab7/bootloader/bootloader.img b/lab7/bootloader/bootloader.img new file mode 100755 index 0000000000000000000000000000000000000000..e777a00530e7c9556531a7e27795ef1319158cab GIT binary patch literal 1105 zcmZ8hO-NKx6#njegZ5)FIzxd)?>%P3Lgi7;j*~Kf`4K&wl{Jo__ZJYuXl5 zf9;V2_)+|o6pY%A3NwQy&>CSRuPek&pDN-GBzF^6rBsu7N;O5v5q?V-k~zbPnKe#j zMsImzzANg*|EObX&Tz7Tlf7!fT@M7GNFE*W_tZ7kT)Um}!3ETS2j9G{A$|#V1HSaV z3b9TV>vXb4h&}D}sit=N(e3t)yR`jbBq#D-JVCrRhg$LCQrlu57Wd|OPMtZ!T;mFL zysKmt`{9X$dRJQ{%oSx15+4WZTK$JE+MXA0h3}~3(c#2?`#B8{)&YaQM7di^YxUVf zsUEn`bSL&1<*vq@AM}!Ht!(=CVMpC*0Tyz)HZ@y1QrYQ4GU^|x{M22BZ!LFo@Q2SCu$1^+iP_mhXK$nb+YiZp88sdk%cO_bsOfrY>`aTF2%Jg;Y$i zh0*hkP}RMRcgHkWv1g}(_fGx=#xnGKXccZ1_{r5+H?8P}e~x~jES+_b&RWDKwPzTs zrImf*wG%t*(pkZ>&+`pC>(kl9Dn3b!4S)BK3*MB@PFqEOvtaV4SNX??C9migH`>ej z-lr2sc!z(^-K-{um@mkAOCQ2LM2&%M=SMlC89i7H_OsaBI4S*z{@_}@+#B_xHTdR5 zUsuqhpck#^_AvIl{{Q#B$TtkW9fxn@t>@ir-C;-g9oGNLe^i{4^h-{TtMCo^ksM>6 zOXF~BIX}@~(gFkBC2;$9VZr=rL=v*U)m~l#9t>+yH=stdFQv{FMEbShyy(Fg_&v)x x^S#d|q(=ojEWR7NXnk0iAy;As{{t)&3oll2&E9>rb@lrXL>dxp?H#8(@e4F4mGl4r literal 0 HcmV?d00001 diff --git a/lab7/bootloader/include/mini_uart.h b/lab7/bootloader/include/mini_uart.h new file mode 100644 index 000000000..aebc2c5a2 --- /dev/null +++ b/lab7/bootloader/include/mini_uart.h @@ -0,0 +1,9 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + +void uart_init(void); +char uart_getc(void); +void uart_putc(char c); +void uart_puts(char* str); + +#endif \ No newline at end of file diff --git a/lab7/bootloader/include/mm.h b/lab7/bootloader/include/mm.h new file mode 100644 index 000000000..119624a2b --- /dev/null +++ b/lab7/bootloader/include/mm.h @@ -0,0 +1,17 @@ +#ifndef _MM_H +#define _MM_H + +#define PAGE_SHIFT 12 +#define TABLE_SHIFT 9 +#define SECTION_SHIFT (PAGE_SHIFT + TABLE_SHIFT) + +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define SECTION_SIZE (1 << SECTION_SHIFT) + +#define LOW_MEMORY (2 * SECTION_SIZE) + +#ifndef __ASSEMBLER__ +void memzero(unsigned long src, unsigned long n); +#endif + +#endif \ No newline at end of file diff --git a/lab7/bootloader/include/peripherals/base.h b/lab7/bootloader/include/peripherals/base.h new file mode 100644 index 000000000..d7eb1f9b5 --- /dev/null +++ b/lab7/bootloader/include/peripherals/base.h @@ -0,0 +1,6 @@ +#ifndef _PER_BASE_H_ +#define _PER_BASE_H_ + +#define PHY_BASE_ADDR 0x3F000000 + +#endif \ No newline at end of file diff --git a/lab7/bootloader/include/peripherals/gpio.h b/lab7/bootloader/include/peripherals/gpio.h new file mode 100644 index 000000000..1132dae95 --- /dev/null +++ b/lab7/bootloader/include/peripherals/gpio.h @@ -0,0 +1,12 @@ +#ifndef _PER_GPIO_H +#define _PER_GPIO_H + +#include "peripherals/base.h" + +#define GPFSEL1 (PHY_BASE_ADDR + 0x00200004) +#define GPSET0 (PHY_BASE_ADDR + 0x0020001C) +#define GPCLR0 (PHY_BASE_ADDR + 0x00200028) +#define GPPUD (PHY_BASE_ADDR + 0x00200094) +#define GPPUDCLK0 (PHY_BASE_ADDR + 0x00200098) + +#endif \ No newline at end of file diff --git a/lab7/bootloader/include/peripherals/mini_uart.h b/lab7/bootloader/include/peripherals/mini_uart.h new file mode 100644 index 000000000..c08d34831 --- /dev/null +++ b/lab7/bootloader/include/peripherals/mini_uart.h @@ -0,0 +1,18 @@ +#ifndef _PER_MINI_UART_H_ +#define _PER_MINI_UART_H_ + +#include "peripherals/base.h" +#define AUX_ENABLES (PHY_BASE_ADDR + 0x00215004) +#define AUX_MU_IO_REG (PHY_BASE_ADDR + 0x00215040) +#define AUX_MU_IER_REG (PHY_BASE_ADDR + 0x00215044) +#define AUX_MU_IIR_REG (PHY_BASE_ADDR + 0x00215048) +#define AUX_MU_LCR_REG (PHY_BASE_ADDR + 0x0021504C) +#define AUX_MU_MCR_REG (PHY_BASE_ADDR + 0x00215050) +#define AUX_MU_LSR_REG (PHY_BASE_ADDR + 0x00215054) +#define AUX_MU_MSR_REG (PHY_BASE_ADDR + 0x00215058) +#define AUX_MU_SCRATCH (PHY_BASE_ADDR + 0x0021505C) +#define AUX_MU_CNTL_REG (PHY_BASE_ADDR + 0x00215060) +#define AUX_MU_STAT_REG (PHY_BASE_ADDR + 0x00215064) +#define AUX_MU_BAUD_REG (PHY_BASE_ADDR + 0x00215068) + +#endif \ No newline at end of file diff --git a/lab7/bootloader/include/shell.h b/lab7/bootloader/include/shell.h new file mode 100644 index 000000000..d588b1de9 --- /dev/null +++ b/lab7/bootloader/include/shell.h @@ -0,0 +1,26 @@ +#ifndef _SHELL_H +#define _SHELL_H + +void buffer_clear(); +void execute_command(char *); +void init_shell(); + +void print_input_prompt(); +void get_input(); + +void del_key(); +void left_key(); +void right_key(); +void up_key(); +void down_key(); + +void simple_shell(); + +void shell_hello(); +void shell_help(); +void shell_reboot(); +void shell_boot_uart(); + +void shell_ls(); + +#endif \ No newline at end of file diff --git a/lab7/bootloader/include/stdint.h b/lab7/bootloader/include/stdint.h new file mode 100644 index 000000000..ebc26e483 --- /dev/null +++ b/lab7/bootloader/include/stdint.h @@ -0,0 +1,18 @@ +#ifndef _STDINT_H +#define _STDINT_H + +typedef unsigned long long int uint64_t; +typedef signed long long int int64_t; + +typedef unsigned int uint32_t; +typedef signed int int32_t; + +typedef unsigned short int uint16_t; +typedef signed short int int16_t; + +typedef unsigned char uint8_t; +typedef signed char int8_t; + +uint8_t hex_to_int64(char*); +uint64_t hex_to_int8(char); +#endif \ No newline at end of file diff --git a/lab7/bootloader/include/str_tool.h b/lab7/bootloader/include/str_tool.h new file mode 100644 index 000000000..3d5018e36 --- /dev/null +++ b/lab7/bootloader/include/str_tool.h @@ -0,0 +1,24 @@ +#ifndef _STR_TOOL_H +#define _STR_TOOL_H +#include "stdint.h" + +typedef struct { + char c_magic[6]; + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[8]; + char c_filesize[8]; + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; + char c_check[8]; +} cpio_newc_header; + +int strcmp(char*, char*); +char* itoa(int64_t, int); +#endif \ No newline at end of file diff --git a/lab7/bootloader/include/utils.h b/lab7/bootloader/include/utils.h new file mode 100644 index 000000000..99dfeecc6 --- /dev/null +++ b/lab7/bootloader/include/utils.h @@ -0,0 +1,8 @@ +#ifndef _UTILS_H_ +#define _UTILS_H_ + +void delay(unsigned long); +void put32(unsigned long, unsigned int); +unsigned int get32(unsigned long); + +#endif \ No newline at end of file diff --git a/lab7/bootloader/link.ld b/lab7/bootloader/link.ld new file mode 100644 index 000000000..dfbf24cf2 --- /dev/null +++ b/lab7/bootloader/link.ld @@ -0,0 +1,13 @@ +SECTIONS +{ + . = 0x50000; + .text : { KEEP(*(.text.boot)) *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + + . = ALIGN(0x8); + bss_begin = .; + .bss : { *(.bss*) } + bss_end = .; + _end = .; +} diff --git a/lab7/bootloader/main.c b/lab7/bootloader/main.c new file mode 100644 index 000000000..46afb4dfb --- /dev/null +++ b/lab7/bootloader/main.c @@ -0,0 +1,31 @@ +#include "mini_uart.h" +#include "utils.h" +#include "stdint.h" + +union large_int_by_byte{ + uint8_t int_by_byte[8]; + uint64_t larg_int; +}; + +void boot_main(){ + uart_init(); + + union large_int_by_byte program; + volatile uint8_t *program_addr = (volatile uint8_t *)0x80000; + + // read dirty message until end + while(1) { + uint8_t data; + data = uart_getc(); + if(data==4)break; + } + + // read kernel size + for(int i=0; i<8; i++) + program.int_by_byte[i] = uart_getc(); + + for(uint64_t offset=0; offset= '0' && hex <= '9') + return hex-'0'; + else if(hex >= 'A' && hex <= 'Z') + return hex-'A'+10; + else if(hex >= 'a' && hex <= 'z') + return hex-'a'+10; + else + return -1; +} + +uint64_t hex_to_int64(char* num){ + uint64_t res=0; + for(int i=0; i<8; i++){ + res = (res<<4) + hex_to_int8(num[i]); + } + return res; +} \ No newline at end of file diff --git a/lab7/bootloader/str_tool.c b/lab7/bootloader/str_tool.c new file mode 100644 index 000000000..cb955f297 --- /dev/null +++ b/lab7/bootloader/str_tool.c @@ -0,0 +1,23 @@ +#include "stdint.h" + +int strcmp(char *s1, char *s2){ + while(*s1!='\0' && *s2!='\0' && *s1==*s2){ + s1 += 1; + s2 += 1; + } + return *s1 - *s2; +} + +char* itoa(int64_t val, int base){ + static char buf[32] = {0}; + int i = 30; + if (val == 0) { + buf[i] = '0'; + return &buf[i]; + } + + for (; val && i; --i, val /= base) + buf[i] = "0123456789abcdef"[val % base]; + + return &buf[i + 1]; +} \ No newline at end of file diff --git a/lab7/bootloader/utils.S b/lab7/bootloader/utils.S new file mode 100644 index 000000000..e735f1dc7 --- /dev/null +++ b/lab7/bootloader/utils.S @@ -0,0 +1,15 @@ +.globl put32 +put32: + str w1, [x0] + ret + +.globl get32 +get32: + ldr w0, [x0] + ret + +.globl delay +delay: + subs x0, x0, #1 + bne delay + ret \ No newline at end of file diff --git a/lab7/bootloader/utils/mini_uart.c b/lab7/bootloader/utils/mini_uart.c new file mode 100644 index 000000000..46ca9cfe0 --- /dev/null +++ b/lab7/bootloader/utils/mini_uart.c @@ -0,0 +1,47 @@ +#include "utils.h" +#include "peripherals/gpio.h" +#include "peripherals/mini_uart.h" + +void uart_init(){ + unsigned int selector; + + selector = get32(GPFSEL1); + selector &= ~(7<<12); // clean gpio 14 + selector |= 2<<12; // set alt5 at gpio14 + selector &= ~(7<<15); // clean gpio 15 + selector |= 2<<15; // set alt5 at gpio 15 + put32(GPFSEL1, selector); + + put32(GPPUD, 0); // disable pull-up/down + delay(150); // wait 150 cycles + put32(GPPUDCLK0, (1<<14)|(1<<15)); // only modify GPIO 14 and 15 + delay(150); + put32(GPPUDCLK0, 0); // remove the clock + + put32(AUX_ENABLES, 1); // enable mini UART + put32(AUX_MU_CNTL_REG, 0); // Disable transmitter and receiver during configuration + put32(AUX_MU_IER_REG, 0); // Disable interrupt + put32(AUX_MU_LCR_REG, 3); // Set the data size to 8 bit + put32(AUX_MU_MCR_REG, 0); // Don’t need auto flow control + put32(AUX_MU_BAUD_REG, 270); // Set baud rate to 115200 + + put32(AUX_MU_IIR_REG, 6); // No FIFO + put32(AUX_MU_CNTL_REG, 3); // Enable the transmitter and receiver +} + +void uart_putc(char c){ + while(!(get32(AUX_MU_LSR_REG)&0x20)); + put32(AUX_MU_IO_REG, c); +} + +char uart_getc(void){ + while(!(get32(AUX_MU_LSR_REG)&0x01)); + return get32(AUX_MU_IO_REG); +} + +void uart_puts(char* str){ + while(*str){ + uart_putc(*str); + str += 1; + } +} \ No newline at end of file diff --git a/lab7/bootloader/utils/mm.S b/lab7/bootloader/utils/mm.S new file mode 100644 index 000000000..f9b279e14 --- /dev/null +++ b/lab7/bootloader/utils/mm.S @@ -0,0 +1,6 @@ +.globl memzero +memzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero + ret \ No newline at end of file diff --git a/lab7/bootloader/utils/stdint.c b/lab7/bootloader/utils/stdint.c new file mode 100644 index 000000000..c41cc43ea --- /dev/null +++ b/lab7/bootloader/utils/stdint.c @@ -0,0 +1,21 @@ +typedef unsigned long long int uint64_t; +typedef unsigned char uint8_t; + +uint8_t hex_to_int8(char hex){ + if(hex >= '0' && hex <= '9') + return hex-'0'; + else if(hex >= 'A' && hex <= 'Z') + return hex-'A'+10; + else if(hex >= 'a' && hex <= 'z') + return hex-'a'+10; + else + return -1; +} + +uint64_t hex_to_int64(char* num){ + uint64_t res=0; + for(int i=0; i<8; i++){ + res = (res<<4) + hex_to_int8(num[i]); + } + return res; +} \ No newline at end of file diff --git a/lab7/bootloader/utils/str_tool.c b/lab7/bootloader/utils/str_tool.c new file mode 100644 index 000000000..cb955f297 --- /dev/null +++ b/lab7/bootloader/utils/str_tool.c @@ -0,0 +1,23 @@ +#include "stdint.h" + +int strcmp(char *s1, char *s2){ + while(*s1!='\0' && *s2!='\0' && *s1==*s2){ + s1 += 1; + s2 += 1; + } + return *s1 - *s2; +} + +char* itoa(int64_t val, int base){ + static char buf[32] = {0}; + int i = 30; + if (val == 0) { + buf[i] = '0'; + return &buf[i]; + } + + for (; val && i; --i, val /= base) + buf[i] = "0123456789abcdef"[val % base]; + + return &buf[i + 1]; +} \ No newline at end of file diff --git a/lab7/bootloader/utils/utils.S b/lab7/bootloader/utils/utils.S new file mode 100644 index 000000000..e735f1dc7 --- /dev/null +++ b/lab7/bootloader/utils/utils.S @@ -0,0 +1,15 @@ +.globl put32 +put32: + str w1, [x0] + ret + +.globl get32 +get32: + ldr w0, [x0] + ret + +.globl delay +delay: + subs x0, x0, #1 + bne delay + ret \ No newline at end of file diff --git a/lab7/config.txt b/lab7/config.txt new file mode 100644 index 000000000..261480683 --- /dev/null +++ b/lab7/config.txt @@ -0,0 +1,4 @@ +kernel_address=0x60000 +kernel=bootloader.img +arm_64bit=1 +initramfs initramfs.cpio 0x8000000 \ No newline at end of file diff --git a/lab7/kernel/Makefile b/lab7/kernel/Makefile new file mode 100644 index 000000000..54fc6c2c5 --- /dev/null +++ b/lab7/kernel/Makefile @@ -0,0 +1,49 @@ +CC = aarch64-linux-gnu-gcc +CFLAGS = -Iinclude -Wall -nostdlib -nostartfiles -ffreestanding +# ASMFLAGS = +LD = aarch64-linux-gnu-ld +OBJCOPY = aarch64-linux-gnu-objcopy +OBJCOPYFLAGS = -O binary + +QEMU = qemu-system-aarch64 + +BUILD_DIR = build +SRC_DIR = src + +all: initramfs.cpio kernel8.img + +initramfs.cpio: + cd rootfs; find . | cpio -o -H newc > ../initramfs.cpio; cd ..; + +clean: + rm $(BUILD_DIR)/* initramfs.cpio + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(CC) $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(CC) $(ASMFLAGS) -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +kernel8.elf: $(SRC_DIR)/linker.ld $(OBJ_FILES) + $(LD) -T $(SRC_DIR)/linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + +kernel8.img: kernel8.elf + $(OBJCOPY) $(OBJCOPYFLAGS) $(BUILD_DIR)/kernel8.elf $(BUILD_DIR)/kernel8.img + +run: + $(QEMU) -M raspi3 -kernel $(BUILD_DIR)/kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + +run1: + killall -9 qemu-system-aarch64 + $(QEMU) -M raspi3 -kernel $(BUILD_DIR)/kernel8.img -display vnc=127.0.0.4:0 -serial null -serial stdio -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + + +debug: + killall -9 qemu-system-aarch64 + $(QEMU) -M raspi3 -kernel $(BUILD_DIR)/kernel8.img -serial null -serial stdio -display none -S -s -initrd initramfs.cpio \ No newline at end of file diff --git a/lab7/kernel/gdb_file b/lab7/kernel/gdb_file new file mode 100644 index 000000000..8e9744669 --- /dev/null +++ b/lab7/kernel/gdb_file @@ -0,0 +1,2 @@ +file build/kernel8.elf +target remote :1234 \ No newline at end of file diff --git a/lab7/kernel/include/alloc.h b/lab7/kernel/include/alloc.h new file mode 100644 index 000000000..ff3819985 --- /dev/null +++ b/lab7/kernel/include/alloc.h @@ -0,0 +1,42 @@ +#pragma once +#include "utils.h" +#include +#define PAGE_BASE_ADDR ((uint64_t)0x10000000) +#define PAGE_END_ADDR ((uint64_t)0x20000000) +#define PAGE_SIZE ((uint64_t)(4 * kb)) +#define MAX_PAGE_NUM \ + ((uint64_t)((PAGE_END_ADDR - PAGE_BASE_ADDR) / PAGE_SIZE)) // 65536 +#define MAX_FRAME_ORDER 16 // 2^16 = 65536 +#define FRAME_LIST_NUM (MAX_FRAME_ORDER + 1) + +typedef struct PageFrame { + int id; + int order; + int is_allocated; + uint64_t addr; + struct PageFrame *next; +} page_frame; + +typedef struct DMAHeader { + uint64_t total_size; + uint64_t used_size; + int is_allocated; + page_frame *frame_ptr; + struct DMAHeader *prev, *next; +} dma_header; + +page_frame frames[MAX_PAGE_NUM]; +page_frame *free_frame_lists[FRAME_LIST_NUM], *used_frame_lists[FRAME_LIST_NUM]; + +dma_header *free_dma_list; + +void buddy_init(); +void buddy_test(); +page_frame *buddy_allocate(uint64_t size); +void buddy_free(page_frame *frame); +void buddy_unlink(int index, int type); +void print_frame_lists(); +void dma_test(); +void *malloc(uint64_t size); +void free(void *ptr); +void print_dma_list(); diff --git a/lab7/kernel/include/cpio.h b/lab7/kernel/include/cpio.h new file mode 100644 index 000000000..6f1d50bf2 --- /dev/null +++ b/lab7/kernel/include/cpio.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#define RAMFS_ADDR 0x8000000 +#define CPIO_MAGIC "070701" +#define CPIO_END "TRAILER!!!" + +typedef struct { + char c_magic[6]; + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[8]; + char c_filesize[8]; + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; + char c_check[8]; +} cpio_newc_header; + +void cpio_ls(); +void cpio_cat(char *filename); +uint32_t cpio_load_user_program(const char *target_program, + uint64_t target_addr); \ No newline at end of file diff --git a/lab7/kernel/include/delays.h b/lab7/kernel/include/delays.h new file mode 100644 index 000000000..ebbeb94ce --- /dev/null +++ b/lab7/kernel/include/delays.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * 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. + * + */ + +void wait_cycles(unsigned int n); +void wait_msec(unsigned int n); +unsigned long get_system_timer(); +void wait_msec_st(unsigned int n); diff --git a/lab7/kernel/include/dtb.h b/lab7/kernel/include/dtb.h new file mode 100644 index 000000000..f4dfc9163 --- /dev/null +++ b/lab7/kernel/include/dtb.h @@ -0,0 +1,38 @@ +#pragma once + +#include "utils.h" + +#define FDT_BEGIN_NODE (0x00000001) +#define FDT_END_NODE (0x00000002) +#define FDT_PROP (0x00000003) +#define FDT_NOP (0x00000004) +#define FDT_END (0x00000009) + +typedef struct { + uint32_t magic; + uint32_t totalsize; + uint32_t off_dt_struct; + uint32_t off_dt_strings; + uint32_t off_mem_rsvmap; + uint32_t version; + uint32_t last_comp_version; + uint32_t boot_cpuid_phys; + uint32_t size_dt_strings; + uint32_t size_dt_struct; +} fdt_header; + +void mailbox_probe(uint64_t struct_addr, uint64_t strings_addr, int depth); +void gpio_probe(uint64_t struct_addr, uint64_t strings_addr, int depth); +void rtx3080ti_probe(uint64_t struct_addr, uint64_t strings_addr, int depth); +void default_probe(uint64_t struct_addr, uint64_t strings_addr, int depth); +int check_compatibility(uint64_t struct_addr, uint64_t strings_addr, + char *compatible_name); + +void dtb_print(int all); +void dtb_parse(uint64_t struct_addr, uint64_t strings_addr, + void (*callback)(uint64_t, uint64_t, int)); +uint64_t ignore_current_node(uint64_t struct_addr, uint64_t strings_addr); +uint64_t print_node(uint64_t struct_addr, uint64_t strings_addr, int depth); +uint64_t print_property(uint64_t struct_addr, uint64_t strings_addr, int depth); +uint32_t dtb_read_int(uint64_t addr_ptr); +// char *dtb_read_string(uint64_t *addr_ptr); \ No newline at end of file diff --git a/lab7/kernel/include/exception.h b/lab7/kernel/include/exception.h new file mode 100644 index 000000000..b6e34b279 --- /dev/null +++ b/lab7/kernel/include/exception.h @@ -0,0 +1,12 @@ +#pragma once + +#include "gpio.h" +#include "utils.h" +#include +void sync_handler_currentEL_ELx(); +void sync_handler_lowerEL_64(uint64_t sp_addr); +void irq_handler_currentEL_ELx(); +void irq_handler_lowerEL_64(); +void default_handler(); +void enable_interrupt(); +void disable_interrupt(); \ No newline at end of file diff --git a/lab7/kernel/include/gpio.h b/lab7/kernel/include/gpio.h new file mode 100644 index 000000000..52fa671d0 --- /dev/null +++ b/lab7/kernel/include/gpio.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * 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. + * + */ + +#define MMIO_BASE 0x3F000000 + +#define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE+0x00200000)) +#define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE+0x00200004)) +#define GPFSEL2 ((volatile unsigned int*)(MMIO_BASE+0x00200008)) +#define GPFSEL3 ((volatile unsigned int*)(MMIO_BASE+0x0020000C)) +#define GPFSEL4 ((volatile unsigned int*)(MMIO_BASE+0x00200010)) +#define GPFSEL5 ((volatile unsigned int*)(MMIO_BASE+0x00200014)) +#define GPSET0 ((volatile unsigned int*)(MMIO_BASE+0x0020001C)) +#define GPSET1 ((volatile unsigned int*)(MMIO_BASE+0x00200020)) +#define GPCLR0 ((volatile unsigned int*)(MMIO_BASE+0x00200028)) +#define GPLEV0 ((volatile unsigned int*)(MMIO_BASE+0x00200034)) +#define GPLEV1 ((volatile unsigned int*)(MMIO_BASE+0x00200038)) +#define GPEDS0 ((volatile unsigned int*)(MMIO_BASE+0x00200040)) +#define GPEDS1 ((volatile unsigned int*)(MMIO_BASE+0x00200044)) +#define GPHEN0 ((volatile unsigned int*)(MMIO_BASE+0x00200064)) +#define GPHEN1 ((volatile unsigned int*)(MMIO_BASE+0x00200068)) +#define GPPUD ((volatile unsigned int*)(MMIO_BASE+0x00200094)) +#define GPPUDCLK0 ((volatile unsigned int*)(MMIO_BASE+0x00200098)) +#define GPPUDCLK1 ((volatile unsigned int*)(MMIO_BASE+0x0020009C)) diff --git a/lab7/kernel/include/math.h b/lab7/kernel/include/math.h new file mode 100644 index 000000000..b3c6a317f --- /dev/null +++ b/lab7/kernel/include/math.h @@ -0,0 +1,6 @@ +#ifndef MATH_H +#define MATH_H + +int pow(int base, int exponent); + +#endif \ No newline at end of file diff --git a/lab7/kernel/include/mbox.h b/lab7/kernel/include/mbox.h new file mode 100644 index 000000000..b08665886 --- /dev/null +++ b/lab7/kernel/include/mbox.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * 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. + * + */ + +/* a properly aligned buffer */ +extern unsigned int mbox[36]; + +#define MBOX_REQUEST 0 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define MBOX_TAG_SETPOWER 0x28001 +#define MBOX_TAG_SETCLKRATE 0x38002 +#define MBOX_TAG_GETSERIAL 0x10004 +#define MBOX_TAG_GETBDVS 0x00010002 +#define MBOX_TAG_GETARMMEM 0x00010005 + +#define MBOX_TAG_LAST 0 + +int mbox_call(unsigned char ch, unsigned int* mbox); diff --git a/lab7/kernel/include/power.h b/lab7/kernel/include/power.h new file mode 100644 index 000000000..4216fa556 --- /dev/null +++ b/lab7/kernel/include/power.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * 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. + * + */ + +void power_off(); +void reset(); diff --git a/lab7/kernel/include/printf.h b/lab7/kernel/include/printf.h new file mode 100644 index 000000000..e58f666dc --- /dev/null +++ b/lab7/kernel/include/printf.h @@ -0,0 +1,117 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// 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. +// +// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. +// Use this instead of bloated standard/newlib printf. +// These routines are thread safe and reentrant. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _PRINTF_H_ +#define _PRINTF_H_ + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Output a character to a custom device like UART, used by the printf() function + * This function is declared here only. You have to write your custom implementation somewhere + * \param character Character to output + */ +void _putchar(char character); + + +/** + * Tiny printf implementation + * You have to implement _putchar if you use printf() + * To avoid conflicts with the regular printf() API it is overridden by macro defines + * and internal underscore-appended functions like printf_() are used + * \param format A string that specifies the format of the output + * \return The number of characters that are written into the array, not counting the terminating null character + */ +#define printf printf_ +int printf_(const char* format, ...); + + +/** + * Tiny sprintf implementation + * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! + * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! + * \param format A string that specifies the format of the output + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + */ +#define sprintf sprintf_ +int sprintf_(char* buffer, const char* format, ...); + + +/** + * Tiny snprintf/vsnprintf implementation + * \param buffer A pointer to the buffer where to store the formatted string + * \param count The maximum number of characters to store in the buffer, including a terminating null character + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that COULD have been written into the buffer, not counting the terminating + * null character. A value equal or larger than count indicates truncation. Only when the returned value + * is non-negative and less than count, the string has been completely written. + */ +#define snprintf snprintf_ +#define vsnprintf vsnprintf_ +int snprintf_(char* buffer, size_t count, const char* format, ...); +int vsnprintf_(char* buffer, size_t count, const char* format, va_list va); + + +/** + * Tiny vprintf implementation + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + */ +#define vprintf vprintf_ +int vprintf_(const char* format, va_list va); + + +/** + * printf with output function + * You may use this as dynamic alternative to printf() with its fixed _putchar() output + * \param out An output function which takes one character and an argument pointer + * \param arg An argument pointer for user data passed to output function + * \param format A string that specifies the format of the output + * \return The number of characters that are sent to the output function, not counting the terminating null character + */ +int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...); + + +#ifdef __cplusplus +} +#endif + + +#endif // _PRINTF_H_ \ No newline at end of file diff --git a/lab7/kernel/include/shell.h b/lab7/kernel/include/shell.h new file mode 100644 index 000000000..1f7075b10 --- /dev/null +++ b/lab7/kernel/include/shell.h @@ -0,0 +1,32 @@ +#include "uart.h" +#include "string.h" +#include "power.h" +#include "mbox.h" +#include "cpio.h" +#include "timer.h" +#include "exception.h" +#include "alloc.h" +#include "utils.h" +#include "thread.h" +#include "printf.h" +// #include "device_tree.h" +#define RAMFS_ADDR 0x8000000 + +void clean_buffer(char * buffer, int buffer_len); +void command_help(); +void command_hello(); +void command_not_found(char * buffer); +void command_ls(); +void command_cat(char* pathname); +void command_mailbox(); +void command_test(); +void command_load_user_program(const char *program_name); +void command_set_timeout(char *args); +void command_buddy_test(); +void command_dma_test(); +void command_thread_test1() ; +void command_thread_test2() ; +void command_thread_test3() ; +void command_thread_test4() ; +void parse_command(char * buffer); +void run_shell(); diff --git a/lab7/kernel/include/string.h b/lab7/kernel/include/string.h new file mode 100644 index 000000000..5782c937d --- /dev/null +++ b/lab7/kernel/include/string.h @@ -0,0 +1,6 @@ +#pragma once + +int strcmp(const char *p1, const char *p2); +int strncmp(const char *s1, const char *s2, unsigned n); +int strlen(const char *s); +char *strstr(const char *s, const char *find); \ No newline at end of file diff --git a/lab7/kernel/include/thread.h b/lab7/kernel/include/thread.h new file mode 100644 index 000000000..1b0a22a25 --- /dev/null +++ b/lab7/kernel/include/thread.h @@ -0,0 +1,73 @@ +#pragma once + +#include "utils.h" + +#define STACK_SIZE 4096 +#define USER_PROGRAM_BASE 0x30000000 +#define USER_PROGRAM_SIZE (1 * mb) + +#define THREAD_DEAD 1 +#define THREAD_FORK 2 +#define THREAD_READY 4 + +typedef struct { + uint64_t x19; + uint64_t x20; + uint64_t x21; + uint64_t x22; + uint64_t x23; + uint64_t x24; + uint64_t x25; + uint64_t x26; + uint64_t x27; + uint64_t x28; + uint64_t fp; + uint64_t lr; + uint64_t sp; +} cpu_context; + +typedef struct thread_info { + cpu_context context; + uint32_t pid; + uint32_t child_pid; + int status; + uint64_t trap_frame_addr; + uint64_t kernel_stack_base; + uint64_t user_stack_base; + uint64_t user_program_base; + uint32_t user_program_size; + struct thread_info *next; +} thread_info; + +typedef struct { + thread_info *head, *tail; +} thread_queue; + +typedef struct { + uint64_t x[31]; +} trap_frame_t; + +thread_queue run_queue; +uint32_t thread_cnt; + +extern thread_info *get_current(); +extern void switch_to(thread_info *, thread_info *); + +void foo(); +void thread_test1(); +void thread_test2(); +void thread_test3(); +void thread_test4(); + +void thread_init(); +thread_info *thread_create(void (*func)()); +void schedule(); +void idle(); +void exit(); +void run_queue_push(thread_info *thread); +void kill_zombies(); +void exec(const char *program_name, const char **argv); +void fork(uint64_t sp); +void handle_fork(); +void create_child(thread_info *parent, thread_info *child); +void kill (int kill_pid); \ No newline at end of file diff --git a/lab7/kernel/include/timer.h b/lab7/kernel/include/timer.h new file mode 100644 index 000000000..e42bee18d --- /dev/null +++ b/lab7/kernel/include/timer.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#define CORE0_TIMER_IRQ_CTRL ((volatile unsigned int *)(0x40000040)) +#define CORE0_INTERRUPT_SOURCE ((volatile unsigned int *)(0x40000060)) + +typedef struct timeout_event { + uint32_t register_time; + uint32_t duration; + void (*callback)(char *); + char args[20]; + struct timeout_event *prev, *next; +} timeout_event; + +timeout_event *timeout_queue_head, *timeout_queue_tail; + +void timeout_event_init(); +void core_timer_enable(); +void core_timer_disable(); +void core_timer_handler_lowerEL_64(); +void core_timer_handler_currentEL_ELx(); +void add_timer(void (*callback)(char *), char *args, uint32_t duration); +uint64_t get_current_time(); +void set_expired_time(uint32_t duration); +void timer_callback(char *msg); \ No newline at end of file diff --git a/lab7/kernel/include/uart.h b/lab7/kernel/include/uart.h new file mode 100644 index 000000000..e624348c0 --- /dev/null +++ b/lab7/kernel/include/uart.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * 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. + * + */ + +#pragma once +#include "gpio.h" +#include +#define ARM_IRQ_REG_BASE (MMIO_BASE + 0x0000b000) + +#define IRQ_PENDING_1 ((volatile unsigned int *)(ARM_IRQ_REG_BASE + 0x00000204)) +#define ENABLE_IRQS_1 ((volatile unsigned int *)(ARM_IRQ_REG_BASE + 0x00000210)) +#define DISABLE_IRQS_1 \ + ((volatile unsigned int *)(ARM_IRQ_REG_BASE + 0x0000021c)) + +#define AUX_IRQ (1 << 29) + +#define UART_BUFFER_SIZE 20 +char read_buf[UART_BUFFER_SIZE]; +char write_buf[UART_BUFFER_SIZE]; +int read_buf_start, read_buf_end; +int write_buf_start, write_buf_end; + +void uart_init(); +void uart_send(unsigned int c); +char uart_getc(); +uint32_t uart_gets(char *buf, uint32_t size); +void uart_puts(char *s); +void uart_hex(unsigned int d); +void uart_putc(char c); +void uart_int(int x); +uint32_t uart_write(char *s, uint32_t size); + +void enable_uart_interrupt(); +void disable_uart_interrupt(); +void assert_transmit_interrupt(); +void clear_transmit_interrupt(); +void uart_handler(); +char uart_async_getc(); +void uart_async_puts(char *str); \ No newline at end of file diff --git a/lab7/kernel/include/utils.h b/lab7/kernel/include/utils.h new file mode 100644 index 000000000..085a90b13 --- /dev/null +++ b/lab7/kernel/include/utils.h @@ -0,0 +1,15 @@ +#ifndef _UTILS_H_ +#define _UTILS_H_ +#include +uint64_t hex_to_int64(char* num); +uint8_t hex_to_int8(char hex); +uint64_t hex2int(char *hex, int len); +uint64_t align_up(uint64_t addr, uint64_t alignment); +uint64_t align_up_exp(uint64_t n); +#define kb ((uint64_t)0x400) +#define mb ((uint64_t)0x100000) +#define gb ((uint64_t)0x40000000) +uint64_t log2(uint64_t num); +void delay(int num); +uint32_t be2le(uint32_t x); +#endif diff --git a/lab7/kernel/src/alloc.c b/lab7/kernel/src/alloc.c new file mode 100644 index 000000000..a4d026a16 --- /dev/null +++ b/lab7/kernel/src/alloc.c @@ -0,0 +1,446 @@ +#include "alloc.h" +#include "uart.h" +#include "utils.h" +#include "printf.h" + +void buddy_test() { + print_frame_lists(); + uint64_t size[6] = { + PAGE_SIZE * 1, PAGE_SIZE * 13, PAGE_SIZE * 16, + PAGE_SIZE * 2, PAGE_SIZE * 4, PAGE_SIZE * 8, + }; + page_frame *frame_ptr[6]; + printf("********** buddy allocation test **********\n"); + for (int i = 0; i < 6; i++) { + printf("Press any key to continue..."); + char c = uart_getc(); + if (c != '\n') printf("\n"); + frame_ptr[i] = buddy_allocate(size[i]); + printf("Successfully allocate %lld pages\n", size[i] / PAGE_SIZE); + // if (c == 'p') + print_frame_lists(); + } + print_frame_lists(); + printf("********** buddy free test **********\n"); + for (int i = 0; i < 6; i++) { + printf("Press any key to continue..."); + char c = uart_getc(); + if (c != '\n') printf("\n"); + buddy_free(frame_ptr[i]); + printf("Successfully free %lld pages\n", size[i] / PAGE_SIZE); + // if (c == 'p') + print_frame_lists(); + } +} + +void dma_test() { + print_frame_lists(); + print_dma_list(); + // int *ptr1 = malloc(sizeof(int)); + // int *ptr2 = malloc(sizeof(int) * 1024); + // int *ptr3 = malloc(sizeof(int)); + // print_dma_list(); + // free(ptr1); + // print_dma_list(); + // free(ptr2); + // print_dma_list(); + // free(ptr3); + + uint64_t size[6] = { + sizeof(int) * 1, sizeof(int) * 8, sizeof(int) * 2201, + sizeof(int) * 9, sizeof(int) * 3068, sizeof(int) * 100, + }; + void *ptr[6]; + + printf("********** malloc test **********\n"); + for (int i = 0; i < 6; i++) { + printf("Press any key to continue..."); + char c = uart_getc(); + if (c != '\n') printf("\n"); + ptr[i] = malloc(size[i]); + printf("Successfully allocate %lld bytes in address %p\n", size[i], ptr[i]); + // if (c == 'p') { + print_frame_lists(); + print_dma_list(); // printf( + // "put frame index %d back to free lists (4K x 2^%lld = %lld KB)\n", + // id, frames[id].order, 1 << (frames[id].order + 2)); + // } + } + // print_frame_lists(); + // print_dma_list(); + printf("********** free test **********\n"); + for (int i = 0; i < 6; i++) { + printf("Press any key to continue..."); + char c = uart_getc(); + if (c != '\n') printf("\n"); + free(ptr[i]); + printf("Successfully free %lld bytes in address %p\n", size[i], ptr[i]); + // if (c == 'p') { + print_frame_lists(); + print_dma_list(); + // } + } +} + +void buddy_init() { + for (int i = 0; i < MAX_PAGE_NUM; i++) { + frames[i].id = i; + frames[i].order = -1; + frames[i].is_allocated = 0; + frames[i].addr = PAGE_BASE_ADDR + i * PAGE_SIZE; + frames[i].next = 0; + } + for (int i = 0; i < FRAME_LIST_NUM; i++) { + free_frame_lists[i] = 0; + used_frame_lists[i] = 0; + } + frames[0].order = MAX_FRAME_ORDER; + free_frame_lists[MAX_FRAME_ORDER] = &frames[0]; + free_dma_list = 0; +} + +page_frame * buddy_allocate(uint64_t size) { + // printf("Enter size (kb): "); + // int kb_size = read_i(); + uint64_t page_num = size / PAGE_SIZE; + if (size % PAGE_SIZE != 0) page_num++; + page_num = align_up_exp(page_num); + uint64_t order = log2(page_num); + + for (uint64_t i = order; i <= MAX_FRAME_ORDER; i++) { + // printf("i = "); + // uart_int(i); + // printf("\n"); + + if (free_frame_lists[i]) { + int cur_id = free_frame_lists[i]->id; + free_frame_lists[i] = free_frame_lists[i]->next; + frames[cur_id].order = order; + frames[cur_id].is_allocated = 1; + frames[cur_id].next = used_frame_lists[order]; + used_frame_lists[order] = &frames[cur_id]; + // printf("allocate frame index %d (4K x 2^%lld = %lld KB)\n", cur_id, order, + // 1 << (order + 2)); + + // release redundant memory block + for (; i > order; i--) { + int id = cur_id + (1 << (i - 1)); + frames[id].order = i - 1; + frames[id].is_allocated = 0; + frames[id].next = free_frame_lists[i - 1]; + free_frame_lists[i - 1] = &frames[id]; + // printf( + // "put frame index %d back to free lists (4K x 2^%lld = %lld KB)\n", + // id, frames[id].order, 1 << (frames[id].order + 2)); + } + // printf("\n"); + // print_frame_lists(); + return &frames[cur_id]; + } + } + return 0; +} + +void buddy_free(page_frame *frame) { + // printf("Enter address (hex): "); + // uint64_t addr = read_h(); + uint64_t index = frame->id; + if (!frames[index].is_allocated) { + printf("Error: it is already free\n"); + return; + } + uint64_t order = frames[index].order; + // printf("index :"); + // uart_int(index); + // printf("order :"); + // uart_int(order); + // printf("\n"); + buddy_unlink(index, 1); + // iterative merge + while (order <= MAX_FRAME_ORDER) { + uint64_t target_index = index ^ (1 << order); // XOR to find same size page + // printf("target_index :"); + // uart_int(target_index); + // printf("\n"); + if ((target_index >= MAX_PAGE_NUM) || frames[target_index].is_allocated || + (frames[target_index].order != order)) + break; + + // printf("merge with frame index %d (4K x 2^%lld = %lld KB)\n", target_index, + // frames[target_index].order, 1 << (frames[target_index].order + 2)); + order += 1; + // iterative part + if (index > target_index) index = target_index; + } + frames[index].order = order; + frames[index].next = free_frame_lists[order]; + free_frame_lists[order] = &frames[index]; + // printf("put frame index %d back (4K x 2^%lld = %lld KB)\n", index, + // frames[index].order, 1 << (frames[index].order + 2)); + // print_frame_lists(); +} + +void buddy_unlink(int index, int type) { + uint64_t order = frames[index].order; + frames[index].order = -1; + frames[index].is_allocated = 0; + + if (type == 0) { + if (free_frame_lists[order] == &frames[index]) { + free_frame_lists[order] = frames[index].next; + frames[index].next = 0; + } else { + // printf("=========linked list search free=======\n"); + for (page_frame *cur = free_frame_lists[order]; cur; cur = cur->next) { + if (cur->next == &frames[index]) { + cur->next = frames[index].next; + frames[index].next = 0; + break; + } + } + } + } + if (type == 1) { + if (used_frame_lists[order] == &frames[index]) { + used_frame_lists[order] = frames[index].next; + frames[index].next = 0; + } else { + // printf("=========linked list search used=======\n"); + for (page_frame *cur = used_frame_lists[order]; cur; cur = cur->next) { + if (cur->next == &frames[index]) { + cur->next = frames[index].next; + frames[index].next = 0; + break; + } + } + } + } +} + +void print_frame_lists() { + printf("========================\n"); + printf("Free frame lists: \n"); + for (int i = MAX_FRAME_ORDER; i >= 0; i--) { + printf("4K x 2^%d (%d KB):", i, 1 << (i + 2)); + for (page_frame *cur = free_frame_lists[i]; cur; cur = cur->next) { + printf(" index %d(0x%x)", cur->id, cur->addr); + } + printf("\n"); + } + printf("\n"); + printf("Used frame lists: \n"); + for (int i = MAX_FRAME_ORDER; i >= 0; i--) { + printf("4K x 2^%d (%d KB):", i, 1 << (i + 2)); + for (page_frame *cur = used_frame_lists[i]; cur; cur = cur->next) { + printf(" index %d(0x%x)", cur->id, cur->addr); + } + printf("\n"); + } + printf("========================\n"); +} + +void *malloc(uint64_t size) { + dma_header *free_slot = 0; + uint64_t min_size = ((uint64_t)1) << 63; + // printf("min_size :"); + // uart_int(min_size); + // printf("\n"); + // printf("size :"); + // uart_int(size); + // printf("\n"); + // find the smallest free slot which is bigger than the required size + for (dma_header *cur = free_dma_list; cur; cur = cur->next) { + // printf("find the smallest free slot which is bigger than the required size\n"); + + uint64_t data_size = cur->total_size - align_up(sizeof(dma_header), 8); + if (data_size >= align_up(size, 8) && data_size < min_size) { + free_slot = cur; + min_size = data_size; + } + } + + uint64_t allocated_size = align_up(sizeof(dma_header), 8) + align_up(size, 8); + // printf("allocated_size :"); + // uart_int(allocated_size); + // printf("\n"); + if (free_slot) { + // printf("have free_slot\n"); + + uint64_t addr = (uint64_t)free_slot; + uint64_t total_size = free_slot->total_size; + // rewrite the found free slot + free_slot->total_size = allocated_size; + free_slot->used_size = size; + free_slot->is_allocated = 1; + if (free_slot->prev) { + // printf("if (free_slot->prev)\n"); + free_slot->prev->next = free_slot->next; + } + if (free_slot->next) { + // printf("if (free_slot->next)\n"); + free_slot->next->prev = free_slot->prev; + } + if (free_dma_list == free_slot){ + // printf("if (free_slot->prev)\n"); + free_dma_list = free_slot->next; + } + free_slot->prev = 0; + free_slot->next = 0; + + // create another free slot if remaining size is big enough + int64_t free_size = + total_size - allocated_size - align_up(sizeof(dma_header), 8); + if (free_size > 0) { + dma_header *new_header = (dma_header *)(addr + allocated_size); + new_header->total_size = total_size - allocated_size; + new_header->used_size = 0; + new_header->is_allocated = 0; + new_header->frame_ptr = free_slot->frame_ptr; + new_header->prev = 0; + new_header->next = free_dma_list; + if (free_dma_list) free_dma_list->prev = new_header; + free_dma_list = new_header; + } else { + free_slot->total_size = total_size; + } + return (void *)(addr + align_up(sizeof(dma_header), 8)); + } else { + // printf("no free_slot\n"); + + // allocate a page + page_frame *frame_ptr = buddy_allocate(allocated_size); + uint64_t addr = frame_ptr->addr; + // printf("addr :"); + // uart_hex(addr); + // printf("\n"); + // create a free slot + dma_header *allocated_header = (dma_header *)addr; + allocated_header->total_size = allocated_size; + allocated_header->used_size = size; + allocated_header->is_allocated = 1; + allocated_header->frame_ptr = frame_ptr; + allocated_header->prev = 0; + allocated_header->next = 0; + // create another free slot if remaining size is big enough + uint64_t order = frame_ptr->order; + uint64_t total_size = (1 << order) * 4 * kb; + int64_t free_size = total_size - allocated_size - align_up(sizeof(dma_header), 8); + // printf("order :"); + // uart_int(order); + // printf("\n"); + // printf("total_size :"); + // uart_int(total_size); + // printf("\n"); + // printf("free_size :"); + // uart_int(free_size); + // printf("\n"); + if (free_size > 0) { + dma_header *new_header = (dma_header *)(addr + allocated_size); + new_header->total_size = total_size - allocated_size; + new_header->used_size = 0; + new_header->is_allocated = 0; + new_header->frame_ptr = frame_ptr; + new_header->prev = 0; + new_header->next = free_dma_list; + if (free_dma_list) free_dma_list->prev = new_header; + free_dma_list = new_header; + } else { + allocated_header->total_size = total_size; + } + return (void *)(addr + align_up(sizeof(dma_header), 8)); + } + return 0; +} + +void free(void *ptr) { + uint64_t target_addr = (uint64_t)ptr - align_up(sizeof(dma_header), 8); + dma_header *target_header = (dma_header *)target_addr; + target_header->used_size = 0; + target_header->is_allocated = 0; + target_header->prev = 0; + target_header->next = free_dma_list; + if (free_dma_list) free_dma_list->prev = target_header; + free_dma_list = target_header; + + // uart_hex((uint64_t)ptr); + // printf("\n"); + // uart_hex(target_addr); + // printf("\n"); + + page_frame *frame_ptr = target_header->frame_ptr; + uint64_t base_addr = frame_ptr->addr; + uint64_t order = frame_ptr->order; + uint64_t total_frame_size = (1 << order) * 4 * kb; + uint64_t boundary = base_addr + total_frame_size; + + // uart_hex(base_addr); + // printf("\n"); + // uart_hex(total_size); + // printf("\n"); + + // merge next slot if it is free + uint64_t next_addr = target_addr + target_header->total_size; + dma_header *next_header = (dma_header *)next_addr; + if (next_addr < boundary && !next_header->is_allocated) { + if (next_header->prev) next_header->prev->next = next_header->next; + if (next_header->next) next_header->next->prev = next_header->prev; + if (free_dma_list == next_header) free_dma_list = next_header->next; + next_header->prev = 0; + next_header->next = 0; + target_header->total_size += next_header->total_size; + } + // uart_int(target_header->total_size); + // printf("\n"); + // print_dma_list(); + + // merge previous slot if it is free + uint64_t current_addr = base_addr; + while (current_addr < boundary) { + dma_header *header = (dma_header *)current_addr; + uint64_t next_addr = current_addr + header->total_size; + // uart_hex(current_addr); + // printf("\n"); + // uart_hex(next_addr); + // printf("\n"); + if (next_addr == target_addr) { + if (!header->is_allocated) { + header->total_size += target_header->total_size; + // uart_int(header->total_size); + // printf("\n"); + if (target_header->prev) + target_header->prev->next = target_header->next; + if (target_header->next) + target_header->next->prev = target_header->prev; + if (free_dma_list == target_header) free_dma_list = target_header->next; + target_header->prev = 0; + target_header->next = 0; + } + break; + } + current_addr = next_addr; + } + + // free page frame if all slots are free + dma_header *base_header = (dma_header *)base_addr; + if (base_header->total_size == total_frame_size) { + if (base_header->prev) base_header->prev->next = base_header->next; + if (base_header->next) base_header->next->prev = base_header->prev; + if (free_dma_list == base_header) free_dma_list = base_header->next; + base_header->prev = 0; + base_header->next = 0; + buddy_free(frame_ptr); + } +} + +void print_dma_list() { + printf("========================\n"); + printf("Free DMA slots: \n"); + for (dma_header *cur = free_dma_list; cur; cur = cur->next) { + printf("size: "); + uart_int(cur->total_size - align_up(sizeof(dma_header), 8)); + printf(", frame index: "); + uart_int(cur->frame_ptr->id); + printf("\n"); + } + printf("========================\n"); +} diff --git a/lab7/kernel/src/cpio.c b/lab7/kernel/src/cpio.c new file mode 100644 index 000000000..1c1a96b91 --- /dev/null +++ b/lab7/kernel/src/cpio.c @@ -0,0 +1,86 @@ +#include "cpio.h" + +#include "printf.h" +#include "string.h" +#include "utils.h" +void cpio_ls() { + unsigned long long ptr = RAMFS_ADDR; + cpio_newc_header *header; + char *pathname; + + while (1) { + header = (cpio_newc_header *)ptr; + unsigned long long namesize = hex2int(header->c_namesize, 8); + unsigned long long filesize = hex2int(header->c_filesize, 8); + + ptr += sizeof(cpio_newc_header); + pathname = (char *)ptr; + // the end is indicated by a special record with pathname "TRAILER!!!" + if (strcmp(pathname, CPIO_END) == 0) break; + printf("%s ", pathname); + + ptr = align_up(ptr + namesize, 4); + ptr = align_up(ptr + filesize, 4); + } + printf("\n"); +} + +void cpio_cat(char *pathname_to_cat) { + unsigned long long ptr = RAMFS_ADDR; + cpio_newc_header *header; + char *pathname; + + while (1) { + header = (cpio_newc_header *)ptr; + unsigned long long namesize = hex2int(header->c_namesize, 8); + unsigned long long filesize = hex2int(header->c_filesize, 8); + + ptr += sizeof(cpio_newc_header); + pathname = (char *)ptr; + // the end is indicated by a special record with pathname "TRAILER!!!" + if (strcmp(pathname, CPIO_END) == 0) break; + + ptr = align_up(ptr + namesize, 4); + if (strcmp(pathname, pathname_to_cat) == 0) { + char *content = (char *)ptr; + for (unsigned long long i = 0; i < filesize; i++) { + printf("%c", content[i]); + } + printf("\n"); + return; + } + ptr = align_up(ptr + filesize, 4); + } + printf("No such file\n"); +} + +uint32_t cpio_load_user_program(const char *target_program, + uint64_t target_addr) { + unsigned long long ptr = RAMFS_ADDR; + cpio_newc_header *header; + char *pathname; + + while (1) { + header = (cpio_newc_header *)ptr; + unsigned long long namesize = hex2int(header->c_namesize, 8); + unsigned long long filesize = hex2int(header->c_filesize, 8); + + ptr += sizeof(cpio_newc_header); + pathname = (char *)ptr; + // the end is indicated by a special record with pathname "TRAILER!!!" + if (strcmp(pathname, CPIO_END) == 0) break; + + ptr = align_up(ptr + namesize, 4); + if (strcmp(pathname, target_program) == 0) { + char *content = (char *)ptr; + char *target_content = (char *)target_addr; + for (unsigned long long i = 0; i < filesize; i++) { + target_content[i] = content[i]; + } + return filesize; + } + ptr = align_up(ptr + filesize, 4); + } + printf("No such file\n"); + return 0; +} \ No newline at end of file diff --git a/lab7/kernel/src/delays.c b/lab7/kernel/src/delays.c new file mode 100644 index 000000000..aba77264d --- /dev/null +++ b/lab7/kernel/src/delays.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * 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 "gpio.h" + +#define SYSTMR_LO ((volatile unsigned int*)(MMIO_BASE+0x00003004)) +#define SYSTMR_HI ((volatile unsigned int*)(MMIO_BASE+0x00003008)) + +/** + * Wait N CPU cycles (ARM CPU only) + */ +void wait_cycles(unsigned int n) +{ + if(n) while(n--) { asm volatile("nop"); } +} + +/** + * Wait N microsec (ARM CPU only) + */ +void wait_msec(unsigned int n) +{ + register unsigned long f, t, r; + // get the current counter frequency + asm volatile ("mrs %0, cntfrq_el0" : "=r"(f)); + // read the current counter + asm volatile ("mrs %0, cntpct_el0" : "=r"(t)); + // calculate expire value for counter + t+=((f/1000)*n)/1000; + do{asm volatile ("mrs %0, cntpct_el0" : "=r"(r));}while(roff_dt_struct); + uint64_t strings_addr = dtb_addr + be2le(header->off_dt_strings); + + if (all) { + dtb_parse(struct_addr, strings_addr, default_probe); + } else { + printf("\ndevice for mailbox driver function: \n"); + dtb_parse(struct_addr, strings_addr, mailbox_probe); + printf("\ndevice for gpio driver function: \n"); + dtb_parse(struct_addr, strings_addr, gpio_probe); + printf("\ndevice for rtx3080ti driver function: \n"); + dtb_parse(struct_addr, strings_addr, rtx3080ti_probe); + } +} + +void dtb_parse(uint64_t struct_addr, uint64_t strings_addr, + void (*callback)(uint64_t, uint64_t, int)) { + int depth = 0; + while (1) { + uint32_t token = dtb_read_int(struct_addr); + token = be2le(token); + struct_addr += 4; + + if (token == FDT_BEGIN_NODE) { + callback(struct_addr, strings_addr, depth); + struct_addr = ignore_current_node(struct_addr, strings_addr); + depth++; + } else if (token == FDT_END_NODE) { + depth--; + } else if (token == FDT_NOP) { + continue; + } else if (token == FDT_END) { + break; + } + } +} + +uint64_t ignore_current_node(uint64_t struct_addr, uint64_t strings_addr) { + char *name = (char *)(struct_addr); + struct_addr += strlen(name) + 1; + struct_addr = align_up(struct_addr, 4); + + while (1) { + uint32_t token = dtb_read_int(struct_addr); + token = be2le(token); + struct_addr += 4; + + if (token == FDT_BEGIN_NODE) { + struct_addr -= 4; + break; + } else if (token == FDT_END_NODE) { + struct_addr -= 4; + break; + } else if (token == FDT_PROP) { + uint32_t len = dtb_read_int(struct_addr); + len = be2le(len); + struct_addr += 4; + uint32_t nameoff = dtb_read_int(struct_addr); + nameoff = be2le(nameoff); + struct_addr += 4; + struct_addr += len; + struct_addr = align_up(struct_addr, 4); + } else if (token == FDT_NOP) { + continue; + } + } + return struct_addr; +} + +uint64_t print_node(uint64_t struct_addr, uint64_t strings_addr, int depth) { + char *name = (char *)(struct_addr); + struct_addr += strlen(name) + 1; + struct_addr = align_up(struct_addr, 4); + for (int i = 0; i < depth; i++) printf(" "); + printf("node: %s\n", name); + + while (1) { + uint32_t token = dtb_read_int(struct_addr); + token = be2le(token); + struct_addr += 4; + + if (token == FDT_BEGIN_NODE) { + break; + } else if (token == FDT_END_NODE) { + struct_addr -= 4; + break; + } else if (token == FDT_PROP) { + struct_addr = print_property(struct_addr, strings_addr, depth + 1); + } else if (token == FDT_NOP) { + continue; + } + } + return struct_addr; +} + +uint64_t print_property(uint64_t struct_addr, uint64_t strings_addr, + int depth) { + uint32_t len = dtb_read_int(struct_addr); + len = be2le(len); + struct_addr += 4; + uint32_t nameoff = dtb_read_int(struct_addr); + nameoff = be2le(nameoff); + struct_addr += 4; + char *property = (char *)(strings_addr + nameoff); + + int value_type = 0; + char *is_u32[] = {"phandle", "#address-cells", "#size-cells", "virtual-reg", + "interrupt-parent"}; + char *is_string[] = {"compatible", "model", "status", "name", "device_type"}; + + for (int i = 0; i < sizeof(is_u32) / sizeof(is_u32[0]); i++) { + if (strcmp(property, is_u32[i]) == 0) { + value_type = 1; + break; + } + } + for (int i = 0; i < sizeof(is_string) / sizeof(is_string[0]); i++) { + if (strcmp(property, is_string[i]) == 0) { + value_type = 2; + break; + } + } + + for (int i = 0; i < depth; i++) printf(" "); + printf("%s = ", property); + + // hex, e.g. <0x4600 0x100> + if (value_type == 0) { + int count = 0; + printf("<"); + for (uint32_t i = 0; i < len; i += 4) { + if (count > 0) printf(" "); + count++; + uint32_t num = dtb_read_int(struct_addr); + num = be2le(num); + struct_addr += 4; + printf("0x%x", num); + } + printf(">"); + } + // int, e.g. <1> + if (value_type == 1) { + uint32_t num = dtb_read_int(struct_addr); + num = be2le(num); + struct_addr += 4; + printf("<%d>", num); + } + // string or string list, e.g. "fsl,MPC8349EMITX" or "fsl,mpc8641", "ns16550" + if (value_type == 2) { + int count = 0; + uint64_t end = struct_addr + len; + + while (struct_addr < end) { + if (count > 0) printf(", "); + count++; + char *string = (char *)struct_addr; + struct_addr += strlen(string) + 1; + printf("\"%s\"", string); + } + } + printf("\n"); + + struct_addr = align_up(struct_addr, 4); + return struct_addr; +} + +uint32_t dtb_read_int(uint64_t addr_ptr) { + char *base = (char *)(addr_ptr); + uint32_t value = 0; + for (int i = 3; i >= 0; i--) { + value = (value << 8) | (*(base + i) & 0xFF); + } + return value; +} + +// char *dtb_read_string(uint64_t addr_ptr) { +// char *base = (char *)(addr_ptr); +// char *string_start = base; +// return string_start; +// } \ No newline at end of file diff --git a/lab7/kernel/src/exception.S b/lab7/kernel/src/exception.S new file mode 100644 index 000000000..9ef00764b --- /dev/null +++ b/lab7/kernel/src/exception.S @@ -0,0 +1,127 @@ +// save general registers to stack +.macro save_reg + sub sp, sp, 32 * 9 + stp x0, x1, [sp, 16 * 0] + stp x2, x3, [sp, 16 * 1] + stp x4, x5, [sp, 16 * 2] + stp x6, x7, [sp, 16 * 3] + stp x8, x9, [sp, 16 * 4] + stp x10, x11, [sp, 16 * 5] + stp x12, x13, [sp, 16 * 6] + stp x14, x15, [sp, 16 * 7] + stp x16, x17, [sp, 16 * 8] + stp x18, x19, [sp, 16 * 9] + stp x20, x21, [sp, 16 * 10] + stp x22, x23, [sp, 16 * 11] + stp x24, x25, [sp, 16 * 12] + stp x26, x27, [sp, 16 * 13] + stp x28, x29, [sp, 16 * 14] + //str x30, [sp, 16 * 15] + mrs x10, spsr_el1 + mrs x11, elr_el1 + mrs x12, sp_el0 + stp x30, x10, [sp, 16 * 15] + stp x11, x12, [sp, 16 * 16] +.endm + +// load general registers from stack +.macro load_reg + ldp x30, x10, [sp, 16 * 15] + ldp x11, x12, [sp, 16 * 16] + msr spsr_el1, x10 + msr elr_el1, x11 + msr sp_el0, x12 + ldp x0, x1, [sp, 16 * 0] + ldp x2, x3, [sp, 16 * 1] + ldp x4, x5, [sp, 16 * 2] + ldp x6, x7, [sp, 16 * 3] + ldp x8, x9, [sp, 16 * 4] + ldp x10, x11, [sp, 16 * 5] + ldp x12, x13, [sp, 16 * 6] + ldp x14, x15, [sp, 16 * 7] + ldp x16, x17, [sp, 16 * 8] + ldp x18, x19, [sp, 16 * 9] + ldp x20, x21, [sp, 16 * 10] + ldp x22, x23, [sp, 16 * 11] + ldp x24, x25, [sp, 16 * 12] + ldp x26, x27, [sp, 16 * 13] + ldp x28, x29, [sp, 16 * 14] + //ldr x30, [sp, 16 * 15] + //ldp x30, x10, [sp, 16 * 15] + //ldp x11, x12, [sp, 16 * 16] + //msr spsr_el1, x10 + //msr elr_el1, x11 + //msr sp_el0, x12 + add sp, sp, 32 * 9 +.endm + +.align 11 // vector table should be aligned to 0x800 +.global exception_vector_table +exception_vector_table: + b _default_handler // branch to a handler function. + .align 7 // entry size is 0x80, .align will pad 0 + b _default_handler + .align 7 + b _default_handler + .align 7 + b _default_handler + .align 7 + + b _sync_handler_currentEL_ELx + .align 7 + b _irq_handler_currentEL_ELx + .align 7 + b _default_handler + .align 7 + b _default_handler + .align 7 + + b _sync_handler_lowerEL_64 + .align 7 + b _irq_handler_lowerEL_64 + .align 7 + b _default_handler + .align 7 + b _default_handler + .align 7 + + b _default_handler + .align 7 + b _default_handler + .align 7 + b _default_handler + .align 7 + b _default_handler + .align 7 + +_sync_handler_currentEL_ELx: + save_reg + bl sync_handler_currentEL_ELx // exception.c + load_reg + eret + +_sync_handler_lowerEL_64: + save_reg + //mrs x0, sp_el0 + mov x0, sp + bl sync_handler_lowerEL_64 // exception.c + load_reg + eret + +_irq_handler_currentEL_ELx: + save_reg + bl irq_handler_currentEL_ELx // exception.c + load_reg + eret + +_irq_handler_lowerEL_64: + save_reg + bl irq_handler_lowerEL_64 // exception.c + load_reg + eret + +_default_handler: + save_reg + bl default_handler // exception.c + load_reg + eret \ No newline at end of file diff --git a/lab7/kernel/src/exception.c b/lab7/kernel/src/exception.c new file mode 100644 index 000000000..3addfcadb --- /dev/null +++ b/lab7/kernel/src/exception.c @@ -0,0 +1,111 @@ +#include "exception.h" +#include "uart.h" +#include "utils.h" +#include "timer.h" +#include "string.h" +#include "thread.h" +#include "printf.h" +#include "mbox.h" +int count = 0; + +void enable_interrupt() { asm volatile("msr DAIFClr, 0xf"); } + +void disable_interrupt() { asm volatile("msr DAIFSet, 0xf"); } + +void sync_handler_currentEL_ELx() { + // printf("[sync_handler_currentEL_ELx]\n"); + + uint64_t spsr_el1, elr_el1, esr_el1; + asm volatile("mrs %0, spsr_el1" : "=r"(spsr_el1)); + asm volatile("mrs %0, elr_el1" : "=r"(elr_el1)); + asm volatile("mrs %0, esr_el1" : "=r"(esr_el1)); + // printf("SPSR_EL1: 0x%08x\n", spsr_el1); + // printf("ELR_EL1: 0x%08x\n", elr_el1); + // printf("ESR_EL1: 0x%08x\n", esr_el1); + // printf("hi\n"); +} + +void sync_handler_lowerEL_64(uint64_t sp) { + // printf("sync_handler_lowerEL_64 sp : %x\n",sp); + uint64_t spsr_el1, elr_el1, esr_el1; + asm volatile("mrs %0, spsr_el1" : "=r"(spsr_el1)); + asm volatile("mrs %0, elr_el1" : "=r"(elr_el1)); + asm volatile("mrs %0, esr_el1" : "=r"(esr_el1)); + // printf("sync, SPSR_EL1: 0x%08x\n", spsr_el1); + // printf("ELR_EL1: 0x%08x\n", elr_el1); + // printf("ESR_EL1: 0x%08x\n", esr_el1); + + uint32_t ec = (esr_el1 >> 26) & 0x3f; + // printf("EC: %x\n", ec); + if (ec == 0b010101) { // SVC instruction + // printf("pid = %d, ",get_current()->pid); + uint64_t iss; + asm volatile("mov %0, x8" : "=r"(iss)); + // printf("syscall number: %d\n", iss); + trap_frame_t *trap_frame = (trap_frame_t *)sp; + + if (iss == 0) { // getpid + uint32_t pid = get_current()->pid; + trap_frame->x[0] = pid; + } else if (iss == 1) { // uartread + // printf("[read]\n"); + disable_uart_interrupt(); + enable_interrupt(); + char *str = (char *)(trap_frame->x[0]); + uint32_t size = (uint32_t)(trap_frame->x[1]); + size = uart_gets(str, size); + trap_frame->x[0] = size; + } else if (iss == 2) { // uartwrite + // printf("[write]\n"); + char *str = (char *)(trap_frame->x[0]); + trap_frame->x[0] = uart_write(str,trap_frame->x[1]); + } else if (iss == 3) { // exec + const char *program_name = (const char *)trap_frame->x[0]; + const char **argv = (const char **)trap_frame->x[1]; + exec(program_name, argv); + } else if (iss == 4) { // fork + // printf("[fork]\n"); + fork(sp); + } else if (iss == 5) { // exit + exit(); + } else if (iss == 6) { // mbox_call + // printf("[mbox_call]\n"); + trap_frame->x[0] = mbox_call(trap_frame->x[0],(unsigned int *)trap_frame->x[1]); + } else if (iss == 7) { // kill + kill((int)trap_frame->x[0]); + } + } +} + + +void irq_handler_currentEL_ELx() { + // printf("====irq_handler_currentEL_ELx=====\n"); + + disable_interrupt(); + uint32_t is_uart = (*IRQ_PENDING_1 & AUX_IRQ); + uint32_t is_core_timer = (*CORE0_INTERRUPT_SOURCE & 0x2); + + if (is_uart) { + uart_handler(); + } else if (is_core_timer) { + core_timer_handler_lowerEL_64(); + } + enable_interrupt(); +} + +void irq_handler_lowerEL_64() { + // printf("====irq_handler_lowerEL_64=====\n"); + disable_interrupt(); + uint32_t is_uart = (*IRQ_PENDING_1 & AUX_IRQ); + uint32_t is_core_timer = (*CORE0_INTERRUPT_SOURCE & 0x2); + + if (is_uart) { + uart_handler(); + } else if (is_core_timer) { + core_timer_handler_lowerEL_64(); + } + enable_interrupt(); +} + + +void default_handler() { uart_puts("===== default handler =====\n"); } diff --git a/lab7/kernel/src/linker.ld b/lab7/kernel/src/linker.ld new file mode 100644 index 000000000..ef09ab120 --- /dev/null +++ b/lab7/kernel/src/linker.ld @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * 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. + * + */ + +SECTIONS +{ + . = 0x80000; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start)>>3; \ No newline at end of file diff --git a/lab7/kernel/src/main.c b/lab7/kernel/src/main.c new file mode 100644 index 000000000..869bc35f7 --- /dev/null +++ b/lab7/kernel/src/main.c @@ -0,0 +1,29 @@ +#include "uart.h" +#include "string.h" +#include "power.h" +#include "mbox.h" +#include "cpio.h" +#include "timer.h" +#include "exception.h" +#include "alloc.h" +#include "utils.h" +#include "thread.h" +#include "printf.h" +#include "shell.h" + +// #include "device_tree.h" +void main() +{ + // set up serial console + uart_init(); + buddy_init(); + //welcome message + uart_puts("*****************************\r\n"); + uart_puts("* welcome OSC2022 *\r\n"); + uart_puts("*****************************\r\n"); + timeout_event_init(); + enable_interrupt(); + thread_init(); + run_shell(); +} + diff --git a/lab7/kernel/src/math.c b/lab7/kernel/src/math.c new file mode 100644 index 000000000..2b89b515c --- /dev/null +++ b/lab7/kernel/src/math.c @@ -0,0 +1,9 @@ +int pow(int base, int exponent) +{ + int result = 1; + for ( ; exponent > 0; exponent--) + { + result = result * base; + } + return result; +} \ No newline at end of file diff --git a/lab7/kernel/src/mbox.c b/lab7/kernel/src/mbox.c new file mode 100644 index 000000000..f0ce82048 --- /dev/null +++ b/lab7/kernel/src/mbox.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * 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 "gpio.h" + +/* mailbox message buffer */ +volatile unsigned int __attribute__((aligned(16))) mbox[36]; + +#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880) +#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0)) +#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10)) +#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14)) +#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18)) +#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C)) +#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20)) +#define MBOX_RESPONSE 0x80000000 +#define MBOX_FULL 0x80000000 +#define MBOX_EMPTY 0x40000000 + +/** + * Make a mailbox call. Returns 0 on failure, non-zero on success + */ +int mbox_call(unsigned char ch, unsigned int *user_mbox) +{ + unsigned int r = (((unsigned int)((unsigned long)user_mbox)&~0xF) | (ch&0xF)); + /* wait until we can write to the mailbox */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL); + /* write the address of our message to the mailbox with channel identifier */ + *MBOX_WRITE = r; + /* now wait for the response */ + while(1) { + /* is there a response? */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY); + /* is it a response to our message? */ + if(r == *MBOX_READ) + /* is it a valid successful response? */ + return user_mbox[1]==MBOX_RESPONSE; + } + return 0; +} diff --git a/lab7/kernel/src/power.c b/lab7/kernel/src/power.c new file mode 100644 index 000000000..c066b6259 --- /dev/null +++ b/lab7/kernel/src/power.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * 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 "gpio.h" +#include "mbox.h" +#include "delays.h" + +#define PM_RSTC ((volatile unsigned int*)(MMIO_BASE+0x0010001c)) +#define PM_RSTS ((volatile unsigned int*)(MMIO_BASE+0x00100020)) +#define PM_WDOG ((volatile unsigned int*)(MMIO_BASE+0x00100024)) +#define PM_WDOG_MAGIC 0x5a000000 +#define PM_RSTC_FULLRST 0x00000020 + +/** + * Shutdown the board + */ +void power_off() +{ + unsigned long r; + + // power off devices one by one + for(r=0;r<16;r++) { + mbox[0]=8*4; + mbox[1]=MBOX_REQUEST; + mbox[2]=MBOX_TAG_SETPOWER; // set power state + mbox[3]=8; + mbox[4]=8; + mbox[5]=(unsigned int)r; // device id + mbox[6]=0; // bit 0: off, bit 1: no wait + mbox[7]=MBOX_TAG_LAST; + mbox_call(MBOX_CH_PROP,mbox); + } + + // power off gpio pins (but not VCC pins) + *GPFSEL0 = 0; *GPFSEL1 = 0; *GPFSEL2 = 0; *GPFSEL3 = 0; *GPFSEL4 = 0; *GPFSEL5 = 0; + *GPPUD = 0; + wait_cycles(150); + *GPPUDCLK0 = 0xffffffff; *GPPUDCLK1 = 0xffffffff; + wait_cycles(150); + *GPPUDCLK0 = 0; *GPPUDCLK1 = 0; // flush GPIO setup + + // power off the SoC (GPU + CPU) + r = *PM_RSTS; r &= ~0xfffffaaa; + r |= 0x555; // partition 63 used to indicate halt + *PM_RSTS = PM_WDOG_MAGIC | r; + *PM_WDOG = PM_WDOG_MAGIC | 10; + *PM_RSTC = PM_WDOG_MAGIC | PM_RSTC_FULLRST; +} + +/** + * Reboot + */ +void reset() +{ + unsigned int r; + // trigger a restart by instructing the GPU to boot from partition 0 + r = *PM_RSTS; r &= ~0xfffffaaa; + *PM_RSTS = PM_WDOG_MAGIC | r; // boot from partition 0 + *PM_WDOG = PM_WDOG_MAGIC | 10; + *PM_RSTC = PM_WDOG_MAGIC | PM_RSTC_FULLRST; +} diff --git a/lab7/kernel/src/printf.c b/lab7/kernel/src/printf.c new file mode 100644 index 000000000..13b92a7b4 --- /dev/null +++ b/lab7/kernel/src/printf.c @@ -0,0 +1,921 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// 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. +// +// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. These routines are thread +// safe and reentrant! +// Use this instead of the bloated standard/newlib printf cause these use +// malloc for printf (and may not be thread safe). +// +/////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "printf.h" + + +// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the +// printf_config.h header file +// default: undefined +#ifdef PRINTF_INCLUDE_CONFIG_H +#include "printf_config.h" +#endif + + +// 'ntoa' conversion buffer size, this must be big enough to hold one converted +// numeric number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef PRINTF_NTOA_BUFFER_SIZE +#define PRINTF_NTOA_BUFFER_SIZE 32U +#endif + +// 'ftoa' conversion buffer size, this must be big enough to hold one converted +// float number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef PRINTF_FTOA_BUFFER_SIZE +#define PRINTF_FTOA_BUFFER_SIZE 32U +#endif + +// support for the floating point type (%f) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_FLOAT +#define PRINTF_SUPPORT_FLOAT +#endif + +// support for exponential floating point notation (%e/%g) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL +#define PRINTF_SUPPORT_EXPONENTIAL +#endif + +// define the default floating point precision +// default: 6 digits +#ifndef PRINTF_DEFAULT_FLOAT_PRECISION +#define PRINTF_DEFAULT_FLOAT_PRECISION 6U +#endif + +// define the largest float suitable to print with %f +// default: 1e9 +#ifndef PRINTF_MAX_FLOAT +#define PRINTF_MAX_FLOAT 1e9 +#endif + +// support for the long long types (%llu or %p) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG +#define PRINTF_SUPPORT_LONG_LONG +#endif + +// support for the ptrdiff_t type (%t) +// ptrdiff_t is normally defined in as long or long long type +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T +#define PRINTF_SUPPORT_PTRDIFF_T +#endif + +/////////////////////////////////////////////////////////////////////////////// + +// internal flag definitions +#define FLAGS_ZEROPAD (1U << 0U) +#define FLAGS_LEFT (1U << 1U) +#define FLAGS_PLUS (1U << 2U) +#define FLAGS_SPACE (1U << 3U) +#define FLAGS_HASH (1U << 4U) +#define FLAGS_UPPERCASE (1U << 5U) +#define FLAGS_CHAR (1U << 6U) +#define FLAGS_SHORT (1U << 7U) +#define FLAGS_LONG (1U << 8U) +#define FLAGS_LONG_LONG (1U << 9U) +#define FLAGS_PRECISION (1U << 10U) +#define FLAGS_ADAPT_EXP (1U << 11U) + + +// import float.h for DBL_MAX +#if defined(PRINTF_SUPPORT_FLOAT) +#include +#endif + +// my custom implementation of _putchar +#include "uart.h" +void _putchar(char character) { + if (character == '\n') uart_send('\r'); + uart_send(character); +} + + +// output function type +typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen); + + +// wrapper (used as buffer) for output function type +typedef struct { + void (*fct)(char character, void* arg); + void* arg; +} out_fct_wrap_type; + + +// internal buffer output +static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen) +{ + if (idx < maxlen) { + ((char*)buffer)[idx] = character; + } +} + + +// internal null output +static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)character; (void)buffer; (void)idx; (void)maxlen; +} + + +// internal _putchar wrapper +static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)buffer; (void)idx; (void)maxlen; + if (character) { + _putchar(character); + } +} + + +// internal output function wrapper +static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)idx; (void)maxlen; + if (character) { + // buffer is the output fct pointer + ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg); + } +} + + +// internal secure strlen +// \return The length of the string (excluding the terminating 0) limited by 'maxsize' +static inline unsigned int _strnlen_s(const char* str, size_t maxsize) +{ + const char* s; + for (s = str; *s && maxsize--; ++s); + return (unsigned int)(s - str); +} + + +// internal test if char is a digit (0-9) +// \return true if char is a digit +static inline bool _is_digit(char ch) +{ + return (ch >= '0') && (ch <= '9'); +} + + +// internal ASCII string to unsigned int conversion +static unsigned int _atoi(const char** str) +{ + unsigned int i = 0U; + while (_is_digit(**str)) { + i = i * 10U + (unsigned int)(*((*str)++) - '0'); + } + return i; +} + + +// output the specified string in reverse, taking care of any zero-padding +static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags) +{ + const size_t start_idx = idx; + + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (size_t i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } + } + + // reverse string + while (len) { + out(buf[--len], buffer, idx++, maxlen); + } + + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) { + out(' ', buffer, idx++, maxlen); + } + } + + return idx; +} + + +// internal itoa format +static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) +{ + // pad leading zeros + if (!(flags & FLAGS_LEFT)) { + if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + // handle hash + if (flags & FLAGS_HASH) { + if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) { + len--; + if (len && (base == 16U)) { + len--; + } + } + if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'x'; + } + else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'X'; + } + else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'b'; + } + if (len < PRINTF_NTOA_BUFFER_SIZE) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_NTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } + else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + + +// internal itoa for 'long' type +static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { + flags &= ~FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} + + +// internal itoa for 'long long' type +#if defined(PRINTF_SUPPORT_LONG_LONG) +static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { + flags &= ~FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} +#endif // PRINTF_SUPPORT_LONG_LONG + + +#if defined(PRINTF_SUPPORT_FLOAT) + +#if defined(PRINTF_SUPPORT_EXPONENTIAL) +// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT +static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags); +#endif + + +// internal ftoa for fixed decimal floating point +static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_FTOA_BUFFER_SIZE]; + size_t len = 0U; + double diff = 0.0; + + // powers of 10 + static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + + // test for special values + if (value != value) + return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); + if (value < -DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); + if (value > DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags); + + // test for very large values + // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad + if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) { +#if defined(PRINTF_SUPPORT_EXPONENTIAL) + return _etoa(out, buffer, idx, maxlen, value, prec, width, flags); +#else + return 0U; +#endif + } + + // test for negative + bool negative = false; + if (value < 0) { + negative = true; + value = 0 - value; + } + + // set default precision, if not set explicitly + if (!(flags & FLAGS_PRECISION)) { + prec = PRINTF_DEFAULT_FLOAT_PRECISION; + } + // limit precision to 9, cause a prec >= 10 can lead to overflow errors + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { + buf[len++] = '0'; + prec--; + } + + int whole = (int)value; + double tmp = (value - whole) * pow10[prec]; + unsigned long frac = (unsigned long)tmp; + diff = tmp - frac; + + if (diff > 0.5) { + ++frac; + // handle rollover, e.g. case 0.99 with prec 1 is 1.0 + if (frac >= pow10[prec]) { + frac = 0; + ++whole; + } + } + else if (diff < 0.5) { + } + else if ((frac == 0U) || (frac & 1U)) { + // if halfway, round up if odd OR if last digit is 0 + ++frac; + } + + if (prec == 0U) { + diff = value - (double)whole; + if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) { + // exactly 0.5 and ODD, then round up + // 1.5 -> 2, but 2.5 -> 2 + ++whole; + } + } + else { + unsigned int count = prec; + // now do fractional part, as an unsigned number + while (len < PRINTF_FTOA_BUFFER_SIZE) { + --count; + buf[len++] = (char)(48U + (frac % 10U)); + if (!(frac /= 10U)) { + break; + } + } + // add extra 0s + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { + buf[len++] = '0'; + } + if (len < PRINTF_FTOA_BUFFER_SIZE) { + // add decimal + buf[len++] = '.'; + } + } + + // do whole part, number is reversed + while (len < PRINTF_FTOA_BUFFER_SIZE) { + buf[len++] = (char)(48 + (whole % 10)); + if (!(whole /= 10)) { + break; + } + } + + // pad leading zeros + if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) { + if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_FTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } + else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + + +#if defined(PRINTF_SUPPORT_EXPONENTIAL) +// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse +static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + // check for NaN and special values + if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) { + return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags); + } + + // determine the sign + const bool negative = value < 0; + if (negative) { + value = -value; + } + + // default precision + if (!(flags & FLAGS_PRECISION)) { + prec = PRINTF_DEFAULT_FLOAT_PRECISION; + } + + // determine the decimal exponent + // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) + union { + uint64_t U; + double F; + } conv; + + conv.F = value; + int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 + conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) + // now approximate log10 from the log2 integer part and an expansion of ln around 1.5 + int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); + // now we want to compute 10^expval but we want to be sure it won't overflow + exp2 = (int)(expval * 3.321928094887362 + 0.5); + const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; + const double z2 = z * z; + conv.U = (uint64_t)(exp2 + 1023) << 52U; + // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex + conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); + // correct for rounding errors + if (value < conv.F) { + expval--; + conv.F /= 10; + } + + // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters + unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U; + + // in "%g" mode, "prec" is the number of *significant figures* not decimals + if (flags & FLAGS_ADAPT_EXP) { + // do we want to fall-back to "%f" mode? + if ((value >= 1e-4) && (value < 1e6)) { + if ((int)prec > expval) { + prec = (unsigned)((int)prec - expval - 1); + } + else { + prec = 0; + } + flags |= FLAGS_PRECISION; // make sure _ftoa respects precision + // no characters in exponent + minwidth = 0U; + expval = 0; + } + else { + // we use one sigfig for the whole part + if ((prec > 0) && (flags & FLAGS_PRECISION)) { + --prec; + } + } + } + + // will everything fit? + unsigned int fwidth = width; + if (width > minwidth) { + // we didn't fall-back so subtract the characters required for the exponent + fwidth -= minwidth; + } else { + // not enough characters, so go back to default sizing + fwidth = 0U; + } + if ((flags & FLAGS_LEFT) && minwidth) { + // if we're padding on the right, DON'T pad the floating part + fwidth = 0U; + } + + // rescale the float value + if (expval) { + value /= conv.F; + } + + // output the floating part + const size_t start_idx = idx; + idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP); + + // output the exponent part + if (minwidth) { + // output the exponential symbol + out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); + // output the exponent value + idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS); + // might need to right-pad spaces + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) out(' ', buffer, idx++, maxlen); + } + } + return idx; +} +#endif // PRINTF_SUPPORT_EXPONENTIAL +#endif // PRINTF_SUPPORT_FLOAT + + +// internal vsnprintf +static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va) +{ + unsigned int flags, width, precision, n; + size_t idx = 0U; + + if (!buffer) { + // use null output function + out = _out_null; + } + + while (*format) + { + // format specifier? %[flags][width][.precision][length] + if (*format != '%') { + // no + out(*format, buffer, idx++, maxlen); + format++; + continue; + } + else { + // yes, evaluate it + format++; + } + + // evaluate flags + flags = 0U; + do { + switch (*format) { + case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break; + case '-': flags |= FLAGS_LEFT; format++; n = 1U; break; + case '+': flags |= FLAGS_PLUS; format++; n = 1U; break; + case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break; + case '#': flags |= FLAGS_HASH; format++; n = 1U; break; + default : n = 0U; break; + } + } while (n); + + // evaluate width field + width = 0U; + if (_is_digit(*format)) { + width = _atoi(&format); + } + else if (*format == '*') { + const int w = va_arg(va, int); + if (w < 0) { + flags |= FLAGS_LEFT; // reverse padding + width = (unsigned int)-w; + } + else { + width = (unsigned int)w; + } + format++; + } + + // evaluate precision field + precision = 0U; + if (*format == '.') { + flags |= FLAGS_PRECISION; + format++; + if (_is_digit(*format)) { + precision = _atoi(&format); + } + else if (*format == '*') { + const int prec = (int)va_arg(va, int); + precision = prec > 0 ? (unsigned int)prec : 0U; + format++; + } + } + + // evaluate length field + switch (*format) { + case 'l' : + flags |= FLAGS_LONG; + format++; + if (*format == 'l') { + flags |= FLAGS_LONG_LONG; + format++; + } + break; + case 'h' : + flags |= FLAGS_SHORT; + format++; + if (*format == 'h') { + flags |= FLAGS_CHAR; + format++; + } + break; +#if defined(PRINTF_SUPPORT_PTRDIFF_T) + case 't' : + flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; +#endif + case 'j' : + flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + case 'z' : + flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + default : + break; + } + + // evaluate specifier + switch (*format) { + case 'd' : + case 'i' : + case 'u' : + case 'x' : + case 'X' : + case 'o' : + case 'b' : { + // set the base + unsigned int base; + if (*format == 'x' || *format == 'X') { + base = 16U; + } + else if (*format == 'o') { + base = 8U; + } + else if (*format == 'b') { + base = 2U; + } + else { + base = 10U; + flags &= ~FLAGS_HASH; // no hash for dec format + } + // uppercase + if (*format == 'X') { + flags |= FLAGS_UPPERCASE; + } + + // no plus or space flag for u, x, X, o, b + if ((*format != 'i') && (*format != 'd')) { + flags &= ~(FLAGS_PLUS | FLAGS_SPACE); + } + + // ignore '0' flag when precision is given + if (flags & FLAGS_PRECISION) { + flags &= ~FLAGS_ZEROPAD; + } + + // convert the integer + if ((*format == 'i') || (*format == 'd')) { + // signed + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + const long long value = va_arg(va, long long); + idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); +#endif + } + else if (flags & FLAGS_LONG) { + const long value = va_arg(va, long); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + else { + const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + } + else { + // unsigned + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags); +#endif + } + else if (flags & FLAGS_LONG) { + idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags); + } + else { + const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int); + idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); + } + } + format++; + break; + } +#if defined(PRINTF_SUPPORT_FLOAT) + case 'f' : + case 'F' : + if (*format == 'F') flags |= FLAGS_UPPERCASE; + idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; +#if defined(PRINTF_SUPPORT_EXPONENTIAL) + case 'e': + case 'E': + case 'g': + case 'G': + if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP; + if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE; + idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; +#endif // PRINTF_SUPPORT_EXPONENTIAL +#endif // PRINTF_SUPPORT_FLOAT + case 'c' : { + unsigned int l = 1U; + // pre padding + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // char output + out((char)va_arg(va, int), buffer, idx++, maxlen); + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 's' : { + const char* p = va_arg(va, char*); + unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1); + // pre padding + if (flags & FLAGS_PRECISION) { + l = (l < precision ? l : precision); + } + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // string output + while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { + out(*(p++), buffer, idx++, maxlen); + } + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 'p' : { + width = sizeof(void*) * 2U; + flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; +#if defined(PRINTF_SUPPORT_LONG_LONG) + const bool is_ll = sizeof(uintptr_t) == sizeof(long long); + if (is_ll) { + idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags); + } + else { +#endif + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags); +#if defined(PRINTF_SUPPORT_LONG_LONG) + } +#endif + format++; + break; + } + + case '%' : + out('%', buffer, idx++, maxlen); + format++; + break; + + default : + out(*format, buffer, idx++, maxlen); + format++; + break; + } + } + + // termination + out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + + // return written chars without terminating \0 + return (int)idx; +} + + +/////////////////////////////////////////////////////////////////////////////// + +int printf_(const char* format, ...) +{ + va_list va; + va_start(va, format); + char buffer[1]; + const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + + +int sprintf_(char* buffer, const char* format, ...) +{ + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + + +int snprintf_(char* buffer, size_t count, const char* format, ...) +{ + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, count, format, va); + va_end(va); + return ret; +} + + +int vprintf_(const char* format, va_list va) +{ + char buffer[1]; + return _vsnprintf(_out_char, buffer, (size_t)-1, format, va); +} + + +int vsnprintf_(char* buffer, size_t count, const char* format, va_list va) +{ + return _vsnprintf(_out_buffer, buffer, count, format, va); +} + + +int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...) +{ + va_list va; + va_start(va, format); + const out_fct_wrap_type out_fct_wrap = { out, arg }; + const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va); + va_end(va); + return ret; +} \ No newline at end of file diff --git a/lab7/kernel/src/shell.c b/lab7/kernel/src/shell.c new file mode 100644 index 000000000..9953a2d6f --- /dev/null +++ b/lab7/kernel/src/shell.c @@ -0,0 +1,237 @@ +#include "uart.h" +#include "string.h" +#include "power.h" +#include "mbox.h" +#include "cpio.h" +#include "timer.h" +#include "exception.h" +#include "alloc.h" +#include "utils.h" +#include "thread.h" +#include "printf.h" +#include "dtb.h" + +void clean_buffer(char * buffer, int buffer_len) +{ + for(int i = 0 ; i < buffer_len ; i++) + buffer[i] = '\0'; +} + +void command_help() +{ + uart_puts("This is kernel shell\n"); + uart_puts("help\t\t: print this help menu\n"); + uart_puts("hello\t\t: print Hello World!\n"); + uart_puts("reboot\t\t: reboot the device\n"); + uart_puts("mailbox\t\t: show information through mailbox\n"); + uart_puts("dtb\t\t: parse device tree message\n"); + uart_puts("dtb all\t\t: parse device tree message\n"); + uart_puts("ls\t\t: show all files\n"); + uart_puts("cat\t\t: show file info\n"); + uart_puts("test\t\t: test simple allocator\n"); + uart_puts("user\t\t: load and run a user program in the initramfs\n"); + uart_puts("timer\t\t: core_timer_enable\n"); + uart_puts("puts\t\t: async_puts Test Message\n"); + uart_puts("buddy test\t: test for buddy system\n"); + uart_puts("dma test \t: test for dynamic memory allocation\n"); + uart_puts("setTimeout [MESSAGE] [SECONDS]\t: prints MESSAGE after SECONDS\n"); +} + +void command_hello() +{ + uart_puts("\n"); + uart_puts("Hello World!\n"); +} + +void command_not_found(char * buffer) +{ + uart_puts("\n"); + uart_puts("command *"); + uart_puts(buffer); + uart_puts("* not exist\n"); +} + +void command_ls(){ + cpio_ls(); +} + + +void command_cat(char* pathname){ + cpio_cat(pathname); +} + +void command_mailbox() +{ + // get serail number + mbox[0] = 8*4; // length of the message + mbox[1] = MBOX_REQUEST; // this is a request message + + mbox[2] = MBOX_TAG_GETSERIAL; // get serial number command + mbox[3] = 8; // buffer size + mbox[4] = 8; + mbox[5] = 0; // clear output buffer + mbox[6] = 0; + + mbox[7] = MBOX_TAG_LAST; + uart_puts("\n"); + if (mbox_call(MBOX_CH_PROP,mbox)) { + uart_puts("serial number is: "); + uart_hex(mbox[6]); + uart_hex(mbox[5]); + uart_puts("\n"); + } + // get board revision + mbox[0] = 8*4; // length of the message + mbox[1] = MBOX_REQUEST; // this is a request message + + mbox[2] = MBOX_TAG_GETBDVS; // get board revision + mbox[3] = 4; // buffer size + mbox[4] = 4; + mbox[5] = 0; // clear output buffer + mbox[6] = 0; + + mbox[7] = MBOX_TAG_LAST; + if (mbox_call(MBOX_CH_PROP,mbox)) { + uart_puts("board revision is: "); + uart_hex(mbox[6]); + uart_hex(mbox[5]); + uart_puts("\n"); + } + + // get arm memory + mbox[0] = 8*4; // length of the message + mbox[1] = MBOX_REQUEST; // this is a request message + + mbox[2] = MBOX_TAG_GETARMMEM; // get arm memory info + mbox[3] = 8; // buffer size + mbox[4] = 8; + mbox[5] = 0; // clear output buffer + mbox[6] = 0; + + mbox[7] = MBOX_TAG_LAST; + if (mbox_call(MBOX_CH_PROP,mbox)) { + uart_puts("arm base addr: "); + uart_hex(mbox[5]); + uart_puts("\n"); + uart_puts("arm addr size: "); + uart_hex(mbox[6]); + uart_puts("\n"); + } +} + +void command_test() +{ + // test malloc + uart_puts("\r"); + uart_puts("test malloc\n"); + char * c = malloc(30); + c[0]='a'; + c[1]='b'; + c[2]='\0'; + uart_puts("c:"); + uart_puts(c); + uart_puts("\r\n"); + char * d = malloc(30); + d[0]='x'; + d[1]='y'; + d[2]='\0'; + uart_puts("d:"); + uart_puts(d); + uart_puts("\r\n"); +} + +void command_load_user_program(const char *program_name) { + uint64_t spsr_el1 = 0x0; // EL0t with interrupt enabled + uint64_t target_addr = 0x30100000; + uint64_t target_sp = 0x10007030; + cpio_load_user_program(program_name, target_addr); + // core_timer_enable(); + asm volatile("msr spsr_el1, %0" : : "r"(spsr_el1)); + asm volatile("msr elr_el1, %0" : : "r"(target_addr)); + asm volatile("msr sp_el0, %0" : : "r"(target_sp)); + asm volatile("eret"); +} + +void command_set_timeout(char *args) { + uint32_t duration = 0; + for (int i = 0; args[i]; i++) { + if (args[i] == ' ') { + for (int j = i + 1; args[j]; j++) { + duration = duration * 10 + (args[j] - '0'); + } + args[i] = '\0'; + break; + } + } + add_timer(timer_callback, args, duration); +} + +void command_buddy_test() { + buddy_test(); +} +void command_dma_test() { + dma_test(); +} +void command_thread_test1() { + thread_test1(); +} +void command_thread_test2() { + thread_test2(); +} +void command_thread_test3() { + thread_test3(); +} +void command_thread_test4() { + thread_test4(); +} +void command_dtb_print(int all) { dtb_print(all); } + +void parse_command(char * buffer) +{ + if ( !strcmp(buffer, "help")) command_help(); + else if ( !strcmp(buffer, "hello")) command_hello(); + else if ( !strcmp(buffer, "mailbox")) command_mailbox(); + else if ( !strcmp(buffer, "ls")) command_ls(); + else if ( !strncmp(buffer, "cat", 3)) command_cat(&buffer[4]); + else if ( !strcmp(buffer, "test")) command_test(); + else if ( !strcmp(buffer, "reboot")) reset(); + else if ( !strncmp(buffer, "run", 3)) command_load_user_program(&buffer[4]); + else if ( !strcmp(buffer, "puts")) uart_async_puts("Test Message!\n"); + else if ( !strcmp(buffer, "timer")) core_timer_enable(); + else if ( !strncmp(buffer, "setTimeout", 10)) command_set_timeout(&buffer[11]); + else if ( !strcmp(buffer, "buddy test")) command_buddy_test(); + else if ( !strcmp(buffer, "dma test")) command_dma_test(); + else if ( !strcmp(buffer, "dtb")) command_dtb_print(0); + else if ( !strcmp(buffer, "dtb all")) command_dtb_print(1); + else if ( !strcmp(buffer, "t1")) command_thread_test1(); + else if ( !strcmp(buffer, "t2")) command_thread_test2(); + else if ( !strcmp(buffer, "t3")) command_thread_test3(); + else if ( !strcmp(buffer, "t4")) command_thread_test4(); + else command_not_found(buffer); +} + +void run_shell() +{ + char buffer[64]={'\0'}; + int buffer_len=0; + //clean buffer + clean_buffer(buffer, 64); + // echo everything back + while(1) { + printf("# "); + while(1){ + char c = uart_async_getc(); + if(c=='\n')uart_send('\r'); + uart_send(c); + if(c=='\n'){ + //parse buffer + parse_command(buffer); + //clean buffer + clean_buffer(buffer, 64); + buffer_len = 0; + break; + } + buffer[buffer_len++] = c; + } + } +} diff --git a/lab7/kernel/src/start.S b/lab7/kernel/src/start.S new file mode 100644 index 000000000..ccc0e40fb --- /dev/null +++ b/lab7/kernel/src/start.S @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * 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. + * + */ + +.section ".text.boot" + +.global _start + +_start: + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, master + b hang_loop // cpu id > 0, stop + +master: // cpu id == 0 + + // save dtb loading address + ldr x1, =0x9000000 + str x0, [x1] + + bl from_el2_to_el1 + bl set_exception_vector_table + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size + +clear_bss_start: + cbz w2, clear_bss_done + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, clear_bss_start + + +clear_bss_done: + // set top of stack just before our code (stack grows to a lower address per AAPCS64) + ldr x1, =_start + mov sp, x1 + + bl main // jump to C code, should not return + b hang_loop // for failsafe, halt this core too + +from_el2_to_el1: + mov x0, (1 << 31) // EL1 uses aarch64 + msr hcr_el2, x0 + mov x0, 0x3c5 // EL1h with interrupt disabled + msr spsr_el2, x0 + msr elr_el2, lr + + // IMPORTANT: disable exceptions of accessing the SIMD and floating-point registers + mov x0, #(3 << 20) + msr cpacr_el1, x0 + + eret // return to EL1 + +set_exception_vector_table: + adr x0, exception_vector_table + msr vbar_el1, x0 + ret + +hang_loop: + wfe + b hang_loop \ No newline at end of file diff --git a/lab7/kernel/src/string.c b/lab7/kernel/src/string.c new file mode 100644 index 000000000..00a00ebfd --- /dev/null +++ b/lab7/kernel/src/string.c @@ -0,0 +1,76 @@ +#include "string.h" + +/* Compare S1 and S2, returning less than, equal to or + greater than zero if S1 is lexicographically less than, + equal to or greater than S2. */ +int strcmp(const char *p1, const char *p2) { + const unsigned char *s1 = (const unsigned char *)p1; + const unsigned char *s2 = (const unsigned char *)p2; + unsigned char c1, c2; + do { + c1 = (unsigned char)*s1++; + c2 = (unsigned char)*s2++; + if (c1 == '\0') return c1 - c2; + } while (c1 == c2); + return c1 - c2; +} + +/* Compare no more than N characters of S1 and S2, + returning less than, equal to or greater than zero + if S1 is lexicographically less than, equal to or + greater than S2. */ +int strncmp(const char *s1, const char *s2, unsigned n) { + unsigned char c1 = '\0'; + unsigned char c2 = '\0'; + if (n >= 4) { + unsigned n4 = n >> 2; + do { + c1 = (unsigned char)*s1++; + c2 = (unsigned char)*s2++; + if (c1 == '\0' || c1 != c2) return c1 - c2; + c1 = (unsigned char)*s1++; + c2 = (unsigned char)*s2++; + if (c1 == '\0' || c1 != c2) return c1 - c2; + c1 = (unsigned char)*s1++; + c2 = (unsigned char)*s2++; + if (c1 == '\0' || c1 != c2) return c1 - c2; + c1 = (unsigned char)*s1++; + c2 = (unsigned char)*s2++; + if (c1 == '\0' || c1 != c2) return c1 - c2; + } while (--n4 > 0); + n &= 3; + } + while (n > 0) { + c1 = (unsigned char)*s1++; + c2 = (unsigned char)*s2++; + if (c1 == '\0' || c1 != c2) return c1 - c2; + n--; + } + return c1 - c2; +} + +int strlen(const char *s) { + int len = 0; + while (s[len] != '\0') { + len++; + } + return len; +} + +/* + * Find the first occurrence of find in s. + */ +char *strstr(const char *s, const char *find) { + char c, sc; + int len; + if ((c = *find++) != 0) { + len = strlen(find); + do { + do { + if ((sc = *s++) == 0) return 0; + } while (sc != c); + } while (strncmp(s, find, len) != 0); + s--; + } + return ((char *)s); +} \ No newline at end of file diff --git a/lab7/kernel/src/thread.S b/lab7/kernel/src/thread.S new file mode 100644 index 000000000..514958efa --- /dev/null +++ b/lab7/kernel/src/thread.S @@ -0,0 +1,26 @@ +.global switch_to +switch_to: + stp x19, x20, [x0, 16 * 0] + stp x21, x22, [x0, 16 * 1] + stp x23, x24, [x0, 16 * 2] + stp x25, x26, [x0, 16 * 3] + stp x27, x28, [x0, 16 * 4] + stp fp, lr, [x0, 16 * 5] + mov x9, sp + str x9, [x0, 16 * 6] + + ldp x19, x20, [x1, 16 * 0] + ldp x21, x22, [x1, 16 * 1] + ldp x23, x24, [x1, 16 * 2] + ldp x25, x26, [x1, 16 * 3] + ldp x27, x28, [x1, 16 * 4] + ldp fp, lr, [x1, 16 * 5] + ldr x9, [x1, 16 * 6] + mov sp, x9 + msr tpidr_el1, x1 + ret + +.global get_current +get_current: + mrs x0, tpidr_el1 + ret \ No newline at end of file diff --git a/lab7/kernel/src/thread.c b/lab7/kernel/src/thread.c new file mode 100644 index 000000000..68a0cbcdc --- /dev/null +++ b/lab7/kernel/src/thread.c @@ -0,0 +1,272 @@ +#include "thread.h" +#include "timer.h" +#include "alloc.h" +#include "cpio.h" +#include "exception.h" +#include "printf.h" +#include "utils.h" +#include "shell.h" + +void foo() { + for (int i = 0; i < 4; ++i) { + printf("Thread id: %d, %d\r\n", get_current()->pid, i); + delay(1000000); + schedule(); + } + exit(); + return; +} + +void user_test1() { + const char *argv[] = {"argv_test", "-o", "arg2", 0}; + exec("my_test", argv); +} + +void user_test2() { + const char *argv[] = {"argv_test", "-o", "arg2", 0}; + exec("my_test2", argv); +} +void user_test3() { + const char *argv[] = {"argv_test", "-o", "arg2", 0}; + exec("fork_test", argv); +} + +void user_test4() { + const char *argv[] = {"argv_test", "-o", "arg2", 0}; + exec("syscall.img", argv); +} + +void user_test5() { + const char *argv[] = {"argv_test", "-o", "arg2", 0}; + exec("vm.img", argv); +} + +void thread_test1() { // thread test + thread_info *idle_t = thread_create(0); + asm volatile("msr tpidr_el1, %0\n" ::"r"((uint64_t)idle_t)); + thread_create(user_test1); + thread_create(user_test2); + idle(); +} + +void thread_test2() { // fork test + thread_info *idle_t = thread_create(0); + asm volatile("msr tpidr_el1, %0\n" ::"r"((uint64_t)idle_t)); + thread_create(user_test3); + idle(); +} + +void thread_test3() { //vedio player1 test + thread_info *idle_t = thread_create(0); + asm volatile("msr tpidr_el1, %0\n" ::"r"((uint64_t)idle_t)); + thread_create(user_test4); + idle(); +} + +void thread_test4() { //vedio player1 test + thread_info *idle_t = thread_create(0); + asm volatile("msr tpidr_el1, %0\n" ::"r"((uint64_t)idle_t)); + thread_create(user_test5); + idle(); +} + +void thread_init() { + run_queue.head = 0; + run_queue.tail = 0; + thread_cnt = 0; +} + +thread_info *thread_create(void (*func)()) { + // printf("create thread pid = %d\n",thread_cnt); + thread_info *thread = (thread_info *)malloc(sizeof(thread_info)); + thread->pid = thread_cnt++; + thread->status = THREAD_READY; + thread->next = 0; + thread->kernel_stack_base = (uint64_t)malloc(STACK_SIZE); + thread->user_stack_base = (uint64_t)malloc(STACK_SIZE); + thread->user_program_base = + USER_PROGRAM_BASE + thread->pid * USER_PROGRAM_SIZE; + thread->context.fp = thread->kernel_stack_base + STACK_SIZE; + thread->context.lr = (uint64_t)func; + thread->context.sp = thread->kernel_stack_base + STACK_SIZE; + run_queue_push(thread); + return thread; +} + +void schedule() { + // printf("[schdule]\n"); + if (run_queue.head == 0) { + // printf("no thread\n"); + enable_uart_interrupt(); + core_timer_disable(); + enable_interrupt(); + return; + } + if (run_queue.head == run_queue.tail) { // idle thread + // printf("left idle thread\n"); + free(run_queue.head); + run_queue.head = run_queue.tail = 0; + thread_cnt = 0; + enable_interrupt(); // need uart interrupt when go back to shell + return; + } + + do { + run_queue.tail->next = run_queue.head; + run_queue.tail = run_queue.head; + run_queue.head = run_queue.head->next; + run_queue.tail->next = 0; + } while (run_queue.head->status != THREAD_READY); + // printf("get_current()->pid = %d\n",get_current()->pid); + // printf("run_queue.head->pid = %d\n",run_queue.head->pid); + enable_interrupt(); + switch_to(get_current(), run_queue.head); +} + +void idle() { + // printf("[idle]\n"); + + while (1) { + kill_zombies(); + handle_fork(); + schedule(); + if (run_queue.head == 0) break; //blcok here if any thread exist= + } +} + +void exit() { + thread_info *cur = get_current(); + cur->status = THREAD_DEAD; + schedule(); +} + +void run_queue_push(thread_info *thread) { + if (run_queue.head == 0) { + run_queue.head = run_queue.tail = thread; + } else { + run_queue.tail->next = thread; + run_queue.tail = thread; + } +} + +void kill_zombies() { + if (run_queue.head == 0) return; + for (thread_info *ptr = run_queue.head; ptr->next != 0; ptr = ptr->next) { + for (thread_info *cur = ptr->next; + cur != 0 && (cur->status == THREAD_DEAD);) { + thread_info *tmp = cur->next; + free((void *)cur); + ptr->next = tmp; + cur = tmp; + } + if (ptr->next == 0) { + run_queue.tail = ptr; + break; + } + } +} + +void exec(const char *program_name, const char **argv) { + thread_info *cur = get_current(); + + uint64_t user_sp = cur->user_stack_base + STACK_SIZE; + cur->user_program_size = cpio_load_user_program(program_name, cur->user_program_base); + // printf("cur->pid = %d, cur->user_program_base = %x\n",cur->pid,cur->user_program_base); + + // return to user program + uint64_t spsr_el1 = 0x0; // EL0t with interrupt enabled + uint64_t target_addr = cur->user_program_base; + uint64_t target_sp = user_sp; + core_timer_enable(); + asm volatile("msr spsr_el1, %0" : : "r"(spsr_el1)); + asm volatile("msr elr_el1, %0" : : "r"(target_addr)); + asm volatile("msr sp_el0, %0" : : "r"(target_sp)); + asm volatile("eret"); +} + +void fork(uint64_t sp) { + run_queue.head->status = THREAD_FORK; + run_queue.head->trap_frame_addr = sp; + schedule(); + trap_frame_t *trap_frame = (trap_frame_t *)(get_current()->trap_frame_addr); + trap_frame->x[0] = run_queue.head->child_pid; +} + +void handle_fork() { + // printf("[handle_fork]\n"); + for (thread_info *ptr = run_queue.head->next; ptr != 0; ptr = ptr->next) { + if ((ptr->status) == THREAD_FORK) { + thread_info *child = thread_create(0); + create_child(ptr, child); + ptr->status = THREAD_READY; + child->status = THREAD_READY; + } + } +} + +void create_child(thread_info *parent, thread_info *child) { + // printf("[create_child]\n"); + disable_interrupt(); + child->user_stack_base = (uint64_t)malloc(STACK_SIZE); + child->user_program_size = parent->user_program_size; + parent->child_pid = child->pid; + child->child_pid = 0; + + char *src, *dst; + // copy saved context in thread info + src = (char *)&(parent->context); + dst = (char *)&(child->context); + for (uint32_t i = 0; i < sizeof(cpu_context); ++i, ++src, ++dst) { + *dst = *src; + } + // copy kernel stack + src = (char *)(parent->kernel_stack_base); + dst = (char *)(child->kernel_stack_base); + for (uint32_t i = 0; i < STACK_SIZE; ++i, ++src, ++dst) { + *dst = *src; + } + // copy user stack + src = (char *)(parent->user_stack_base); + dst = (char *)(child->user_stack_base); + for (uint32_t i = 0; i < STACK_SIZE; ++i, ++src, ++dst) { + *dst = *src; + } + // copy user program + src = (char *)(parent->user_program_base); + dst = (char *)(child->user_program_base); + for (uint32_t i = 0; i < parent->user_program_size; ++i, ++src, ++dst) { + *dst = *src; + } + + // set correct address for child + uint64_t kernel_stack_base_dist = + child->kernel_stack_base - parent->kernel_stack_base; + uint64_t user_stack_base_dist = + child->user_stack_base - parent->user_stack_base; + uint64_t user_program_base_dist = + child->user_program_base - parent->user_program_base; + + child->context.fp += kernel_stack_base_dist; + child->context.sp += kernel_stack_base_dist; + child->trap_frame_addr = parent->trap_frame_addr + kernel_stack_base_dist; + trap_frame_t *trap_frame = (trap_frame_t *)(child->trap_frame_addr); + trap_frame->x[29] += user_stack_base_dist; // fp (x29) + trap_frame->x[30] += user_program_base_dist; // lr (x30) + trap_frame->x[32] += user_program_base_dist; // elr_el1 + trap_frame->x[33] += user_stack_base_dist; // sp_el0 + enable_interrupt(); +} +void kill (int kill_pid) +{ + if (run_queue.head == 0) return; + for (thread_info *ptr = run_queue.head; ptr->next != 0; ptr = ptr->next) { + if(ptr->pid == kill_pid){ + printf("Kill pid = %d\n",kill_pid); + ptr->status = THREAD_DEAD; + schedule(); + return; + } + } + printf("pid = %d not exist\n",kill_pid); + +} \ No newline at end of file diff --git a/lab7/kernel/src/timer.c b/lab7/kernel/src/timer.c new file mode 100644 index 000000000..02095c58d --- /dev/null +++ b/lab7/kernel/src/timer.c @@ -0,0 +1,146 @@ +#include "timer.h" +#include "alloc.h" +#include "uart.h" +#include "utils.h" +#include "thread.h" + +void timeout_event_init() { + timeout_queue_head = 0; + timeout_queue_tail = 0; +} + +void core_timer_enable() { + asm volatile("mov x0, 1"); + asm volatile("msr cntp_ctl_el0, x0"); // enable + asm volatile("mrs x0, cntfrq_el0"); + asm volatile("msr cntp_tval_el0, x0"); // set expired time + asm volatile("mov x0, 2"); + asm volatile("ldr x1, =0x40000040"); + asm volatile("str w0, [x1]"); // unmask timer interrupt + + uint64_t tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); +} + +// void core_timer_handler() { +// uart_puts("===== timer handler =====\n"); +// uint64_t cntpct_el0, cntfrq_el0; +// asm volatile("mrs %0, cntpct_el0" : "=r"(cntpct_el0)); +// asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq_el0)); +// asm volatile("mrs x0, cntfrq_el0"); +// asm volatile("mov x1, 2"); +// asm volatile("mul x0, x0, x1"); +// asm volatile("msr cntp_tval_el0, x0"); +// uart_puts("Time elapsed after booting: "); +// // char c = cntpct_el0 / cntfrq_el0; +// uart_int(cntpct_el0 / cntfrq_el0); +// uart_puts("s\n"); +// } + +void core_timer_disable() { + asm volatile("mov x0, 0"); + asm volatile("msr cntp_ctl_el0, x0"); // disable + asm volatile("mov x0, 0"); + asm volatile("ldr x1, =0x40000040"); + asm volatile("str w0, [x1]"); // unmask timer interrupt +} + +void core_timer_handler_lowerEL_64() { // required 2 + set_expired_time(1); + // uart_puts("Time elapsed after booting: "); + // uart_int(get_current_time()); + // uart_puts("s\n"); + schedule(); +} + +void core_timer_handler_currentEL_ELx() { // elective 2 + uart_puts("Current time: "); + uart_int(get_current_time()); + uart_puts("s, "); + uart_puts("Command executed time: "); + uart_int(timeout_queue_head->register_time); + uart_puts("s, "); + uart_puts("Duration: "); + uart_int(timeout_queue_head->duration); + uart_puts("s\n"); + timeout_queue_head->callback(timeout_queue_head->args); + timeout_event *next = timeout_queue_head->next; + // free(timeout_queue_head); + if (next) { + next->prev = 0; + timeout_queue_head = next; + uint64_t next_duration = + next->register_time + next->duration - get_current_time(); + set_expired_time(next_duration); + } else { + timeout_queue_head = 0; + timeout_queue_tail = 0; + core_timer_disable(); + } +} + +void add_timer(void (*callback)(char *), char *args, uint32_t duration) { + timeout_event *new_timeout_event = + (timeout_event *)malloc(sizeof(timeout_event)); + new_timeout_event->register_time = get_current_time(); + new_timeout_event->duration = duration; + new_timeout_event->callback = callback; + for (int i = 0; i < 20; i++) { + new_timeout_event->args[i] = args[i]; + if (args[i] == '\0') break; + } + new_timeout_event->prev = 0; + new_timeout_event->next = 0; + + if (timeout_queue_head == 0) { + timeout_queue_head = new_timeout_event; + timeout_queue_tail = new_timeout_event; + core_timer_enable(); + set_expired_time(duration); + } else { + timeout_event *cur; + uint64_t timeout = + new_timeout_event->register_time + new_timeout_event->duration; + for (cur = timeout_queue_head; cur; cur = cur->next) { + if (cur->register_time + cur->duration > timeout) break; + } + + if (cur == 0) { + new_timeout_event->prev = timeout_queue_tail; + timeout_queue_tail->next = new_timeout_event; + timeout_queue_tail = new_timeout_event; + } else if (cur->prev == 0) { + new_timeout_event->next = cur; + timeout_queue_head->prev = new_timeout_event; + timeout_queue_head = new_timeout_event; + set_expired_time(duration); + } else { + new_timeout_event->prev = cur->prev; + new_timeout_event->next = cur; + cur->prev->next = new_timeout_event; + cur->prev = new_timeout_event; + } + } +} + +uint64_t get_current_time() { + uint64_t cntpct_el0, cntfrq_el0; + asm volatile("mrs %0, cntpct_el0" : "=r"(cntpct_el0)); + asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq_el0)); + return cntpct_el0 / cntfrq_el0; +} + + +void set_expired_time(uint32_t duration) { + uint64_t cntfrq_el0; + asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq_el0)); + asm volatile("msr cntp_tval_el0, %0" : : "r"(cntfrq_el0 * duration / 32)); +} + +void timer_callback(char *msg) { + uart_puts("Message: "); + uart_puts(msg); + uart_puts("\n"); +} \ No newline at end of file diff --git a/lab7/kernel/src/uart.c b/lab7/kernel/src/uart.c new file mode 100644 index 000000000..bfa6b7bf2 --- /dev/null +++ b/lab7/kernel/src/uart.c @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * 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 "gpio.h" +#include "utils.h" +#include "uart.h" +/* Auxilary mini UART registers */ +#define AUX_ENABLE ((volatile unsigned int*)(MMIO_BASE+0x00215004)) +#define AUX_MU_IO ((volatile unsigned int*)(MMIO_BASE+0x00215040)) +#define AUX_MU_IER ((volatile unsigned int*)(MMIO_BASE+0x00215044)) +#define AUX_MU_IIR ((volatile unsigned int*)(MMIO_BASE+0x00215048)) +#define AUX_MU_LCR ((volatile unsigned int*)(MMIO_BASE+0x0021504C)) +#define AUX_MU_MCR ((volatile unsigned int*)(MMIO_BASE+0x00215050)) +#define AUX_MU_LSR ((volatile unsigned int*)(MMIO_BASE+0x00215054)) +#define AUX_MU_MSR ((volatile unsigned int*)(MMIO_BASE+0x00215058)) +#define AUX_MU_SCRATCH ((volatile unsigned int*)(MMIO_BASE+0x0021505C)) +#define AUX_MU_CNTL ((volatile unsigned int*)(MMIO_BASE+0x00215060)) +#define AUX_MU_STAT ((volatile unsigned int*)(MMIO_BASE+0x00215064)) +#define AUX_MU_BAUD ((volatile unsigned int*)(MMIO_BASE+0x00215068)) +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init() +{ + register unsigned int r; + + /* initialize UART */ + *AUX_ENABLE |=1; // enable UART1, AUX mini uart + *AUX_MU_CNTL = 0; + *AUX_MU_LCR = 3; // 8 bits + *AUX_MU_MCR = 0; + *AUX_MU_IER = 1; + // comment this line to avoid weird character + // *AUX_MU_IIR = 0xc6; // disable interrupts + *AUX_MU_BAUD = 270; // 115200 baud + /* map UART1 to GPIO pins */ + r=*GPFSEL1; + r&=~((7<<12)|(7<<15)); // gpio14, gpio15 + r|=(2<<12)|(2<<15); // alt5 + *GPFSEL1 = r; + *GPPUD = 0; // enable pins 14 and 15 + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = (1<<14)|(1<<15); + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = 0; // flush GPIO setup + *AUX_MU_CNTL = 3; // enable Tx, Rx + + read_buf_start = read_buf_end = 0; + write_buf_start = write_buf_end = 0; + enable_uart_interrupt(); +} + +/** + * Send a character + */ +void uart_send(unsigned int c) { + /* wait until we can send */ + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); + /* write the character to the buffer */ + *AUX_MU_IO=c; +} + +/** + * Receive a character + */ +char uart_getc() { + char r; + /* wait until something is in the buffer */ + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01)); + /* read it and return */ + r=(char)(*AUX_MU_IO); + /* convert carrige return to newline */ + return r=='\r'?'\n':r; +} + +uint32_t uart_gets(char *buf, uint32_t size) { + for (int i = 0; i < size; ++i) { + buf[i] = uart_getc(); + // uart_send(buf[i]); + if (buf[i] == '\n' || buf[i] == '\r') { + // uart_send('\r'); + // buf[i] = '\0'; + return i; + } + } + return size; +} + +/** + * Display a string + */ +void uart_puts(char *s) { + while(*s) { + /* convert newline to carrige return + newline */ + if(*s=='\n') + uart_send('\r'); + uart_send(*s++); + } +} + +uint32_t uart_write(char *s, uint32_t size) { + for(int i = 0 ; i=0;c-=4) { + // get highest tetrad + n=(d>>c)&0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n+=n>9?0x37:0x30; + uart_send(n); + } +} + +void uart_int(int x) { + if (x < 0) { + uart_send('-'); + x = -x; + } + if (x >= 10) uart_int(x / 10); + uart_send(x % 10 + '0'); +} + +void enable_uart_interrupt() { *ENABLE_IRQS_1 = AUX_IRQ; } + +void disable_uart_interrupt() { *DISABLE_IRQS_1 = AUX_IRQ; } + +void assert_transmit_interrupt() { *AUX_MU_IER |= 0x2; } + +void clear_transmit_interrupt() { *AUX_MU_IER &= ~(0x2); } + +void uart_handler() { + disable_uart_interrupt(); + int is_read = (*AUX_MU_IIR & 0x4); + int is_write = (*AUX_MU_IIR & 0x2); + + if (is_read) { + // uart_puts("===== is_read =====\n"); + + char c = (char)(*AUX_MU_IO); + read_buf[read_buf_end++] = c; + if (read_buf_end == UART_BUFFER_SIZE) read_buf_end = 0; + } else if (is_write) { + // uart_puts("===== is_write =====\n"); + + while (*AUX_MU_LSR & 0x20) { + if (write_buf_start == write_buf_end) { + clear_transmit_interrupt(); + break; + } + char c = write_buf[write_buf_start++]; + *AUX_MU_IO = c; + if (write_buf_start == UART_BUFFER_SIZE) write_buf_start = 0; + } + } + enable_uart_interrupt(); +} + +char uart_async_getc() { + // wait until there are new data + // uart_puts("===== uart getc =====\n"); + while (read_buf_start == read_buf_end) { + // uart_puts("===== read_buf_start == read_buf_end =====\n"); + asm volatile("nop"); + } + char c = read_buf[read_buf_start++]; + if (read_buf_start == UART_BUFFER_SIZE) read_buf_start = 0; + // '\r' => '\n' + return c == '\r' ? '\n' : c; +} + +void uart_async_puts(char *str) { + for (int i = 0; str[i]; i++) { + if (str[i] == '\n') write_buf[write_buf_end++] = '\r'; + write_buf[write_buf_end++] = str[i]; + if (write_buf_end == UART_BUFFER_SIZE) write_buf_end = 0; + } + assert_transmit_interrupt(); +} diff --git a/lab7/kernel/src/utils.S b/lab7/kernel/src/utils.S new file mode 100644 index 000000000..894a1fdc8 --- /dev/null +++ b/lab7/kernel/src/utils.S @@ -0,0 +1,9 @@ +.globl put32 +put32: + str w1, [x0] + ret + +.globl get32 +get32: + ldr w0, [x0] + ret diff --git a/lab7/kernel/src/utils.c b/lab7/kernel/src/utils.c new file mode 100644 index 000000000..8047ee2c7 --- /dev/null +++ b/lab7/kernel/src/utils.c @@ -0,0 +1,71 @@ +// typedef unsigned long long int uint64_t; +// typedef unsigned char uint8_t; +#include "utils.h" + +uint8_t hex_to_int8(char hex){ + if(hex >= '0' && hex <= '9') + return hex-'0'; + else if(hex >= 'A' && hex <= 'Z') + return hex-'A'+10; + else if(hex >= 'a' && hex <= 'z') + return hex-'a'+10; + else + return -1; +} + +uint64_t hex_to_int64(char* num){ + uint64_t res=0; + for(int i=0; i<8; i++){ + res = (res<<4) + hex_to_int8(num[i]); + } + return res; +} + +uint64_t log2(uint64_t num) { + for (uint64_t i = 0; i < 64; i++) { + if (num == (1 << i)) return i; + } + return 0; +} +uint64_t align_up(uint64_t addr, uint64_t alignment) { + return (addr + alignment - 1) & (~(alignment - 1)); +} + +uint64_t align_up_exp(uint64_t n) { + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n |= n >> 32; + n++; + return n; +} + +void delay(int num) { + while (num--) + ; +} + +uint64_t hex2int(char *hex, int len) { + uint64_t val = 0; + for (int i = 0; i < len; i++) { + // get current character then increment + uint64_t byte = *(hex + i); + if (byte >= '0' && byte <= '9') + byte = byte - '0'; + else if (byte >= 'A' && byte <= 'F') + byte = byte - 'A' + 10; + else if (byte >= 'a' && byte <= 'f') + byte = byte - 'a' + 10; + + val = (val << 4) | (byte & 0xF); + } + return val; +} + +uint32_t be2le(uint32_t x) { + return (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8) | + (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24); +} \ No newline at end of file diff --git a/lab7/make.sh b/lab7/make.sh new file mode 100755 index 000000000..893cdd3e6 --- /dev/null +++ b/lab7/make.sh @@ -0,0 +1,9 @@ +#bin/sh! + +make +cd kernel +make +cd .. +cd bootloader +make +cd .. diff --git a/lab7/qemu_run.sh b/lab7/qemu_run.sh new file mode 100755 index 000000000..4673212bd --- /dev/null +++ b/lab7/qemu_run.sh @@ -0,0 +1,4 @@ +# sudo chmod 777 /dev/ttyUSB0 +# python3 ./script/send_file.py -s bootloader.img +# python3 ./script/send_file.py -s kernel/build/kernel8.img -t /dev/ttyUSB0 +python3 ./script/send_file.py -s kernel/build/kernel8.img -t /dev/pts/14 diff --git a/lab7/run.sh b/lab7/run.sh new file mode 100755 index 000000000..a8d89f256 --- /dev/null +++ b/lab7/run.sh @@ -0,0 +1,4 @@ +sudo chmod 777 /dev/ttyUSB0 +# python3 ./script/send_file.py -s bootloader.img +python3 ./script/send_file.py -s kernel/build/kernel8.img -t /dev/ttyUSB0 +# python3 ./script/send_file.py -s kernel8.img -t /dev/pts/9 diff --git a/lab7/script/send_file.py b/lab7/script/send_file.py new file mode 100644 index 000000000..475fab1ec --- /dev/null +++ b/lab7/script/send_file.py @@ -0,0 +1,42 @@ +import argparse +from pathlib import Path +import serial + +def send_all_data(tty, data): + while len(data) > 0: + write_cnt = tty.write(data) + data = data[write_cnt:] + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument( + "-s", + "--src_file_pth", + type=str, + help='source file path', + default='../kernel8.img' + ) + parser.add_argument( + "-t", + "--target_pth", + nargs='?', + type=str, + help='target path', + default='/dev/ttyUSB0' + ) + args = parser.parse_args() + + with serial.Serial(args.target_pth, 115200, xonxoff=True) as tty: + magic = 0x01020304.to_bytes(4, 'big') + send_all_data(tty, magic) + + file_size = Path(args.src_file_pth).stat().st_size.to_bytes(8, 'little') + send_all_data(tty, file_size) + + with open(args.src_file_pth, 'rb') as src_file: + while True: + data = src_file.read() + if data == b'': + break + send_all_data(tty, data) + print("finish sending kernel8.img\n") \ No newline at end of file diff --git a/lab7/user/Makefile b/lab7/user/Makefile new file mode 100644 index 000000000..8961cfcb5 --- /dev/null +++ b/lab7/user/Makefile @@ -0,0 +1,32 @@ +CC = aarch64-linux-gnu-gcc +CFLAGS = -Wall -g -ffreestanding -march=armv8-a +LD = aarch64-linux-gnu-ld +OBJCOPY = aarch64-linux-gnu-objcopy +OBJCOPYFLAGS = -O binary + +BUILD_DIR = build +SRC_DIR = src +C_FILES = $(wildcard $(SRC_DIR)/*.c) +TARGET_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%) +LINKER = $(SRC_DIR)/linker.ld + +all: $(TARGET_FILES) + +clean: + rm $(BUILD_DIR)/* + +$(BUILD_DIR)/%: $(BUILD_DIR)/%.elf + $(OBJCOPY) $(OBJCOPYFLAGS) $< $@ + cp $@ ../kernel/rootfs && \ + cd ../kernel/rootfs && \ + rm -f ../initramfs.cpio && \ + find . | cpio -o -H newc > ../initramfs.cpio + +$(BUILD_DIR)/%.elf: $(BUILD_DIR)/%.o $(BUILD_DIR)/start.asmo + $(LD) -T $(LINKER) --gc-sections -g -o $@ $< $(BUILD_DIR)/start.asmo + +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/start.asmo: $(SRC_DIR)/start.S + $(CC) $(CFLAGS) -c $< -o $@ diff --git a/lab7/user/src/argv_test.c b/lab7/user/src/argv_test.c new file mode 100644 index 000000000..aa9c5bed3 --- /dev/null +++ b/lab7/user/src/argv_test.c @@ -0,0 +1,17 @@ +#include "start.h" + +int main(int argc, char **argv) { + // printf("Argv Test, pid %d\n", getpid()); + print_s("Argv Test, pid "); + print_i(getpid()); + print_s("\n"); + for (int i = 0; i < argc; ++i) { + // puts(argv[i]); + print_s(argv[i]); + print_s("\n"); + } + char *fork_argv[] = {"fork_test", 0}; + exec("fork_test", fork_argv); + + return 0; +} \ No newline at end of file diff --git a/lab7/user/src/fork_test.c b/lab7/user/src/fork_test.c new file mode 100644 index 000000000..a8b65a079 --- /dev/null +++ b/lab7/user/src/fork_test.c @@ -0,0 +1,46 @@ +#include "start.h" + +int main() { + // printf("Fork Test, pid %d\n", getpid()); + print_s("Fork Test, pid "); + print_i(getpid()); + print_s("\n"); + int cnt = 1; + int ret = 0; + if ((ret = fork()) == 0) { // child + // printf("pid: %d, cnt: %d, ptr: %p\n", getpid(), cnt, &cnt); + print_s("pid: "); + print_i(getpid()); + print_s(", cnt: "); + print_i(cnt); + print_s(", ptr: "); + print_h((unsigned long long)&cnt); + print_s("\n"); + ++cnt; + fork(); + while (cnt < 5) { + // printf("pid: %d, cnt: %d, ptr: %p\n", getpid(), cnt, &cnt); + print_s("pid: "); + print_i(getpid()); + print_s(", cnt: "); + print_i(cnt); + print_s(", ptr: "); + print_h((unsigned long long)&cnt); + print_s("\n"); + delay(1000000000); + ++cnt; + } + } else { + // printf("parent here, pid %d, child %d\n", getpid(), ret); + for(int i = 0 ; i < 5;i++){ + print_s("parent here, pid: "); + print_i(getpid()); + print_s(", child: "); + print_i(ret); + print_s("\n"); + delay(1000000000); + } + } + // while(1); + return 0; +} \ No newline at end of file diff --git a/lab7/user/src/linker.ld b/lab7/user/src/linker.ld new file mode 100644 index 000000000..8e6ab1c9d --- /dev/null +++ b/lab7/user/src/linker.ld @@ -0,0 +1,17 @@ +SECTIONS +{ + . = 0x80000; + + .text : { KEEP(*(.text.boot)) *(.text .text.*) } + + .rodata : { *(.rodata .rodata.*) } + + .data : { *(.data .data.*) } + + .bss : { + *(.bss .bss.*) + *(COMMON) + } + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} \ No newline at end of file diff --git a/lab7/user/src/my_test.c b/lab7/user/src/my_test.c new file mode 100644 index 000000000..ef5620ae8 --- /dev/null +++ b/lab7/user/src/my_test.c @@ -0,0 +1,12 @@ +#include "start.h" +int main(int argc, char **argv) { + for(int i = 0 ; i<10 ; i++){ + print_s("Test1, pid "); + print_i(getpid()); + print_s("\n"); + delay(1000000000); + // asm volatile("mov x8, #9"); + // asm volatile("svc 0"); + } + return 0; +} \ No newline at end of file diff --git a/lab7/user/src/my_test2.c b/lab7/user/src/my_test2.c new file mode 100644 index 000000000..8024d8bbd --- /dev/null +++ b/lab7/user/src/my_test2.c @@ -0,0 +1,12 @@ +#include "start.h" +int main(int argc, char **argv) { + for(int i = 0 ; i<10 ; i++){ + print_s("Test2, pid "); + print_i(getpid()); + print_s("\n"); + delay(1000000000); + // asm volatile("mov x8, #9"); + // asm volatile("svc 0"); + } + return 0 ; +} \ No newline at end of file diff --git a/lab7/user/src/start.S b/lab7/user/src/start.S new file mode 100644 index 000000000..fc5a50624 --- /dev/null +++ b/lab7/user/src/start.S @@ -0,0 +1,49 @@ +.section ".text.boot" + +.global _start + +_start: + bl main + b exit + +.section ".text" + +.global uart_read +.global uart_write +.global getpid +.global fork +.global exec +.global exit + +getpid: + mov x8, #0 + svc 0 + ret + +uart_read: + mov x8, #1 + svc 0 + ret + +uart_write: + mov x8, #2 + svc 0 + ret + +exec: + mov x8, #3 + svc 0 + ret + +fork: + mov x8, #4 + svc 0 + ret + +exit: + mov x8, #5 + svc 0 + ret + + + diff --git a/lab7/user/src/start.h b/lab7/user/src/start.h new file mode 100644 index 000000000..24468b7ca --- /dev/null +++ b/lab7/user/src/start.h @@ -0,0 +1,54 @@ +#ifndef START_H +#define START_H + +#include +#include + +unsigned long uart_read(char buf[], size_t size); +unsigned long uart_write(const char buf[], size_t size); +int getpid(); +unsigned long fork(); +int exec(const char *name, char *const argv[]); +void exit(); + +void delay(int n) { + while (n--) + ; +} + +int strlen(const char *s) { + int len = 0; + while (s[len] != '\0') { + len++; + } + return len; +} + +void print_c(char c) { + char s[2]; + s[0] = c; + s[1] = '\0'; + uart_write(s, strlen(s)); +} + +void print_s(char *s) { uart_write(s, strlen(s)); } + +void print_i(int x) { + if (x < 0) { + print_c('-'); + x = -x; + } + if (x >= 10) print_i(x / 10); + print_c(x % 10 + '0'); +} + +void print_h(unsigned long x) { + print_s("0x"); + for (int c = 28; c >= 0; c -= 4) { + int n = (x >> c) & 0xF; + n += n > 9 ? 'A' - 10 : '0'; + print_c(n); + } +} + +#endif \ No newline at end of file diff --git a/lab7/user/src/svc_test.c b/lab7/user/src/svc_test.c new file mode 100644 index 000000000..a3fbfe8dd --- /dev/null +++ b/lab7/user/src/svc_test.c @@ -0,0 +1,7 @@ +int main() { + for (int i = 0; i < 5; i++) { + asm volatile("svc 0"); + } + + return 0; +} \ No newline at end of file diff --git a/lab7/user/src/user_program.S b/lab7/user/src/user_program.S new file mode 100644 index 000000000..838323763 --- /dev/null +++ b/lab7/user/src/user_program.S @@ -0,0 +1,11 @@ +.section ".text" +.global _start +_start: + mov x0, 0 +1: + add x0, x0, 1 + svc 0 + cmp x0, 5 + blt 1b +1: + b 1b \ No newline at end of file