From 5d9b85a00c81077a04bc895d9fc0701fcbc4ff65 Mon Sep 17 00:00:00 2001 From: a13579and2468 Date: Sun, 22 May 2022 16:22:00 +0800 Subject: [PATCH 1/8] lab6 basic complete --- lab6/.gitignore | 3 + lab6/Makefile | 61 +++++ lab6/bcm2710-rpi-3-b-plus.dtb | Bin 0 -> 31790 bytes lab6/bootloader/Makefile | 50 ++++ lab6/bootloader/include/gpio.h | 25 ++ lab6/bootloader/include/mbox.h | 26 ++ lab6/bootloader/include/shell.h | 8 + lab6/bootloader/include/string.h | 9 + lab6/bootloader/include/system.h | 14 + lab6/bootloader/include/uart.h | 16 ++ lab6/bootloader/linker.ld | 22 ++ lab6/bootloader/src/main.c | 44 ++++ lab6/bootloader/src/mbox.c | 37 +++ lab6/bootloader/src/shell.c | 63 +++++ lab6/bootloader/src/start.S | 33 +++ lab6/bootloader/src/string.c | 45 ++++ lab6/bootloader/src/system.c | 121 +++++++++ lab6/bootloader/src/uart.c | 189 ++++++++++++++ lab6/config.txt | 3 + lab6/include/cpio.h | 40 +++ lab6/include/dtb.h | 24 ++ lab6/include/exception.h | 89 +++++++ lab6/include/filesystem.h | 12 + lab6/include/gpio.h | 27 ++ lab6/include/irqtask.h | 25 ++ lab6/include/list.h | 137 ++++++++++ lab6/include/malloc.h | 49 ++++ lab6/include/mbox.h | 44 ++++ lab6/include/mmu.h | 39 +++ lab6/include/registers.h | 12 + lab6/include/sched.h | 67 +++++ lab6/include/shell.h | 8 + lab6/include/signal.h | 15 ++ lab6/include/sprintf.h | 27 ++ lab6/include/stddef.h | 6 + lab6/include/string.h | 16 ++ lab6/include/syscall.h | 18 ++ lab6/include/system.h | 11 + lab6/include/timer.h | 34 +++ lab6/include/uart.h | 51 ++++ lab6/linker.ld | 21 ++ lab6/rootfs/get_simpleexec.sh | 5 + lab6/rootfs/linker.ld | 5 + lab6/rootfs/testfile1 | 2 + lab6/rootfs/testfile112345 | 1 + lab6/rootfs/testfile2222 | 1 + lab6/rootfs/user_exception_test.S | 11 + lab6/send_kernel_to_bootloader.py | 31 +++ lab6/src/cpio.c | 64 +++++ lab6/src/dtb.c | 146 +++++++++++ lab6/src/entry.S | 206 +++++++++++++++ lab6/src/exception.c | 180 +++++++++++++ lab6/src/filesystem.c | 148 +++++++++++ lab6/src/irqtask.c | 86 +++++++ lab6/src/main.c | 39 +++ lab6/src/malloc.c | 410 ++++++++++++++++++++++++++++++ lab6/src/mbox.c | 26 ++ lab6/src/mmu.c | 89 +++++++ lab6/src/sched.S | 59 +++++ lab6/src/sched.c | 161 ++++++++++++ lab6/src/shell.c | 113 ++++++++ lab6/src/signal.c | 62 +++++ lab6/src/sprintf.c | 160 ++++++++++++ lab6/src/start.S | 92 +++++++ lab6/src/string.c | 131 ++++++++++ lab6/src/syscall.c | 188 ++++++++++++++ lab6/src/system.c | 82 ++++++ lab6/src/timer.c | 177 +++++++++++++ lab6/src/uart.c | 403 +++++++++++++++++++++++++++++ 69 files changed, 4619 insertions(+) create mode 100644 lab6/.gitignore create mode 100644 lab6/Makefile create mode 100644 lab6/bcm2710-rpi-3-b-plus.dtb create mode 100644 lab6/bootloader/Makefile create mode 100644 lab6/bootloader/include/gpio.h create mode 100644 lab6/bootloader/include/mbox.h create mode 100644 lab6/bootloader/include/shell.h create mode 100644 lab6/bootloader/include/string.h create mode 100644 lab6/bootloader/include/system.h create mode 100644 lab6/bootloader/include/uart.h create mode 100644 lab6/bootloader/linker.ld create mode 100644 lab6/bootloader/src/main.c create mode 100644 lab6/bootloader/src/mbox.c create mode 100644 lab6/bootloader/src/shell.c create mode 100644 lab6/bootloader/src/start.S create mode 100644 lab6/bootloader/src/string.c create mode 100644 lab6/bootloader/src/system.c create mode 100644 lab6/bootloader/src/uart.c create mode 100644 lab6/config.txt create mode 100644 lab6/include/cpio.h create mode 100644 lab6/include/dtb.h create mode 100644 lab6/include/exception.h create mode 100644 lab6/include/filesystem.h create mode 100644 lab6/include/gpio.h create mode 100644 lab6/include/irqtask.h create mode 100644 lab6/include/list.h create mode 100644 lab6/include/malloc.h create mode 100644 lab6/include/mbox.h create mode 100644 lab6/include/mmu.h create mode 100644 lab6/include/registers.h create mode 100644 lab6/include/sched.h create mode 100644 lab6/include/shell.h create mode 100644 lab6/include/signal.h create mode 100644 lab6/include/sprintf.h create mode 100644 lab6/include/stddef.h create mode 100644 lab6/include/string.h create mode 100644 lab6/include/syscall.h create mode 100644 lab6/include/system.h create mode 100644 lab6/include/timer.h create mode 100644 lab6/include/uart.h create mode 100644 lab6/linker.ld create mode 100644 lab6/rootfs/get_simpleexec.sh create mode 100644 lab6/rootfs/linker.ld create mode 100644 lab6/rootfs/testfile1 create mode 100644 lab6/rootfs/testfile112345 create mode 100644 lab6/rootfs/testfile2222 create mode 100644 lab6/rootfs/user_exception_test.S create mode 100644 lab6/send_kernel_to_bootloader.py create mode 100644 lab6/src/cpio.c create mode 100644 lab6/src/dtb.c create mode 100644 lab6/src/entry.S create mode 100644 lab6/src/exception.c create mode 100644 lab6/src/filesystem.c create mode 100644 lab6/src/irqtask.c create mode 100644 lab6/src/main.c create mode 100644 lab6/src/malloc.c create mode 100644 lab6/src/mbox.c create mode 100644 lab6/src/mmu.c create mode 100644 lab6/src/sched.S create mode 100644 lab6/src/sched.c create mode 100644 lab6/src/shell.c create mode 100644 lab6/src/signal.c create mode 100644 lab6/src/sprintf.c create mode 100644 lab6/src/start.S create mode 100644 lab6/src/string.c create mode 100644 lab6/src/syscall.c create mode 100644 lab6/src/system.c create mode 100644 lab6/src/timer.c create mode 100644 lab6/src/uart.c diff --git a/lab6/.gitignore b/lab6/.gitignore new file mode 100644 index 000000000..1d0691eb3 --- /dev/null +++ b/lab6/.gitignore @@ -0,0 +1,3 @@ +.vscode +build +*.img \ No newline at end of file diff --git a/lab6/Makefile b/lab6/Makefile new file mode 100644 index 000000000..144854087 --- /dev/null +++ b/lab6/Makefile @@ -0,0 +1,61 @@ +# debug use CFLAGS='-g3' ASMFLAGS='-g3' +# Modify from +# https://github.com/s-matyukevich/raspberry-pi-os/blob/master/src/lesson01/Makefile +ARMGNU ?= aarch64-linux-gnu + +COPS = $(CFLAGS) -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude #-ggdb #-D__FS_DEBUG #-D__DEBUG #-D__DEBUG_MM #-D__DEBUG_MM_ALLOC #-D__DEBUG_MM_SCHED +ASMOPS = $(ASMFLAGS) -Iinclude + +BUILD_DIR = build +SRC_DIR = src + +all : kernel8.img bootloader/bootloader.img + +debug: COPS += -DDEBUG +debug: ASMOPS += -DDEBUG +debug: all + +clean : + rm -rf $(BUILD_DIR) *.img + make -C bootloader clean + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -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) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -g -T linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy -g $(BUILD_DIR)/kernel8.elf -O binary kernel8.img + +run: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + +run_display: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -serial null -serial stdio -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + +run_display_debug: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -serial null -serial stdio -s -S -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + +run_debug: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -s -S -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + +connect_raspi: + sudo screen /dev/ttyUSB0 115200 + +bootloader/bootloader.img: + make -C bootloader + +filesystem: + cd rootfs;find . | cpio -o -H newc > ../initramfs.cpio + diff --git a/lab6/bcm2710-rpi-3-b-plus.dtb b/lab6/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 0000000000000000000000000000000000000000..3934b3a26eb82fd65dbcdfca6f6916da427a3fae GIT binary patch literal 31790 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 literal 0 HcmV?d00001 diff --git a/lab6/bootloader/Makefile b/lab6/bootloader/Makefile new file mode 100644 index 000000000..6b7bb6b60 --- /dev/null +++ b/lab6/bootloader/Makefile @@ -0,0 +1,50 @@ +# debug use CFLAGS='-g' ASMFLAGS='-g' +# Modify from +# https://github.com/s-matyukevich/raspberry-pi-os/blob/master/src/lesson01/Makefile +ARMGNU ?= aarch64-linux-gnu + +COPS = $(CFLAGS) -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude #-ggdb #-D__FS_DEBUG #-D__DEBUG #-D__DEBUG_MM #-D__DEBUG_MM_ALLOC #-D__DEBUG_MM_SCHED +ASMOPS = $(ASMFLAGS) -Iinclude + +BUILD_DIR = build +SRC_DIR = src + +all : bootloader.img + +clean : + rm -rf $(BUILD_DIR) *.img + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -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) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +bootloader.img: linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -g -T linker.ld -o $(BUILD_DIR)/bootloader.elf $(OBJ_FILES) + $(ARMGNU)-objcopy -g $(BUILD_DIR)/bootloader.elf -O binary bootloader.img + +run: + qemu-system-aarch64 -M raspi3 -kernel bootloader.img -display none -serial null -serial stdio + +run_pty: + qemu-system-aarch64 -M raspi3 -kernel bootloader.img -display none -serial null -serial pty -initrd ../initramfs.cpio -dtb ../bcm2710-rpi-3-b-plus.dtb + +run_debug: + qemu-system-aarch64 -M raspi3 -kernel bootloader.img -display none -serial null -serial stdio -dtb ../bcm2710-rpi-3-b-plus.dtb -s -S + +run_debug_pty: + qemu-system-aarch64 -M raspi3 -kernel bootloader.img -display none -serial null -serial pty -s -S + +connect_raspi: + sudo screen /dev/ttyUSB0 115200 + diff --git a/lab6/bootloader/include/gpio.h b/lab6/bootloader/include/gpio.h new file mode 100644 index 000000000..399ae80f2 --- /dev/null +++ b/lab6/bootloader/include/gpio.h @@ -0,0 +1,25 @@ +#ifndef GPIO_H +#define GPIO_H + +#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)) + +#endif diff --git a/lab6/bootloader/include/mbox.h b/lab6/bootloader/include/mbox.h new file mode 100644 index 000000000..46160f821 --- /dev/null +++ b/lab6/bootloader/include/mbox.h @@ -0,0 +1,26 @@ +/* a properly aligned buffer */ +/* use this buffer(global variable) directly and the mbox_call will use it after call*/ +/* mbox format https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */ +/* mbox address need to be aligned to 16 bytes */ +extern volatile 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 GET_BOARD_REVISION 0x10002 +#define MBOX_TAG_GETSERIAL 0x10004 +#define GET_ARM_MEMORY 0x10005 +#define MBOX_TAG_LAST 0 + +int mbox_call(unsigned char ch); \ No newline at end of file diff --git a/lab6/bootloader/include/shell.h b/lab6/bootloader/include/shell.h new file mode 100644 index 000000000..74bd0aa42 --- /dev/null +++ b/lab6/bootloader/include/shell.h @@ -0,0 +1,8 @@ +#ifndef SHELL_H +#define SHELL_H + +void shell(); +void do_cmd(char* cmd); +void print_system_messages(); + +#endif \ No newline at end of file diff --git a/lab6/bootloader/include/string.h b/lab6/bootloader/include/string.h new file mode 100644 index 000000000..8123bc2d4 --- /dev/null +++ b/lab6/bootloader/include/string.h @@ -0,0 +1,9 @@ +#ifndef STRING_H +#define STRING_H + +int strcmp (const char * s1, const char * s2 ); +char* strcat (char *dest, const char *src); +unsigned long long strlen(const char *str); +char* strcpy (char *dest, const char *src); +char* memcpy (void *dest, const void *src, unsigned long long len); +#endif \ No newline at end of file diff --git a/lab6/bootloader/include/system.h b/lab6/bootloader/include/system.h new file mode 100644 index 000000000..79410c43e --- /dev/null +++ b/lab6/bootloader/include/system.h @@ -0,0 +1,14 @@ +#ifndef SYSTEM_H +#define SYSTEM_H + +extern char* _dtb; + +int get_board_revision(unsigned int* board_revision); +int get_arm_memory_info(unsigned int* base_addr,unsigned int* size); +void set(long addr, unsigned int value); +void reboot(); +void reset(int tick); +void cancel_reset(); +void load_kernel(); + +#endif \ No newline at end of file diff --git a/lab6/bootloader/include/uart.h b/lab6/bootloader/include/uart.h new file mode 100644 index 000000000..e226d69aa --- /dev/null +++ b/lab6/bootloader/include/uart.h @@ -0,0 +1,16 @@ +#ifndef UART_H +#define UART_H + +#define MAX_BUF_SIZE 0x100 + +void uart_init(); +void uart_putc(char c); +char uart_getc(); +int uart_puts(char *s); +char* uart_gets(char *buf); +int uart_printf(char *s); +void uart_hex(unsigned int d); +void disable_uart(); +char uart_getc_pure(); + +#endif diff --git a/lab6/bootloader/linker.ld b/lab6/bootloader/linker.ld new file mode 100644 index 000000000..3d0a0f5d1 --- /dev/null +++ b/lab6/bootloader/linker.ld @@ -0,0 +1,22 @@ +SECTIONS +{ + . = 0x70000; + _code_relocate_place = .; + /*bootloader on 0x80000, kernel on 0x80000 need to self relocate bootloader to other place*/ + . = 0x80000; + PROVIDE(_start = .); + .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 = .; +} +__bss_size = (__bss_end - __bss_start)>>3; +__code_size = (_end - _start); diff --git a/lab6/bootloader/src/main.c b/lab6/bootloader/src/main.c new file mode 100644 index 000000000..b56ee1741 --- /dev/null +++ b/lab6/bootloader/src/main.c @@ -0,0 +1,44 @@ +#include "uart.h" +#include "mbox.h" +#include "shell.h" +#include "string.h" +#include "system.h" + +extern char* _code_relocate_place; +extern unsigned long long __code_size; +extern unsigned long long _start; +extern char* _dtb; + +void code_relocate(char * addr); + +int relocate=1; + +void main(char* arg) +{ + _dtb = arg; + char* reloc_place = (char*)&_code_relocate_place; + + if(relocate) // only do relocate once + { + relocate = 0; + code_relocate(reloc_place); + } + + // set up serial console + uart_init(); + + shell(); +} + +// relocate code and jump to there +void code_relocate(char * addr) +{ + unsigned long long size = (unsigned long long)&__code_size; + char* start = (char *)&_start; + for(unsigned long long i=0;i request successful +#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) // Mailbox 0 define several channels, but we only use channel 8 (CPU->GPU) for communication. +{ + unsigned int r = (((unsigned int)((unsigned long)&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 mbox[1]==MBOX_RESPONSE; + } + return 0; +} \ No newline at end of file diff --git a/lab6/bootloader/src/shell.c b/lab6/bootloader/src/shell.c new file mode 100644 index 000000000..e0f1766d1 --- /dev/null +++ b/lab6/bootloader/src/shell.c @@ -0,0 +1,63 @@ +#include "uart.h" +#include "string.h" +#include "shell.h" +#include "mbox.h" +#include "system.h" + +void shell() +{ + char cmd[MAX_BUF_SIZE]; + print_system_messages(); + uart_puts("Welcome, this is bootloader. Try to load kernel with uart with protocol in system.c(load_kernel)"); + while(1) + { + uart_printf("# "); + uart_gets(cmd); + do_cmd(cmd); + } +} + +void do_cmd(char* cmd) +{ + if(strcmp(cmd,"help")==0) + { + uart_puts("help : print this help menu"); + uart_puts("hello : print Hello World!"); + uart_puts("reboot : reboot the device"); + uart_puts("load_kernel : load kernel code from uart to 0x80000 and jump to it!"); + } + else if(strcmp(cmd,"hello")==0) + { + uart_puts("Hello World!"); + } + else if(strcmp(cmd,"reboot")==0) + { + reboot(); + }else if(strcmp(cmd,"load_kernel")==0) + { + load_kernel(); + }else + { + uart_puts("Unknown command!"); + } +} + +void print_system_messages() +{ + unsigned int board_revision; + get_board_revision(&board_revision); + uart_printf("Board revision is : 0x"); + uart_hex(board_revision); + uart_puts(""); + + unsigned int arm_mem_base_addr; + unsigned int arm_mem_size; + + get_arm_memory_info(&arm_mem_base_addr,&arm_mem_size); + uart_printf("ARM memory base address in bytes : 0x"); + uart_hex(arm_mem_base_addr); + uart_puts(""); + uart_printf("ARM memory size in bytes : 0x"); + uart_hex(arm_mem_size); + uart_puts(""); +} \ No newline at end of file diff --git a/lab6/bootloader/src/start.S b/lab6/bootloader/src/start.S new file mode 100644 index 000000000..446a11244 --- /dev/null +++ b/lab6/bootloader/src/start.S @@ -0,0 +1,33 @@ +.section ".text.boot" + +.global _start + +//avoid use x0 which stored dtb place +_start: + + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, 2f + // cpu id > 0, stop +1: wfe + b 1b +2: // cpu id == 0 + + // set top of stack just before our code (stack grows to a lower address per AAPCS64) + ldr x1, =_start + mov sp, x1 + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size +3: cbz w2, 4f + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, 3b + +4: + // jump to C code, should not return + bl main + // for failsafe, halt this core too + b 1b diff --git a/lab6/bootloader/src/string.c b/lab6/bootloader/src/string.c new file mode 100644 index 000000000..de4783cae --- /dev/null +++ b/lab6/bootloader/src/string.c @@ -0,0 +1,45 @@ +#include "string.h" +#include + +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; +} + +char* strcat (char *dest, const char *src) +{ + strcpy (dest + strlen (dest), src); + return dest; +} + +char* strcpy (char *dest, const char *src) +{ + return memcpy (dest, src, strlen (src) + 1); +} + +unsigned long long strlen(const char *str) +{ + size_t count = 0; + while((unsigned char)*str++)count++; + return count; +} + +char* memcpy (void *dest, const void *src, unsigned long long len) +{ + char *d = dest; + const char *s = src; + while (len--) + *d++ = *s++; + return dest; +} \ No newline at end of file diff --git a/lab6/bootloader/src/system.c b/lab6/bootloader/src/system.c new file mode 100644 index 000000000..286d0d676 --- /dev/null +++ b/lab6/bootloader/src/system.c @@ -0,0 +1,121 @@ +#include "system.h" +#include "uart.h" +#include "mbox.h" + +extern char _start[]; //bootloader load kernel to here +char* _dtb; + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +/* For all return 0 -> success , -1 failure*/ + +int get_board_revision(unsigned int* board_revision) +{ + /* + GET_BOARD_REVISION + */ + mbox[0] = 7*4; // length of the message + mbox[1] = MBOX_REQUEST; // request code + mbox[2] = GET_BOARD_REVISION; // tag identifier + mbox[3] = 4; // value buffer size in bytes + mbox[4] = 0; // request codes : b31 clear, b30-b0 reversed + mbox[5] = 0; // clear output buffer + mbox[6] = MBOX_TAG_LAST; // end tag + // send the message to the GPU and receive answer + if (mbox_call(MBOX_CH_PROP)) { + *board_revision = mbox[5]; + return 0; + } else { + uart_puts("Unable to query serial!"); + *board_revision = mbox[5] = -1; + return -1; + } +} + +int get_arm_memory_info(unsigned int* base_addr,unsigned int* size) +{ + /* + GET arm_memory address and size + */ + mbox[0] = 8*4; // length of the message + mbox[1] = MBOX_REQUEST; // request code + mbox[2] = GET_ARM_MEMORY; // tag identifier + mbox[3] = 8; // value buffer size in bytes + mbox[4] = 0; // request codes : b31 clear, b30-b0 reversed + mbox[5] = 0; // clear output buffer ( u32: base address in bytes ) + mbox[6] = 0; // clear output buffer ( u32: size in bytes ) + mbox[7] = MBOX_TAG_LAST; // end tag + + // send the message to the GPU and receive answer + if (mbox_call(MBOX_CH_PROP)) { + *base_addr = mbox[5]; + *size = mbox[6]; + return 0; + } else { + uart_puts("Unable to query serial!"); + return -1; + } +} + +void set(long addr, unsigned int value) +{ + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +void reboot() +{ + //disable_uart(); + reset(1); // timeout = 1/16th of a second? (whatever) +} + +void reset(int tick) +{ // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick + while(1); // wati for clock +} + +void cancel_reset() +{ + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} + + +//編譯器不要優化這段 +#pragma GCC push_options +#pragma GCC optimize ("O0") + +void load_kernel() +{ + // prevent dtb been rewrited by kernel + char* temp_dtb = _dtb; + char c; + unsigned long long kernel_size=0; + char* kernel_start = (char*) (&_start); + + uart_puts("kernel size:"); + for(int i=0;i<8;i++) //protocol : use little endian to get kernel size + { + c = uart_getc_pure(); + kernel_size += c<<(i*8); + } + + + for(int i=0;i get del + { + uart_putc('\b'); + uart_putc(' '); + uart_putc('\b'); + }else + { + uart_putc(r); + } + /* convert carrige return to newline */ + return r=='\r'?'\n':r; +} + +/** + * Display a string with newline + */ +int uart_puts(char *s) { + int i=0; + + while(*s) { + uart_putc(*s++); + i++; + } + uart_putc('\r'); + uart_putc('\n'); + + return i+2; +} + +/** + * get a string + */ +char* uart_gets(char *buf) +{ + int count; + char c; + char *s; + for (s = buf,count = 0; (c = uart_getc()) != '\n' && count!=MAX_BUF_SIZE-1 ;count++) + { + *s = c; + if(*s=='\x7f') + { + count--; + if(count==-1) + { + uart_putc(' '); // prevent back over command line # + continue; + } + s--; + count--; + continue; + } + s++; + } + *s = '\0'; + return buf; +} + +/** + * printf (TODO) + */ +int uart_printf(char *s) { + int i = 0; + while(*s) { + uart_putc(*s++); + i++; + } + return i; +} + +/** + * Display a binary value in hexadecimal + */ +void uart_hex(unsigned int d) { + unsigned int n; + int c; + for(c=28;c>=0;c-=4) { + // get highest tetrad + n=(d>>c)&0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n+=n>9?0x37:0x30; + uart_putc(n); + } +} + + +/** + * Receive a character without echo and any translation + */ +char uart_getc_pure() { + 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); + return r; +} diff --git a/lab6/config.txt b/lab6/config.txt new file mode 100644 index 000000000..49fc25695 --- /dev/null +++ b/lab6/config.txt @@ -0,0 +1,3 @@ +kernel=bootloader.img +arm_64bit=1 +initramfs initramfs.cpio 0x20000000 diff --git a/lab6/include/cpio.h b/lab6/include/cpio.h new file mode 100644 index 000000000..d92d441c4 --- /dev/null +++ b/lab6/include/cpio.h @@ -0,0 +1,40 @@ +#ifndef CPIO_H +#define CPIO_H + + +/* + cpio format : https://www.freebsd.org/cgi/man.cgi?query=cpio&sektion=5 + header,file path,file data,header ...... + header+file path (padding 4 bytes) + file data (padding 4 bytes) (max size 4gb) +*/ + +#define CPIO_NEWC_HEADER_MAGIC "070701" // big endian + +void* CPIO_DEFAULT_PLACE; // init in main +void *CPIO_DEFAULT_END; + +struct cpio_newc_header +{ + char c_magic[6]; //magic The string "070701". + 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]; //check This field is always set to zero by writers and ignored by readers. +}; + +/* write pathname,data,next header into corresponding parameter*/ +int cpio_newc_parse_header(struct cpio_newc_header *this_header_pointer, + char **pathname, unsigned int *filesize, char **data, + struct cpio_newc_header **next_header_pointer); + +#endif \ No newline at end of file diff --git a/lab6/include/dtb.h b/lab6/include/dtb.h new file mode 100644 index 000000000..17c387b6c --- /dev/null +++ b/lab6/include/dtb.h @@ -0,0 +1,24 @@ +#ifndef DTB_H +#define DTB_H + +#define uint32_t unsigned int +#define uint64_t unsigned long long + +// manipulate device tree with dtb file format +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + +char* dtb_place; +extern void* CPIO_DEFAULT_PLACE; // initialize by callback dtb_callback_initramfs in main 本來是寫死的 +typedef void (*dtb_callback)(uint32_t node_type, char *name, void *value, uint32_t name_size); + +uint32_t uint32_endian_big2lttle(uint32_t data); +void traverse_device_tree(void *base,dtb_callback callback); //traverse dtb tree +void dtb_callback_show_tree(uint32_t node_type, char *name, void *value, uint32_t name_size); +void dtb_callback_initramfs(uint32_t node_type, char *name, void *value, uint32_t name_size); +void reserve_memory_block_with_dtb(); + +#endif \ No newline at end of file diff --git a/lab6/include/exception.h b/lab6/include/exception.h new file mode 100644 index 000000000..2416e2b23 --- /dev/null +++ b/lab6/include/exception.h @@ -0,0 +1,89 @@ +#ifndef EXCEPTION_H +#define EXCEPTION_H + +// https://github.com/Tekki/raspberrypi-documentation/blob/master/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf p16 +#define CORE0_INTERRUPT_SOURCE ((volatile unsigned int *)(PHYS_TO_VIRT(0x40000060))) + +/* +The basic pending register shows which interrupt are pending. To speed up interrupts processing, a +number of 'normal' interrupt status bits have been added to this register. This makes the 'IRQ +pending base' register different from the other 'base' interrupt registers +p112-115 https://cs140e.sergio.bz/docs/BCM2837-ARM-Peripherals.pdf +*/ +#define PBASE PHYS_TO_VIRT(0x3F000000) +#define IRQ_BASIC_PENDING ((volatile unsigned int*)(PBASE+0x0000B200)) +#define IRQ_PENDING_1 ((volatile unsigned int*)(PBASE+0x0000B204)) +#define IRQ_PENDING_2 ((volatile unsigned int*)(PBASE+0x0000B208)) +#define FIQ_CONTROL ((volatile unsigned int*)(PBASE+0x0000B20C)) +#define ENABLE_IRQS_1 ((volatile unsigned int*)(PBASE+0x0000B210)) +#define ENABLE_IRQS_2 ((volatile unsigned int*)(PBASE+0x0000B214)) +#define ENABLE_BASIC_IRQS ((volatile unsigned int*)(PBASE+0x0000B218)) +#define DISABLE_IRQS_1 ((volatile unsigned int*)(PBASE+0x0000B21C)) +#define DISABLE_IRQS_2 ((volatile unsigned int*)(PBASE+0x0000B220)) +#define DISABLE_BASIC_IRQS ((volatile unsigned int*)(PBASE+0x0000B224)) + +#define IRQ_PENDING_1_AUX_INT (1<<29) +#define INTERRUPT_SOURCE_GPU (1<<8) +#define INTERRUPT_SOURCE_CNTPNSIRQ (1<<1) +//#define SYSTEM_TIMER_MATCH_1 (1<<1) +//#define SYSTEM_TIMER_MATCH_3 (1<<3) +//#define UART_INT (1ULL<<57) + +typedef struct trapframe +{ + unsigned long x0; + unsigned long x1; + unsigned long x2; + unsigned long x3; + unsigned long x4; + unsigned long x5; + unsigned long x6; + unsigned long x7; + unsigned long x8; + unsigned long x9; + unsigned long x10; + unsigned long x11; + unsigned long x12; + unsigned long x13; + unsigned long x14; + unsigned long x15; + unsigned long x16; + unsigned long x17; + unsigned long x18; + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + unsigned long x29; + unsigned long x30; + unsigned long spsr_el1; + unsigned long elr_el1; + unsigned long sp_el0; + +} trapframe_t; + +void sync_64_router(trapframe_t *tpf); +void irq_router(trapframe_t *tpf); +void invalid_exception_router(); + +static inline void enable_interrupt() +{ + __asm__ __volatile__("msr daifclr, 0xf"); +} + +static inline void disable_interrupt() +{ + __asm__ __volatile__("msr daifset, 0xf"); +} + +unsigned long long is_disable_interrupt(); +void lock(); +void unlock(); + +#endif \ No newline at end of file diff --git a/lab6/include/filesystem.h b/lab6/include/filesystem.h new file mode 100644 index 000000000..3ea204a03 --- /dev/null +++ b/lab6/include/filesystem.h @@ -0,0 +1,12 @@ +#ifndef FILESYSTEM_H +#define FILESYSTEM_H + +extern void* CPIO_DEFAULT_PLACE; + +int ls(char* working_dir); +int cat(char* thefilepath); +int execfile(char* thefilepath); +unsigned int get_file_size(char *thefilepath); +char *get_file_start(char *thefilepath); + +#endif \ No newline at end of file diff --git a/lab6/include/gpio.h b/lab6/include/gpio.h new file mode 100644 index 000000000..bb286555a --- /dev/null +++ b/lab6/include/gpio.h @@ -0,0 +1,27 @@ +#include + +#ifndef GPIO_H +#define GPIO_H + +#define MMIO_BASE PHYS_TO_VIRT(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)) + +#endif diff --git a/lab6/include/irqtask.h b/lab6/include/irqtask.h new file mode 100644 index 000000000..1aaccc86a --- /dev/null +++ b/lab6/include/irqtask.h @@ -0,0 +1,25 @@ +#ifndef IRQTASK_H +#define IRQTASK_H + +#include "list.h" + +// set uart irq priority = 1, timer = 0 +#define UART_IRQ_PRIORITY 1 +#define TIMER_IRQ_PRIORITY 0 + +//like timer_event +typedef struct irq_task +{ + struct list_head listhead; + + unsigned long long priority; //store priority (smaller number is more preemptive) + + void *task_function; // task function pointer +} irq_task_t; + +void add_task(void *task_function, unsigned long long priority); +void run_task(irq_task_t *the_task); +void run_preemptive_tasks(); +void task_list_init(); + +#endif \ No newline at end of file diff --git a/lab6/include/list.h b/lab6/include/list.h new file mode 100644 index 000000000..5794e63c1 --- /dev/null +++ b/lab6/include/list.h @@ -0,0 +1,137 @@ +#ifndef LIST_H +#define LIST_H + +/* + * Circular doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + * + * https://github.com/torvalds/linux/blob/master/include/linux/list.h + * https://elixir.bootlin.com/linux/latest/source/scripts/kconfig/list.h#L24 + */ + +typedef struct list_head { + struct list_head *next, *prev; +}list_head_t; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +/** + * INIT_LIST_HEAD - Initialize a list_head structure + * @list: list_head structure to be initialized. + * + * Initializes the list_head to point to itself. If it is a list header, + * the result is an empty list. + */ +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +static inline void list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + + +/** + * list_is_head - tests whether @list is the list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_head(const struct list_head *list, const struct list_head *head) +{ + return list == head; +} + + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next) + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_size(const struct list_head *head) +{ + list_head_t *pos; + int i= 0; + list_for_each(pos, head) + { + i++; + } + return i; +} + +#endif \ No newline at end of file diff --git a/lab6/include/malloc.h b/lab6/include/malloc.h new file mode 100644 index 000000000..7047568de --- /dev/null +++ b/lab6/include/malloc.h @@ -0,0 +1,49 @@ +#ifndef MALLOC_H +#define MALLOC_H + +#include "list.h" +#include "uart.h" +#include "exception.h" +#include "dtb.h" + +#define MAXORDER 6 +#define MAXCACHEORDER 4 // 32, 64, 128, 256, 512 (for every 32bytes) + +// simple_malloc +void *simple_malloc(unsigned int size); + +#define BUDDYSYSTEM_START PHYS_TO_VIRT(0x0) //0x10000000L +#define BUDDYSYSTEM_PAGE_COUNT 0x3C000 +//buddy system (for >= 4K pages) +void *allocpage(unsigned int size); +void freepage(void *ptr); + +//Basic Exercise 2 - Dynamic Memory Allocator - 30% +//For (< 4K) +//small memory allocation +//store listhead in cache first 16 bytes +void *alloccache(unsigned int size); +void freecache(void *ptr); +void page2caches(int order); + +void *kmalloc(unsigned int size); +void kfree(void *ptr); + +typedef struct frame +{ + struct list_head listhead; + int val; // val is order + int isused; + int cacheorder; // -1 means isn't used for cache + unsigned int idx; +} frame_t; + +void init_allocator(); +frame_t *release_redundant(frame_t *frame); +frame_t *get_buddy(frame_t *frame); +frame_t *coalesce(frame_t* f); +void dump_freelist_info(); +void dump_cachelist_info(); +void memory_reserve(unsigned long long start, unsigned long long end); +void alloctest(); +#endif \ No newline at end of file diff --git a/lab6/include/mbox.h b/lab6/include/mbox.h new file mode 100644 index 000000000..c53870dee --- /dev/null +++ b/lab6/include/mbox.h @@ -0,0 +1,44 @@ +#ifndef MBOX_H +#define MBOX_H + +#include "gpio.h" + +/* a properly aligned buffer */ +/* use this buffer(global variable) directly and the mbox_call will use it after call*/ +/* mbox format https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */ +/* mbox address need to be aligned to 16 bytes */ +extern volatile unsigned int mbox[72]; + +#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 GET_BOARD_REVISION 0x10002 +#define MBOX_TAG_GETSERIAL 0x10004 +#define GET_ARM_MEMORY 0x10005 +#define MBOX_TAG_LAST 0 + +#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 // mbox[1] = 0x80000000 -> request successful +#define MBOX_FULL 0x80000000 +#define MBOX_EMPTY 0x40000000 + +int mbox_call(unsigned char ch); + +#endif \ No newline at end of file diff --git a/lab6/include/mmu.h b/lab6/include/mmu.h new file mode 100644 index 000000000..f05936053 --- /dev/null +++ b/lab6/include/mmu.h @@ -0,0 +1,39 @@ +#ifndef MMU_H +#define MMU_H + +#include "stddef.h" + +#define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16)) +#define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30)) +#define TCR_CONFIG_DEFAULT (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB) + +#define MAIR_DEVICE_nGnRnE 0b00000000 +#define MAIR_NORMAL_NOCACHE 0b01000100 +#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_NORMAL_NOCACHE 1 + +#define PD_TABLE 0b11L +#define PD_BLOCK 0b01L +#define PD_UNX (1L<<54) +#define PD_ACCESS (1L << 10) +#define PD_UK_ACCESS (1L << 6) +#define BOOT_PGD_ATTR PD_TABLE +#define BOOT_PUD_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK) + +#define PHYS_TO_VIRT(x) (x + 0xffff000000000000) +#define VIRT_TO_PHYS(x) (x - 0xffff000000000000) +#define ENTRY_ADDR_MASK 0xfffffffff000L + +#ifndef __ASSEMBLER__ + +#define kernel_pgd_addr 0x1000 +#define kernel_pud_addr 0x2000 + +void *set_2M_kernel_mmu(void *x0); +void map_one_page(size_t *pgd_p, size_t va, size_t pa); +void mappages(size_t *pgd_p, size_t va, size_t size, size_t pa); +void free_page_tables(size_t *page_table, int level); + +#endif //__ASSEMBLER__ + +#endif \ No newline at end of file diff --git a/lab6/include/registers.h b/lab6/include/registers.h new file mode 100644 index 000000000..41886d8d6 --- /dev/null +++ b/lab6/include/registers.h @@ -0,0 +1,12 @@ +#ifndef REGISTERS_H +#define REGISTERS_H + +// CPACR_EL1, Architectural Feature Access Control Register +#define CPACR_EL1_FPEN (0b11 << 20) +#define CPACR_EL1_VALUE (CPACR_EL1_FPEN) +#define IRQS1 ((volatile unsigned int *)(PHYS_TO_VIRT(0x3f00b210))) + +#define STR(x) #x +#define XSTR(s) STR(s) + +#endif \ No newline at end of file diff --git a/lab6/include/sched.h b/lab6/include/sched.h new file mode 100644 index 000000000..f0a1bc824 --- /dev/null +++ b/lab6/include/sched.h @@ -0,0 +1,67 @@ +#ifndef SCHED_H +#define SCHED_H + +#include "list.h" + +#define PIDMAX 32768 +#define USTACK_SIZE 0x4000 +#define KSTACK_SIZE 0x4000 +#define SIGNAL_MAX 64 + +extern void switch_to(void *curr_context, void *next_context); +extern void store_context(void *curr_context); +extern void load_context(void *curr_context); +extern void *get_current(); + +typedef struct thread_context +{ + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + unsigned long fp; + unsigned long lr; + unsigned long sp; + void* ttbr0_el1; // use for MMU mapping (user space) +} thread_context_t; + +typedef struct thread +{ + list_head_t listhead; + thread_context_t context; + char *data; + unsigned int datasize; + int iszombie; + int pid; + int isused; + char* stack_alloced_ptr; + char *kernel_stack_alloced_ptr; + void (*singal_handler[SIGNAL_MAX+1])(); + int sigcount[SIGNAL_MAX + 1]; + void (*curr_signal_handler)(); + int signal_is_checking; + thread_context_t signal_saved_context; +} thread_t; + +thread_t *curr_thread; +list_head_t *run_queue; +list_head_t *wait_queue; + +thread_t threads[PIDMAX + 1]; + +void schedule_timer(char *notuse); +void init_thread_sched(); +void idle(); +void schedule(); +void kill_zombies(); +void thread_exit(); +thread_t *thread_create(void *start, unsigned int filesize); +int exec_thread(char *data, unsigned int filesize); + +#endif \ No newline at end of file diff --git a/lab6/include/shell.h b/lab6/include/shell.h new file mode 100644 index 000000000..74bd0aa42 --- /dev/null +++ b/lab6/include/shell.h @@ -0,0 +1,8 @@ +#ifndef SHELL_H +#define SHELL_H + +void shell(); +void do_cmd(char* cmd); +void print_system_messages(); + +#endif \ No newline at end of file diff --git a/lab6/include/signal.h b/lab6/include/signal.h new file mode 100644 index 000000000..0f6352a2f --- /dev/null +++ b/lab6/include/signal.h @@ -0,0 +1,15 @@ +#ifndef SIGNAL_H +#define SIGNAL_H + +#define SIGKILL_NO 9 + +#include "syscall.h" +#include "sched.h" +#include "malloc.h" + +void signal_default_handler(); +void check_signal(trapframe_t *tpf); +void run_signal(trapframe_t* tpf,int signal); +void signal_handler_wrapper(); + +#endif \ No newline at end of file diff --git a/lab6/include/sprintf.h b/lab6/include/sprintf.h new file mode 100644 index 000000000..101e564e3 --- /dev/null +++ b/lab6/include/sprintf.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. + * + */ + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); \ No newline at end of file diff --git a/lab6/include/stddef.h b/lab6/include/stddef.h new file mode 100644 index 000000000..c189f9730 --- /dev/null +++ b/lab6/include/stddef.h @@ -0,0 +1,6 @@ +#ifndef STDDEF_H +#define STDDEF_H + +#define size_t unsigned long + +#endif \ No newline at end of file diff --git a/lab6/include/string.h b/lab6/include/string.h new file mode 100644 index 000000000..e8c814ed4 --- /dev/null +++ b/lab6/include/string.h @@ -0,0 +1,16 @@ +#include "stddef.h" + +#ifndef STRING_H +#define STRING_H + +int strcmp (const char * s1, const char * s2 ); +int strncmp (const char *s1, const char *s2, unsigned long long n); +char* strcat (char *dest, const char *src); +unsigned long long strlen(const char *str); +char* strcpy (char *dest, const char *src); +char* memcpy (void *dest, const void *src, unsigned long long len); +char* strchr (register const char *s, int c); +int atoi(char* str); +void *memset(void *s, int c, size_t n); + +#endif \ No newline at end of file diff --git a/lab6/include/syscall.h b/lab6/include/syscall.h new file mode 100644 index 000000000..30d75e79a --- /dev/null +++ b/lab6/include/syscall.h @@ -0,0 +1,18 @@ +#ifndef SYSCALL_H +#define SYSCALL_H + +#include "stddef.h" +#include "exception.h" +int getpid(trapframe_t *tpf); +size_t uartread(trapframe_t *tpf,char buf[], size_t size); +size_t uartwrite(trapframe_t *tpf,const char buf[], size_t size); +int exec(trapframe_t *tpf,const char *name, char *const argv[]); +int fork(trapframe_t *tpf); +void exit(trapframe_t *tpf,int status); +int syscall_mbox_call(trapframe_t *tpf, unsigned char ch, unsigned int *mbox); +void kill(trapframe_t *tpf,int pid); +void signal_register(int signal, void (*handler)()); +void signal_kill(int pid, int signal); +void sigreturn(trapframe_t *tpf); + +#endif diff --git a/lab6/include/system.h b/lab6/include/system.h new file mode 100644 index 000000000..34bee2bd0 --- /dev/null +++ b/lab6/include/system.h @@ -0,0 +1,11 @@ +#ifndef SYSTEM_H +#define SYSTEM_H + +int get_board_revision(unsigned int* board_revision); +int get_arm_memory_info(unsigned int* base_addr,unsigned int* size); +void set(long addr, unsigned int value); +void reboot(); +void reset(int tick); +void cancel_reset(); + +#endif \ No newline at end of file diff --git a/lab6/include/timer.h b/lab6/include/timer.h new file mode 100644 index 000000000..2b84b854a --- /dev/null +++ b/lab6/include/timer.h @@ -0,0 +1,34 @@ +#ifndef TIMER_H +#define TIMER_H + +#include "list.h" +//https://github.com/Tekki/raspberrypi-documentation/blob/master/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf p13 +#define CORE0_TIMER_IRQ_CTRL PHYS_TO_VIRT(0x40000040) + +typedef struct timer_event +{ + struct list_head listhead; + + unsigned long long interrupt_time; //store as tick time after cpu start + + void *callback; // interrupt -> timer_callback -> callback(args) + + char *args; // need to free the string by event callback function +} timer_event_t; + +struct list_head *timer_event_list; // first head has nothing, store timer_event_t after it + +void core_timer_enable(); +void core_timer_disable(); +void core_timer_handler(); + +//now the callback only support "funcion(char *)", char* in args (defualt by second) +void add_timer(void *callback, unsigned long long timeout, char *args, int bytick); +unsigned long long get_tick_plus_s(unsigned long long second); +void set_core_timer_interrupt(unsigned long long expired_time); +void set_core_timer_interrupt_by_tick(unsigned long long tick); +void two_second_alert(char *str); +void timer_list_init(); +int timer_list_get_size(); + +#endif \ No newline at end of file diff --git a/lab6/include/uart.h b/lab6/include/uart.h new file mode 100644 index 000000000..adef0cf64 --- /dev/null +++ b/lab6/include/uart.h @@ -0,0 +1,51 @@ +#ifndef UART_H +#define UART_H + +#include "gpio.h" +#include "uart.h" +#include "sprintf.h" +#include "registers.h" + +#define MAX_BUF_SIZE 0x1000 + +/* 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)) + +void uart_init(); +void uart_disable_echo(); +void uart_enable_echo(); +void uart_putc(char c); +char uart_getc(); +int uart_puts(char *s); +int uart_async_puts(char *s); +char* uart_gets(char *buf); +char* uart_async_gets(char *buf); +int uart_printf(char *fmt, ...); +int uart_async_printf(char *fmt, ...); +void disable_uart(); +void uart_interrupt_r_handler(); +void uart_interrupt_w_handler(); +void enable_mini_uart_interrupt(); +void enable_mini_uart_w_interrupt(); +void enable_mini_uart_r_interrupt(); +void disable_mini_uart_interrupt(); +void disable_mini_uart_w_interrupt(); +void disable_mini_uart_r_interrupt(); +int mini_uart_r_interrupt_is_enable(); +int mini_uart_w_interrupt_is_enable(); + +char uart_async_getc(); +void uart_async_putc(char c); + +#endif diff --git a/lab6/linker.ld b/lab6/linker.ld new file mode 100644 index 000000000..16ef10f6d --- /dev/null +++ b/lab6/linker.ld @@ -0,0 +1,21 @@ +SECTIONS +{ + . = 0xffff000000000000; + . += 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 = .; + } + _heap_start = .; + _end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start)>>3; diff --git a/lab6/rootfs/get_simpleexec.sh b/lab6/rootfs/get_simpleexec.sh new file mode 100644 index 000000000..782bd723b --- /dev/null +++ b/lab6/rootfs/get_simpleexec.sh @@ -0,0 +1,5 @@ +#!bin/bash + +aarch64-linux-gnu-gcc -c user_exception_test.S +aarch64-linux-gnu-ld -T linker.ld -o user_exception_test.elf user_exception_test.o +aarch64-linux-gnu-objcopy -O binary user_exception_test.elf user_exception_test.img \ No newline at end of file diff --git a/lab6/rootfs/linker.ld b/lab6/rootfs/linker.ld new file mode 100644 index 000000000..783ebe038 --- /dev/null +++ b/lab6/rootfs/linker.ld @@ -0,0 +1,5 @@ +SECTIONS +{ + . = 0x80000; + .text : { *(.text) } +} \ No newline at end of file diff --git a/lab6/rootfs/testfile1 b/lab6/rootfs/testfile1 new file mode 100644 index 000000000..734d5d5db --- /dev/null +++ b/lab6/rootfs/testfile1 @@ -0,0 +1,2 @@ +1 +1111111111111111111111111111 diff --git a/lab6/rootfs/testfile112345 b/lab6/rootfs/testfile112345 new file mode 100644 index 000000000..539a7773b --- /dev/null +++ b/lab6/rootfs/testfile112345 @@ -0,0 +1 @@ +1111111111111111111111 diff --git a/lab6/rootfs/testfile2222 b/lab6/rootfs/testfile2222 new file mode 100644 index 000000000..876c79950 --- /dev/null +++ b/lab6/rootfs/testfile2222 @@ -0,0 +1 @@ +222222 diff --git a/lab6/rootfs/user_exception_test.S b/lab6/rootfs/user_exception_test.S new file mode 100644 index 000000000..838323763 --- /dev/null +++ b/lab6/rootfs/user_exception_test.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 diff --git a/lab6/send_kernel_to_bootloader.py b/lab6/send_kernel_to_bootloader.py new file mode 100644 index 000000000..f25abfcb6 --- /dev/null +++ b/lab6/send_kernel_to_bootloader.py @@ -0,0 +1,31 @@ +from serial import Serial +from pwn import * +import argparse + +parser = argparse.ArgumentParser(description='NYCU OSDI kernel sender') +parser.add_argument('--filename', metavar='PATH', default='kernel8.img', type=str, help='path to kernel8.img') +parser.add_argument('--device', metavar='TTY',default='/dev/ttyUSB0', type=str, help='path to UART device') +parser.add_argument('--baud', metavar='Hz',default=115200, type=int, help='baud rate') +args = parser.parse_args() + +with open(args.filename,'rb') as fd: + with Serial(args.device, args.baud) as ser: + + kernel_raw = fd.read() + length = len(kernel_raw) + + print("Kernel image size : ", hex(length)) + for i in range(8): + ser.write(p64(length)[i:i+1]) + ser.flush() + + print("Start sending kernel img by uart...") + for i in range(length): + # Use kernel_raw[i: i+1] is byte type. Instead of using kernel_raw[i] it will retrieve int type then cause error + ser.write(kernel_raw[i: i+1]) + ser.flush() + if i % 100 == 0: + print("{:>6}/{:>6} bytes".format(i, length)) + print("{:>6}/{:>6} bytes".format(length, length)) + print("Transfer finished!") + \ No newline at end of file diff --git a/lab6/src/cpio.c b/lab6/src/cpio.c new file mode 100644 index 000000000..0f354b5fd --- /dev/null +++ b/lab6/src/cpio.c @@ -0,0 +1,64 @@ +#include "cpio.h" +#include "string.h" +#include "uart.h" + + +/* Parse an ASCII hex string into an integer. (big endian)*/ +static unsigned int parse_hex_str(char *s, unsigned int max_len) +{ + unsigned int r = 0; + + for (unsigned int i = 0; i < max_len; i++) { + r *= 16; + if (s[i] >= '0' && s[i] <= '9') { + r += s[i] - '0'; + } else if (s[i] >= 'a' && s[i] <= 'f') { + r += s[i] - 'a' + 10; + } else if (s[i] >= 'A' && s[i] <= 'F') { + r += s[i] - 'A' + 10; + } else { + return r; + } + } + return r; +} + + +/* write pathname,data,next header into corresponding parameter */ +/* if no next header, next_header_pointer = 0 */ +/* return -1 if parse error*/ +int cpio_newc_parse_header(struct cpio_newc_header *this_header_pointer, char **pathname, unsigned int *filesize, char **data, struct cpio_newc_header **next_header_pointer) +{ + /* Ensure magic header exists. */ + if (strncmp(this_header_pointer->c_magic, CPIO_NEWC_HEADER_MAGIC,sizeof(this_header_pointer->c_magic)) != 0)return -1; + + //transfer big endian 8 byte hex string to unsinged int and store into *filesize + *filesize = parse_hex_str(this_header_pointer->c_filesize,8); + + // end of header is the pathname + *pathname = ((char *)this_header_pointer) + sizeof(struct cpio_newc_header); + + // get file data, file data is just after pathname + unsigned int pathname_length = parse_hex_str(this_header_pointer->c_namesize,8); + unsigned int offset = pathname_length+sizeof(struct cpio_newc_header); + offset = offset%4==0?offset:(offset+4-offset%4); //padding + *data = (char *)this_header_pointer+offset; + + //get next header pointer + if(*filesize==0) + { + *next_header_pointer = (struct cpio_newc_header*)*data; + }else + { + offset = *filesize; + *next_header_pointer = (struct cpio_newc_header*)(*data + (offset%4==0?offset:(offset+4-offset%4))); + } + + // if filepath is TRAILER!!! means there is no more files. + if(strncmp(*pathname,"TRAILER!!!",sizeof("TRAILER!!!"))==0) + { + *next_header_pointer = 0; + } + + return 0; +} \ No newline at end of file diff --git a/lab6/src/dtb.c b/lab6/src/dtb.c new file mode 100644 index 000000000..86cb6e200 --- /dev/null +++ b/lab6/src/dtb.c @@ -0,0 +1,146 @@ +#include "dtb.h" +#include "uart.h" +#include "string.h" +#include "cpio.h" +#include "malloc.h" + +//stored as big endian +struct fdt_header { + 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; +}; + +struct fdt_reserve_entry +{ + uint64_t address; + uint64_t size; +}; + +uint32_t uint32_endian_big2lttle(uint32_t data) +{ + char* r = (char*)&data; + return (r[3]<<0) | (r[2]<<8) | (r[1]<<16) | (r[0]<<24); +} + +uint64_t uint64_endian_big2lttle(uint64_t data) +{ + char *r = (char *)&data; + return ((unsigned long long)r[7] << 0) | ((unsigned long long)r[6] << 8) | ((unsigned long long)r[5] << 16) | ((unsigned long long)r[4] << 24) | ((unsigned long long)r[3] << 32) | ((unsigned long long)r[2] << 40) | ((unsigned long long)r[1] << 48) | ((unsigned long long)r[0] << 56); +} + +void traverse_device_tree(void *dtb_ptr,dtb_callback callback) +{ + struct fdt_header* header = dtb_ptr; + if(uint32_endian_big2lttle(header->magic) != 0xD00DFEED) + { + uart_puts("traverse_device_tree : wrong magic in traverse_device_tree"); + return; + } + + uint32_t struct_size = uint32_endian_big2lttle(header->size_dt_struct); + char* dt_struct_ptr = (char*)((char*)header + uint32_endian_big2lttle(header->off_dt_struct)); + char* dt_strings_ptr = (char*)((char*)header + uint32_endian_big2lttle(header->off_dt_strings)); + + char* end = (char*)dt_struct_ptr + struct_size; + char* pointer = dt_struct_ptr; + + while(pointer < end) + { + uint32_t token_type = uint32_endian_big2lttle(*(uint32_t*)pointer); + + pointer += 4; + if(token_type == FDT_BEGIN_NODE) + { + callback(token_type,pointer,0,0); + pointer += strlen(pointer); + pointer += 4 - (unsigned long long)pointer%4; //alignment 4 byte + }else if(token_type == FDT_END_NODE) + { + callback(token_type,0,0,0); + }else if(token_type == FDT_PROP) + { + uint32_t len = uint32_endian_big2lttle(*(uint32_t*)pointer); + pointer += 4; + char* name = (char*)dt_strings_ptr + uint32_endian_big2lttle(*(uint32_t*)pointer); + pointer += 4; + callback(token_type,name,pointer,len); + pointer += len; + if((unsigned long long)pointer % 4 !=0)pointer += 4 - (unsigned long long)pointer%4; //alignment 4 byte + }else if(token_type == FDT_NOP) + { + callback(token_type,0,0,0); + }else if(token_type == FDT_END) + { + callback(token_type,0,0,0); + }else + { + uart_printf("error type:%x\r\n",token_type); + return; + } + } +} + +void dtb_callback_show_tree(uint32_t node_type, char *name, void *data, uint32_t name_size) +{ + static int level = 0; + if(node_type==FDT_BEGIN_NODE) + { + for(int i=0;imagic) != 0xD00DFEED) + { + uart_puts("traverse_device_tree : wrong magic in traverse_device_tree"); + return; + } + + char *dt_mem_rsvmap_ptr = (char *)((char *)header + uint32_endian_big2lttle(header->off_mem_rsvmap)); + struct fdt_reserve_entry *reverse_entry = (struct fdt_reserve_entry *)dt_mem_rsvmap_ptr; + + while (reverse_entry->address != 0 || reverse_entry->size != 0) + { + unsigned long long start = PHYS_TO_VIRT(uint64_endian_big2lttle(reverse_entry->address)); + unsigned long long end = uint64_endian_big2lttle(reverse_entry->size) + start; + memory_reserve(start, end); + reverse_entry++; + } + + //also reserve device tree + memory_reserve((unsigned long long)dtb_place, (unsigned long long)dtb_place + uint32_endian_big2lttle(header->totalsize)); +} diff --git a/lab6/src/entry.S b/lab6/src/entry.S new file mode 100644 index 000000000..99f9a64c7 --- /dev/null +++ b/lab6/src/entry.S @@ -0,0 +1,206 @@ +// save general registers to stack +.global save_all +.macro save_all + 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] + + //using for nested interrupt + mrs x0, spsr_el1 + str x0, [sp, 16 * 15 + 8] + mrs x0, elr_el1 + str x0, [sp, 16 * 16] + mrs x0, sp_el0 + str x0, [sp, 16 * 16 + 8] + + ldp x0, x1, [sp ,16 * 0] // restore x0 + +.endm + +// load general registers from +.global load_all +.macro load_all + 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] + + //using for nested interrupt + ldr x0, [sp, 16 * 15 + 8] + msr spsr_el1,x0 + ldr x0, [sp, 16 * 16] + msr elr_el1, x0 + ldr x0, [sp, 16 * 16 + 8] + msr sp_el0, x0 + + ldp x0, x1, [sp ,16 * 0] // restore x0 + + add sp, sp, 32 * 9 +.endm + +.macro ventry label + .align 7 + b \label +.endm + +.align 11 // vector table should be aligned to 0x800 +.global exception_vector_table +exception_vector_table: + + //Exception from the current EL while using SP_EL0 + ventry sync_invalid_el1t // Synchronous EL1t + ventry irq_invalid_el1t // IRQ EL1t + ventry fiq_invalid_el1t // FIQ EL1t + ventry error_invalid_el1t // Error EL1t + + //Exception from the current EL while using SP_ELx + ventry sync_el1h // Synchronous EL1h + ventry irq_el1h // IRQ EL1h + ventry fiq_invalid_el1h // FIQ EL1h + ventry error_invalid_el1h // Error EL1h + + //Exception from a lower EL and at least one lower EL is AArch64 + ventry sync_el0_64 // Synchronous 64-bit EL0 + ventry irq_el0_64 // IRQ 64-bit EL0 + ventry fiq_invalid_el0_64 // FIQ 64-bit EL0 + ventry error_invalid_el0_64 // Error 64-bit EL0 + + //Exception from a lower EL and at least all lower EL are AArch32 + ventry sync_invalid_el0_32 // Synchronous 32-bit EL0 + ventry irq_invalid_el0_32 // IRQ 32-bit EL0 + ventry fiq_invalid_el0_32 // FIQ 32-bit EL0 + ventry error_invalid_el0_32 // Error 32-bit EL0 + + + +sync_invalid_el1t: + //save_all + mov x0,0 + bl invalid_exception_router + //load_all + eret +irq_invalid_el1t: + save_all + mov x0,1 + bl invalid_exception_router + load_all + eret +fiq_invalid_el1t: + save_all + mov x0,2 + bl invalid_exception_router + load_all + eret +error_invalid_el1t: + save_all + mov x0,3 + bl invalid_exception_router + load_all + eret + + + +sync_el1h: + //save_all + mov x0,4 + bl invalid_exception_router + //load_all + eret +irq_el1h: + save_all + mov x0, sp // trap_frame + bl irq_router + load_all + eret +fiq_invalid_el1h: + save_all + mov x0,6 + bl invalid_exception_router + load_all + eret +error_invalid_el1h: + save_all + mov x0,7 + bl invalid_exception_router + load_all + eret + + + +sync_el0_64: + save_all + mov x0, sp // trap_frame + bl sync_64_router + load_all + eret +irq_el0_64: + save_all + mov x0, sp // trap_frame + bl irq_router + load_all + eret +fiq_invalid_el0_64: + save_all + mov x0,10 + bl invalid_exception_router + load_all + eret +error_invalid_el0_64: + save_all + mov x0,11 + bl invalid_exception_router + load_all + eret + + + +sync_invalid_el0_32: + save_all + mov x0,12 + bl invalid_exception_router + load_all + eret +irq_invalid_el0_32: + save_all + mov x0,13 + bl invalid_exception_router + load_all + eret +fiq_invalid_el0_32: + save_all + mov x0,14 + bl invalid_exception_router + load_all + eret +error_invalid_el0_32: + save_all + mov x0,15 + bl invalid_exception_router + load_all + eret \ No newline at end of file diff --git a/lab6/src/exception.c b/lab6/src/exception.c new file mode 100644 index 000000000..1dd77ef29 --- /dev/null +++ b/lab6/src/exception.c @@ -0,0 +1,180 @@ +#include "uart.h" +#include "exception.h" +#include "timer.h" +#include "irqtask.h" +#include "syscall.h" +#include "sched.h" +#include "signal.h" + + +// For svc 0 (supervisor call) +void sync_64_router(trapframe_t* tpf) +{ + enable_interrupt(); + unsigned long long syscall_no = tpf->x8; + + if (syscall_no == 0) + { + getpid(tpf); + } + else if(syscall_no == 1) + { + uartread(tpf,(char *) tpf->x0, tpf->x1); + } + else if (syscall_no == 2) + { + uartwrite(tpf,(char *) tpf->x0, tpf->x1); + } + else if (syscall_no == 3) + { + exec(tpf,(char *) tpf->x0, (char **)tpf->x1); + } + else if (syscall_no == 4) + { + fork(tpf); + } + else if (syscall_no == 5) + { + exit(tpf,tpf->x0); + } + else if (syscall_no == 6) + { + syscall_mbox_call(tpf,(unsigned char)tpf->x0, (unsigned int *)tpf->x1); + } + else if (syscall_no == 7) + { + kill(tpf, (int)tpf->x0); + } + else if (syscall_no == 8) + { + signal_register(tpf->x0, (void (*)())tpf->x1); + } + else if (syscall_no == 9) + { + signal_kill(tpf->x0, tpf->x1); + } + else if (syscall_no == 50) + { + sigreturn(tpf); + } + + /* + unsigned long long spsr_el1; + __asm__ __volatile__("mrs %0, SPSR_EL1\n\t" : "=r" (spsr_el1)); + + unsigned long long elr_el1; + __asm__ __volatile__("mrs %0, ELR_EL1\n\t" : "=r" (elr_el1)); + + unsigned long long esr_el1; + __asm__ __volatile__("mrs %0, ESR_EL1\n\t" : "=r" (esr_el1));*/ + + //uart_printf("exception sync_el0_64_router -> spsr_el1 : 0x%x, elr_el1 : 0x%x, esr_el1 : 0x%x\r\n",spsr_el1,elr_el1,esr_el1); +} + +void irq_router(trapframe_t* tpf) +{ + //uart_printf("ena : %d\r\n", is_disable_interrupt()); + //uart_printf("irq_basic_pending: %x\n",*IRQ_BASIC_PENDING); + //uart_printf("irq_pending_1: %x\n",*IRQ_PENDING_1); + //uart_printf("irq_pending_2: %x\n",*IRQ_PENDING_2); + //uart_printf("source : %x\n",*CORE0_INTERRUPT_SOURCE); + + //目前實測能從pending_1 AUX_INT, CORE0_INTERRUPT_SOURCE=GPU 辨別其他都是0(或再找) + + if (*IRQ_PENDING_1 & IRQ_PENDING_1_AUX_INT && *CORE0_INTERRUPT_SOURCE & INTERRUPT_SOURCE_GPU) // from aux && from GPU0 -> uart exception + { + //https://cs140e.sergio.bz/docs/BCM2837-ARM-Peripherals.pdf p13 + /* + AUX_MU_IIR + on read bits[2:1] : + 00 : No interrupts + 01 : Transmit holding register empty + 10 : Receiver holds valid byte + 11: + */ + + // buffer read, write + if (*AUX_MU_IIR & (0b01 << 1)) //can write + { + disable_mini_uart_w_interrupt(); // lab 3 : advanced 2 -> mask device line (enable by handler) + add_task(uart_interrupt_w_handler, UART_IRQ_PRIORITY); + run_preemptive_tasks(); + } + else if (*AUX_MU_IIR & (0b10 << 1)) // can read + { + //不知道為啥關了還會進來 這種時候清除FIFO就可以關掉 (會有最多8個FIFO裡的byte消失) + if (!mini_uart_r_interrupt_is_enable()) + { + *AUX_MU_IIR = 0xC2; + return; + } + + //uart_printf("dd %d %d \r\n", mini_uart_r_interrupt_is_enable(), mini_uart_w_interrupt_is_enable()); + disable_mini_uart_r_interrupt(); // lab 3 : advanced 2 -> mask device line (enable by handler) + add_task(uart_interrupt_r_handler, UART_IRQ_PRIORITY); + run_preemptive_tasks(); + } + else + { + uart_printf("uart handler error\r\n"); + } + + }else if(*CORE0_INTERRUPT_SOURCE & INTERRUPT_SOURCE_CNTPNSIRQ) //from CNTPNS (core_timer) + { + core_timer_disable(); // lab 3 : advanced 2 -> mask device line + add_task(core_timer_handler, TIMER_IRQ_PRIORITY); + run_preemptive_tasks(); + core_timer_enable(); // lab 3 : advanced 2 -> unmask device line + + //at least two trhead running -> schedule for any timer irq + if (run_queue->next->next != run_queue)schedule(); + } + + //only do signal handler when return to user mode + if ((tpf->spsr_el1 & 0b1100) == 0) + { + check_signal(tpf); + } + +} + +void invalid_exception_router(unsigned long long x0){ + unsigned long long elr_el1; + __asm__ __volatile__("mrs %0, ELR_EL1\n\t" + : "=r"(elr_el1)); + uart_printf("invalid exception : 0x%x\r\n", elr_el1); + uart_printf("invalid exception : x0 : %x\r\n",x0); + while(1); +} + +//https://developer.arm.com/documentation/ddi0595/2020-12/AArch64-Registers/DAIF--Interrupt-Mask-Bits +//https://www.twblogs.net/a/5b7c4ca52b71770a43da534e +//zero -> enable +//others -> disable +unsigned long long is_disable_interrupt() +{ + unsigned long long daif; + __asm__ __volatile__("mrs %0, daif\n\t" + : "=r"(daif)); + + return daif; //enable -> daif == 0 (no mask) +} + +static unsigned long long lock_count = 0; +void lock() +{ + disable_interrupt(); + lock_count++; +} + +void unlock() +{ + lock_count--; + if (lock_count<0) + { + uart_printf("lock error !!!\r\n"); + while(1); + } + if (lock_count == 0) + enable_interrupt(); +} \ No newline at end of file diff --git a/lab6/src/filesystem.c b/lab6/src/filesystem.c new file mode 100644 index 000000000..78f3049e2 --- /dev/null +++ b/lab6/src/filesystem.c @@ -0,0 +1,148 @@ +#include "cpio.h" +#include "filesystem.h" +#include "uart.h" +#include "string.h" +#include "sched.h" + +int cat(char* thefilepath) +{ + char* filepath; + char* filedata; + unsigned int filesize; + struct cpio_newc_header *header_pointer = CPIO_DEFAULT_PLACE; + + while(header_pointer!=0) + { + int error = cpio_newc_parse_header(header_pointer,&filepath,&filesize,&filedata,&header_pointer); + //if parse header error + if(error) + { + uart_puts("error"); + break; + } + + if(strcmp(thefilepath,filepath)==0) + { + for(unsigned int i=0;ipriority = priority; // store interrupt time into timer_event + the_task->task_function = task_function; + + // add the timer_event into timer_event_list (sorted) + // if the same priority FIFO + struct list_head *curr; + + lock(); + list_for_each(curr, task_list) + { + if (((irq_task_t *)curr)->priority > the_task->priority) + { + list_add(&the_task->listhead, curr->prev); // add this timer at the place just before the bigger one (sorted) + break; + } + } + + if (list_is_head(curr, task_list)) + { + list_add_tail(&(the_task->listhead), task_list); // for the time is the biggest + } + + unlock(); +} + +void run_preemptive_tasks(){ + + while (1) + { + lock(); + if (list_empty(task_list)) + { + unlock(); + break; + } + + irq_task_t *the_task = (irq_task_t *)task_list->next; + // just run task when priority is lower than the task preempted + if (curr_task_priority <= the_task->priority) + { + unlock(); + break; + } + list_del_entry((struct list_head *)the_task); + int prev_task_priority = curr_task_priority; + curr_task_priority = the_task->priority; + + unlock(); + run_task(the_task); + + curr_task_priority = prev_task_priority; + kfree(the_task); + + } +} + +void run_task(irq_task_t *the_task) +{ + ((void (*)())the_task->task_function)(); +} \ No newline at end of file diff --git a/lab6/src/main.c b/lab6/src/main.c new file mode 100644 index 000000000..207f53abb --- /dev/null +++ b/lab6/src/main.c @@ -0,0 +1,39 @@ +#include "uart.h" +#include "mbox.h" +#include "shell.h" +#include "string.h" +#include "malloc.h" +#include "dtb.h" +#include "cpio.h" +#include "exception.h" +#include "irqtask.h" +#include "mmu.h" + +void init_cpio_default_place(); + +extern char* dtb_place; + +void main(char* dtb) +{ + //stroe dtb pointer to global (device tree) + dtb_place = PHYS_TO_VIRT(dtb); + + init_cpio_default_place(); //store cpio pointer to global (file system) + init_allocator(); + alloctest(); + + //cannot use original input series after interrupt start (input is going to the buffer), use async input instead. + //output series are not affected. (order is affected) + task_list_init(); + enable_mini_uart_interrupt(); + enable_interrupt(); // enable interrupt in EL1 -> EL1 + + uart_printf("dtb : 0x%x\r\n",dtb); + + shell(); +} + +void init_cpio_default_place() +{ + traverse_device_tree(dtb_place,dtb_callback_initramfs); +} diff --git a/lab6/src/malloc.c b/lab6/src/malloc.c new file mode 100644 index 000000000..40ca1960d --- /dev/null +++ b/lab6/src/malloc.c @@ -0,0 +1,410 @@ +#include "malloc.h" +#include "cpio.h" +#include "mmu.h" +extern char _heap_start; +extern char _end; +static char *simple_top = &_heap_start; +static char *kernel_end = &_end; +extern char *dtb_place; + +// simple_malloc +void *simple_malloc(unsigned int size) +{ + char *r = simple_top + 0x10; + if (size < 0x18) + size = 0x18; // minimum size 0x20 //like ptmalloc + size = size + 0x7; + size = 0x10 + size - size % 0x10; + *(unsigned int *)(r - 0x8) = size; + simple_top += size; + return r; +} + +//buddy system allocator +//https://oscapstone.github.io/labs/lab4. +// use val(size) and isused with freelist is enough +//page size = 4K +/* For val (-2 ~ 6) +>=0 -> There is an allocable, contiguous memory that starts from the idx’th frame with size = 2**val * 4kb. +-1 -> allocated (deprecated) +-2 -> free, but it belongs to a larger contiguous memory block (deprecated) +*/ + +static frame_t* framearray; +static list_head_t freelist[MAXORDER + 1]; // 4K * (idx**ORDER) (for every 4K) (page) +static list_head_t cachelist[MAXCACHEORDER + 1]; // 32, 64, 128, 256, 512 (for every 32bytes) + +void init_allocator() +{ + // The usable memory region is from 0x00 to 0x3C000000, you can get this information from the memory node in devicetree. + // Advanced Exercise 3 - Startup Allocation - 20% + framearray = simple_malloc(BUDDYSYSTEM_PAGE_COUNT * sizeof(frame_t)); + + // init framearray + for (int i = 0; i < BUDDYSYSTEM_PAGE_COUNT; i++) + { + if (i % (1 << MAXORDER) == 0) + { + framearray[i].isused = 0; + framearray[i].val = 6; + } + } + + //init frame freelist + for (int i = 0; i <= MAXORDER; i++) + { + INIT_LIST_HEAD(&freelist[i]); + } + + for (int i = 0; i < BUDDYSYSTEM_PAGE_COUNT; i++) + { + //init listhead for each frame + INIT_LIST_HEAD(&framearray[i].listhead); + framearray[i].idx = i; + framearray[i].cacheorder = -1; + + //add init frame into freelist + if (i % (1 << MAXORDER) == 0) + { + list_add(&framearray[i].listhead, &freelist[MAXORDER]); + } + } + + //init cachelist + for (int i = 0; i <= MAXCACHEORDER; i++) + { + INIT_LIST_HEAD(&cachelist[i]); + } + + + /* should reserve these memory region + Spin tables for multicore boot (0x0000 - 0x1000) + Kernel image in the physical memory + Initramfs + Devicetree (Optional, if you have implement it) + Your simple allocator (startup allocator) + stack + */ + reserve_memory_block_with_dtb(); // spin tables can be find + memory_reserve(PHYS_TO_VIRT(0x1000), PHYS_TO_VIRT(0x5000)); // // PGD's page frame at 0x1000 // PUD's page frame at 0x2000 PMD 0x3000-0x5000 + memory_reserve(PHYS_TO_VIRT(0x80000), (unsigned long long)kernel_end); //kernel + memory_reserve((unsigned long long)&_heap_start, (unsigned long long)simple_top); //simple + memory_reserve((unsigned long long)CPIO_DEFAULT_PLACE, (unsigned long long)CPIO_DEFAULT_END); + memory_reserve(PHYS_TO_VIRT(0x2c000000), PHYS_TO_VIRT(0x3c000000)); //0x2c000000L - 0x3c000000L (stack) +} + +//smallest 4K +void *allocpage(unsigned int size) +{ + // get real val size + //int allocsize; + int val; + for (int i = 0; i <= MAXORDER; i++) + { + + if (size <= (0x1000 << i)) + { + val = i; + break; + } + + if (i == MAXORDER) + { + uart_puts("Too large size for kmalloc!!!!\r\n"); + while (1); + return simple_malloc(size); + } + } + + // find the smallest larger frame in freelist + int target_list_val; + for (target_list_val = val; target_list_val <= MAXORDER; target_list_val++) + { + if (!list_empty(&freelist[target_list_val])) + break; + } + + if (target_list_val > MAXORDER) + { + uart_puts("kmalloc ERROR (all lists are empty?)!!!!\r\n"); + while (1); + return simple_malloc(size); + } + + //get the frame + frame_t *target_frame_ptr = (frame_t *)freelist[target_list_val].next; + list_del_entry((struct list_head *)target_frame_ptr); + + // Release redundant memory block + for (int j = target_list_val; j > val; j--) + { + release_redundant(target_frame_ptr); + } + target_frame_ptr->isused = 1; +#ifdef DEBUG + uart_printf("allocpage ret : 0x%x, val : %d\r\n", BUDDYSYSTEM_START + (0x1000 * (target_frame_ptr->idx)), target_frame_ptr->val); +#endif + return (void *)BUDDYSYSTEM_START + (0x1000 * (target_frame_ptr->idx)); +} + +void freepage(void *ptr) +{ + frame_t *target_frame_ptr = &framearray[((unsigned long long)ptr - BUDDYSYSTEM_START) >> 12]; + +#ifdef DEBUG + uart_printf("freepage 0x%x, val = %d\r\n", ptr, target_frame_ptr->val); +#endif + + target_frame_ptr->isused = 0; + frame_t* temp; + while ((temp = coalesce(target_frame_ptr)) != (frame_t *)-1)target_frame_ptr = temp; + + list_add(&target_frame_ptr->listhead, &freelist[target_frame_ptr->val]); +} + +frame_t *release_redundant(frame_t *frame_ptr) +{ + frame_ptr->val -= 1; + frame_t *buddyptr = get_buddy(frame_ptr); + buddyptr->val = frame_ptr->val; + buddyptr->isused = 0; + list_add(&buddyptr->listhead, &freelist[buddyptr->val]); +#ifdef DEBUG + uart_printf("release_redundant idx = %d,%d\r\n", frame_ptr->idx, buddyptr->idx); +#endif + return frame_ptr; +} + +frame_t *get_buddy(frame_t *frame) +{ + return &framearray[frame->idx ^ (1 << frame->val)]; +} + +//return 0 -> success +//return -1 -> cannot coalesce +frame_t* coalesce(frame_t *frame_ptr) +{ + frame_t *buddy = get_buddy(frame_ptr); + + // MAXORDER + if (frame_ptr->val == MAXORDER) + return (frame_t*)-1; + + // val not the same (there is some chunks in the buddy used) + if (frame_ptr->val != buddy->val) + return (frame_t *)-1; + + //buddy is used + if (buddy->isused == 1) + return (frame_t *)-1; + + list_del_entry((struct list_head *)buddy); + frame_ptr->val += 1; + buddy->val += 1; + +#ifdef DEBUG + uart_printf("coalesce idx = %d,%d\r\n", frame_ptr->idx, buddy->idx); +#endif + return buddy> 12]; + pageframe_ptr->cacheorder = order; + + // split page into a lot of caches and push them into cachelist + int cachesize = (32 << order); + for (int i = 0; i < 0x1000; i += cachesize) + { + list_head_t *c = (list_head_t *)(page + i); + list_add(c, &cachelist[order]); + } +} + +void freecache(void *ptr) +{ + list_head_t *c = (list_head_t *)ptr; + frame_t *pageframe_ptr = &framearray[((unsigned long long)ptr - BUDDYSYSTEM_START) >> 12]; + list_add(c, &cachelist[pageframe_ptr->cacheorder]); +#ifdef DEBUG + uart_printf("freecache 0x%x, order : %d\r\n", ptr, pageframe_ptr->cacheorder); +#endif +} + +void *kmalloc(unsigned int size) +{ + lock(); +#ifdef DEBUG + uart_printf("kmalloc size: %d\r\n", size); +#endif + //For page + if (size > (32 << MAXCACHEORDER)) + { + void *r = allocpage(size); +#ifdef DEBUG + dump_freelist_info(); + dump_cachelist_info(); +#endif + unlock(); + return r; + } + + void *r = alloccache(size); + +#ifdef DEBUG + dump_freelist_info(); + dump_cachelist_info(); + uart_printf("kmalloc ret 0x%x\r\n", r); +#endif + //For cache + unlock(); + return r; +} + +void kfree(void *ptr) +{ + lock(); +#ifdef DEBUG + uart_printf("kfree 0x%x\r\n", ptr); +#endif + //For page + if ((unsigned long long)ptr % 0x1000 == 0 && framearray[((unsigned long long)ptr - BUDDYSYSTEM_START) >> 12].cacheorder == -1) + { + freepage(ptr); +#ifdef DEBUG + dump_freelist_info(); + dump_cachelist_info(); +#endif + unlock(); + return; + } + + //For cache + freecache(ptr); +#ifdef DEBUG + dump_freelist_info(); + dump_cachelist_info(); +#endif + unlock(); +} + +void dump_freelist_info() +{ + for (int i = 0; i <= MAXORDER; i++) + uart_printf("freelist %d : %d\r\n", i, list_size(&freelist[i])); +} + +void dump_cachelist_info() +{ + for (int i = 0; i <= MAXCACHEORDER; i++) + uart_printf("cachelist %d : %d\r\n", i, list_size(&cachelist[i])); +} + +void memory_reserve(unsigned long long start, unsigned long long end) +{ + uart_printf("reserve -> start : 0x%x end : 0x%x\r\n", start, end); + start -= start % 0x1000; // floor (align 0x1000) + end = end % 0x1000 ? end + 0x1000 - (end % 0x1000) : end; // ceiling (align 0x1000) + + //delete page from freelist + for (int order = MAXORDER; order >= 0; order--) + { + list_head_t *pos; + list_for_each(pos, &freelist[order]) + { + unsigned long long pagestart = ((frame_t *)pos)->idx * 0x1000L + BUDDYSYSTEM_START; + unsigned long long pageend = pagestart + (0x1000L << order); + + if (start <= pagestart && end >= pageend) // if page all in reserved memory -> delete it from freelist + { + ((frame_t *)pos)->isused = 1; + list_del_entry(pos); +#ifdef DEBUG + uart_printf("del order %d\r\n",order); + //dump_freelist_info(); +#endif + } + else if (start >= pageend || end <= pagestart) // no intersection + { + continue; + } + else // partial intersection (or reversed memory all in the page) + { + list_del_entry(pos); + list_head_t *temppos = pos -> prev; + list_add(&release_redundant((frame_t *)pos)->listhead, &freelist[order - 1]); + pos = temppos; +#ifdef DEBUG + //dump_freelist_info(); +#endif + } + } + } +} + +void alloctest() +{ + uart_printf("alloc test\r\n"); + + //memory_reserve(0x1FFFAddb, 0x1FFFFdda); + + char *a = kmalloc(0x10); + char *b = kmalloc(0x100); + char *c = kmalloc(0x1000); + + kfree(a); + kfree(b); + kfree(c); + + a = kmalloc(32); + char *aa = kmalloc(50); + b = kmalloc(64); + char *bb = kmalloc(64); + c = kmalloc(128); + char *cc = kmalloc(129); + char *d = kmalloc(256); + char *dd = kmalloc(256); + char *e = kmalloc(512); + char *ee = kmalloc(999); + + kfree(a); + kfree(aa); + kfree(b); + kfree(bb); + kfree(c); + kfree(cc); + kfree(dd); + kfree(d); + kfree(e); + kfree(ee); +} \ No newline at end of file diff --git a/lab6/src/mbox.c b/lab6/src/mbox.c new file mode 100644 index 000000000..d4532fdb8 --- /dev/null +++ b/lab6/src/mbox.c @@ -0,0 +1,26 @@ +#include "mbox.h" +#include "uart.h" +/* mailbox message buffer */ +volatile unsigned int __attribute__((aligned(16))) mbox[72]; + +/** + * Make a mailbox call. Returns 0 on failure, non-zero on success + */ +int mbox_call(unsigned char ch) // Mailbox 0 define several channels, but we only use channel 8 (CPU->GPU) for communication. +{ + unsigned long r = (((unsigned long)((unsigned long)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 == PHYS_TO_VIRT(*MBOX_READ)) + /* is it a valid successful response? */ + return mbox[1]==MBOX_RESPONSE; + } + return 0; +} \ No newline at end of file diff --git a/lab6/src/mmu.c b/lab6/src/mmu.c new file mode 100644 index 000000000..781f4effe --- /dev/null +++ b/lab6/src/mmu.c @@ -0,0 +1,89 @@ +#include "mmu.h" +#include "malloc.h" +#include "string.h" +// PGD's page frame at 0x1000 +// PUD's page frame at 0x2000 +// two-level translation (1G) -> three-level translation (2MB) +void* set_2M_kernel_mmu(void* x0) +{ + //unsigned long *pud_table = kmalloc(0x1000); + unsigned long *pud_table = (unsigned long *)0x3000; + for (int i = 0; i < 512; i++) + { + // 0x3F000000 to 0x3FFFFFFF for peripherals + if ((0x00000000 + (0x200000L) * i) >= 0x3F000000L) + { + pud_table[i] = PD_ACCESS + PD_BLOCK + (0x00000000 + (0x200000L) * i) + (MAIR_DEVICE_nGnRnE << 2) + PD_UK_ACCESS; + }else + { + pud_table[i] = PD_ACCESS + PD_BLOCK + (0x00000000 + (0x200000L) * i) + (MAIR_IDX_NORMAL_NOCACHE << 2); + } + } + + //unsigned long *pud_table2 = kmalloc(0x1000); + unsigned long *pud_table2 = (unsigned long *)0x4000; + for (int i = 0; i < 512; i++) + { + pud_table2[i] = PD_ACCESS + PD_BLOCK + (0x40000000L + (0x200000L) * i) + (MAIR_IDX_NORMAL_NOCACHE << 2); + } + + // set PUD + *(unsigned long *)(kernel_pud_addr) = PD_ACCESS + (MAIR_IDX_NORMAL_NOCACHE << 2) + PD_TABLE + (unsigned long)pud_table; + *(unsigned long *)(kernel_pud_addr + 0x8) = PD_ACCESS + (MAIR_IDX_NORMAL_NOCACHE << 2) + PD_TABLE + (unsigned long)pud_table2; + + return x0; +} + +// pa,va aligned to 4K +void map_one_page(size_t *virt_pgd_p, size_t va, size_t pa) +{ + size_t *table_p = virt_pgd_p; + for (int level = 0; level < 4; level++) + { + unsigned int idx = (va >> (39 - level * 9)) & 0x1ff; + + if (level == 3) + { + table_p[idx] = pa; + table_p[idx] |= PD_ACCESS | PD_TABLE | (MAIR_IDX_NORMAL_NOCACHE << 2) | (PD_UK_ACCESS); + return; + } + + if(!table_p[idx]) + { + size_t* newtable_p =kmalloc(0x1000); + memset(newtable_p, 0, 0x1000); + table_p[idx] = VIRT_TO_PHYS((size_t)newtable_p); + table_p[idx] |= PD_ACCESS | PD_TABLE | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_UK_ACCESS; + } + + table_p = (size_t*)PHYS_TO_VIRT((size_t)(table_p[idx] & ENTRY_ADDR_MASK)); + } +} + +//give +void mappages(size_t *virt_pgd_p, size_t va, size_t size, size_t pa) +{ + for (size_t s = 0; s < size; s+=0x1000) + { + map_one_page(virt_pgd_p, va + s, pa + s); + } +} + +void free_page_tables(size_t *page_table, int level) +{ + size_t *table_virt = (size_t*)PHYS_TO_VIRT((char*)page_table); + for (int i = 0; i < 512; i++) + { + if (table_virt[i] != 0) + { + size_t *next_table = (size_t*)(table_virt[i] & ENTRY_ADDR_MASK); + if (table_virt[i] & PD_TABLE) + { + if(level!=2)free_page_tables(next_table, level + 1); + table_virt[i] = 0L; + kfree(PHYS_TO_VIRT((char *)next_table)); + } + } + } +} \ No newline at end of file diff --git a/lab6/src/sched.S b/lab6/src/sched.S new file mode 100644 index 000000000..9ca7221ec --- /dev/null +++ b/lab6/src/sched.S @@ -0,0 +1,59 @@ +.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] + //mrs x9, ttbr0_el1 + //str x9, [x0, 16 * 6 + 8] + + 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] + ldp x9, x0, [x1, 16 * 6] + mov sp, x9 + + dsb ish // ensure write has completed + msr ttbr0_el1, x0 // switch translation based address. + tlbi vmalle1is // invalidate all TLB entries + dsb ish // ensure completion of TLB invalidatation + isb // clear pipeline + + msr tpidr_el1, x1 + ret + +.global store_context +store_context: + 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] + ret + +.global load_context +load_context: + ldp x19, x20, [x0, 16 * 0] + ldp x21, x22, [x0, 16 * 1] + ldp x23, x24, [x0, 16 * 2] + ldp x25, x26, [x0, 16 * 3] + ldp x27, x28, [x0, 16 * 4] + ldp fp, lr, [x0, 16 * 5] + ldr x9, [x0, 16 * 6] + mov sp, x9 + ret + +.global get_current +get_current: + mrs x0, tpidr_el1 + ret \ No newline at end of file diff --git a/lab6/src/sched.c b/lab6/src/sched.c new file mode 100644 index 000000000..ae3ae3d92 --- /dev/null +++ b/lab6/src/sched.c @@ -0,0 +1,161 @@ +#include "sched.h" +#include "exception.h" +#include "malloc.h" +#include "timer.h" +#include "uart.h" +#include "signal.h" +#include "mmu.h" +#include "string.h" + +void init_thread_sched() +{ + lock(); + run_queue = kmalloc(sizeof(list_head_t)); + wait_queue = kmalloc(sizeof(list_head_t)); + INIT_LIST_HEAD(run_queue); + INIT_LIST_HEAD(wait_queue); + + //init pids + for (int i = 0; i <= PIDMAX; i++) + { + threads[i].isused = 0; + threads[i].pid = i; + threads[i].iszombie = 0; + } + + asm volatile("msr tpidr_el1, %0" ::"r"(kmalloc(sizeof(thread_t)))); /// malloc a space for current kernel thread to prevent crash + + thread_t* idlethread = thread_create(idle,0x1000); + curr_thread = idlethread; + unlock(); +} + +void idle(){ + while(1) + { + kill_zombies(); //reclaim threads marked as DEAD + schedule(); //switch to next thread in run queue + } +} + +void schedule(){ + lock(); + do{ + curr_thread = (thread_t *)curr_thread->listhead.next; + } while (list_is_head(&curr_thread->listhead, run_queue) || curr_thread->iszombie); + + unlock(); + switch_to(get_current(), &curr_thread->context); +} + +void kill_zombies(){ + lock(); + list_head_t *curr; + list_for_each(curr,run_queue) + { + if (((thread_t *)curr)->iszombie) + { + list_del_entry(curr); + kfree(((thread_t *)curr)->stack_alloced_ptr); // free stack + kfree(((thread_t *)curr)->kernel_stack_alloced_ptr); // free stack + free_page_tables(((thread_t *)curr)->context.ttbr0_el1,0); + kfree(((thread_t *)curr)->data); // free data (don't free data because of fork) + ((thread_t *)curr)->iszombie = 0; + ((thread_t *)curr)->isused = 0; + } + } + unlock(); +} + +int exec_thread(char *data, unsigned int filesize) +{ + thread_t *t = thread_create(data, filesize); + + mappages(t->context.ttbr0_el1, 0x3C000000L, 0x3000000L, 0x3C000000L); + mappages(t->context.ttbr0_el1, 0x3F000000L, 0x1000000L, 0x3F000000L); + mappages(t->context.ttbr0_el1, 0x40000000L, 0x40000000L, 0x40000000L); + + mappages(t->context.ttbr0_el1, 0xffffffffb000, 0x4000, (size_t)VIRT_TO_PHYS(t->stack_alloced_ptr)); + mappages(t->context.ttbr0_el1, 0x0, filesize, (size_t)VIRT_TO_PHYS(t->data)); + + t->context.ttbr0_el1 = VIRT_TO_PHYS(t->context.ttbr0_el1); + t->context.sp = 0xfffffffff000; + t->context.fp = 0xfffffffff000; + t->context.lr = 0L; + + t->context.lr = (unsigned long)0L; + //copy file into data + for (int i = 0; i < filesize;i++) + { + t->data[i] = data[i]; + } + + //disable echo when going to userspace + uart_disable_echo(); + curr_thread = t; + add_timer(schedule_timer, 1, "", 0); + // eret to exception level 0 + asm("msr tpidr_el1, %0\n\t" + "msr elr_el1, %1\n\t" + "msr spsr_el1, xzr\n\t" // enable interrupt in EL0. You can do it by setting spsr_el1 to 0 before returning to EL0. + "msr sp_el0, %2\n\t" + "mov sp, %3\n\t" + "msr ttbr0_el1, %4\n\t" + "eret\n\t" ::"r"(&t->context),"r"(t->context.lr), "r"(t->context.sp), "r"(t->kernel_stack_alloced_ptr + KSTACK_SIZE), "r"(t->context.ttbr0_el1)); + + return 0; +} + + +//malloc a kstack and a userstack +thread_t *thread_create(void *start, unsigned int filesize) +{ + lock(); + + thread_t *r; + for (int i = 0; i <= PIDMAX; i++) + { + if (!threads[i].isused) + { + r = &threads[i]; + break; + } + } + r->iszombie = 0; + r->isused = 1; + r->context.lr = (unsigned long long)start; + r->stack_alloced_ptr = kmalloc(USTACK_SIZE); + r->kernel_stack_alloced_ptr = kmalloc(KSTACK_SIZE); + r->signal_is_checking = 0; + r->data = kmalloc(filesize); + r->datasize = filesize; + r->context.sp = (unsigned long long)r->kernel_stack_alloced_ptr + KSTACK_SIZE; + r->context.fp = r->context.sp; + + r->context.ttbr0_el1 = kmalloc(0x1000); + memset(r->context.ttbr0_el1, 0, 0x1000); + + //initial signal handler with signal_default_handler (kill thread) + for (int i = 0; i < SIGNAL_MAX; i++) + { + r->singal_handler[i] = signal_default_handler; + r->sigcount[i] = 0; + } + + list_add(&r->listhead, run_queue); + unlock(); + return r; +} + +void thread_exit(){ + lock(); + curr_thread->iszombie = 1; + unlock(); + schedule(); +} + +void schedule_timer(char* notuse){ + unsigned long long cntfrq_el0; + __asm__ __volatile__("mrs %0, cntfrq_el0\n\t": "=r"(cntfrq_el0)); //tick frequency + add_timer(schedule_timer, cntfrq_el0 >> 5, "", 1); +} \ No newline at end of file diff --git a/lab6/src/shell.c b/lab6/src/shell.c new file mode 100644 index 000000000..86289e7a4 --- /dev/null +++ b/lab6/src/shell.c @@ -0,0 +1,113 @@ +#include "uart.h" +#include "string.h" +#include "shell.h" +#include "mbox.h" +#include "system.h" +#include "filesystem.h" +#include "dtb.h" +#include "timer.h" +#include "malloc.h" +#include "sched.h" + +void shell() +{ + char cmd[MAX_BUF_SIZE]; + print_system_messages(); + init_thread_sched(); + timer_list_init(); + core_timer_enable(); + while (1) + { + uart_async_printf("# "); + uart_async_gets(cmd); + do_cmd(cmd); + } +} + +void do_cmd(char *cmd) +{ + if (strcmp(cmd, "help") == 0) + { + uart_async_printf("help : print this help menu\r\n"); + uart_async_printf("hello : print Hello World!\r\n"); + uart_async_printf("reboot : reboot the device\r\n"); + uart_async_printf("ls : list current directory\r\n"); + uart_async_printf("cat : print content of a file\r\n"); + uart_async_printf("show_device_tree : show device tree\r\n"); + uart_async_printf("exec : load a user program in the initramfs and run it in EL0\r\n"); + uart_async_printf("setTimeout [MESSAGE] [SECONDS] : print message after [SECONDS] seconds (non-blocking)\r\n"); + uart_async_printf("clockAlert : alert every two seconds\r\n"); + } + else if (strcmp(cmd, "hello") == 0) + { + uart_async_printf("Hello World!\r\n"); + } + else if (strcmp(cmd, "reboot") == 0) + { + reboot(); + } + else if (strcmp(cmd, "cat") == 0) + { + uart_async_printf("Filename: "); + char filepath[MAX_BUF_SIZE]; + uart_async_gets(filepath); + cat(filepath); + } + else if (strcmp(cmd, "ls") == 0) + { + ls("."); + } + else if (strcmp(cmd, "show_device_tree") == 0) + { + traverse_device_tree(dtb_place, dtb_callback_show_tree); + } + else if (strcmp(cmd, "exec") == 0) // in filesystem.c + { + uart_async_printf("Filename: "); + char filepath[MAX_BUF_SIZE]; + uart_async_gets(filepath); + execfile(filepath); + } + else if (strncmp(cmd, "setTimeout", sizeof("setTimeout") - 1) == 0) + { + strchr(cmd, ' '); + char *message = strchr(cmd, ' '); + if (!message) + { + uart_async_printf("setTimeout wrong format"); + return; + } + message += 1; + char *end_message = strchr(message, ' '); + if (!end_message) + { + uart_async_printf("setTimeout wrong format"); + return; + } + *end_message = '\0'; + char *seconds = end_message + 1; + add_timer(uart_puts, atoi(seconds), message,0); + } + else if (strcmp(cmd, "clockAlert") == 0) + { + add_timer(two_second_alert, 2, "two_second_alert",0); + } + else + { + uart_async_printf("Unknown command!: %s\r\n", cmd); + } +} + +void print_system_messages() +{ + unsigned int board_revision; + get_board_revision(&board_revision); + uart_printf("Board revision is : 0x%x\r\n", board_revision); + + unsigned int arm_mem_base_addr; + unsigned int arm_mem_size; + + get_arm_memory_info(&arm_mem_base_addr, &arm_mem_size); + uart_printf("ARM memory base address in bytes : 0x%x\r\n", arm_mem_base_addr); + uart_printf("ARM memory size in bytes : 0x%x\r\n", arm_mem_size); +} \ No newline at end of file diff --git a/lab6/src/signal.c b/lab6/src/signal.c new file mode 100644 index 000000000..4581ca72d --- /dev/null +++ b/lab6/src/signal.c @@ -0,0 +1,62 @@ +#include "signal.h" + +void check_signal(trapframe_t *tpf) +{ + lock(); + if(curr_thread->signal_is_checking) + { + unlock(); + return; + } + //prevent nested running signal handler + curr_thread->signal_is_checking = 1; + unlock(); + for (int i = 0; i <= SIGNAL_MAX; i++) + { + store_context(&curr_thread->signal_saved_context); + if(curr_thread->sigcount[i]>0) + { + lock(); + curr_thread->sigcount[i]--; + unlock(); + run_signal(tpf,i); + } + } + lock(); + curr_thread->signal_is_checking = 0; + unlock(); +} + +void run_signal(trapframe_t* tpf,int signal) +{ + curr_thread->curr_signal_handler = curr_thread->singal_handler[signal]; + + //run default handler in kernel + if (curr_thread->curr_signal_handler == signal_default_handler) + { + signal_default_handler(); + return; + } + + char *temp_signal_userstack = kmalloc(USTACK_SIZE); + + asm("msr elr_el1, %0\n\t" + "msr sp_el0, %1\n\t" + "msr spsr_el1, %2\n\t" + "eret\n\t" ::"r"(signal_handler_wrapper), + "r"(temp_signal_userstack + USTACK_SIZE), + "r"(tpf->spsr_el1)); +} + +void signal_handler_wrapper() +{ + (curr_thread->curr_signal_handler)(); + //system call sigreturn + asm("mov x8,50\n\t" + "svc 0\n\t"); +} + +void signal_default_handler() +{ + kill(0,curr_thread->pid); +} \ No newline at end of file diff --git a/lab6/src/sprintf.c b/lab6/src/sprintf.c new file mode 100644 index 000000000..63533303f --- /dev/null +++ b/lab6/src/sprintf.c @@ -0,0 +1,160 @@ +/* + * 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. + * + */ + +/** + * minimal sprintf implementation + */ + +#include "uart.h" +#include "string.h" + +unsigned int vsprintf(char *dst, char* fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig=dst, tmpstr[19]; + + // failsafes + if(dst==(void*)0 || fmt==(void*)0) { + return 0; + } + + // main loop + arg = 0; + while(*fmt) { + if (strlen(fmt) > MAX_BUF_SIZE - 0x10 || dst - orig > MAX_BUF_SIZE - 0x10) + { + uart_puts("Error!!! format string too long!!!!"); + *dst = 0; + return dst - orig; + } + // argument access + if(*fmt=='%') { + fmt++; + // literal % + if(*fmt=='%') { + goto put; + } + len=0; + // size modifier + while(*fmt>='0' && *fmt<='9') { + len *= 10; + len += *fmt-'0'; + fmt++; + } + // skip long modifier + if(*fmt=='l') { + fmt++; + } + // character + if(*fmt=='c') { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } else + // decimal number + if(*fmt=='d') { + arg = __builtin_va_arg(args, int); + // check input + sign=0; + if((int)arg<0) { + arg*=-1; + sign++; + } + if(arg>99999999999999999L) { + arg=99999999999999999L; + } + // convert to string + i=18; + tmpstr[i]=0; + do { + tmpstr[--i]='0'+(arg%10); + arg/=10; + } while(arg!=0 && i>0); + if(sign) { + tmpstr[--i]='-'; + } + // padding, only space + if(len>0 && len<18) { + while(i>18-len) { + tmpstr[--i]=' '; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // hex number + if(*fmt=='x') { + arg = __builtin_va_arg(args, long int); + // convert to string + i=16; + tmpstr[i]=0; + do { + char n=arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i]=n+(n>9?0x37:0x30); + arg>>=4; + } while(arg!=0 && i>0); + // padding, only leading zeros + if(len>0 && len<=16) { + while(i>16-len) { + tmpstr[--i]='0'; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // string + if(*fmt=='s') { + p = __builtin_va_arg(args, char*); +copystring: if(p==(void*)0) { + p="(null)"; + } + while(*p) { + *dst++ = *p++; + } + } + } else { +put: *dst++ = *fmt; + } + fmt++; + } + *dst=0; + // number of bytes written + return dst-orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char* fmt, ...) +{ + __builtin_va_list args; + __builtin_va_start(args, fmt); + unsigned int r = vsprintf(dst,fmt,args); + __builtin_va_end(args); + return r; +} \ No newline at end of file diff --git a/lab6/src/start.S b/lab6/src/start.S new file mode 100644 index 000000000..8399d3324 --- /dev/null +++ b/lab6/src/start.S @@ -0,0 +1,92 @@ +#include "registers.h" +#include "mmu.h" + +.section ".text.boot" + +.global _start + +_start: + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, 2f + // cpu id > 0, stop +1: wfe + b 1b +2: // cpu id == 0 + + // Switch from EL2 to EL1 . + bl from_el2_to_el1 + + // set paging configuration (up : 0xffff000000000000 low : 0x0000000000000000) + ldr x4, = TCR_CONFIG_DEFAULT + msr tcr_el1, x4 + + // Set Used Memory Attributes + ldr x4, =((MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8))) + msr mair_el1, x4 + + // set and enable MMU + mov x4, 0x1000 // PGD's page frame at 0x1000 + mov x1, 0x2000 // PUD's page frame at 0x2000 + + ldr x2, = BOOT_PGD_ATTR + orr x2, x1, x2 // combine the physical address of next level page with attribute. + str x2, [x4] + + ldr x2, = BOOT_PUD_ATTR + mov x3, 0x00000000 + orr x3, x2, x3 + str x3, [x1] // 1st 1GB mapped by the 1st entry of PUD + mov x3, 0x40000000 + orr x3, x2, x3 + str x3, [x1, 8] // 2nd 1GB mapped by the 2nd entry of PUD + + msr ttbr0_el1, x4 // load PGD to the bottom translation-based register. + msr ttbr1_el1, x4 // also load PGD to the upper translation based register. + + mov sp, 0x3c000000 + bl set_2M_kernel_mmu + + mrs x2, sctlr_el1 + orr x2 , x2, 1 + msr sctlr_el1, x2 // enable MMU, cache remains disabled + + // indirect branch to the upper virtual address + ldr x2, =set_exception_vector_table + br x2 + +set_exception_vector_table: + adr x1, exception_vector_table + msr vbar_el1, x1 + + // set top of stack at 0xffff00003c000000 (last usable memory) + movz x3, 0x0000 + movk x3, 0x3c00, lsl 16 + movk x3, 0xffff, lsl 48 + mov sp, x3 + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size +3: cbz w2, 4f + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, 3b + + // jump to C code, should not return +4: bl main + // for failsafe, halt this core too + b 1b + +from_el2_to_el1: + ldr x1, =CPACR_EL1_VALUE // Make el0, el1 can use Floating point and Advanced SIMD + msr CPACR_EL1, x1 + mov x1, (1 << 31) // EL1 uses aarch64 + msr hcr_el2, x1 + mov x1, 0x3c5 // EL1h (SPSel = 1) with interrupt disabled + msr spsr_el2, x1 + msr elr_el2, lr + eret // return to EL1 + + diff --git a/lab6/src/string.c b/lab6/src/string.c new file mode 100644 index 000000000..97b28b435 --- /dev/null +++ b/lab6/src/string.c @@ -0,0 +1,131 @@ +#include "string.h" +#include +#include "uart.h" + +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; +} + +int strncmp (const char *s1, const char *s2, unsigned long long n) +{ + unsigned char c1 = '\0'; + unsigned char c2 = '\0'; + if (n >= 4) + { + size_t 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; +} + +char* strcat (char *dest, const char *src) +{ + strcpy (dest + strlen (dest), src); + return dest; +} + +char* strcpy (char *dest, const char *src) +{ + return memcpy (dest, src, strlen (src) + 1); +} + +unsigned long long strlen(const char *str) +{ + size_t count = 0; + while((unsigned char)*str++)count++; + return count; +} + +char* memcpy (void *dest, const void *src, unsigned long long len) +{ + char *d = dest; + const char *s = src; + while (len--) + { + *d++ = *s++; + } + return dest; +} + +char* strchr (register const char *s, int c) +{ + do { + if (*s == c) + { + return (char*)s; + } + } while (*s++); + return (0); +} + +// A simple atoi() function +int atoi(char* str) +{ + // Initialize result + int res = 0; + + // Iterate through all characters + // of input string and update result + // take ASCII character of corresponding digit and + // subtract the code from '0' to get numerical + // value and multiply res by 10 to shuffle + // digits left to update running total + for (int i = 0; str[i] != '\0'; ++i) + { + if(str[i] > '9' || str[i] < '0')return res; + res = res * 10 + str[i] - '0'; + } + + // return result. + return res; +} + +void *memset(void *s, int c, size_t n) +{ + char *start = s; + for (size_t i = 0; i < n; i++) + { + start[i] = c; + } + + return s; +} \ No newline at end of file diff --git a/lab6/src/syscall.c b/lab6/src/syscall.c new file mode 100644 index 000000000..93b8ce553 --- /dev/null +++ b/lab6/src/syscall.c @@ -0,0 +1,188 @@ +#include "syscall.h" +#include "sched.h" +#include "stddef.h" +#include "uart.h" +#include "filesystem.h" +#include "exception.h" +#include "malloc.h" +#include "mbox.h" +#include "signal.h" +#include "mmu.h" +#include "string.h" + +int getpid(trapframe_t* tpf) +{ + tpf->x0 = curr_thread->pid; + return curr_thread->pid; +} + +size_t uartread(trapframe_t *tpf,char buf[], size_t size) +{ + int i = 0; + for (int i = 0; i < size;i++) + { + buf[i] = uart_async_getc(); + } + tpf->x0 = i; + return i; +} + +size_t uartwrite(trapframe_t *tpf,const char buf[], size_t size) +{ + int i = 0; + for (int i = 0; i < size; i++) + { + uart_async_putc(buf[i]); + } + tpf->x0 = i; + return i; +} + +//In this lab, you won’t have to deal with argument passing +int exec(trapframe_t *tpf,const char *name, char *const argv[]) +{ + kfree(curr_thread->data); + curr_thread->datasize = get_file_size((char *)name); + char *new_data = get_file_start((char *)name); + curr_thread->data = kmalloc(curr_thread->datasize); + + //remap code + mappages(PHYS_TO_VIRT(curr_thread->context.ttbr0_el1), 0x0, curr_thread->datasize, (size_t)VIRT_TO_PHYS(curr_thread->data)); + + for (unsigned int i = 0; i < curr_thread->datasize; i++) + { + curr_thread->data[i] = new_data[i]; + } + + //clear signal handler + for (int i = 0; i <= SIGNAL_MAX; i++) + { + curr_thread->singal_handler[i] = signal_default_handler; + } + + tpf->elr_el1 = 0; + tpf->sp_el0 = 0xfffffffff000; + tpf->x0 = 0; + return 0; +} + +int fork(trapframe_t *tpf) +{ + lock(); + thread_t *newt = thread_create(curr_thread->data,curr_thread->datasize); + + //copy signal handler + for (int i = 0; i <= SIGNAL_MAX;i++) + { + newt->singal_handler[i] = curr_thread->singal_handler[i]; + } + + mappages(newt->context.ttbr0_el1, 0x3C000000L, 0x3000000L, 0x3C000000L); + mappages(newt->context.ttbr0_el1, 0x3F000000L, 0x1000000L, 0x3F000000L); + mappages(newt->context.ttbr0_el1, 0x40000000L, 0x40000000L, 0x40000000L); + + // remap code and stack + mappages(newt->context.ttbr0_el1, 0xffffffffb000, 0x4000, (size_t)VIRT_TO_PHYS(newt->stack_alloced_ptr)); + mappages(newt->context.ttbr0_el1, 0x0, newt->datasize, (size_t)VIRT_TO_PHYS(newt->data)); + + //在這段page被蓋爁 + int parent_pid = curr_thread->pid; + + //copy data into new process + for (int i = 0; i < newt->datasize; i++) + { + newt->data[i] = curr_thread->data[i]; + } + + //copy user stack into new process + for (int i = 0; i < USTACK_SIZE; i++) + { + newt->stack_alloced_ptr[i] = curr_thread->stack_alloced_ptr[i]; + } + + //copy stack into new process + for (int i = 0; i < KSTACK_SIZE; i++) + { + newt->kernel_stack_alloced_ptr[i] = curr_thread->kernel_stack_alloced_ptr[i]; + } + + //在這段page被蓋爁 + + store_context(get_current()); + //for child + if( parent_pid != curr_thread->pid) + { + goto child; + } + + void *temp_ttbr0_el1 = newt->context.ttbr0_el1; + newt->context = curr_thread->context; + newt->context.ttbr0_el1 = VIRT_TO_PHYS(temp_ttbr0_el1); + newt->context.fp += newt->kernel_stack_alloced_ptr - curr_thread->kernel_stack_alloced_ptr; // move fp + newt->context.sp += newt->kernel_stack_alloced_ptr - curr_thread->kernel_stack_alloced_ptr; // move kernel sp + + unlock(); + + tpf->x0 = newt->pid; + return newt->pid; + +child: + tpf->x0 = 0; + return 0; +} + +void exit(trapframe_t *tpf, int status) +{ + thread_exit(); +} + +int syscall_mbox_call(trapframe_t *tpf, unsigned char ch, unsigned int *mbox_user) +{ + //mbox_user = (unsigned int *)(curr_thread->stack_alloced_ptr + USTACK_SIZE - (0xfffffffff000 - (size_t)mbox)); + lock(); + + unsigned int size_of_mbox = mbox_user[0]; + memcpy((char *)mbox, mbox_user, size_of_mbox); + mbox_call(ch); + memcpy(mbox_user, (char *)mbox, size_of_mbox); + + tpf->x0 = 8; + unlock(); + return 0; +} + +void kill(trapframe_t *tpf,int pid) +{ + lock(); + if (pid >= PIDMAX || pid < 0 || !threads[pid].isused) + { + unlock(); + return; + } + threads[pid].iszombie = 1; + unlock(); + schedule(); +} + +void signal_register(int signal, void (*handler)()) +{ + if (signal > SIGNAL_MAX || signal < 0)return; + + curr_thread->singal_handler[signal] = handler; +} + +void signal_kill(int pid, int signal) +{ + if (pid > PIDMAX || pid < 0 || !threads[pid].isused)return; + + lock(); + threads[pid].sigcount[signal]++; + unlock(); +} + +void sigreturn(trapframe_t *tpf) +{ + unsigned long signal_ustack = tpf->sp_el0 % USTACK_SIZE == 0 ? tpf->sp_el0 - USTACK_SIZE : tpf->sp_el0 & (~(USTACK_SIZE - 1)); + kfree((char*)signal_ustack); + load_context(&curr_thread->signal_saved_context); +} diff --git a/lab6/src/system.c b/lab6/src/system.c new file mode 100644 index 000000000..c8cd8bc38 --- /dev/null +++ b/lab6/src/system.c @@ -0,0 +1,82 @@ +#include "system.h" +#include "uart.h" +#include "mbox.h" + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC PHYS_TO_VIRT(0x3F10001c) +#define PM_WDOG PHYS_TO_VIRT(0x3F100024) + +/* For all return 0 -> success , -1 failure*/ + +int get_board_revision(unsigned int* board_revision) +{ + /* + GET_BOARD_REVISION + */ + mbox[0] = 7*4; // length of the message + mbox[1] = MBOX_REQUEST; // request code + mbox[2] = GET_BOARD_REVISION; // tag identifier + mbox[3] = 4; // value buffer size in bytes + mbox[4] = 0; // request codes : b31 clear, b30-b0 reversed + mbox[5] = 0; // clear output buffer + mbox[6] = MBOX_TAG_LAST; // end tag + // send the message to the GPU and receive answer + if (mbox_call(MBOX_CH_PROP)) { + *board_revision = mbox[5]; + return 0; + } else { + uart_puts("Unable to query serial!"); + *board_revision = mbox[5] = -1; + return -1; + } +} + +int get_arm_memory_info(unsigned int* base_addr,unsigned int* size) +{ + /* + GET arm_memory address and size + */ + mbox[0] = 8*4; // length of the message + mbox[1] = MBOX_REQUEST; // request code + mbox[2] = GET_ARM_MEMORY; // tag identifier + mbox[3] = 8; // value buffer size in bytes + mbox[4] = 0; // request codes : b31 clear, b30-b0 reversed + mbox[5] = 0; // clear output buffer ( u32: base address in bytes ) + mbox[6] = 0; // clear output buffer ( u32: size in bytes ) + mbox[7] = MBOX_TAG_LAST; // end tag + + // send the message to the GPU and receive answer + if (mbox_call(MBOX_CH_PROP)) { + *base_addr = mbox[5]; + *size = mbox[6]; + return 0; + } else { + uart_puts("Unable to query serial!"); + return -1; + } +} + +void set(long addr, unsigned int value) +{ + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +void reboot() +{ + //disable_uart(); + reset(1); // timeout = 1/16th of a second? (whatever) +} + +void reset(int tick) +{ // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick + while(1); +} + +void cancel_reset() +{ + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} \ No newline at end of file diff --git a/lab6/src/timer.c b/lab6/src/timer.c new file mode 100644 index 000000000..34b71ba24 --- /dev/null +++ b/lab6/src/timer.c @@ -0,0 +1,177 @@ +#include "timer.h" +#include "registers.h" +#include "uart.h" +#include "malloc.h" +#include "string.h" + +void timer_list_init() +{ + uint64_t tmp; + asm volatile("mrs %0, cntkctl_el1": "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0":: "r"(tmp)); + + timer_event_list = kmalloc(sizeof(list_head_t)); + INIT_LIST_HEAD(timer_event_list); +} + +void core_timer_enable() +{ + __asm__ __volatile__( + "mov x1, 1\n\t" + "msr cntp_ctl_el0, x1\n\t" // enable + + //"mrs x1, cntfrq_el0\n\t" + //"mov x2, 0x100000\n\t" + //"mul x1, x1, x2\n\t" //set a big value prevent interrupt immediately + //"msr cntp_tval_el0, x1\n\t" // set expired time + + "mov x2, 2\n\t" + "ldr x1, =" XSTR(CORE0_TIMER_IRQ_CTRL) "\n\t" + "str w2, [x1]\n\t" // unmask timer interrupt + :::"x1","x2"); +} + +void core_timer_disable() +{ + __asm__ __volatile__( + "mov x2, 0\n\t" + "ldr x1, =" XSTR(CORE0_TIMER_IRQ_CTRL) "\n\t" + "str w2, [x1]\n\t" // unmask timer interrupt + :::"x1","x2"); +} + +void timer_event_callback(timer_event_t *timer_event) +{ + ((void (*)(char *))timer_event->callback)(timer_event->args); // call the callback store in event + list_del_entry((struct list_head *)timer_event); // delete the event + kfree(timer_event->args); // kfree the arg space + kfree(timer_event); + + //set interrupt to next time_event if existing + if (!list_empty(timer_event_list)) + { + set_core_timer_interrupt_by_tick(((timer_event_t *)timer_event_list->next)->interrupt_time); + } + else + { + set_core_timer_interrupt(10000); // disable timer interrupt (set a very big value) + } +} + +void two_second_alert(char *str) +{ + unsigned long long cntpct_el0; + __asm__ __volatile__("mrs %0, cntpct_el0\n\t" + : "=r"(cntpct_el0)); //tick now + + unsigned long long cntfrq_el0; + __asm__ __volatile__("mrs %0, cntfrq_el0\n\t" + : "=r"(cntfrq_el0)); //tick frequency + uart_printf("alert '%s': \r\nexception irq_router -> seconds after booting : %d\r\n", str, cntpct_el0 / cntfrq_el0); + + add_timer(two_second_alert, 2, "two_second_alert",0); +} + +void core_timer_handler() +{ + lock(); + //disable_interrupt(); + if (list_empty(timer_event_list)) + { + set_core_timer_interrupt(10000); // disable timer interrupt (set a very big value) + unlock(); + return; + } + + timer_event_callback((timer_event_t *)timer_event_list->next); // do callback and set new interrupt + unlock(); +} + +// give a string argument to callback timeout after seconds +void add_timer(void *callback, unsigned long long timeout, char *args, int bytick) +{ + timer_event_t *the_timer_event = kmalloc(sizeof(timer_event_t)); //need to kfree by event handler + + // store argument string into timer_event + the_timer_event->args = kmalloc(strlen(args) + 1); + strcpy(the_timer_event->args, args); + + if(bytick == 0) + { + the_timer_event->interrupt_time = get_tick_plus_s(timeout); // store interrupt time into timer_event + }else + { + the_timer_event->interrupt_time = get_tick_plus_s(0) + timeout; + } + + the_timer_event->callback = callback; + + // add the timer_event into timer_event_list (sorted) + struct list_head *curr; + + lock(); + list_for_each(curr, timer_event_list) + { + if (((timer_event_t *)curr)->interrupt_time > the_timer_event->interrupt_time) + { + list_add(&the_timer_event->listhead, curr->prev); // add this timer at the place just before the bigger one (sorted) + break; + } + } + + if (list_is_head(curr, timer_event_list)) + { + list_add_tail(&the_timer_event->listhead, timer_event_list); // for the time is the biggest + } + + + // set interrupt to first event + set_core_timer_interrupt_by_tick(((timer_event_t *)timer_event_list->next)->interrupt_time); + unlock(); +} + + +// get cpu tick add some second +unsigned long long get_tick_plus_s(unsigned long long second) +{ + + unsigned long long cntpct_el0 = 0; + __asm__ __volatile__("mrs %0, cntpct_el0\n\t" + : "=r"(cntpct_el0)); //tick now + + unsigned long long cntfrq_el0 = 0; + __asm__ __volatile__("mrs %0, cntfrq_el0\n\t" + : "=r"(cntfrq_el0)); //tick frequency + + return (cntpct_el0 + cntfrq_el0 * second); +} + +// set timer interrupt time to [expired_time] seconds after now (relatively) +void set_core_timer_interrupt(unsigned long long expired_time) +{ + __asm__ __volatile__( + "mrs x1, cntfrq_el0\n\t" //cntfrq_el0 -> relative time + "mul x1, x1, %0\n\t" + "msr cntp_tval_el0, x1\n\t" // set expired time + :: "r"(expired_time):"x1"); +} + +// directly set timer interrupt time to a cpu tick (directly) +void set_core_timer_interrupt_by_tick(unsigned long long tick) +{ + __asm__ __volatile__( + "msr cntp_cval_el0, %0\n\t" //cntp_cval_el0 -> absolute time + :: "r"(tick)); +} + +int timer_list_get_size() +{ + int r = 0; + struct list_head *curr; + list_for_each(curr, timer_event_list) + { + r++; + } + return r; +} \ No newline at end of file diff --git a/lab6/src/uart.c b/lab6/src/uart.c new file mode 100644 index 000000000..d61f02269 --- /dev/null +++ b/lab6/src/uart.c @@ -0,0 +1,403 @@ +#include "gpio.h" +#include "uart.h" +#include "sprintf.h" +#include "registers.h" +#include "exception.h" + +// get address from linker +extern volatile unsigned char _end; + +int echoflag = 1; + +//implement first in first out buffer with a read index and a write index +char uart_tx_buffer[MAX_BUF_SIZE] = {}; +unsigned int uart_tx_buffer_widx = 0; //write index +unsigned int uart_tx_buffer_ridx = 0; //read index +char uart_rx_buffer[MAX_BUF_SIZE] = {}; +unsigned int uart_rx_buffer_widx = 0; +unsigned int uart_rx_buffer_ridx = 0; + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init() +{ + register unsigned int r; + + /* initialize UART */ + *AUX_ENABLE |= 1; // Set AUXENB register to enable mini UART. Then mini UART register can be accessed. + *AUX_MU_CNTL = 0; // Set AUX_MU_CNTL_REG to 0. Disable transmitter and receiver during configuration. + *AUX_MU_IER = 0; // Set AUX_MU_IER_REG to 0. Disable interrupt because currently you don’t need interrupt. + *AUX_MU_LCR = 3; // Set AUX_MU_LCR_REG to 3. Set the data size to 8 bit. + *AUX_MU_MCR = 0; // Set AUX_MU_MCR_REG to 0. Don’t need auto flow control. + *AUX_MU_IIR = 0x6; // 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 (disable pull up/down) + 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 + + while ((*AUX_MU_LSR & 0x01)) + *AUX_MU_IO; //clean rx data +} + +// maybe don't do so many step +void disable_uart() +{ + register unsigned int r; + *AUX_ENABLE &= ~(unsigned int)1; + *AUX_MU_CNTL = 0; + r = *GPFSEL1; + r |= ((7 << 12) | (7 << 15)); // gpio14, gpio15 + r &= ~(2 << 12) | (2 << 15); // alt5 + *GPFSEL1 = r; + *GPPUD = 2; // enable pins 14 and 15 (pull down) + r = 150; + while (r--) + { + asm volatile("nop"); + } + *GPPUDCLK0 = (1 << 14) | (1 << 15); + r = 150; + while (r--) + { + asm volatile("nop"); + } + *GPPUDCLK0 = 0; // flush GPIO setup +} + +/** + * Send a character (only replace uart_put with uart_async_putc when non-echo output) + */ +void uart_putc(char c) +{ + unsigned int intc = c; + /* wait until we can send */ + do + { + asm volatile("nop"); + } while (!(*AUX_MU_LSR & 0x20)); + /* write the character to the buffer */ + *AUX_MU_IO = intc; +} + +/** + * 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); + + /* + echo back (disable it when going to userspace) + */ + if(echoflag) + { + if (r == '\r') + { + uart_printf("\r\r\n"); + do + { + asm volatile("nop"); + } while (!(*AUX_MU_LSR & 0x40)); //wait for output success Transmitter idle + } + else if (r == '\x7f') // backspace -> get del + { + uart_putc('\b'); + uart_putc(' '); + uart_putc('\b'); + } + else + { + uart_putc(r); + } + } + /* convert carrige return to newline */ + return r == '\r' ? '\n' : r; +} + +void uart_disable_echo() +{ + echoflag = 0; +} + +void uart_enable_echo() +{ + echoflag = 1; +} + +/** + * Display a string with newline + */ +int uart_puts(char *s) +{ + int i = 0; + + while (*s) + { + uart_putc(*s++); + i++; + } + uart_putc('\r'); + uart_putc('\n'); + + return i + 2; +} + +/** + * Display a string with newline + */ +int uart_async_puts(char *s) +{ + int i = 0; + + while (*s) + { + uart_async_putc(*s++); + i++; + } + uart_async_putc('\r'); + uart_async_putc('\n'); + + return i + 2; +} + +/** + * get a string (use async getc) + */ +char *uart_async_gets(char *buf) +{ + int count; + char c; + char *s; + for (s = buf, count = 0; (c = uart_async_getc()) != '\n' && count != MAX_BUF_SIZE - 100; count++) + { + *s = c; + if (*s == '\x7f') //delete -> backspace + { + count--; + if (count == -1) + { + uart_putc(' '); // prevent back over command line # + continue; + } + s--; + count--; + continue; + } + s++; + } + *s = '\0'; + return buf; +} + +/** + * get a string (use async getc) + */ +char *uart_gets(char *buf) +{ + int count; + char c; + char *s; + for (s = buf, count = 0; (c = uart_getc()) != '\n' && count != MAX_BUF_SIZE - 100; count++) + { + *s = c; + if (*s == '\x7f') + { + count--; + if (count == -1) + { + uart_putc(' '); // prevent back over command line # + continue; + } + s--; + count--; + continue; + } + s++; + } + *s = '\0'; + return buf; +} + +/** + * printf (from https://github.com/bztsrc/raspi3-tutorial/tree/master/12_printf) + initial printf from github dont use any va_end, and it is also can run. (in assembly there is nothing compiled from __builtin_va_end) + */ +int uart_printf(char *fmt, ...) +{ + __builtin_va_list args; + __builtin_va_start(args, fmt); + char buf[MAX_BUF_SIZE]; + // we don't have memory allocation yet, so we + // simply place our string after our code + char *s = (char *)buf; + // use sprintf to format our string + int count = vsprintf(s, fmt, args); + // print out as usual + while (*s) + { + uart_putc(*s++); + } + __builtin_va_end(args); + return count; +} + +int uart_async_printf(char *fmt, ...) +{ + __builtin_va_list args; + __builtin_va_start(args, fmt); + char buf[MAX_BUF_SIZE]; + // we don't have memory allocation yet, so we + // simply place our string after our code + char *s = (char *)buf; + // use sprintf to format our string + int count = vsprintf(s, fmt, args); + // print out as usual + while (*s) + { + uart_async_putc(*s++); + } + __builtin_va_end(args); + return count; +} + +void uart_interrupt_r_handler() +{ + //read buffer full + if ((uart_rx_buffer_widx + 1) % MAX_BUF_SIZE == uart_rx_buffer_ridx) + { + *AUX_MU_IIR = 0xC2; /* clear the fifos */ // I dont know why need this but it can prevent big input to cause infinite run here (disable_r_interrupt never work) + disable_mini_uart_r_interrupt(); //disable read interrupt when read buffer full + return; + } + uart_rx_buffer[uart_rx_buffer_widx++] = uart_getc(); + if (uart_rx_buffer_widx >= MAX_BUF_SIZE) + uart_rx_buffer_widx = 0; + + enable_mini_uart_r_interrupt(); // lab 3 : advanced 2 -> unmask device line +} + +void uart_interrupt_w_handler() //can write +{ + // buffer empty + if (uart_tx_buffer_ridx == uart_tx_buffer_widx) + { + *AUX_MU_IIR = 0xC4; + disable_mini_uart_w_interrupt(); // disable w_interrupt to prevent interruption without any async output + return; + } + uart_putc(uart_tx_buffer[uart_tx_buffer_ridx++]); + if (uart_tx_buffer_ridx >= MAX_BUF_SIZE) + uart_tx_buffer_ridx = 0; // cycle pointer + + enable_mini_uart_w_interrupt(); // lab 3 : advanced 2 -> unmask device line +} + +void uart_async_putc(char c) +{ + // full buffer wait + while ((uart_tx_buffer_widx + 1) % MAX_BUF_SIZE == uart_tx_buffer_ridx) + { + // start asynchronous transfer + enable_mini_uart_w_interrupt(); + } + + + // critical section + lock(); + uart_tx_buffer[uart_tx_buffer_widx++] = c; + if (uart_tx_buffer_widx >= MAX_BUF_SIZE) + uart_tx_buffer_widx = 0; // cycle pointer + + // start asynchronous transfer + unlock(); + + // enable interrupt to transfer + enable_mini_uart_w_interrupt(); +} + +char uart_async_getc() +{ + enable_mini_uart_r_interrupt(); + // while buffer empty + // enable read interrupt to get some input into buffer + while (uart_rx_buffer_ridx == uart_rx_buffer_widx) + enable_mini_uart_r_interrupt(); + + // critical section + lock(); + char r = uart_rx_buffer[uart_rx_buffer_ridx++]; + + if (uart_rx_buffer_ridx >= MAX_BUF_SIZE) + uart_rx_buffer_ridx = 0; + + unlock(); + + return r; +} + +void enable_mini_uart_interrupt() +{ + enable_mini_uart_r_interrupt(); + enable_mini_uart_w_interrupt(); + *IRQS1 |= 1 << 29; +} + +void disable_mini_uart_interrupt() +{ + disable_mini_uart_r_interrupt(); + disable_mini_uart_w_interrupt(); +} + +void enable_mini_uart_r_interrupt() +{ + *AUX_MU_IER |= 1; // read interrupt +} + +void enable_mini_uart_w_interrupt() +{ + *AUX_MU_IER |= 2; // write interrupt +} + +void disable_mini_uart_r_interrupt() +{ + *AUX_MU_IER &= ~(1); +} + +void disable_mini_uart_w_interrupt() +{ + *AUX_MU_IER &= ~(2); +} + +int mini_uart_r_interrupt_is_enable() +{ + return *AUX_MU_IER & 1; +} + +int mini_uart_w_interrupt_is_enable() +{ + return *AUX_MU_IER & 2; +} From b6087d77ee3e2af1eb70d767f11ab57f8372f52d Mon Sep 17 00:00:00 2001 From: a13579and2468 Date: Sun, 22 May 2022 20:19:02 +0800 Subject: [PATCH 2/8] lab6 MMU signal complete --- lab6/include/mmu.h | 8 +++++--- lab6/include/signal.h | 1 + lab6/src/exception.c | 5 +++++ lab6/src/mmu.c | 14 ++++++++------ lab6/src/sched.c | 21 ++++++++++++++------- lab6/src/signal.c | 16 ++++++++-------- lab6/src/syscall.c | 23 +++++++++++++---------- 7 files changed, 54 insertions(+), 34 deletions(-) diff --git a/lab6/include/mmu.h b/lab6/include/mmu.h index f05936053..df9c522dc 100644 --- a/lab6/include/mmu.h +++ b/lab6/include/mmu.h @@ -14,9 +14,11 @@ #define PD_TABLE 0b11L #define PD_BLOCK 0b01L -#define PD_UNX (1L<<54) +#define PD_UNX (1L << 54) +#define PD_KNX (1L << 53) #define PD_ACCESS (1L << 10) #define PD_UK_ACCESS (1L << 6) +#define PD_RDONLY (1L << 7) #define BOOT_PGD_ATTR PD_TABLE #define BOOT_PUD_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK) @@ -30,8 +32,8 @@ #define kernel_pud_addr 0x2000 void *set_2M_kernel_mmu(void *x0); -void map_one_page(size_t *pgd_p, size_t va, size_t pa); -void mappages(size_t *pgd_p, size_t va, size_t size, size_t pa); +void map_one_page(size_t *pgd_p, size_t va, size_t pa, size_t flag); +void mappages(size_t *pgd_p, size_t va, size_t size, size_t pa, size_t flag); void free_page_tables(size_t *page_table, int level); #endif //__ASSEMBLER__ diff --git a/lab6/include/signal.h b/lab6/include/signal.h index 0f6352a2f..9e6c2cbca 100644 --- a/lab6/include/signal.h +++ b/lab6/include/signal.h @@ -2,6 +2,7 @@ #define SIGNAL_H #define SIGKILL_NO 9 +#define USER_SIG_WRAPPER_VIRT_ADDR_ALIGNED 0xffffffff9000L #include "syscall.h" #include "sched.h" diff --git a/lab6/src/exception.c b/lab6/src/exception.c index 1dd77ef29..c1a087ef3 100644 --- a/lab6/src/exception.c +++ b/lab6/src/exception.c @@ -10,6 +10,11 @@ // For svc 0 (supervisor call) void sync_64_router(trapframe_t* tpf) { + //uart_printf("syscall no : %d\r\n", tpf->x8); + //uart_printf("elr_el1 : 0x%x\r\n", tpf->elr_el1); + //uart_printf("sp_el0 : 0x%x\r\n", tpf->sp_el0); + //uart_printf("spsr_el1 : 0x%x\r\n", tpf->spsr_el1); + //while(1); enable_interrupt(); unsigned long long syscall_no = tpf->x8; diff --git a/lab6/src/mmu.c b/lab6/src/mmu.c index 781f4effe..c8de86f6b 100644 --- a/lab6/src/mmu.c +++ b/lab6/src/mmu.c @@ -14,7 +14,8 @@ void* set_2M_kernel_mmu(void* x0) if ((0x00000000 + (0x200000L) * i) >= 0x3F000000L) { pud_table[i] = PD_ACCESS + PD_BLOCK + (0x00000000 + (0x200000L) * i) + (MAIR_DEVICE_nGnRnE << 2) + PD_UK_ACCESS; - }else + } + else { pud_table[i] = PD_ACCESS + PD_BLOCK + (0x00000000 + (0x200000L) * i) + (MAIR_IDX_NORMAL_NOCACHE << 2); } @@ -35,7 +36,7 @@ void* set_2M_kernel_mmu(void* x0) } // pa,va aligned to 4K -void map_one_page(size_t *virt_pgd_p, size_t va, size_t pa) +void map_one_page(size_t *virt_pgd_p, size_t va, size_t pa, size_t flag) { size_t *table_p = virt_pgd_p; for (int level = 0; level < 4; level++) @@ -45,7 +46,7 @@ void map_one_page(size_t *virt_pgd_p, size_t va, size_t pa) if (level == 3) { table_p[idx] = pa; - table_p[idx] |= PD_ACCESS | PD_TABLE | (MAIR_IDX_NORMAL_NOCACHE << 2) | (PD_UK_ACCESS); + table_p[idx] |= PD_ACCESS | PD_TABLE | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_UK_ACCESS | PD_KNX | flag; return; } @@ -54,7 +55,7 @@ void map_one_page(size_t *virt_pgd_p, size_t va, size_t pa) size_t* newtable_p =kmalloc(0x1000); memset(newtable_p, 0, 0x1000); table_p[idx] = VIRT_TO_PHYS((size_t)newtable_p); - table_p[idx] |= PD_ACCESS | PD_TABLE | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_UK_ACCESS; + table_p[idx] |= PD_ACCESS | PD_TABLE | (MAIR_IDX_NORMAL_NOCACHE << 2) | flag; } table_p = (size_t*)PHYS_TO_VIRT((size_t)(table_p[idx] & ENTRY_ADDR_MASK)); @@ -62,11 +63,12 @@ void map_one_page(size_t *virt_pgd_p, size_t va, size_t pa) } //give -void mappages(size_t *virt_pgd_p, size_t va, size_t size, size_t pa) +void mappages(size_t *virt_pgd_p, size_t va, size_t size, size_t pa, size_t flag) { + pa = pa - (pa % 0x1000); // align for (size_t s = 0; s < size; s+=0x1000) { - map_one_page(virt_pgd_p, va + s, pa + s); + map_one_page(virt_pgd_p, va + s, pa + s, flag); } } diff --git a/lab6/src/sched.c b/lab6/src/sched.c index ae3ae3d92..786d795ec 100644 --- a/lab6/src/sched.c +++ b/lab6/src/sched.c @@ -71,19 +71,21 @@ int exec_thread(char *data, unsigned int filesize) { thread_t *t = thread_create(data, filesize); - mappages(t->context.ttbr0_el1, 0x3C000000L, 0x3000000L, 0x3C000000L); - mappages(t->context.ttbr0_el1, 0x3F000000L, 0x1000000L, 0x3F000000L); - mappages(t->context.ttbr0_el1, 0x40000000L, 0x40000000L, 0x40000000L); + mappages(t->context.ttbr0_el1, 0x3C000000L, 0x3000000L, 0x3C000000L, 0); + mappages(t->context.ttbr0_el1, 0x3F000000L, 0x1000000L, 0x3F000000L, 0); + mappages(t->context.ttbr0_el1, 0x40000000L, 0x40000000L, 0x40000000L, 0); - mappages(t->context.ttbr0_el1, 0xffffffffb000, 0x4000, (size_t)VIRT_TO_PHYS(t->stack_alloced_ptr)); - mappages(t->context.ttbr0_el1, 0x0, filesize, (size_t)VIRT_TO_PHYS(t->data)); + mappages(t->context.ttbr0_el1, 0xffffffffb000, 0x4000, (size_t)VIRT_TO_PHYS(t->stack_alloced_ptr), 0); + mappages(t->context.ttbr0_el1, 0x0, filesize, (size_t)VIRT_TO_PHYS(t->data), 0); + + // for signal wrapper + mappages(t->context.ttbr0_el1, USER_SIG_WRAPPER_VIRT_ADDR_ALIGNED, 0x2000, (size_t)VIRT_TO_PHYS(signal_handler_wrapper), PD_RDONLY); t->context.ttbr0_el1 = VIRT_TO_PHYS(t->context.ttbr0_el1); t->context.sp = 0xfffffffff000; t->context.fp = 0xfffffffff000; t->context.lr = 0L; - t->context.lr = (unsigned long)0L; //copy file into data for (int i = 0; i < filesize;i++) { @@ -100,8 +102,13 @@ int exec_thread(char *data, unsigned int filesize) "msr spsr_el1, xzr\n\t" // enable interrupt in EL0. You can do it by setting spsr_el1 to 0 before returning to EL0. "msr sp_el0, %2\n\t" "mov sp, %3\n\t" + "dsb ish\n\t" // ensure write has completed "msr ttbr0_el1, %4\n\t" - "eret\n\t" ::"r"(&t->context),"r"(t->context.lr), "r"(t->context.sp), "r"(t->kernel_stack_alloced_ptr + KSTACK_SIZE), "r"(t->context.ttbr0_el1)); + "tlbi vmalle1is\n\t" // invalidate all TLB entries + "dsb ish\n\t" // ensure completion of TLB invalidatation + "isb\n\t" // clear pipeline" + "eret\n\t" ::"r"(&t->context), + "r"(t->context.lr), "r"(t->context.sp), "r"(t->kernel_stack_alloced_ptr + KSTACK_SIZE), "r"(t->context.ttbr0_el1)); return 0; } diff --git a/lab6/src/signal.c b/lab6/src/signal.c index 4581ca72d..d2265786e 100644 --- a/lab6/src/signal.c +++ b/lab6/src/signal.c @@ -38,21 +38,21 @@ void run_signal(trapframe_t* tpf,int signal) return; } - char *temp_signal_userstack = kmalloc(USTACK_SIZE); - asm("msr elr_el1, %0\n\t" "msr sp_el0, %1\n\t" "msr spsr_el1, %2\n\t" - "eret\n\t" ::"r"(signal_handler_wrapper), - "r"(temp_signal_userstack + USTACK_SIZE), - "r"(tpf->spsr_el1)); + "mov x0, %3\n\t" + "eret\n\t" ::"r"(USER_SIG_WRAPPER_VIRT_ADDR_ALIGNED + ((size_t)signal_handler_wrapper%0x1000)), + "r"(tpf->sp_el0), + "r"(tpf->spsr_el1), "r"(curr_thread->curr_signal_handler)); } +//TODO : register signal handler after MMU (el0 cannot run in kernel space) void signal_handler_wrapper() { - (curr_thread->curr_signal_handler)(); - //system call sigreturn - asm("mov x8,50\n\t" + //call function and system call sigreturn + asm("blr x0\n\t" + "mov x8,50\n\t" "svc 0\n\t"); } diff --git a/lab6/src/syscall.c b/lab6/src/syscall.c index 93b8ce553..6d07a5648 100644 --- a/lab6/src/syscall.c +++ b/lab6/src/syscall.c @@ -32,7 +32,9 @@ size_t uartwrite(trapframe_t *tpf,const char buf[], size_t size) int i = 0; for (int i = 0; i < size; i++) { - uart_async_putc(buf[i]); + lock(); + uart_putc(buf[i]); + unlock(); } tpf->x0 = i; return i; @@ -47,7 +49,7 @@ int exec(trapframe_t *tpf,const char *name, char *const argv[]) curr_thread->data = kmalloc(curr_thread->datasize); //remap code - mappages(PHYS_TO_VIRT(curr_thread->context.ttbr0_el1), 0x0, curr_thread->datasize, (size_t)VIRT_TO_PHYS(curr_thread->data)); + mappages(PHYS_TO_VIRT(curr_thread->context.ttbr0_el1), 0x0, curr_thread->datasize, (size_t)VIRT_TO_PHYS(curr_thread->data), 0); for (unsigned int i = 0; i < curr_thread->datasize; i++) { @@ -77,13 +79,16 @@ int fork(trapframe_t *tpf) newt->singal_handler[i] = curr_thread->singal_handler[i]; } - mappages(newt->context.ttbr0_el1, 0x3C000000L, 0x3000000L, 0x3C000000L); - mappages(newt->context.ttbr0_el1, 0x3F000000L, 0x1000000L, 0x3F000000L); - mappages(newt->context.ttbr0_el1, 0x40000000L, 0x40000000L, 0x40000000L); + mappages(newt->context.ttbr0_el1, 0x3C000000L, 0x3000000L, 0x3C000000L,0); + mappages(newt->context.ttbr0_el1, 0x3F000000L, 0x1000000L, 0x3F000000L,0); + mappages(newt->context.ttbr0_el1, 0x40000000L, 0x40000000L, 0x40000000L,0); // remap code and stack - mappages(newt->context.ttbr0_el1, 0xffffffffb000, 0x4000, (size_t)VIRT_TO_PHYS(newt->stack_alloced_ptr)); - mappages(newt->context.ttbr0_el1, 0x0, newt->datasize, (size_t)VIRT_TO_PHYS(newt->data)); + mappages(newt->context.ttbr0_el1, 0xffffffffb000, 0x4000, (size_t)VIRT_TO_PHYS(newt->stack_alloced_ptr),0); + mappages(newt->context.ttbr0_el1, 0x0, newt->datasize, (size_t)VIRT_TO_PHYS(newt->data),0); + + // for signal wrapper + mappages(newt->context.ttbr0_el1, USER_SIG_WRAPPER_VIRT_ADDR_ALIGNED, 0x2000, (size_t)VIRT_TO_PHYS(signal_handler_wrapper), PD_RDONLY); //在這段page被蓋爁 int parent_pid = curr_thread->pid; @@ -107,7 +112,7 @@ int fork(trapframe_t *tpf) } //在這段page被蓋爁 - + store_context(get_current()); //for child if( parent_pid != curr_thread->pid) @@ -182,7 +187,5 @@ void signal_kill(int pid, int signal) void sigreturn(trapframe_t *tpf) { - unsigned long signal_ustack = tpf->sp_el0 % USTACK_SIZE == 0 ? tpf->sp_el0 - USTACK_SIZE : tpf->sp_el0 & (~(USTACK_SIZE - 1)); - kfree((char*)signal_ustack); load_context(&curr_thread->signal_saved_context); } From 59a8181eb843595f1e18cc54ab15ef0c9db1b23e Mon Sep 17 00:00:00 2001 From: a13579and2468 Date: Wed, 25 May 2022 23:04:04 +0800 Subject: [PATCH 3/8] demand paging, sys_mmap --- lab6/include/exception.h | 11 +++++- lab6/include/mmu.h | 19 ++++++++- lab6/include/sched.h | 1 + lab6/include/stddef.h | 10 +++++ lab6/include/syscall.h | 2 + lab6/src/entry.S | 2 + lab6/src/exception.c | 24 ++++++++++-- lab6/src/mmu.c | 85 ++++++++++++++++++++++++++++++++++++---- lab6/src/sched.S | 3 +- lab6/src/sched.c | 30 ++++++++------ lab6/src/signal.c | 1 - lab6/src/syscall.c | 72 ++++++++++++++++++++++------------ 12 files changed, 209 insertions(+), 51 deletions(-) diff --git a/lab6/include/exception.h b/lab6/include/exception.h index 2416e2b23..2d9818a2d 100644 --- a/lab6/include/exception.h +++ b/lab6/include/exception.h @@ -1,6 +1,7 @@ #ifndef EXCEPTION_H #define EXCEPTION_H +#include "stddef.h" // https://github.com/Tekki/raspberrypi-documentation/blob/master/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf p16 #define CORE0_INTERRUPT_SOURCE ((volatile unsigned int *)(PHYS_TO_VIRT(0x40000060))) @@ -68,7 +69,7 @@ typedef struct trapframe } trapframe_t; -void sync_64_router(trapframe_t *tpf); +void sync_64_router(trapframe_t *tpf, unsigned long esr_el1); void irq_router(trapframe_t *tpf); void invalid_exception_router(); @@ -86,4 +87,12 @@ unsigned long long is_disable_interrupt(); void lock(); void unlock(); +#define DATA_ABORT_LOWER 0b100100 +#define INS_ABORT_LOWER 0b100000 + +#define TF_LEVEL0 0b000100 +#define TF_LEVEL1 0b000101 +#define TF_LEVEL2 0b000110 +#define TF_LEVEL3 0b000111 + #endif \ No newline at end of file diff --git a/lab6/include/mmu.h b/lab6/include/mmu.h index df9c522dc..301a40f16 100644 --- a/lab6/include/mmu.h +++ b/lab6/include/mmu.h @@ -2,7 +2,6 @@ #define MMU_H #include "stddef.h" - #define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16)) #define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30)) #define TCR_CONFIG_DEFAULT (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB) @@ -31,10 +30,28 @@ #define kernel_pgd_addr 0x1000 #define kernel_pud_addr 0x2000 +#include "sched.h" + void *set_2M_kernel_mmu(void *x0); void map_one_page(size_t *pgd_p, size_t va, size_t pa, size_t flag); void mappages(size_t *pgd_p, size_t va, size_t size, size_t pa, size_t flag); +void add_vma(struct thread *t, size_t va, size_t size, size_t pa, size_t rwx, int is_alloced); void free_page_tables(size_t *page_table, int level); +void handle_abort(esr_el1_t* esr_el1); +void seg_fault(); +void map_one_page_rwx(size_t *pgd_p, size_t va, size_t pa, size_t rwxflag); + +typedef struct vm_area_struct +{ + + list_head_t listhead; + unsigned long virt_addr; + unsigned long phys_addr; + unsigned long area_size; + unsigned long rwx; // 1, 2, 4 + int is_alloced; + +} vm_area_struct_t; #endif //__ASSEMBLER__ diff --git a/lab6/include/sched.h b/lab6/include/sched.h index f0a1bc824..6a1143e64 100644 --- a/lab6/include/sched.h +++ b/lab6/include/sched.h @@ -46,6 +46,7 @@ typedef struct thread int sigcount[SIGNAL_MAX + 1]; void (*curr_signal_handler)(); int signal_is_checking; + list_head_t vma_list; thread_context_t signal_saved_context; } thread_t; diff --git a/lab6/include/stddef.h b/lab6/include/stddef.h index c189f9730..d3f418ebb 100644 --- a/lab6/include/stddef.h +++ b/lab6/include/stddef.h @@ -3,4 +3,14 @@ #define size_t unsigned long +#ifndef __ASSEMBLER__ + +typedef struct{ + unsigned int iss : 25, // Instruction specific syndrome + il : 1, // Instruction length bit + ec : 6; // Exception class +} esr_el1_t; + +#endif //__ASSEMBLER__ + #endif \ No newline at end of file diff --git a/lab6/include/syscall.h b/lab6/include/syscall.h index 30d75e79a..1d0a60aa5 100644 --- a/lab6/include/syscall.h +++ b/lab6/include/syscall.h @@ -3,6 +3,7 @@ #include "stddef.h" #include "exception.h" + int getpid(trapframe_t *tpf); size_t uartread(trapframe_t *tpf,char buf[], size_t size); size_t uartwrite(trapframe_t *tpf,const char buf[], size_t size); @@ -14,5 +15,6 @@ void kill(trapframe_t *tpf,int pid); void signal_register(int signal, void (*handler)()); void signal_kill(int pid, int signal); void sigreturn(trapframe_t *tpf); +void *sys_mmap(trapframe_t *tpf, void *addr, size_t len, int prot, int flags, int fd, int file_offset); #endif diff --git a/lab6/src/entry.S b/lab6/src/entry.S index 99f9a64c7..e6fc28690 100644 --- a/lab6/src/entry.S +++ b/lab6/src/entry.S @@ -62,6 +62,7 @@ ldp x0, x1, [sp ,16 * 0] // restore x0 add sp, sp, 32 * 9 + .endm .macro ventry label @@ -156,6 +157,7 @@ error_invalid_el1h: sync_el0_64: save_all mov x0, sp // trap_frame + mrs x1, esr_el1 bl sync_64_router load_all eret diff --git a/lab6/src/exception.c b/lab6/src/exception.c index c1a087ef3..11a654a25 100644 --- a/lab6/src/exception.c +++ b/lab6/src/exception.c @@ -5,16 +5,27 @@ #include "syscall.h" #include "sched.h" #include "signal.h" - +#include "mmu.h" +#include "stddef.h" // For svc 0 (supervisor call) -void sync_64_router(trapframe_t* tpf) +void sync_64_router(trapframe_t *tpf, unsigned long x1) { //uart_printf("syscall no : %d\r\n", tpf->x8); //uart_printf("elr_el1 : 0x%x\r\n", tpf->elr_el1); //uart_printf("sp_el0 : 0x%x\r\n", tpf->sp_el0); //uart_printf("spsr_el1 : 0x%x\r\n", tpf->spsr_el1); //while(1); + + //For MMU page fault + esr_el1_t *esr; + esr = (esr_el1_t *)&x1; + if (esr->ec == DATA_ABORT_LOWER || esr->ec == INS_ABORT_LOWER) + { + handle_abort(esr); + return; + } + enable_interrupt(); unsigned long long syscall_no = tpf->x8; @@ -57,10 +68,17 @@ void sync_64_router(trapframe_t* tpf) else if (syscall_no == 9) { signal_kill(tpf->x0, tpf->x1); + }else if(syscall_no == 10) + { + sys_mmap(tpf,(void *)tpf->x0,tpf->x1,tpf->x2,tpf->x3,tpf->x4,tpf->x5); } else if (syscall_no == 50) { sigreturn(tpf); + }else + { + uart_printf("unknown syscall\r\n"); + while(1); } /* @@ -131,7 +149,7 @@ void irq_router(trapframe_t* tpf) run_preemptive_tasks(); core_timer_enable(); // lab 3 : advanced 2 -> unmask device line - //at least two trhead running -> schedule for any timer irq + //at least two thread running -> schedule for any timer irq if (run_queue->next->next != run_queue)schedule(); } diff --git a/lab6/src/mmu.c b/lab6/src/mmu.c index c8de86f6b..fbe2c791a 100644 --- a/lab6/src/mmu.c +++ b/lab6/src/mmu.c @@ -1,6 +1,8 @@ #include "mmu.h" #include "malloc.h" #include "string.h" +#include "threads.h" +#include "exception.h" // PGD's page frame at 0x1000 // PUD's page frame at 0x2000 // two-level translation (1G) -> three-level translation (2MB) @@ -13,11 +15,11 @@ void* set_2M_kernel_mmu(void* x0) // 0x3F000000 to 0x3FFFFFFF for peripherals if ((0x00000000 + (0x200000L) * i) >= 0x3F000000L) { - pud_table[i] = PD_ACCESS + PD_BLOCK + (0x00000000 + (0x200000L) * i) + (MAIR_DEVICE_nGnRnE << 2) + PD_UK_ACCESS; + pud_table[i] = PD_ACCESS | PD_BLOCK | (0x00000000 + (0x200000L) * i) | (MAIR_DEVICE_nGnRnE << 2) | PD_UK_ACCESS | PD_UNX | PD_KNX; } else { - pud_table[i] = PD_ACCESS + PD_BLOCK + (0x00000000 + (0x200000L) * i) + (MAIR_IDX_NORMAL_NOCACHE << 2); + pud_table[i] = PD_ACCESS | PD_BLOCK | (0x00000000 | (0x200000L) * i) | (MAIR_IDX_NORMAL_NOCACHE << 2); } } @@ -25,12 +27,12 @@ void* set_2M_kernel_mmu(void* x0) unsigned long *pud_table2 = (unsigned long *)0x4000; for (int i = 0; i < 512; i++) { - pud_table2[i] = PD_ACCESS + PD_BLOCK + (0x40000000L + (0x200000L) * i) + (MAIR_IDX_NORMAL_NOCACHE << 2); + pud_table2[i] = PD_ACCESS | PD_BLOCK | (0x40000000L | (0x200000L) * i) | (MAIR_IDX_NORMAL_NOCACHE << 2); } // set PUD - *(unsigned long *)(kernel_pud_addr) = PD_ACCESS + (MAIR_IDX_NORMAL_NOCACHE << 2) + PD_TABLE + (unsigned long)pud_table; - *(unsigned long *)(kernel_pud_addr + 0x8) = PD_ACCESS + (MAIR_IDX_NORMAL_NOCACHE << 2) + PD_TABLE + (unsigned long)pud_table2; + *(unsigned long *)(kernel_pud_addr) = PD_ACCESS | PD_TABLE | (unsigned long)pud_table; + *(unsigned long *)(kernel_pud_addr + 0x8) = PD_ACCESS | PD_TABLE | (unsigned long)pud_table2; return x0; } @@ -46,7 +48,7 @@ void map_one_page(size_t *virt_pgd_p, size_t va, size_t pa, size_t flag) if (level == 3) { table_p[idx] = pa; - table_p[idx] |= PD_ACCESS | PD_TABLE | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_UK_ACCESS | PD_KNX | flag; + table_p[idx] |= PD_ACCESS | PD_TABLE | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_KNX | flag; return; } @@ -55,7 +57,7 @@ void map_one_page(size_t *virt_pgd_p, size_t va, size_t pa, size_t flag) size_t* newtable_p =kmalloc(0x1000); memset(newtable_p, 0, 0x1000); table_p[idx] = VIRT_TO_PHYS((size_t)newtable_p); - table_p[idx] |= PD_ACCESS | PD_TABLE | (MAIR_IDX_NORMAL_NOCACHE << 2) | flag; + table_p[idx] |= PD_ACCESS | PD_TABLE | (MAIR_IDX_NORMAL_NOCACHE << 2); } table_p = (size_t*)PHYS_TO_VIRT((size_t)(table_p[idx] & ENTRY_ADDR_MASK)); @@ -72,6 +74,17 @@ void mappages(size_t *virt_pgd_p, size_t va, size_t size, size_t pa, size_t flag } } +void add_vma(thread_t *t, size_t va, size_t size, size_t pa, size_t rwx, int is_alloced) +{ + vm_area_struct_t* new_area = kmalloc(sizeof(vm_area_struct_t)); + new_area->rwx = rwx; + new_area->area_size = size; + new_area->virt_addr = va; + new_area->phys_addr = pa; + new_area->is_alloced = is_alloced; + list_add_tail((list_head_t *)new_area, &t->vma_list); +} + void free_page_tables(size_t *page_table, int level) { size_t *table_virt = (size_t*)PHYS_TO_VIRT((char*)page_table); @@ -88,4 +101,62 @@ void free_page_tables(size_t *page_table, int level) } } } +} + +void handle_abort(esr_el1_t* esr_el1) +{ + unsigned long long far_el1; + __asm__ __volatile__("mrs %0, FAR_EL1\n\t": "=r"(far_el1)); + + list_head_t *pos; + vm_area_struct_t *the_area_ptr = 0; + list_for_each(pos, &curr_thread->vma_list) + { + if (((vm_area_struct_t *)pos)->virt_addr <= far_el1 && ((vm_area_struct_t *)pos)->virt_addr + ((vm_area_struct_t *)pos)->area_size >= far_el1) + { + the_area_ptr = (vm_area_struct_t *)pos; + break; + } + } + + if (!the_area_ptr) + { + seg_fault(); + } + + // For translation fault + if ((esr_el1->iss & 0x3f) == TF_LEVEL0 || (esr_el1->iss & 0x3f) == TF_LEVEL1 || (esr_el1->iss & 0x3f) == TF_LEVEL2 || (esr_el1->iss & 0x3f) == TF_LEVEL3) + { + uart_printf("[Translation fault]: 0x%x\r\n",far_el1); + + size_t addr_offset = (far_el1 - the_area_ptr->virt_addr); + addr_offset = (addr_offset % 0x1000) == 0 ? addr_offset : addr_offset - (addr_offset % 0x1000); + map_one_page_rwx(PHYS_TO_VIRT(curr_thread->context.ttbr0_el1), the_area_ptr->virt_addr + addr_offset, the_area_ptr->phys_addr + +addr_offset, the_area_ptr->rwx); + }else + { + // For other Fault (permisson ...etc) + seg_fault(); + } +} + +void map_one_page_rwx(size_t *pgd_p, size_t va, size_t pa, size_t rwxflag) +{ + size_t flag = 0; + + //execute + if(!(rwxflag & 0b100))flag |= PD_UNX; + + //write + if(!(rwxflag & 0b10))flag |= PD_RDONLY; + + //read + if (rwxflag & 0b1)flag |= PD_UK_ACCESS; + + map_one_page(pgd_p, va, pa, flag); +} + +void seg_fault() +{ + uart_printf("[Segmentation fault]: Kill Process\r\n"); + thread_exit(); } \ No newline at end of file diff --git a/lab6/src/sched.S b/lab6/src/sched.S index 9ca7221ec..de22ee0ef 100644 --- a/lab6/src/sched.S +++ b/lab6/src/sched.S @@ -20,13 +20,14 @@ switch_to: ldp x9, x0, [x1, 16 * 6] mov sp, x9 + msr tpidr_el1, x1 + dsb ish // ensure write has completed msr ttbr0_el1, x0 // switch translation based address. tlbi vmalle1is // invalidate all TLB entries dsb ish // ensure completion of TLB invalidatation isb // clear pipeline - msr tpidr_el1, x1 ret .global store_context diff --git a/lab6/src/sched.c b/lab6/src/sched.c index 786d795ec..930d44bda 100644 --- a/lab6/src/sched.c +++ b/lab6/src/sched.c @@ -56,10 +56,20 @@ void kill_zombies(){ if (((thread_t *)curr)->iszombie) { list_del_entry(curr); - kfree(((thread_t *)curr)->stack_alloced_ptr); // free stack - kfree(((thread_t *)curr)->kernel_stack_alloced_ptr); // free stack + kfree(((thread_t *)curr)->kernel_stack_alloced_ptr); // free kstack free_page_tables(((thread_t *)curr)->context.ttbr0_el1,0); - kfree(((thread_t *)curr)->data); // free data (don't free data because of fork) + + // free alloced area and vma struct + list_head_t *pos = curr_thread->vma_list.next; + while(pos != &curr_thread->vma_list){ + if (((vm_area_struct_t *)pos)->is_alloced) + kfree( (void*)((vm_area_struct_t *)pos)->phys_addr ); + + list_head_t* next_pos = pos->next; + kfree(pos); + pos = next_pos; + } + ((thread_t *)curr)->iszombie = 0; ((thread_t *)curr)->isused = 0; } @@ -71,15 +81,10 @@ int exec_thread(char *data, unsigned int filesize) { thread_t *t = thread_create(data, filesize); - mappages(t->context.ttbr0_el1, 0x3C000000L, 0x3000000L, 0x3C000000L, 0); - mappages(t->context.ttbr0_el1, 0x3F000000L, 0x1000000L, 0x3F000000L, 0); - mappages(t->context.ttbr0_el1, 0x40000000L, 0x40000000L, 0x40000000L, 0); - - mappages(t->context.ttbr0_el1, 0xffffffffb000, 0x4000, (size_t)VIRT_TO_PHYS(t->stack_alloced_ptr), 0); - mappages(t->context.ttbr0_el1, 0x0, filesize, (size_t)VIRT_TO_PHYS(t->data), 0); - - // for signal wrapper - mappages(t->context.ttbr0_el1, USER_SIG_WRAPPER_VIRT_ADDR_ALIGNED, 0x2000, (size_t)VIRT_TO_PHYS(signal_handler_wrapper), PD_RDONLY); + add_vma(t, 0x3C000000L, 0x3000000L, 0x3C000000L,3, 0); // device + add_vma(t, 0xffffffffb000, 0x4000, (size_t)VIRT_TO_PHYS(t->stack_alloced_ptr), 7, 1); //stack + add_vma(t, 0x0, filesize, (size_t)VIRT_TO_PHYS(t->data), 7, 1); // text + add_vma(t, USER_SIG_WRAPPER_VIRT_ADDR_ALIGNED, 0x2000, (size_t)VIRT_TO_PHYS(signal_handler_wrapper), 5, 0); // for signal wrapper t->context.ttbr0_el1 = VIRT_TO_PHYS(t->context.ttbr0_el1); t->context.sp = 0xfffffffff000; @@ -128,6 +133,7 @@ thread_t *thread_create(void *start, unsigned int filesize) break; } } + INIT_LIST_HEAD(&r->vma_list); r->iszombie = 0; r->isused = 1; r->context.lr = (unsigned long long)start; diff --git a/lab6/src/signal.c b/lab6/src/signal.c index d2265786e..9475bf27c 100644 --- a/lab6/src/signal.c +++ b/lab6/src/signal.c @@ -47,7 +47,6 @@ void run_signal(trapframe_t* tpf,int signal) "r"(tpf->spsr_el1), "r"(curr_thread->curr_signal_handler)); } -//TODO : register signal handler after MMU (el0 cannot run in kernel space) void signal_handler_wrapper() { //call function and system call sigreturn diff --git a/lab6/src/syscall.c b/lab6/src/syscall.c index 6d07a5648..cafe9f131 100644 --- a/lab6/src/syscall.c +++ b/lab6/src/syscall.c @@ -32,9 +32,7 @@ size_t uartwrite(trapframe_t *tpf,const char buf[], size_t size) int i = 0; for (int i = 0; i < size; i++) { - lock(); - uart_putc(buf[i]); - unlock(); + uart_putc(buf[i]); // some unknown bugs occur when uart_async_putc } tpf->x0 = i; return i; @@ -79,31 +77,27 @@ int fork(trapframe_t *tpf) newt->singal_handler[i] = curr_thread->singal_handler[i]; } - mappages(newt->context.ttbr0_el1, 0x3C000000L, 0x3000000L, 0x3C000000L,0); - mappages(newt->context.ttbr0_el1, 0x3F000000L, 0x1000000L, 0x3F000000L,0); - mappages(newt->context.ttbr0_el1, 0x40000000L, 0x40000000L, 0x40000000L,0); - - // remap code and stack - mappages(newt->context.ttbr0_el1, 0xffffffffb000, 0x4000, (size_t)VIRT_TO_PHYS(newt->stack_alloced_ptr),0); - mappages(newt->context.ttbr0_el1, 0x0, newt->datasize, (size_t)VIRT_TO_PHYS(newt->data),0); + list_head_t *pos; + list_for_each(pos, &curr_thread->vma_list){ - // for signal wrapper - mappages(newt->context.ttbr0_el1, USER_SIG_WRAPPER_VIRT_ADDR_ALIGNED, 0x2000, (size_t)VIRT_TO_PHYS(signal_handler_wrapper), PD_RDONLY); + // ignore device and signal wrapper + if (((vm_area_struct_t *)pos)->virt_addr == USER_SIG_WRAPPER_VIRT_ADDR_ALIGNED || ((vm_area_struct_t *)pos)->virt_addr == 0x3C000000L) + { + continue; + } - //在這段page被蓋爁 - int parent_pid = curr_thread->pid; + char *new_alloc = kmalloc(((vm_area_struct_t *)pos)->area_size); + add_vma(newt, ((vm_area_struct_t *)pos)->virt_addr, ((vm_area_struct_t *)pos)->area_size, (size_t)VIRT_TO_PHYS(new_alloc), ((vm_area_struct_t *)pos)->rwx, 1); - //copy data into new process - for (int i = 0; i < newt->datasize; i++) - { - newt->data[i] = curr_thread->data[i]; + memcpy(new_alloc, (void*)PHYS_TO_VIRT(((vm_area_struct_t *)pos)->phys_addr), ((vm_area_struct_t *)pos)->area_size); } - //copy user stack into new process - for (int i = 0; i < USTACK_SIZE; i++) - { - newt->stack_alloced_ptr[i] = curr_thread->stack_alloced_ptr[i]; - } + // device + add_vma(newt, 0x3C000000L, 0x3000000L, 0x3C000000L, 3, 0); + // for signal wrapper + add_vma(newt, USER_SIG_WRAPPER_VIRT_ADDR_ALIGNED, 0x2000, (size_t)VIRT_TO_PHYS(signal_handler_wrapper), 5, 0); // for signal wrapper + + int parent_pid = curr_thread->pid; //copy stack into new process for (int i = 0; i < KSTACK_SIZE; i++) @@ -111,8 +105,6 @@ int fork(trapframe_t *tpf) newt->kernel_stack_alloced_ptr[i] = curr_thread->kernel_stack_alloced_ptr[i]; } - //在這段page被蓋爁 - store_context(get_current()); //for child if( parent_pid != curr_thread->pid) @@ -189,3 +181,33 @@ void sigreturn(trapframe_t *tpf) { load_context(&curr_thread->signal_saved_context); } + +//only need to implement the anonymous page mapping in this Lab. +void *sys_mmap(trapframe_t *tpf, void *addr, size_t len, int prot, int flags, int fd, int file_offset) +{ + len = len%0x1000?len + (0x1000 - len % 0x1000):len; // rounds up + addr = (unsigned long)addr%0x1000?addr + (0x1000 - (unsigned long)addr % 0x1000):addr; + + // check if overlap + list_head_t *pos; + vm_area_struct_t *the_area_ptr = 0; + list_for_each(pos, &curr_thread->vma_list) + { + if (!(((vm_area_struct_t *)pos)->virt_addr >= (unsigned long)(addr + len) || ((vm_area_struct_t *)pos)->virt_addr + ((vm_area_struct_t *)pos)->area_size <= (unsigned long)addr)) + { + the_area_ptr = (vm_area_struct_t *)pos; + break; + } + } + + // test the end of the area as addr + if (the_area_ptr) + { + tpf->x0 = (unsigned long)sys_mmap(tpf, (void *)(the_area_ptr->virt_addr + the_area_ptr->area_size), len, prot, flags, fd, file_offset); + return (void *)tpf->x0; + } + + add_vma(curr_thread, (unsigned long)addr, len, VIRT_TO_PHYS((unsigned long)kmalloc(len)), prot, 1); + tpf->x0 = (unsigned long)addr; + return (void*)tpf->x0; +} From 83042c3cffab5b518fa4040e164ef0691d00976a Mon Sep 17 00:00:00 2001 From: a13579and2468 Date: Thu, 26 May 2022 00:16:48 +0800 Subject: [PATCH 4/8] demand paging, sys_mmap --- lab6/src/mmu.c | 5 ++++- lab6/src/sched.c | 8 +++++--- lab6/src/syscall.c | 41 +++++++++++++++++++++++++++++++++-------- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/lab6/src/mmu.c b/lab6/src/mmu.c index fbe2c791a..4a120decd 100644 --- a/lab6/src/mmu.c +++ b/lab6/src/mmu.c @@ -76,7 +76,10 @@ void mappages(size_t *virt_pgd_p, size_t va, size_t size, size_t pa, size_t flag void add_vma(thread_t *t, size_t va, size_t size, size_t pa, size_t rwx, int is_alloced) { - vm_area_struct_t* new_area = kmalloc(sizeof(vm_area_struct_t)); + // alignment + size = size % 0x1000 ? size + (0x1000 - size%0x1000): size; + + vm_area_struct_t *new_area = kmalloc(sizeof(vm_area_struct_t)); new_area->rwx = rwx; new_area->area_size = size; new_area->virt_addr = va; diff --git a/lab6/src/sched.c b/lab6/src/sched.c index 930d44bda..5aa620803 100644 --- a/lab6/src/sched.c +++ b/lab6/src/sched.c @@ -60,16 +60,18 @@ void kill_zombies(){ free_page_tables(((thread_t *)curr)->context.ttbr0_el1,0); // free alloced area and vma struct - list_head_t *pos = curr_thread->vma_list.next; - while(pos != &curr_thread->vma_list){ + list_head_t *pos = ((thread_t *)curr)->vma_list.next; + while (pos != &((thread_t *)curr)->vma_list) + { if (((vm_area_struct_t *)pos)->is_alloced) - kfree( (void*)((vm_area_struct_t *)pos)->phys_addr ); + kfree((void*)PHYS_TO_VIRT(((vm_area_struct_t *)pos)->phys_addr)); list_head_t* next_pos = pos->next; kfree(pos); pos = next_pos; } + kfree(PHYS_TO_VIRT(((thread_t *)curr)->context.ttbr0_el1)); // free PGD ((thread_t *)curr)->iszombie = 0; ((thread_t *)curr)->isused = 0; } diff --git a/lab6/src/syscall.c b/lab6/src/syscall.c index cafe9f131..758971e12 100644 --- a/lab6/src/syscall.c +++ b/lab6/src/syscall.c @@ -41,18 +41,43 @@ size_t uartwrite(trapframe_t *tpf,const char buf[], size_t size) //In this lab, you won’t have to deal with argument passing int exec(trapframe_t *tpf,const char *name, char *const argv[]) { - kfree(curr_thread->data); + // free alloced area and vma struct + // free alloced area and vma struct + list_head_t *pos = curr_thread->vma_list.next; + while (pos != &curr_thread->vma_list) + { + if (((vm_area_struct_t *)pos)->is_alloced) + kfree((void *)PHYS_TO_VIRT(((vm_area_struct_t *)pos)->phys_addr)); + + list_head_t *next_pos = pos->next; + kfree(pos); + pos = next_pos; + } + + INIT_LIST_HEAD(&curr_thread->vma_list); curr_thread->datasize = get_file_size((char *)name); char *new_data = get_file_start((char *)name); curr_thread->data = kmalloc(curr_thread->datasize); + curr_thread->stack_alloced_ptr = kmalloc(USTACK_SIZE); + + asm("dsb ish\n\t"); // ensure write has completed + free_page_tables(curr_thread->context.ttbr0_el1, 0); + memset(PHYS_TO_VIRT(curr_thread->context.ttbr0_el1), 0, 0x1000); + asm("tlbi vmalle1is\n\t" // invalidate all TLB entries + "dsb ish\n\t" // ensure completion of TLB invalidatation + "isb\n\t"); // clear pipeline + + // remap code + add_vma(curr_thread, 0, curr_thread->datasize, (size_t)VIRT_TO_PHYS(curr_thread->data), 7,1); + // remap stack + add_vma(curr_thread, 0xffffffffb000, 0x4000, (size_t)VIRT_TO_PHYS(curr_thread->stack_alloced_ptr), 7, 1); + // device + add_vma(curr_thread, 0x3C000000L, 0x3000000L, 0x3C000000L, 3, 0); + // for signal wrapper + add_vma(curr_thread, USER_SIG_WRAPPER_VIRT_ADDR_ALIGNED, 0x2000, (size_t)VIRT_TO_PHYS(signal_handler_wrapper), 5, 0); - //remap code - mappages(PHYS_TO_VIRT(curr_thread->context.ttbr0_el1), 0x0, curr_thread->datasize, (size_t)VIRT_TO_PHYS(curr_thread->data), 0); - - for (unsigned int i = 0; i < curr_thread->datasize; i++) - { - curr_thread->data[i] = new_data[i]; - } + //copy file into data + memcpy(curr_thread->data, new_data, curr_thread->datasize); //clear signal handler for (int i = 0; i <= SIGNAL_MAX; i++) From d748830d58e36011229fb63a678df59b13fa2042 Mon Sep 17 00:00:00 2001 From: a13579and2468 Date: Thu, 26 May 2022 00:17:48 +0800 Subject: [PATCH 5/8] demand paging, sys_mmap --- sdcard/bcm2710-rpi-3-b-plus.dtb | Bin 0 -> 31790 bytes sdcard/bootcode.bin | Bin 0 -> 52304 bytes sdcard/config.txt | 3 +++ sdcard/fixup.dat | Bin 0 -> 6745 bytes 4 files changed, 3 insertions(+) create mode 100644 sdcard/bcm2710-rpi-3-b-plus.dtb create mode 100644 sdcard/bootcode.bin create mode 100644 sdcard/config.txt create mode 100644 sdcard/fixup.dat diff --git a/sdcard/bcm2710-rpi-3-b-plus.dtb b/sdcard/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 0000000000000000000000000000000000000000..3934b3a26eb82fd65dbcdfca6f6916da427a3fae GIT binary patch literal 31790 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 literal 0 HcmV?d00001 diff --git a/sdcard/bootcode.bin b/sdcard/bootcode.bin new file mode 100644 index 0000000000000000000000000000000000000000..944263a654c7ab1bdcced973988d4e75dee80de3 GIT binary patch literal 52304 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 F{tH{OT897t literal 0 HcmV?d00001 diff --git a/sdcard/config.txt b/sdcard/config.txt new file mode 100644 index 000000000..49fc25695 --- /dev/null +++ b/sdcard/config.txt @@ -0,0 +1,3 @@ +kernel=bootloader.img +arm_64bit=1 +initramfs initramfs.cpio 0x20000000 diff --git a/sdcard/fixup.dat b/sdcard/fixup.dat new file mode 100644 index 0000000000000000000000000000000000000000..e928ee3fc1bf00e638365cfa0bc4c9d94940bd7f GIT binary patch literal 6745 zcmeHLUx*cD6#str?009!>v+4adf8pK)wXTjmZ(iCMAXDAO{y1Dq)f6R5wZ}(h$7A2 z3L+mQ^(6?QKza-8B^0E`q=!K8t)d`&i0DBmsdK*h&dfLC+`Zo2G=t9EnRCAL_q*pi z-=CT005yBOa32hHf%RSF-NcVMg$1}o1|P%J=ieUVWou3xT-MD}<*mqK+Zb#TVcw)+ zlmf0UH8_x@4D7$nOK|xP&$_r&m2t%?>5aP}9BTAtP~i`o=I+C}#iM;)JA)_Zch#xr zW5~kk1#@+gyTiNn9-ZN*S*8o$_!`Kg_d;P|uRV=0H0y|1p>^6zA5&dioV~5{fb;Lj zbjQY)dDUz_ZOot682*_C-&>g=#+UkyIlPM;UFY_P7kG_e{6SwT7v68nYB*#fYjNjp z)2ae2vW6O~u&*X4)~PJf_ts4Gv-IZ_7Qw8u3{7l;vCRfivprz#6tz=>?nK5;APKic4au-bzMeXz{oSe#O;k}m`j$lvS;Mk(B zt2gKS*Oir8c)YOomS-F@T!tRII>!v@p_0t)Yaq6=&M*YA-F!122qYmhP>dEX@6327gxr8Lue# zy-uvHP^W=loD-Vo4A z;`6aAg?ygCKAw<#L}6HO#~W=*;sFlJfvdu(lSZrY)J$+bZ+3X8pcZeT z@i-Hc9IOc1mLMs_5}d)uSA|IGr~rc``|AYXTr3VoD4W1xAn!?3q|;Mz&`oFOA1yv| z?~^0p>PVvX)&LaxSEUX`WFZWhM-vLU0+JK3$!ow@&Q+{JH#0R$r&a66M#r}IoZ zYUt)eyjf*XssYrxznQ45b<WRw*eNqS&qc7S3W4(J zkh1+@pr8{pQcwJ$%S}G6Y-Zr{c>b28{VLLkf(J-E?N{|a=lZKqk zXN2HXo_20@@MggB8x>@@yw2n)KR$CJaz&+LYD>xU@VdKXj=T9Ih=8i!NL-5DEmW+q zeWYZ0%QoZkT#&cPQfjlIVDdK6Dp_lD zz?D({-j`iCOW}$Xu~YVRL~?^6f3DW|qtG+Xz{HbbwnM3-s|MHeY=njRd(SnN-5JL_ zs-V_&d^*~aoj92bu>wZUL^FUU-KqF`s{WSYonS4Qbc4qEnpu3E@F0fH5ni+gyY>)H TT!2(M{@_o%dmo8$>KOh8=fLZL literal 0 HcmV?d00001 From 3036c3d8c50d569e5c6a76ddae2b8d7911805bc5 Mon Sep 17 00:00:00 2001 From: a13579and2468 Date: Fri, 27 May 2022 01:20:30 +0800 Subject: [PATCH 6/8] disable async io for a bug only occur when using raspi --- lab6/src/dtb.c | 12 ++++++------ lab6/src/exception.c | 1 + lab6/src/filesystem.c | 4 ++-- lab6/src/main.c | 2 +- lab6/src/shell.c | 38 +++++++++++++++++++------------------- lab6/src/syscall.c | 9 ++++++--- lab6/src/uart.c | 4 ++++ 7 files changed, 39 insertions(+), 31 deletions(-) diff --git a/lab6/src/dtb.c b/lab6/src/dtb.c index 86cb6e200..1bec30680 100644 --- a/lab6/src/dtb.c +++ b/lab6/src/dtb.c @@ -93,18 +93,18 @@ void dtb_callback_show_tree(uint32_t node_type, char *name, void *data, uint32_t static int level = 0; if(node_type==FDT_BEGIN_NODE) { - for(int i=0;i EL1 uart_printf("dtb : 0x%x\r\n",dtb); diff --git a/lab6/src/shell.c b/lab6/src/shell.c index 86289e7a4..470020895 100644 --- a/lab6/src/shell.c +++ b/lab6/src/shell.c @@ -18,8 +18,8 @@ void shell() core_timer_enable(); while (1) { - uart_async_printf("# "); - uart_async_gets(cmd); + uart_printf("# "); + uart_gets(cmd); do_cmd(cmd); } } @@ -28,19 +28,19 @@ void do_cmd(char *cmd) { if (strcmp(cmd, "help") == 0) { - uart_async_printf("help : print this help menu\r\n"); - uart_async_printf("hello : print Hello World!\r\n"); - uart_async_printf("reboot : reboot the device\r\n"); - uart_async_printf("ls : list current directory\r\n"); - uart_async_printf("cat : print content of a file\r\n"); - uart_async_printf("show_device_tree : show device tree\r\n"); - uart_async_printf("exec : load a user program in the initramfs and run it in EL0\r\n"); - uart_async_printf("setTimeout [MESSAGE] [SECONDS] : print message after [SECONDS] seconds (non-blocking)\r\n"); - uart_async_printf("clockAlert : alert every two seconds\r\n"); + uart_printf("help : print this help menu\r\n"); + uart_printf("hello : print Hello World!\r\n"); + uart_printf("reboot : reboot the device\r\n"); + uart_printf("ls : list current directory\r\n"); + uart_printf("cat : print content of a file\r\n"); + uart_printf("show_device_tree : show device tree\r\n"); + uart_printf("exec : load a user program in the initramfs and run it in EL0\r\n"); + uart_printf("setTimeout [MESSAGE] [SECONDS] : print message after [SECONDS] seconds (non-blocking)\r\n"); + uart_printf("clockAlert : alert every two seconds\r\n"); } else if (strcmp(cmd, "hello") == 0) { - uart_async_printf("Hello World!\r\n"); + uart_printf("Hello World!\r\n"); } else if (strcmp(cmd, "reboot") == 0) { @@ -48,9 +48,9 @@ void do_cmd(char *cmd) } else if (strcmp(cmd, "cat") == 0) { - uart_async_printf("Filename: "); + uart_printf("Filename: "); char filepath[MAX_BUF_SIZE]; - uart_async_gets(filepath); + uart_gets(filepath); cat(filepath); } else if (strcmp(cmd, "ls") == 0) @@ -63,9 +63,9 @@ void do_cmd(char *cmd) } else if (strcmp(cmd, "exec") == 0) // in filesystem.c { - uart_async_printf("Filename: "); + uart_printf("Filename: "); char filepath[MAX_BUF_SIZE]; - uart_async_gets(filepath); + uart_gets(filepath); execfile(filepath); } else if (strncmp(cmd, "setTimeout", sizeof("setTimeout") - 1) == 0) @@ -74,14 +74,14 @@ void do_cmd(char *cmd) char *message = strchr(cmd, ' '); if (!message) { - uart_async_printf("setTimeout wrong format"); + uart_printf("setTimeout wrong format"); return; } message += 1; char *end_message = strchr(message, ' '); if (!end_message) { - uart_async_printf("setTimeout wrong format"); + uart_printf("setTimeout wrong format"); return; } *end_message = '\0'; @@ -94,7 +94,7 @@ void do_cmd(char *cmd) } else { - uart_async_printf("Unknown command!: %s\r\n", cmd); + uart_printf("Unknown command!: %s\r\n", cmd); } } diff --git a/lab6/src/syscall.c b/lab6/src/syscall.c index 758971e12..4d615cbc8 100644 --- a/lab6/src/syscall.c +++ b/lab6/src/syscall.c @@ -21,7 +21,7 @@ size_t uartread(trapframe_t *tpf,char buf[], size_t size) int i = 0; for (int i = 0; i < size;i++) { - buf[i] = uart_async_getc(); + buf[i] = uart_getc(); } tpf->x0 = i; return i; @@ -32,7 +32,7 @@ size_t uartwrite(trapframe_t *tpf,const char buf[], size_t size) int i = 0; for (int i = 0; i < size; i++) { - uart_putc(buf[i]); // some unknown bugs occur when uart_async_putc + uart_putc(buf[i]); // TODO : debug -> some unknown bugs occur when uart_async_putc (only in qemu) } tpf->x0 = i; return i; @@ -210,7 +210,10 @@ void sigreturn(trapframe_t *tpf) //only need to implement the anonymous page mapping in this Lab. void *sys_mmap(trapframe_t *tpf, void *addr, size_t len, int prot, int flags, int fd, int file_offset) { - len = len%0x1000?len + (0x1000 - len % 0x1000):len; // rounds up + // relocate to zero + if (len + (unsigned long)addr >= 0xfffffffff000L)addr = 0L; + + len = len % 0x1000 ? len + (0x1000 - len % 0x1000) : len; // rounds up addr = (unsigned long)addr%0x1000?addr + (0x1000 - (unsigned long)addr % 0x1000):addr; // check if overlap diff --git a/lab6/src/uart.c b/lab6/src/uart.c index d61f02269..2ee329899 100644 --- a/lab6/src/uart.c +++ b/lab6/src/uart.c @@ -293,11 +293,13 @@ void uart_interrupt_r_handler() disable_mini_uart_r_interrupt(); //disable read interrupt when read buffer full return; } + lock(); uart_rx_buffer[uart_rx_buffer_widx++] = uart_getc(); if (uart_rx_buffer_widx >= MAX_BUF_SIZE) uart_rx_buffer_widx = 0; enable_mini_uart_r_interrupt(); // lab 3 : advanced 2 -> unmask device line + unlock(); } void uart_interrupt_w_handler() //can write @@ -309,11 +311,13 @@ void uart_interrupt_w_handler() //can write disable_mini_uart_w_interrupt(); // disable w_interrupt to prevent interruption without any async output return; } + lock(); uart_putc(uart_tx_buffer[uart_tx_buffer_ridx++]); if (uart_tx_buffer_ridx >= MAX_BUF_SIZE) uart_tx_buffer_ridx = 0; // cycle pointer enable_mini_uart_w_interrupt(); // lab 3 : advanced 2 -> unmask device line + unlock(); } void uart_async_putc(char c) From 99af856e78c049d5af2845e3dc9869b23cd2af90 Mon Sep 17 00:00:00 2001 From: a13579and2468 Date: Sat, 28 May 2022 02:39:03 +0800 Subject: [PATCH 7/8] =?UTF-8?q?=E8=AC=8E=E4=B9=8Basync=5Fio=20bug=20de?= =?UTF-8?q?=E5=8F=AF=E8=83=BD=E4=B8=80=E5=8D=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lab6/include/uart.h | 2 +- lab6/src/sched.c | 1 + lab6/src/syscall.c | 2 +- lab6/src/uart.c | 29 ++++++++++++++++++----------- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/lab6/include/uart.h b/lab6/include/uart.h index adef0cf64..08949d221 100644 --- a/lab6/include/uart.h +++ b/lab6/include/uart.h @@ -6,7 +6,7 @@ #include "sprintf.h" #include "registers.h" -#define MAX_BUF_SIZE 0x1000 +#define MAX_BUF_SIZE 0x10000 /* Auxilary mini UART registers */ #define AUX_ENABLE ((volatile unsigned int *)(MMIO_BASE + 0x00215004)) diff --git a/lab6/src/sched.c b/lab6/src/sched.c index 5aa620803..8b67897c6 100644 --- a/lab6/src/sched.c +++ b/lab6/src/sched.c @@ -109,6 +109,7 @@ int exec_thread(char *data, unsigned int filesize) "msr spsr_el1, xzr\n\t" // enable interrupt in EL0. You can do it by setting spsr_el1 to 0 before returning to EL0. "msr sp_el0, %2\n\t" "mov sp, %3\n\t" + "mov fp, sp\n\t" "dsb ish\n\t" // ensure write has completed "msr ttbr0_el1, %4\n\t" "tlbi vmalle1is\n\t" // invalidate all TLB entries diff --git a/lab6/src/syscall.c b/lab6/src/syscall.c index 4d615cbc8..b9598ca9b 100644 --- a/lab6/src/syscall.c +++ b/lab6/src/syscall.c @@ -32,7 +32,7 @@ size_t uartwrite(trapframe_t *tpf,const char buf[], size_t size) int i = 0; for (int i = 0; i < size; i++) { - uart_putc(buf[i]); // TODO : debug -> some unknown bugs occur when uart_async_putc (only in qemu) + uart_putc(buf[i]); // TODO : debug -> some unknown bugs occur when uart_async_putc (only in qemu) } tpf->x0 = i; return i; diff --git a/lab6/src/uart.c b/lab6/src/uart.c index 2ee329899..5c9d5024c 100644 --- a/lab6/src/uart.c +++ b/lab6/src/uart.c @@ -10,10 +10,10 @@ extern volatile unsigned char _end; int echoflag = 1; //implement first in first out buffer with a read index and a write index -char uart_tx_buffer[MAX_BUF_SIZE] = {}; +static char uart_tx_buffer[MAX_BUF_SIZE] = {}; unsigned int uart_tx_buffer_widx = 0; //write index unsigned int uart_tx_buffer_ridx = 0; //read index -char uart_rx_buffer[MAX_BUF_SIZE] = {}; +static char uart_rx_buffer[MAX_BUF_SIZE] = {}; unsigned int uart_rx_buffer_widx = 0; unsigned int uart_rx_buffer_ridx = 0; @@ -287,13 +287,15 @@ int uart_async_printf(char *fmt, ...) void uart_interrupt_r_handler() { //read buffer full + lock(); if ((uart_rx_buffer_widx + 1) % MAX_BUF_SIZE == uart_rx_buffer_ridx) { *AUX_MU_IIR = 0xC2; /* clear the fifos */ // I dont know why need this but it can prevent big input to cause infinite run here (disable_r_interrupt never work) disable_mini_uart_r_interrupt(); //disable read interrupt when read buffer full + unlock(); return; } - lock(); + //lock(); uart_rx_buffer[uart_rx_buffer_widx++] = uart_getc(); if (uart_rx_buffer_widx >= MAX_BUF_SIZE) uart_rx_buffer_widx = 0; @@ -305,13 +307,15 @@ void uart_interrupt_r_handler() void uart_interrupt_w_handler() //can write { // buffer empty + lock(); if (uart_tx_buffer_ridx == uart_tx_buffer_widx) { *AUX_MU_IIR = 0xC4; disable_mini_uart_w_interrupt(); // disable w_interrupt to prevent interruption without any async output + unlock(); return; } - lock(); + uart_putc(uart_tx_buffer[uart_tx_buffer_ridx++]); if (uart_tx_buffer_ridx >= MAX_BUF_SIZE) uart_tx_buffer_ridx = 0; // cycle pointer @@ -322,25 +326,25 @@ void uart_interrupt_w_handler() //can write void uart_async_putc(char c) { + // full buffer wait + lock(); while ((uart_tx_buffer_widx + 1) % MAX_BUF_SIZE == uart_tx_buffer_ridx) { + unlock(); // start asynchronous transfer enable_mini_uart_w_interrupt(); + lock(); } - - // critical section - lock(); uart_tx_buffer[uart_tx_buffer_widx++] = c; if (uart_tx_buffer_widx >= MAX_BUF_SIZE) uart_tx_buffer_widx = 0; // cycle pointer // start asynchronous transfer - unlock(); - // enable interrupt to transfer enable_mini_uart_w_interrupt(); + unlock(); } char uart_async_getc() @@ -348,11 +352,14 @@ char uart_async_getc() enable_mini_uart_r_interrupt(); // while buffer empty // enable read interrupt to get some input into buffer + lock(); while (uart_rx_buffer_ridx == uart_rx_buffer_widx) + { + unlock(); enable_mini_uart_r_interrupt(); + lock(); + } - // critical section - lock(); char r = uart_rx_buffer[uart_rx_buffer_ridx++]; if (uart_rx_buffer_ridx >= MAX_BUF_SIZE) From ef0160a975c81ef17faa2938a9dbbd8d730a8548 Mon Sep 17 00:00:00 2001 From: a13579and2468 Date: Thu, 2 Jun 2022 02:10:09 +0800 Subject: [PATCH 8/8] lab6 --- lab6/include/uart.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lab6/include/uart.h b/lab6/include/uart.h index 08949d221..adef0cf64 100644 --- a/lab6/include/uart.h +++ b/lab6/include/uart.h @@ -6,7 +6,7 @@ #include "sprintf.h" #include "registers.h" -#define MAX_BUF_SIZE 0x10000 +#define MAX_BUF_SIZE 0x1000 /* Auxilary mini UART registers */ #define AUX_ENABLE ((volatile unsigned int *)(MMIO_BASE + 0x00215004))