From adfe31a54b5d8e1b291665a632e4b58214dbfd44 Mon Sep 17 00:00:00 2001 From: eugenechouy Date: Thu, 2 Jun 2022 15:53:26 +0800 Subject: [PATCH 1/2] lab6 / lab7 --- lab6/Makefile | 55 +++++ lab6/boot/Makefile | 54 +++++ lab6/boot/boot.S | 30 +++ lab6/boot/linker.ld | 43 ++++ lab6/boot/main.c | 42 ++++ lab6/boot/relocate.c | 17 ++ lab6/documentation/mm.md | 29 +++ lab6/documentation/sched.md | 5 + lab6/include/bitmap.h | 66 ++++++ lab6/include/byteswap.h | 9 + lab6/include/dtb.h | 40 ++++ lab6/include/kern/cpio.h | 35 +++ lab6/include/kern/irq.h | 16 ++ lab6/include/kern/kio.h | 32 +++ lab6/include/kern/mm.h | 17 ++ lab6/include/kern/mm_types.h | 48 ++++ lab6/include/kern/page.h | 35 +++ lab6/include/kern/sched.h | 98 ++++++++ lab6/include/kern/shell.h | 22 ++ lab6/include/kern/signal.h | 31 +++ lab6/include/kern/slab.h | 37 +++ lab6/include/kern/softirq.h | 18 ++ lab6/include/kern/sync.h | 20 ++ lab6/include/kern/timer.h | 25 ++ lab6/include/list.h | 134 +++++++++++ lab6/include/mmu.h | 46 ++++ lab6/include/peripheral/arm.h | 13 + lab6/include/peripheral/aux.h | 36 +++ lab6/include/peripheral/gpio.h | 51 ++++ lab6/include/peripheral/interrupt.h | 19 ++ lab6/include/peripheral/mailbox.h | 53 +++++ lab6/include/peripheral/mmio.h | 8 + lab6/include/peripheral/uart.h | 27 +++ lab6/include/reset.h | 12 + lab6/include/startup_alloc.h | 8 + lab6/include/string.h | 14 ++ lab6/include/syscall.h | 26 ++ lab6/include/user_lib.h | 6 + lab6/kern/cpio.c | 139 +++++++++++ lab6/kern/entry.S | 135 +++++++++++ lab6/kern/exception_vector_table.S | 136 +++++++++++ lab6/kern/irq.c | 76 ++++++ lab6/kern/kio.c | 65 +++++ lab6/kern/linker.ld | 44 ++++ lab6/kern/main.c | 127 ++++++++++ lab6/kern/mm.c | 242 +++++++++++++++++++ lab6/kern/page.c | 157 ++++++++++++ lab6/kern/sched.S | 41 ++++ lab6/kern/sched.c | 324 +++++++++++++++++++++++++ lab6/kern/shell.c | 79 ++++++ lab6/kern/signal.c | 113 +++++++++ lab6/kern/slab.c | 169 +++++++++++++ lab6/kern/softirq.c | 45 ++++ lab6/kern/sync.c | 204 ++++++++++++++++ lab6/kern/syscall.S | 60 +++++ lab6/kern/timer.S | 44 ++++ lab6/kern/timer.c | 130 ++++++++++ lab6/lib/dtb.c | 60 +++++ lab6/lib/mailbox.c | 89 +++++++ lab6/lib/reset.c | 16 ++ lab6/lib/startup_alloc.c | 22 ++ lab6/lib/string.c | 114 +++++++++ lab6/lib/uart.c | 176 ++++++++++++++ lab6/lib/user_lib.c | 65 +++++ lab6/raspi3/bcm2710-rpi-3-b-plus.dtb | Bin 0 -> 31790 bytes lab6/raspi3/config.txt | 3 + lab6/rootfs/Makefile | 20 ++ lab6/rootfs/file1 | 1 + lab6/rootfs/file2.txt | 1 + lab6/rootfs/linker.ld | 31 +++ lab6/rootfs/user_prog.S | 14 ++ lab7/Makefile | 58 +++++ lab7/boot/Makefile | 54 +++++ lab7/boot/boot.S | 30 +++ lab7/boot/linker.ld | 43 ++++ lab7/boot/main.c | 42 ++++ lab7/boot/relocate.c | 17 ++ lab7/documentation/mm.md | 29 +++ lab7/documentation/sched.md | 5 + lab7/fs/tmpfs.c | 272 +++++++++++++++++++++ lab7/fs/uartfs.c | 49 ++++ lab7/fs/vfs.c | 258 ++++++++++++++++++++ lab7/include/bitmap.h | 66 ++++++ lab7/include/byteswap.h | 9 + lab7/include/dtb.h | 40 ++++ lab7/include/fs/tmpfs.h | 17 ++ lab7/include/fs/uartfs.h | 6 + lab7/include/fs/vfs.h | 97 ++++++++ lab7/include/kern/cpio.h | 37 +++ lab7/include/kern/fdtable.h | 19 ++ lab7/include/kern/irq.h | 16 ++ lab7/include/kern/kio.h | 32 +++ lab7/include/kern/mm.h | 17 ++ lab7/include/kern/mm_types.h | 48 ++++ lab7/include/kern/page.h | 36 +++ lab7/include/kern/sched.h | 104 ++++++++ lab7/include/kern/shell.h | 22 ++ lab7/include/kern/signal.h | 31 +++ lab7/include/kern/slab.h | 37 +++ lab7/include/kern/softirq.h | 18 ++ lab7/include/kern/sync.h | 20 ++ lab7/include/kern/timer.h | 25 ++ lab7/include/list.h | 134 +++++++++++ lab7/include/mmu.h | 46 ++++ lab7/include/peripheral/arm.h | 13 + lab7/include/peripheral/aux.h | 36 +++ lab7/include/peripheral/gpio.h | 51 ++++ lab7/include/peripheral/interrupt.h | 19 ++ lab7/include/peripheral/mailbox.h | 53 +++++ lab7/include/peripheral/mmio.h | 12 + lab7/include/peripheral/uart.h | 27 +++ lab7/include/reset.h | 12 + lab7/include/startup_alloc.h | 8 + lab7/include/string.h | 15 ++ lab7/include/syscall.h | 51 ++++ lab7/include/test_func.h | 9 + lab7/include/user_lib.h | 6 + lab7/kern/cpio.c | 113 +++++++++ lab7/kern/entry.S | 135 +++++++++++ lab7/kern/exception_vector_table.S | 136 +++++++++++ lab7/kern/fdtable.c | 35 +++ lab7/kern/irq.c | 76 ++++++ lab7/kern/kio.c | 65 +++++ lab7/kern/linker.ld | 44 ++++ lab7/kern/main.c | 95 ++++++++ lab7/kern/mm.c | 242 +++++++++++++++++++ lab7/kern/page.c | 158 ++++++++++++ lab7/kern/sched.S | 41 ++++ lab7/kern/sched.c | 334 ++++++++++++++++++++++++++ lab7/kern/shell.c | 75 ++++++ lab7/kern/signal.c | 113 +++++++++ lab7/kern/slab.c | 169 +++++++++++++ lab7/kern/softirq.c | 45 ++++ lab7/kern/sync.c | 343 +++++++++++++++++++++++++++ lab7/kern/syscall.S | 107 +++++++++ lab7/kern/timer.S | 44 ++++ lab7/kern/timer.c | 130 ++++++++++ lab7/lib/dtb.c | 60 +++++ lab7/lib/mailbox.c | 89 +++++++ lab7/lib/reset.c | 16 ++ lab7/lib/startup_alloc.c | 22 ++ lab7/lib/string.c | 118 +++++++++ lab7/lib/test_func.c | 89 +++++++ lab7/lib/uart.c | 184 ++++++++++++++ lab7/lib/user_lib.c | 65 +++++ lab7/raspi3/bcm2710-rpi-3-b-plus.dtb | Bin 0 -> 31790 bytes lab7/raspi3/config.txt | 3 + lab7/rootfs/Makefile | 20 ++ lab7/rootfs/dir1/file3.txt | 1 + lab7/rootfs/dir1/file5.txt | 1 + lab7/rootfs/file1 | 1 + lab7/rootfs/file2.txt | 1 + lab7/rootfs/linker.ld | 31 +++ lab7/rootfs/user_prog.S | 14 ++ 154 files changed, 9480 insertions(+) create mode 100644 lab6/Makefile create mode 100644 lab6/boot/Makefile create mode 100644 lab6/boot/boot.S create mode 100644 lab6/boot/linker.ld create mode 100644 lab6/boot/main.c create mode 100644 lab6/boot/relocate.c create mode 100644 lab6/documentation/mm.md create mode 100644 lab6/documentation/sched.md create mode 100644 lab6/include/bitmap.h create mode 100644 lab6/include/byteswap.h create mode 100644 lab6/include/dtb.h create mode 100644 lab6/include/kern/cpio.h create mode 100644 lab6/include/kern/irq.h create mode 100644 lab6/include/kern/kio.h create mode 100644 lab6/include/kern/mm.h create mode 100644 lab6/include/kern/mm_types.h create mode 100644 lab6/include/kern/page.h create mode 100644 lab6/include/kern/sched.h create mode 100644 lab6/include/kern/shell.h create mode 100644 lab6/include/kern/signal.h create mode 100644 lab6/include/kern/slab.h create mode 100644 lab6/include/kern/softirq.h create mode 100644 lab6/include/kern/sync.h create mode 100644 lab6/include/kern/timer.h create mode 100644 lab6/include/list.h create mode 100644 lab6/include/mmu.h create mode 100644 lab6/include/peripheral/arm.h create mode 100644 lab6/include/peripheral/aux.h create mode 100644 lab6/include/peripheral/gpio.h create mode 100644 lab6/include/peripheral/interrupt.h create mode 100644 lab6/include/peripheral/mailbox.h create mode 100644 lab6/include/peripheral/mmio.h create mode 100644 lab6/include/peripheral/uart.h create mode 100644 lab6/include/reset.h create mode 100644 lab6/include/startup_alloc.h create mode 100644 lab6/include/string.h create mode 100644 lab6/include/syscall.h create mode 100644 lab6/include/user_lib.h create mode 100644 lab6/kern/cpio.c create mode 100644 lab6/kern/entry.S create mode 100644 lab6/kern/exception_vector_table.S create mode 100644 lab6/kern/irq.c create mode 100644 lab6/kern/kio.c create mode 100644 lab6/kern/linker.ld create mode 100644 lab6/kern/main.c create mode 100644 lab6/kern/mm.c create mode 100644 lab6/kern/page.c create mode 100644 lab6/kern/sched.S create mode 100644 lab6/kern/sched.c create mode 100644 lab6/kern/shell.c create mode 100644 lab6/kern/signal.c create mode 100644 lab6/kern/slab.c create mode 100644 lab6/kern/softirq.c create mode 100644 lab6/kern/sync.c create mode 100644 lab6/kern/syscall.S create mode 100644 lab6/kern/timer.S create mode 100644 lab6/kern/timer.c create mode 100644 lab6/lib/dtb.c create mode 100644 lab6/lib/mailbox.c create mode 100644 lab6/lib/reset.c create mode 100644 lab6/lib/startup_alloc.c create mode 100644 lab6/lib/string.c create mode 100644 lab6/lib/uart.c create mode 100644 lab6/lib/user_lib.c create mode 100644 lab6/raspi3/bcm2710-rpi-3-b-plus.dtb create mode 100644 lab6/raspi3/config.txt create mode 100644 lab6/rootfs/Makefile create mode 100644 lab6/rootfs/file1 create mode 100644 lab6/rootfs/file2.txt create mode 100644 lab6/rootfs/linker.ld create mode 100644 lab6/rootfs/user_prog.S create mode 100644 lab7/Makefile create mode 100644 lab7/boot/Makefile create mode 100644 lab7/boot/boot.S create mode 100644 lab7/boot/linker.ld create mode 100644 lab7/boot/main.c create mode 100644 lab7/boot/relocate.c create mode 100644 lab7/documentation/mm.md create mode 100644 lab7/documentation/sched.md create mode 100644 lab7/fs/tmpfs.c create mode 100644 lab7/fs/uartfs.c create mode 100644 lab7/fs/vfs.c create mode 100644 lab7/include/bitmap.h create mode 100644 lab7/include/byteswap.h create mode 100644 lab7/include/dtb.h create mode 100644 lab7/include/fs/tmpfs.h create mode 100644 lab7/include/fs/uartfs.h create mode 100644 lab7/include/fs/vfs.h create mode 100644 lab7/include/kern/cpio.h create mode 100644 lab7/include/kern/fdtable.h create mode 100644 lab7/include/kern/irq.h create mode 100644 lab7/include/kern/kio.h create mode 100644 lab7/include/kern/mm.h create mode 100644 lab7/include/kern/mm_types.h create mode 100644 lab7/include/kern/page.h create mode 100644 lab7/include/kern/sched.h create mode 100644 lab7/include/kern/shell.h create mode 100644 lab7/include/kern/signal.h create mode 100644 lab7/include/kern/slab.h create mode 100644 lab7/include/kern/softirq.h create mode 100644 lab7/include/kern/sync.h create mode 100644 lab7/include/kern/timer.h create mode 100644 lab7/include/list.h create mode 100644 lab7/include/mmu.h create mode 100644 lab7/include/peripheral/arm.h create mode 100644 lab7/include/peripheral/aux.h create mode 100644 lab7/include/peripheral/gpio.h create mode 100644 lab7/include/peripheral/interrupt.h create mode 100644 lab7/include/peripheral/mailbox.h create mode 100644 lab7/include/peripheral/mmio.h create mode 100644 lab7/include/peripheral/uart.h create mode 100644 lab7/include/reset.h create mode 100644 lab7/include/startup_alloc.h create mode 100644 lab7/include/string.h create mode 100644 lab7/include/syscall.h create mode 100644 lab7/include/test_func.h create mode 100644 lab7/include/user_lib.h create mode 100644 lab7/kern/cpio.c create mode 100644 lab7/kern/entry.S create mode 100644 lab7/kern/exception_vector_table.S create mode 100644 lab7/kern/fdtable.c create mode 100644 lab7/kern/irq.c create mode 100644 lab7/kern/kio.c create mode 100644 lab7/kern/linker.ld create mode 100644 lab7/kern/main.c create mode 100644 lab7/kern/mm.c create mode 100644 lab7/kern/page.c create mode 100644 lab7/kern/sched.S create mode 100644 lab7/kern/sched.c create mode 100644 lab7/kern/shell.c create mode 100644 lab7/kern/signal.c create mode 100644 lab7/kern/slab.c create mode 100644 lab7/kern/softirq.c create mode 100644 lab7/kern/sync.c create mode 100644 lab7/kern/syscall.S create mode 100644 lab7/kern/timer.S create mode 100644 lab7/kern/timer.c create mode 100644 lab7/lib/dtb.c create mode 100644 lab7/lib/mailbox.c create mode 100644 lab7/lib/reset.c create mode 100644 lab7/lib/startup_alloc.c create mode 100644 lab7/lib/string.c create mode 100644 lab7/lib/test_func.c create mode 100644 lab7/lib/uart.c create mode 100644 lab7/lib/user_lib.c create mode 100644 lab7/raspi3/bcm2710-rpi-3-b-plus.dtb create mode 100644 lab7/raspi3/config.txt create mode 100644 lab7/rootfs/Makefile create mode 100644 lab7/rootfs/dir1/file3.txt create mode 100644 lab7/rootfs/dir1/file5.txt create mode 100644 lab7/rootfs/file1 create mode 100644 lab7/rootfs/file2.txt create mode 100644 lab7/rootfs/linker.ld create mode 100644 lab7/rootfs/user_prog.S diff --git a/lab6/Makefile b/lab6/Makefile new file mode 100644 index 000000000..fb08ccf78 --- /dev/null +++ b/lab6/Makefile @@ -0,0 +1,55 @@ +# OSC 2022 +CC = aarch64-linux-gnu-gcc +LD = aarch64-linux-gnu-ld +OBJCOPY = aarch64-linux-gnu-objcopy + + +IMG = kernel8.img +ELF = kernel8.elf +LINKER_FILE = kern/linker.ld + +OUT_DIR = out +INC_DIR = include + +SRCS := $(wildcard kern/*.S) +SRCS += $(wildcard kern/*.c) +SRCS += $(wildcard lib/*.c) +SRCS := $(notdir $(SRCS)) +OBJS := $(patsubst %.c, $(OUT_DIR)/%_c.o, $(SRCS)) +OBJS := $(patsubst %.S, $(OUT_DIR)/%_s.o, $(OBJS)) + +# -fno-stack-protector: to disable stack protection +# -fno-builtin is required to avoid refs to undefined functions in the kernel. +# Only optimize to -O1 to discourage inlining, which complicates backtraces. +CFLAGS := -O1 -fno-builtin -nostdinc +CFLAGS += -Wall -I$(INC_DIR) -c -fno-stack-protector + +.PHONY: asm debug clean run + + +$(IMG): $(ELF) + $(OBJCOPY) -O binary $(ELF) $(IMG) +$(ELF): $(OBJS) $(LINKER_FILE $(OUT_DIR)/boot.o + $(LD) -T $(LINKER_FILE) -o $(ELF) $(OBJS) + +$(OUT_DIR)/%_s.o: kern/%.S $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ +$(OUT_DIR)/%_c.o: kern/%.c $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ +$(OUT_DIR)/%_c.o: lib/%.c $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ + +$(OUT_DIR): + @mkdir -p $(OUT_DIR) + + +asm: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -d in_asm +debug: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -serial null -serial stdio -initrd initramfs.cpio -S -s +run: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -serial null -serial stdio -initrd initramfs.cpio +run-display: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -serial null -serial stdio -initrd initramfs.cpio +clean: + rm -rf $(OUT_DIR) $(ELF) $(IMG) \ No newline at end of file diff --git a/lab6/boot/Makefile b/lab6/boot/Makefile new file mode 100644 index 000000000..aa6ee3b50 --- /dev/null +++ b/lab6/boot/Makefile @@ -0,0 +1,54 @@ +# bootloader +CC = aarch64-linux-gnu-gcc +LD = aarch64-linux-gnu-ld +OBJCOPY = aarch64-linux-gnu-objcopy + + +IMG = bootloader.img +ELF = bootloader.elf + +OUT_DIR = out +INC_DIR = ../include + +SRCS := boot.S \ + relocate.c \ + main.c \ + ../lib/uart.c \ + ../lib/string.c +SRCS := $(notdir $(SRCS)) +OBJS := $(patsubst %.c, $(OUT_DIR)/%.o, $(SRCS)) +OBJS := $(patsubst %.S, $(OUT_DIR)/%.o, $(OBJS)) + +# -fno-stack-protector: to disable stack protection +CFLAGS := -O1 -fno-builtin -nostdinc +CFLAGS += -Wall -I$(INC_DIR) -c -fno-stack-protector + +.PHONY: asm debug clean run pty + + +$(IMG): $(ELF) + $(OBJCOPY) -O binary $(ELF) $(IMG) +$(ELF): $(OBJS) linker.ld $(OUT_DIR)/boot.o + $(LD) -T linker.ld -o $(ELF) $(OBJS) + +$(OUT_DIR)/boot.o: boot.S $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ +$(OUT_DIR)/%.o: %.c $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ +$(OUT_DIR)/%.o: ../lib/%.c $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ + +$(OUT_DIR): + @mkdir -p $(OUT_DIR) + + +asm: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -d in_asm +debug: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -S -s +run: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -serial null -serial stdio +pty: + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -serial null -serial pty -initrd ../initramfs.cpio -dtb ../raspi3/bcm2710-rpi-3-b-plus.dtb +clean: + rm -rf $(OUT_DIR) $(ELF) $(IMG) \ No newline at end of file diff --git a/lab6/boot/boot.S b/lab6/boot/boot.S new file mode 100644 index 000000000..e26a31ce3 --- /dev/null +++ b/lab6/boot/boot.S @@ -0,0 +1,30 @@ +.section ".text.relocate" + +.global _relocate +_relocate: + // save dtb address + mov x23, x0 +2: + ldr x0, = __stack_top + mov sp, x0 + + // clear bss + ldr x0, =__bss_start + ldr x1, =__bss_size +3: cbz x1, 4f + // [x0] = 0, x0 = x0 + 8 + str xzr, [x0], #8 + // x1 = x1 - 1 + sub x1, x1, #1 + cbnz x1, 3b +4: bl relocate + + + +.section ".text.boot" + +.global _start +_start: + bl main +1: wfe + b 1b diff --git a/lab6/boot/linker.ld b/lab6/boot/linker.ld new file mode 100644 index 000000000..723384a45 --- /dev/null +++ b/lab6/boot/linker.ld @@ -0,0 +1,43 @@ +SECTIONS +{ + . = 0x80000; + .relocate : { + KEEP(*(.text.relocate)) + } + + /* Adjust the address for the data segment to the next page */ + . = ALIGN(0x1000); + + __begin = .; + .text : { + KEEP(*(.text.boot)) + *(.text .text.* .gnu.linkonce.t.*) + } + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + . = ALIGN(0x1000); + + /* The data segment */ + .data : { + *(.data) + } + + .bss ALIGN(16) (NOLOAD) : { + PROVIDE(__bss_start = .); + *(.bss) + PROVIDE(__bss_end = .); + BYTE(0) + } + __end = .; + + /DISCARD/ : { + *(.eh_frame .note.GNU-stack) + } +} + +__stack_top = 0x20000000; +__bss_size = (__bss_end - __bss_start) >> 3; +__bootloader = 0x60000; \ No newline at end of file diff --git a/lab6/boot/main.c b/lab6/boot/main.c new file mode 100644 index 000000000..139ba2ec1 --- /dev/null +++ b/lab6/boot/main.c @@ -0,0 +1,42 @@ +#include "peripheral/uart.h" + +#define KERNEL_ADDR 0x80000 +#define READ_INT(var) \ + var = 0; \ + for (i=0 ; i<4 ; i++) {\ + var <<= 8; \ + var |= (int)uart_sync_read_raw(); \ + } \ + +int main() { + int img_size; + int img_checksum; + int i; + + uart_init(); + uart_flush(); + + READ_INT(img_size); + READ_INT(img_checksum); + + uart_sync_printNum(img_size, 10); + uart_sync_puts("\n"); + uart_sync_printNum(img_checksum, 10); + uart_sync_puts("\n"); + + for (i=0 ; i>= 32; + } +#endif + if ((word & 0xffff) == 0) { + num += 16; + word >>= 16; + } + if ((word & 0xff) == 0) { + num += 8; + word >>= 8; + } + if ((word & 0xf) == 0) { + num += 4; + word >>= 4; + } + if ((word & 0x3) == 0) { + num += 2; + word >>= 2; + } + if ((word & 0x1) == 0) + num += 1; + return num; +} + +/* +bitops +*/ +static inline void __set_bit(int nr, volatile unsigned long *addr) { + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *) addr) + BIT_WORD(nr); + *p |= mask; +} + +static inline void __clear_bit(int nr, volatile unsigned long *addr) { + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *) addr) + BIT_WORD(nr); + *p &= ~mask; +} + +#endif \ No newline at end of file diff --git a/lab6/include/byteswap.h b/lab6/include/byteswap.h new file mode 100644 index 000000000..b58305de9 --- /dev/null +++ b/lab6/include/byteswap.h @@ -0,0 +1,9 @@ +#ifndef BYTESWAP_H +#define BYTESWAP_H + +/* Swap bytes in 32-bit value. */ +#define __bswap_32(x) \ + ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) \ + | (((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24)) + +#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..921ef309b --- /dev/null +++ b/lab6/include/dtb.h @@ -0,0 +1,40 @@ +#ifndef DTB_H +#define DTB_H + +// #define FDT_HEADER_MAGIC 0xd00dfeed +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + +// All the header fields are stored in big-endian format +struct fdt_header { + unsigned int magic; + unsigned int totalsize; + unsigned int off_dt_struct; + unsigned int off_dt_strings; + unsigned int off_mem_rsvmap; + unsigned int version; + unsigned int last_comp_version; + unsigned int boot_cpuid_phys; + unsigned int size_dt_strings; + unsigned int size_dt_struct; +}; + +struct fdt_reserve_entry { + unsigned long long address; + unsigned long long size; +}; + +struct fdt_prop { + unsigned int len; + unsigned int nameoff; +}; + +int fdt_init(); +int fdt_traverse(void (*cb)(char *, char *, void *)); + +void fdt_reserve(); + +#endif \ No newline at end of file diff --git a/lab6/include/kern/cpio.h b/lab6/include/kern/cpio.h new file mode 100644 index 000000000..5bddbb739 --- /dev/null +++ b/lab6/include/kern/cpio.h @@ -0,0 +1,35 @@ +#ifndef CPIO_H +#define CPIO_H + +// #define CPIO_ADDRESS (void*)0x8000000 + +#define CPIO_MAGIC "070701" +#define CPIO_END "TRAILER!!!" + +// New ASCII Format +struct cpio_newc_header { + char c_magic[6]; + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[8]; + char c_filesize[8]; + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char sc_rdevminor[8]; + char c_namesize[8]; + char c_check[8]; +}; + +void initramfs_callback(char *node_name, char *prop_name, void *prop_value); +void cpio_ls(); +void cpio_cat(const char *filename); +void cpio_exec(const char *filename); +char* cpio_find(const char *filename); + +void cpio_reserve(); + +#endif \ No newline at end of file diff --git a/lab6/include/kern/irq.h b/lab6/include/kern/irq.h new file mode 100644 index 000000000..6be242108 --- /dev/null +++ b/lab6/include/kern/irq.h @@ -0,0 +1,16 @@ +#ifndef IRQ_H +#define IRQ_H + +struct trapframe { + long x[31]; + long sp_el0; + long spsr_el1; + long elr_el1; +}; + +void int_enable(); +void int_disable(); + +void int_init(); + +#endif \ No newline at end of file diff --git a/lab6/include/kern/kio.h b/lab6/include/kern/kio.h new file mode 100644 index 000000000..e2d90fcb9 --- /dev/null +++ b/lab6/include/kern/kio.h @@ -0,0 +1,32 @@ +#ifndef KIO_H +#define KIO_H + +#include "peripheral/uart.h" + +static inline void kio_init() { + uart_init(); + uart_flush(); + uart_enable_int(); +} + +static inline void kputc(char c) +{ + uart_async_write(c); +} + +static inline void kputs(char *s) +{ + uart_async_puts(s); +} + +static inline void kflush() { + uart_write_flush(); +} + +static inline char kscanc() { + return uart_async_read(); +} + +void kprintf(char* fmt, ...); + +#endif \ No newline at end of file diff --git a/lab6/include/kern/mm.h b/lab6/include/kern/mm.h new file mode 100644 index 000000000..7e1b7035c --- /dev/null +++ b/lab6/include/kern/mm.h @@ -0,0 +1,17 @@ +#ifndef MM_H +#define MM_H + +#include "kern/mm_types.h" +#include "kern/slab.h" + +void mm_reserve(void *start, void *end); + +void mm_callback(char *node_name, char *prop_name, void *prop_value); + +void mm_init(); + +struct page* get_page_from_addr(void *addr); +struct page* alloc_pages(unsigned int order); +void free_pages(void *addr); + +#endif \ No newline at end of file diff --git a/lab6/include/kern/mm_types.h b/lab6/include/kern/mm_types.h new file mode 100644 index 000000000..1cedcdfd7 --- /dev/null +++ b/lab6/include/kern/mm_types.h @@ -0,0 +1,48 @@ +#ifndef MM_TYPES_H +#define MM_TYPES_H + +#include "list.h" + +#define MEM_TOTAL 0x40000000 +#define MEM_LIMIT 0x3B400000 + +struct free_area { + struct list_head free_list; + unsigned int nr_free; + unsigned int order; +}; + +#define PG_USED 0 +#define PG_HEAD 1 +#define PG_TAIL 2 +#define PG_SLAB 3 + +struct page { + unsigned int flags; + unsigned int pg_index; + unsigned int compound_order; + + struct slab_t *slab; + + struct list_head list; +}; + +struct mm_struct { + unsigned long *pgd; +}; + + +#include "kern/page.h" + +#define MAX_ORDER 10 + +#define PHY_FRAMES_NUM (MEM_TOTAL / PAGE_SIZE) + +#define PFN_2_PHY(pfn) (long)( pfn << PAGE_SHIFT ) +#define PHY_2_PFN(adr) ((long)adr >> PAGE_SHIFT ) + +// kernel space address translation +#define VIRT_2_PHY(vaddr) ((long)vaddr & 0x0000ffffffffffff) +#define PHY_2_VIRT(vaddr) ((long)vaddr | 0xffff000000000000) + +#endif \ No newline at end of file diff --git a/lab6/include/kern/page.h b/lab6/include/kern/page.h new file mode 100644 index 000000000..c426dac2e --- /dev/null +++ b/lab6/include/kern/page.h @@ -0,0 +1,35 @@ +#ifndef PAGE_H +#define PAGE_H + +#define PAGE_SIZE 4096 +#define PAGE_SHIFT 12 +#define PAGE_MASK (~(PAGE_SIZE-1)) + + +#define PGD_SHIFT 39 +#define PUD_SHIFT 30 +#define PMD_SHIFT 21 + +#define PTRS_PER_PGD 512 +#define PTRS_PER_PUD 512 +#define PTRS_PER_PMD 512 +#define PTRS_PER_PTE 512 + +#define pgd_index(vaddr) (((vaddr) >> PGD_SHIFT) & (PTRS_PER_PGD - 1)) +#define pgd_offset(mm, vaddr) ((mm)->pgd + pgd_index(vaddr)) + +#define pud_index(vaddr) (((vaddr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)) + +#define pmd_index(vaddr) (((vaddr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) + +#define pte_index(vaddr) (((vaddr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) + +void create_pgd(struct mm_struct *mm); +void free_pgd(struct mm_struct *mm); + +void *walk(struct mm_struct *mm, unsigned long vaddr, unsigned long paddr); +void *mappages(struct mm_struct *mm, unsigned long vaddr, unsigned long size, unsigned long paddr); + +void identity_paging(struct mm_struct *mm, unsigned long vaddr, unsigned long paddr); + +#endif \ No newline at end of file diff --git a/lab6/include/kern/sched.h b/lab6/include/kern/sched.h new file mode 100644 index 000000000..67c1a1549 --- /dev/null +++ b/lab6/include/kern/sched.h @@ -0,0 +1,98 @@ +#ifndef SCHED_H +#define SCHED_H + +#include "list.h" +#include "bitmap.h" +#include "signal.h" +#include "mm_types.h" + +#define MAX_PRIV_TASK_NUM 50 +#define TASK_CTIME 1 + +enum task_state { + RUNNING, READY, WAITING, INT, DEAD +}; + +struct task_context { + long x19; + long x20; + long x21; + long x22; + long x23; + long x24; + long x25; + long x26; + long x27; + long x28; + long fp; + long lr; + long sp; +}; + +struct task_struct { + + int tid; + int used; + + enum task_state state; + + int prio; + + int ctime; + int resched; + + void *stk_addr; + void *ustk_addr; + + struct list_head signal_list; + struct list_head signal_pend_list; + struct signal_context_t *signal_context; + struct task_context task_context; + + struct mm_struct mm; + + struct list_head list; +}; + +#define MAX_PRIO 128 + +static inline int sched_find_first_bit(const unsigned long *b) { + if (b[0]) + return __ffs(b[0]); + if (b[1]) + return __ffs(b[1]) + 64; + return 128; +} + +void task_init(); +void runqueue_init(); +struct task_struct *privilege_task_create(void (*func)(), int prio); +struct task_struct *task_create(void (*func)(), int prio); + +void schedule(); +void kill_zombies(); + +void switch_to(struct task_context *prev, struct task_context *next); +void update_current(struct task_struct *task); +void update_pgd(unsigned long pgd); +struct task_struct* get_current(); +struct task_struct* get_task_struct(int pid); + +int __getpid(); +void __exec(const char *name, char *const argv[]); +int __fork(void *trapframe); +void __exit(); +void __kill(int pid); + +void do_exec(void (*func)()); + +static inline void thread_create(void (*func)()) { + task_create(func, 100); +} + +#define USER_STK_HIGH 0xfffffffff000 +#define USER_STK_LOW 0xffffffffb000 + +#define STACKSIZE 16384 // 4096 * 4 + +#endif \ No newline at end of file diff --git a/lab6/include/kern/shell.h b/lab6/include/kern/shell.h new file mode 100644 index 000000000..398dc84b8 --- /dev/null +++ b/lab6/include/kern/shell.h @@ -0,0 +1,22 @@ +#ifndef SHELL_H +#define SHELL_H + +#define BACKSPACE 8 +#define ESC 27 +#define DELETE 127 + +#define LEFT_SHIFT kputc(ESC); \ + kputc('['); \ + kputc('D'); + +#define RIGHT_SHIFT kputc(ESC); \ + kputc('['); \ + kputc('C'); + +#define MAX_INPUT_LEN 128 + +void shell_input(char *cmd); +void shell_parse(char *cmd); +void shell_start(); + +#endif \ No newline at end of file diff --git a/lab6/include/kern/signal.h b/lab6/include/kern/signal.h new file mode 100644 index 000000000..23c25504f --- /dev/null +++ b/lab6/include/kern/signal.h @@ -0,0 +1,31 @@ +#ifndef SIGNAL_H +#define SIGNAL_H + +#include "list.h" + +#define SIGKILL 9 + +struct signal_t { + int num; + void (*handler)(); + struct list_head list; +}; + +struct signal_pend_t { + int num; + struct list_head list; +}; + +struct signal_context_t { + void *trapframe; + void *stk_addr; +}; + +struct signal_t *signal_create(int SIGNAL, void (*handler)()); +void signal_back(void *trapframe); +void signal_run(); + +void __signal(int SIGNAL, void (*handler)()); +void __sigkill(int pid, int SIGNAL, void *trapframe); + +#endif \ No newline at end of file diff --git a/lab6/include/kern/slab.h b/lab6/include/kern/slab.h new file mode 100644 index 000000000..24c5bba6d --- /dev/null +++ b/lab6/include/kern/slab.h @@ -0,0 +1,37 @@ +#ifndef SLAB_H +#define SLAB_H + +#include "list.h" + +/* + Fixed object size to multiple of 8 if object size less than 128. (16 pools) + Fixed object size to multiple of 12 for next 8 pools. + The remaining pool contain arbitrary size object. (224 bytes ~ 4096 bytes) +*/ +#define MAX_OBJ_CACHE_NUM 40 +#define SMALL_OBJ_SIZE 128 +#define MEDIUM_OBJ_SIZE 224 + +struct kmem_pool { + int object_size; // -1 indicate free + unsigned int gfporder; + unsigned int num; // object per slab + + struct list_head slab_list; +}; + +struct slab_t { + unsigned int inuse; + unsigned int nr_free; + void *head_addr; + struct list_head free_list; + + struct list_head list; +}; + +void slab_init(); + +void* kmalloc(unsigned int size); +void kfree(void *addr); + +#endif \ No newline at end of file diff --git a/lab6/include/kern/softirq.h b/lab6/include/kern/softirq.h new file mode 100644 index 000000000..b840fd690 --- /dev/null +++ b/lab6/include/kern/softirq.h @@ -0,0 +1,18 @@ +#ifndef SOFTIRQ_H +#define SOFTIRQ_H + +#define SOFTIRQ_NUM 64 + +#define SOFTIRQ_TIMER 1 +#define SOFTIRQ_UART 2 + +enum irq_state { + IRQ_RUNNING, IRQ_READY, IRQ_IDLE +}; + +void softirq_init(); +void softirq_register(void (*cb)(), int num); +void softirq_active(int num); +void softirq_run(); + +#endif diff --git a/lab6/include/kern/sync.h b/lab6/include/kern/sync.h new file mode 100644 index 000000000..0e6cee841 --- /dev/null +++ b/lab6/include/kern/sync.h @@ -0,0 +1,20 @@ +#ifndef SYNC_H +#define SYNC_H + +/* + ESR-EL1 +*/ +#define EC_BITS(esr_el1) ((esr_el1 >> 26) & 0b111111) +#define EC_SVC_32 0b010001 +#define EC_SVC_64 0b010101 +#define EC_IA_EL0 0b100000 +#define EC_IA_EL1 0b100001 +#define EC_DA_EL0 0b100100 +#define EC_DA_EL1 0b100101 + +#define IFSC(esr_el1) (esr_el1 & 0b111111) +#define DFSC(esr_el1) (esr_el1 & 0b111111) + +#define TRANS_FAULT_0 0b000100 + +#endif diff --git a/lab6/include/kern/timer.h b/lab6/include/kern/timer.h new file mode 100644 index 000000000..c33f0e1df --- /dev/null +++ b/lab6/include/kern/timer.h @@ -0,0 +1,25 @@ +#ifndef TIMER_H +#define TIMER_H + +struct timer_queue { + unsigned long register_time; + unsigned int duration; + char message[128]; + struct timer_queue *prev; + struct timer_queue *next; + void (*callback)(char *, unsigned long); +}; + +void timer_el0_handler(); +void timer_el1_handler(); +void timer_unknown_handler(); +void timer_init(); +void set_timeout(char *args); + +extern void core_timer_enable(); +extern void core_timer_disable(); +extern void timer_enable_int(); +extern void timer_disable_int(); +extern void timer_sched_latency(); + +#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..4cc825c8a --- /dev/null +++ b/lab6/include/list.h @@ -0,0 +1,134 @@ +#ifndef LIST_H +#define LIST_H + +struct list_head { + struct list_head *prev; + struct list_head *next; +}; + +#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; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +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; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = entry; + entry->prev = entry; +} + +/** + * 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; pos != (head); pos = pos->next) + +#define list_for_each_back(pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + + +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define list_entry(ptr,type,member) \ + container_of(ptr, type, member) + +#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..69b68e35f --- /dev/null +++ b/lab6/include/mmu.h @@ -0,0 +1,46 @@ +#ifndef MMU_H +#define MMU_H + + +#define KERNEL_VA_BASE 0xffff000000000000 + +/* + TCR +*/ +#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) + +/* + MAIR + Device memory 0b0000dd00 + Normal memory 0booooiiii, (oooo != 0000 and iiii != 0000) + oooo == 0b0100 Outer Non-cacheable (L2) + iiii == 0b0100 Inner Non-cacheable (L1) +*/ +#define MAIR_DEVICE_nGnRnE 0b00000000 +#define MAIR_NORMAL_NOCACHE 0b01000100 +#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_NORMAL_NOCACHE 1 +#define MAIR_CONFIG_DEFAULT ((MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8))) + +/* + Page’s Descriptor +*/ +#define PD_TABLE 0b11 +#define PD_BLOCK 0b01 +#define PD_PAGE 0b11 + +#define PD_USER_RW (0b01 << 6) + +#define PD_ACCESS (1 << 10) + +#define PGD0_ATTR PD_TABLE +#define PUD0_ATTR PD_TABLE +#define PUD1_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK) +#define PMD0_ATTR PD_TABLE +#define PTE_DEVICE_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_PAGE) +#define PTE_NORMAL_ATTR (PD_ACCESS | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_PAGE) +#define PTE_NORMAL_LAZY_ATTR ((MAIR_IDX_NORMAL_NOCACHE << 2) | PD_PAGE) + +#endif \ No newline at end of file diff --git a/lab6/include/peripheral/arm.h b/lab6/include/peripheral/arm.h new file mode 100644 index 000000000..ed2784ae7 --- /dev/null +++ b/lab6/include/peripheral/arm.h @@ -0,0 +1,13 @@ +#ifndef ARM_H +#define ARM_H + +#include "mmu.h" + +#define ARM_PERI_BASE (KERNEL_VA_BASE | 0x40000000) + +#define CORE0_TIMER_IRQ_CTRL (ARM_PERI_BASE + 0x40) + +// QA7_rev3.4 p.7 +#define CORE0_IRQ_SRC ((volatile unsigned int*)(ARM_PERI_BASE + 0x60)) + +#endif \ No newline at end of file diff --git a/lab6/include/peripheral/aux.h b/lab6/include/peripheral/aux.h new file mode 100644 index 000000000..a854b68f8 --- /dev/null +++ b/lab6/include/peripheral/aux.h @@ -0,0 +1,36 @@ +#ifndef AUX_H +#define AUX_H + +#include "mmio.h" + +// spec p.8 +// start at 0x7E21,5000 +#define AUX_BASE (MMIO_BASE + 0x215000) + +#define AUX_IRQ ((volatile unsigned int*)(AUX_BASE + 0x00)) +#define AUX_ENABLES ((volatile unsigned int*)(AUX_BASE + 0x04)) +#define AUX_MU_IO ((volatile unsigned int*)(AUX_BASE + 0x40)) +#define AUX_MU_IER ((volatile unsigned int*)(AUX_BASE + 0x44)) +#define AUX_MU_IIR ((volatile unsigned int*)(AUX_BASE + 0x48)) +#define AUX_MU_LCR ((volatile unsigned int*)(AUX_BASE + 0x4C)) +#define AUX_MU_MCR ((volatile unsigned int*)(AUX_BASE + 0x50)) +#define AUX_MU_LSR ((volatile unsigned int*)(AUX_BASE + 0x54)) +#define AUX_MU_MSR ((volatile unsigned int*)(AUX_BASE + 0x58)) +#define AUX_MU_SCRATCH ((volatile unsigned int*)(AUX_BASE + 0x5C)) +#define AUX_MU_CNTL ((volatile unsigned int*)(AUX_BASE + 0x60)) +#define AUX_MU_STAT ((volatile unsigned int*)(AUX_BASE + 0x64)) +#define AUX_MU_BAUD ((volatile unsigned int*)(AUX_BASE + 0x68)) +#define AUX_SPI0_CNTL0 ((volatile unsigned int*)(AUX_BASE + 0x80)) +#define AUX_SPI0_CNTL1 ((volatile unsigned int*)(AUX_BASE + 0x84)) +#define AUX_SPI0_STAT ((volatile unsigned int*)(AUX_BASE + 0x88)) +#define AUX_SPI0_IO ((volatile unsigned int*)(AUX_BASE + 0x90)) +#define AUX_SPI0_PEEK ((volatile unsigned int*)(AUX_BASE + 0x94)) +#define AUX_SPI1_CNTL0 ((volatile unsigned int*)(AUX_BASE + 0xC0)) +#define AUX_SPI1_CNTL1 ((volatile unsigned int*)(AUX_BASE + 0xC4)) +#define AUX_SPI1_STAT ((volatile unsigned int*)(AUX_BASE + 0xC8)) +#define AUX_SPI1_IO ((volatile unsigned int*)(AUX_BASE + 0xD0)) +#define AUX_SPI1_PEEK ((volatile unsigned int*)(AUX_BASE + 0xD4)) + +#define AUX_INT (1 << 29) + +#endif \ No newline at end of file diff --git a/lab6/include/peripheral/gpio.h b/lab6/include/peripheral/gpio.h new file mode 100644 index 000000000..596db3d74 --- /dev/null +++ b/lab6/include/peripheral/gpio.h @@ -0,0 +1,51 @@ +#ifndef GPIO_H +#define GPIO_H + +#include "mmio.h" + +// spec p.90 +// start at 0x7E20,0000 +#define GPIO_BASE (MMIO_BASE + 0x200000) + +#define GPFSEL0 ((volatile unsigned int*)(GPIO_BASE + 0x00)) +#define GPFSEL1 ((volatile unsigned int*)(GPIO_BASE + 0x04)) +#define GPFSEL2 ((volatile unsigned int*)(GPIO_BASE + 0x08)) +#define GPFSEL3 ((volatile unsigned int*)(GPIO_BASE + 0x0C)) +#define GPFSEL4 ((volatile unsigned int*)(GPIO_BASE + 0x10)) +#define GPFSEL5 ((volatile unsigned int*)(GPIO_BASE + 0x14)) +// 0x18 Reserved +#define GPSET0 ((volatile unsigned int*)(GPIO_BASE + 0x1C)) +#define GPSET1 ((volatile unsigned int*)(GPIO_BASE + 0x20)) +// 0x24 Reserved +#define GPCLR0 ((volatile unsigned int*)(GPIO_BASE + 0x28)) +#define GPCLR1 ((volatile unsigned int*)(GPIO_BASE + 0x2C)) +// 0x30 Reserved +#define GPLEV0 ((volatile unsigned int*)(GPIO_BASE + 0x34)) +#define GPLEV1 ((volatile unsigned int*)(GPIO_BASE + 0x38)) +// 0x3C Reserved +#define GPEDS0 ((volatile unsigned int*)(GPIO_BASE + 0x40)) +#define GPEDS1 ((volatile unsigned int*)(GPIO_BASE + 0x44)) +// 0x48 Reserved +#define GPREN0 ((volatile unsigned int*)(GPIO_BASE + 0x4C)) +#define GPREN1 ((volatile unsigned int*)(GPIO_BASE + 0x50)) +// 0x54 Reserved +#define GPFEN0 ((volatile unsigned int*)(GPIO_BASE + 0x58)) +#define GPFEN1 ((volatile unsigned int*)(GPIO_BASE + 0x5C)) +// 0x60 Reserved +#define GPHEN0 ((volatile unsigned int*)(GPIO_BASE + 0x64)) +#define GPHEN1 ((volatile unsigned int*)(GPIO_BASE + 0x68)) +// 0x6C Reserved +#define GPLEN0 ((volatile unsigned int*)(GPIO_BASE + 0x70)) +#define GPLEN1 ((volatile unsigned int*)(GPIO_BASE + 0x74)) +// 0x78 Reserved +#define GPAREN0 ((volatile unsigned int*)(GPIO_BASE + 0x7C)) +#define GPAREN1 ((volatile unsigned int*)(GPIO_BASE + 0x80)) +// 0x84 Reserved +#define GPAFEN0 ((volatile unsigned int*)(GPIO_BASE + 0x88)) +#define GPAFEN1 ((volatile unsigned int*)(GPIO_BASE + 0x8C)) +// 0x90 Reserved +#define GPPUD ((volatile unsigned int*)(GPIO_BASE + 0x94)) +#define GPPUDCLK0 ((volatile unsigned int*)(GPIO_BASE + 0x98)) +#define GPPUDCLK1 ((volatile unsigned int*)(GPIO_BASE + 0x9C)) + +#endif \ No newline at end of file diff --git a/lab6/include/peripheral/interrupt.h b/lab6/include/peripheral/interrupt.h new file mode 100644 index 000000000..5bcfd69da --- /dev/null +++ b/lab6/include/peripheral/interrupt.h @@ -0,0 +1,19 @@ +#ifndef IRQ_H +#define IRQ_H + +#include "mmio.h" + +// spec p.112 +// start at 0x7E00,B000 +#define INT_BASE (MMIO_BASE + 0xB000) + +#define IRQ_PENDING_1 ((volatile unsigned int*)(INT_BASE + 0x204)) +#define IRQ_PENDING_2 ((volatile unsigned int*)(INT_BASE + 0x208)) +#define ENABLE_IRQS_1 ((volatile unsigned int*)(INT_BASE + 0x210)) +#define ENABLE_IRQS_2 ((volatile unsigned int*)(INT_BASE + 0x214)) +#define ENABLE_BASIC_IRQS ((volatile unsigned int*)(INT_BASE + 0x218)) +#define DISABLE_IRQS_1 ((volatile unsigned int*)(INT_BASE + 0x21C)) +#define DISABLE_IRQS_2 ((volatile unsigned int*)(INT_BASE + 0x220)) +#define DISABLE_BASIC_IRQS ((volatile unsigned int*)(INT_BASE + 0x224)) + +#endif \ No newline at end of file diff --git a/lab6/include/peripheral/mailbox.h b/lab6/include/peripheral/mailbox.h new file mode 100644 index 000000000..26333553f --- /dev/null +++ b/lab6/include/peripheral/mailbox.h @@ -0,0 +1,53 @@ +#ifndef MAILBOX_H +#define MAILBOX_H + +#include "mmio.h" + +#define MAILBOX_BASE (MMIO_BASE + 0xb880) + +#define MAILBOX_READ ((volatile unsigned int*)(MAILBOX_BASE)) +#define MAILBOX_STATUS ((volatile unsigned int*)(MAILBOX_BASE + 0x18)) +#define MAILBOX_WRITE ((volatile unsigned int*)(MAILBOX_BASE + 0x20)) + +#define MAILBOX_EMPTY 0x40000000 +#define MAILBOX_FULL 0x80000000 + +// Tag +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_MEMORY 0x00010005 +#define REQUEST_CODE 0x00000000 +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +/* +Mailbox 0 defines the following channels: + +0: Power management +1: Framebuffer +2: Virtual UART +3: VCHIQ +4: LEDs +5: Buttons +6: Touch screen +7: +8: Property tags (ARM -> VC) +9: Property tags (VC -> ARM) +*/ +#define MAILBOX_CH_PM 0 +#define MAILBOX_CH_FB 1 +#define MAILBOX_CH_VUART 2 +#define MAILBOX_CH_VCHIQ 3 +#define MAILBOX_CH_LEDS 4 +#define MAILBOX_CH_BTNS 5 +#define MAILBOX_CH_TS 6 +// 7 +#define MAILBOX_CH_ARM2VC 8 +#define MAILBOX_CH_VC2ARM 9 + +unsigned int mailbox_call(unsigned char ch, unsigned int* mailbox); +void get_board_revision(unsigned int *result); +void get_ARM_memory(unsigned int *result); + +#endif \ No newline at end of file diff --git a/lab6/include/peripheral/mmio.h b/lab6/include/peripheral/mmio.h new file mode 100644 index 000000000..f78c3953d --- /dev/null +++ b/lab6/include/peripheral/mmio.h @@ -0,0 +1,8 @@ +#ifndef MMIO_H +#define MMIO_H + +#include "mmu.h" + +#define MMIO_BASE (KERNEL_VA_BASE | 0x3F000000) // -> 0x7E00,0000 + +#endif \ No newline at end of file diff --git a/lab6/include/peripheral/uart.h b/lab6/include/peripheral/uart.h new file mode 100644 index 000000000..174f8e6ee --- /dev/null +++ b/lab6/include/peripheral/uart.h @@ -0,0 +1,27 @@ +#ifndef UART_H +#define UART_H + +void uart_init(); + +void uart_enable_int(); +void uart_disable_int(); +void uart_int_handler(); + +char uart_sync_read(); +char uart_sync_read_raw(); +void uart_sync_write(unsigned int c); +void uart_sync_puts(char *s); +void uart_sync_printNum(long num, int base); + +char uart_async_read(); +void uart_async_write(unsigned int c); +void uart_async_puts(char *s); + +void uart_flush(); +void uart_write_flush(); + + +#define ENABLE_IRQS_1_AUX (*ENABLE_IRQS_1 |= AUX_INT) +#define DISABLE_IRQS_1_AUX (*DISABLE_IRQS_1 |= AUX_INT) + +#endif \ No newline at end of file diff --git a/lab6/include/reset.h b/lab6/include/reset.h new file mode 100644 index 000000000..122fca62a --- /dev/null +++ b/lab6/include/reset.h @@ -0,0 +1,12 @@ +#ifndef RESET_H +#define RESET_H + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +void set(long addr, unsigned int value); +void reset(int tick); +void cancel_reset(); + +#endif \ No newline at end of file diff --git a/lab6/include/startup_alloc.h b/lab6/include/startup_alloc.h new file mode 100644 index 000000000..f62ce6003 --- /dev/null +++ b/lab6/include/startup_alloc.h @@ -0,0 +1,8 @@ +#ifndef STARTUP_ALLOC +#define STARTUP_ALLOC + +void* sumalloc(unsigned int size); + +void reserved_kern_startup(); + +#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..ea4e4b664 --- /dev/null +++ b/lab6/include/string.h @@ -0,0 +1,14 @@ +#ifndef STRING_H +#define STRING_H + +unsigned int strlen (const char *str); +int strcmp (const char *p1, const char *p2); +int strncmp (const char *s1, const char *s2, unsigned int len); + +int itoa(long num, char* str, int base); +long atoi(char* str, int base, unsigned int len); + +void* memcpy (void* dest, const void* src, unsigned int len); +void* memset (void* dest, int val, unsigned int len); + +#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..9c1f27b61 --- /dev/null +++ b/lab6/include/syscall.h @@ -0,0 +1,26 @@ +#ifndef SYSCALL_H +#define SYSCALL_H + +#define SYS_GET_PID 0 +#define SYS_UART_READ 1 +#define SYS_UART_WRITE 2 +#define SYS_EXEC 3 +#define SYS_FORK 4 +#define SYS_EXIT 5 +#define SYS_MBOX_CALL 6 +#define SYS_KILL 7 +#define SYS_SIGNAL 8 +#define SYS_SIGKILL 9 + +int getpid(); +int uart_read(char buf[], int size); +int uart_write(const char buf[], int size); +int exec(const char *name, char *const argv[]); +int fork(); +void exit(); +int mbox_call(unsigned char ch, unsigned int *mbox); +void kill(int pid); +void signal(int SIGNAL, void (*handler)()); +void sigkill(int pid, int SIGNAL); + +#endif \ No newline at end of file diff --git a/lab6/include/user_lib.h b/lab6/include/user_lib.h new file mode 100644 index 000000000..d8ec88fdf --- /dev/null +++ b/lab6/include/user_lib.h @@ -0,0 +1,6 @@ +#ifndef USER_LIB_H +#define USER_LIB_H + +void printf(char *fmt, ...); + +#endif \ No newline at end of file diff --git a/lab6/kern/cpio.c b/lab6/kern/cpio.c new file mode 100644 index 000000000..01d6c4f89 --- /dev/null +++ b/lab6/kern/cpio.c @@ -0,0 +1,139 @@ +#include "kern/kio.h" +#include "kern/mm.h" +#include "kern/cpio.h" +#include "kern/sched.h" +#include "string.h" +#include "byteswap.h" + +// qemu default address +void *CPIO_ADDRESS = (void*)PHY_2_VIRT(0x8000000); +void *CPIO_END_ADR = 0; // wired bugs in physical machine + +void initramfs_callback(char *node_name, char *prop_name, void *prop_value) { + if (!strncmp(node_name, "chosen", 6) && !strncmp(prop_name, "linux,initrd-start", 18)) { + kputs("cpio: Find!\n"); + CPIO_ADDRESS = (void*)(__bswap_32(*((unsigned int *)(prop_value)))); + CPIO_ADDRESS = PHY_2_VIRT(CPIO_ADDRESS); + } +} + +void cpio_ls() { + int i = 0; + int filesize = 0; + int namesize = 0; + struct cpio_newc_header *header; + + for ( ; ; i+=namesize+filesize) { + header = ((struct cpio_newc_header *)(CPIO_ADDRESS + i)); + if (strncmp(header->c_magic, CPIO_MAGIC, 6)) { + kputs("cpio: Bad magic\n"); + break; + } + filesize = (atoi(header->c_filesize, 16, 8) + 3) & -4; + namesize = ((atoi(header->c_namesize, 16, 8) + 6 + 3) & -4) - 6; + i += sizeof(struct cpio_newc_header); + if (!strncmp((char *)(CPIO_ADDRESS + i), CPIO_END, 10)) + break; + kprintf("%s\n", (char *)(CPIO_ADDRESS + i)); + } +} + +void cpio_cat(const char *filename) { + int i = 0; + int filesize = 0; + int namesize = 0; + struct cpio_newc_header *header; + + for ( ; ; i+=namesize+filesize) { + header = ((struct cpio_newc_header *)(CPIO_ADDRESS + i)); + if (strncmp(header->c_magic, CPIO_MAGIC, 6)) { + kputs("cpio: Bad magic\n"); + break; + } + filesize = (atoi(header->c_filesize, 16, 8) + 3) & -4; + namesize = ((atoi(header->c_namesize, 16, 8) + 6 + 3) & -4) - 6; + i += sizeof(struct cpio_newc_header); + if (!strcmp((char *)(CPIO_ADDRESS + i), filename)) { + kprintf("%s\n", (char *)(CPIO_ADDRESS + i + namesize)); + return; + } + if (!strncmp((char *)(CPIO_ADDRESS + i), CPIO_END, 10)) + break; + } + kputs("File not exists...\n"); +} + +void cpio_exec(const char *filename) { + int i = 0; + int filesize = 0; + int namesize = 0; + struct cpio_newc_header *header; + + for ( ; ; i+=namesize+filesize) { + header = ((struct cpio_newc_header *)(CPIO_ADDRESS + i)); + if (strncmp(header->c_magic, CPIO_MAGIC, 6)) { + kputs("cpio: Bad magic\n"); + break; + } + filesize = (atoi(header->c_filesize, 16, 8) + 3) & -4; + namesize = ((atoi(header->c_namesize, 16, 8) + 6 + 3) & -4) - 6; + i += sizeof(struct cpio_newc_header); + if (!strcmp((char *)(CPIO_ADDRESS + i), filename)) + break; + if (!strncmp((char *)(CPIO_ADDRESS + i), CPIO_END, 10)) { + kputs("File not exists...\n"); + return; + } + } + i += namesize; + + do_exec(CPIO_ADDRESS + i); +} + +char* cpio_find(const char *filename) { + int i = 0; + int filesize = 0; + int namesize = 0; + struct cpio_newc_header *header; + + for ( ; ; i+=namesize+filesize) { + header = ((struct cpio_newc_header *)(CPIO_ADDRESS + i)); + if (strncmp(header->c_magic, CPIO_MAGIC, 6)) { + kputs("cpio: Bad magic\n"); + break; + } + filesize = (atoi(header->c_filesize, 16, 8) + 3) & -4; + namesize = ((atoi(header->c_namesize, 16, 8) + 6 + 3) & -4) - 6; + i += sizeof(struct cpio_newc_header); + if (!strcmp((char *)(CPIO_ADDRESS + i), filename)) + break; + if (!strncmp((char *)(CPIO_ADDRESS + i), CPIO_END, 10)) { + kputs("File not exists...\n"); + return 0; + } + } + i += namesize; + + return CPIO_ADDRESS + i; +} + +void cpio_reserve() { + int i = 0; + int filesize = 0; + int namesize = 0; + struct cpio_newc_header *header; + + for ( ; ; i+=namesize+filesize) { + header = ((struct cpio_newc_header *)(CPIO_ADDRESS + i)); + if (strncmp(header->c_magic, CPIO_MAGIC, 6)) { + kputs("cpio: Bad magic\n"); + break; + } + filesize = (atoi(header->c_filesize, 16, 8) + 3) & -4; + namesize = ((atoi(header->c_namesize, 16, 8) + 6 + 3) & -4) - 6; + i += sizeof(struct cpio_newc_header); + if (!strncmp((char *)(CPIO_ADDRESS + i), CPIO_END, 10)) + break; + } + mm_reserve(CPIO_ADDRESS, CPIO_ADDRESS+i); +} \ No newline at end of file diff --git a/lab6/kern/entry.S b/lab6/kern/entry.S new file mode 100644 index 000000000..abff6c254 --- /dev/null +++ b/lab6/kern/entry.S @@ -0,0 +1,135 @@ +#include "mmu.h" + +.section ".text.entry" + +.global _start +_start: + bl from_el2_to_el1 + +el1_start: + // Set up TCR_EL1 + ldr x0, =TCR_CONFIG_DEFAULT + msr tcr_el1, x0 + + // Set up mair_el1 + ldr x0, =MAIR_CONFIG_DEFAULT + msr mair_el1, x0 + + bl pgtable_create + + mrs x2, sctlr_el1 + orr x2, x2, #1 + msr sctlr_el1, x2 // enable MMU, cache remains disabled + + // indirect branch + ldr x0, =mmu_open + br x0 + +mmu_open: + // clear bss + ldr x0, =__bss_start + ldr x1, =__bss_size +bss_loop: + cbz x1, ready + str xzr, [x0], #8 // [x0] = 0, x0 = x0 + 8 + sub x1, x1, #1 // x1 = x1 - 1 + cbnz x1, bss_loop + +ready: + // set_exception_vector_table + adr x0, exception_vector_table + msr vbar_el1, x0 + + // change sp to virtual address + ldr x1, =KERNEL_VA_BASE + add sp, sp, x1 + + bl kern_main + +spin: + wfe + b spin + + +from_el2_to_el1: + mov x0, (1 << 31) + msr hcr_el2, x0 + mov x0, 0b1111000101 + msr spsr_el2, x0 + msr elr_el2, lr + ldr x0, = __stack_kernel_top + msr sp_el1, x0 + eret + +.global run_el1_to_el0 +run_el1_to_el0: + msr elr_el1, x0 + mov x0, 0b0 // enable interrupt in EL0 + msr spsr_el1, x0 + msr sp_el0, x1 + eret + +pgtable_create: + ldr x0, =__kernel_pgd // PGD + lsl x0, x0, #16 // omit first 16 bit (using physical address) + lsr x0, x0, #16 + add x1, x0, #4096 // PUD + add x2, x1, #4096 // PMD + add x3, x2, #4096 // PTE + + // Set up PGD + ldr x4, =PGD0_ATTR + orr x4, x1, x4 + str x4, [x0] + + // Set up PUD + ldr x4, =PUD0_ATTR + orr x4, x2, x4 + str x4, [x1] + + ldr x4, =PUD1_ATTR + mov x5, 0x40000000 + orr x4, x5, x4 + str x4, [x1, #8] + + // Set up PMD + mov x5, x3 + mov x6, xzr // i = 0 + mov x7, #512 +pmd_loop: + ldr x4, =PMD0_ATTR + orr x4, x5, x4 + str x4, [x2, x6, lsl #3] // i * 8 + add x6, x6, #1 // i++ + add x5, x5, #4096 + cmp x6, x7 + b.ls pmd_loop + + // Set up normal PTE + mov x4, xzr // physical address + mov x5, xzr // i = 0 + mov x6, #258048 +pte_nloop: + ldr x7, =PTE_NORMAL_ATTR + orr x7, x4, x7 + str x7, [x3, x5, lsl #3] // (i * 8) + add x5, x5, #1 + add x4, x4, #4096 + cmp x5, x6 + b.ls pte_nloop + + // Set up device PTE + add x6, x6, #4096 // 262144 +pte_dloop: + ldr x7, =PTE_DEVICE_ATTR + orr x7, x4, x7 + str x7, [x3, x5, lsl #3] // (i * 8) + add x5, x5, #1 + add x4, x4, #4096 + cmp x5, x6 + b.ls pte_dloop + + msr ttbr0_el1, x0 + msr ttbr1_el1, x0 + + ret \ No newline at end of file diff --git a/lab6/kern/exception_vector_table.S b/lab6/kern/exception_vector_table.S new file mode 100644 index 000000000..556b3d939 --- /dev/null +++ b/lab6/kern/exception_vector_table.S @@ -0,0 +1,136 @@ +.section ".text" + +// save general registers to stack +.macro save_all + sub sp, sp, 32 * 18 + 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] + + mrs x20, sp_el0 + stp x30, x20, [sp, 16 * 15] + + mrs x20, spsr_el1 + mrs x21, elr_el1 + stp x20, x21, [sp ,16 * 16] +.endm + +// load general registers from stack +.macro load_all + ldp x20, x21, [sp ,16 * 16] + msr spsr_el1, x20 + msr elr_el1, x21 + + ldp x30, x20, [sp, 16 * 15] + msr sp_el0, x20 + + 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] + add sp, sp, 32 * 18 +.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 + b exception_handler + .align 7 // entry size is 0x80, .align will pad 0 + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + // Exception from the current EL while using SP_ELx + b sync_handler + .align 7 + b irq_el1_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + // Exception from a lower EL and at least one lower EL is AArch64 + b sync_handler + .align 7 + b irq_el0_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + // Exception from a lower EL and all lower ELs are AArch32 + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + +exception_handler: + b exception_handler + +sync_handler: + save_all + mrs x0, spsr_el1 + mrs x1, elr_el1 + mrs x2, esr_el1 + mov x3, sp + bl sync_main + load_all + eret + +irq_el1_handler: + save_all + bl irq_main + bl irq_resched + mov x0, sp + bl signal_run + load_all + eret + +irq_el0_handler: + save_all + bl irq_main + bl irq_resched + mov x0, sp + bl signal_run + load_all + eret + +.global return_from_fork +return_from_fork: + load_all + eret diff --git a/lab6/kern/irq.c b/lab6/kern/irq.c new file mode 100644 index 000000000..39ef2a1ba --- /dev/null +++ b/lab6/kern/irq.c @@ -0,0 +1,76 @@ +#include "peripheral/aux.h" +#include "peripheral/uart.h" +#include "peripheral/interrupt.h" +#include "peripheral/arm.h" +#include "kern/timer.h" +#include "kern/irq.h" +#include "kern/sched.h" +#include "kern/softirq.h" + +// QA7_rev3.4 p.16 +#define CNTPNSIRQ_INT 1 +#define GPU_INT 8 + +char int_stack[4096]; + +void int_enable() { + asm volatile("msr DAIFClr, 0xf"); +} + +void int_disable() { + asm volatile("msr DAIFSet, 0xf"); +} + +void timer_int_handler() { + struct task_struct *current = get_current(); + if (--current->ctime <= 0) { + current->resched = 1; + } + timer_sched_latency(); + timer_enable_int(); +} + +void int_init() { + softirq_init(); + softirq_register(timer_int_handler, SOFTIRQ_TIMER); + softirq_register(uart_int_handler, SOFTIRQ_UART); + int_enable(); +} + +void irq_router() { + int_disable(); + if (*CORE0_IRQ_SRC & (1 << CNTPNSIRQ_INT)) { + timer_disable_int(); + softirq_active(SOFTIRQ_TIMER); + } else if (*CORE0_IRQ_SRC & (1 << GPU_INT)) { + if (*IRQ_PENDING_1 & AUX_INT) { + uart_disable_int(); + softirq_active(SOFTIRQ_UART); + } + } + int_enable(); + softirq_run(); +} + +void irq_main() { + register char *sp; + asm volatile("mov %0, sp": "=r"(sp)); + if (!(sp <= &int_stack[4095] && sp >= &int_stack[0])) { + asm volatile("mov sp, %0" : : "r"(&int_stack[4080])); + } + + irq_router(); + + if (!(sp <= &int_stack[4095] && sp >= &int_stack[0])) { + asm volatile("mov sp, %0" : : "r"(sp)); + } +} + +void irq_resched() { + struct task_struct *current = get_current(); + if (current->resched) { + current->ctime = 1; + current->resched = 0; + schedule(); + } +} \ No newline at end of file diff --git a/lab6/kern/kio.c b/lab6/kern/kio.c new file mode 100644 index 000000000..b83deafbf --- /dev/null +++ b/lab6/kern/kio.c @@ -0,0 +1,65 @@ +#include "string.h" +#include "kern/kio.h" + +void kprintf(char* fmt, ...) { + char s[124]; + char buffer[64]; + char *dst = s; + char *p; + + __builtin_va_list args; + __builtin_va_start(args, fmt); + + while (*fmt) { + if (*fmt == '%') { + fmt++; + // escape + if (*fmt == '%') { + goto put; + } + // string + else if (*fmt == 's') { + p = __builtin_va_arg(args, char *); + while (*p) + *dst++ = *p++; + } + // char + else if (*fmt == 'c') { + char c = __builtin_va_arg(args, int); + *dst++ = c; + } + // decimal + else if (*fmt == 'd') { + int arg = __builtin_va_arg(args, int); + if (itoa(arg, buffer, 10) != -1) { + p = buffer; + while(*p) + *dst++ = *p++; + } else { + *dst++ = '@'; + } + + } + // hex + else if (*fmt == 'x') { + long arg = __builtin_va_arg(args, long); + if (itoa(arg, buffer, 16) != -1) { + p = buffer; + while(*p) + *dst++ = *p++; + } else { + *dst++ = '@'; + } + } + } + else { + put: + *dst++ = *fmt; + } + *fmt++; + } + *dst = '\0'; + __builtin_va_end(args); + + uart_async_puts(s); +} diff --git a/lab6/kern/linker.ld b/lab6/kern/linker.ld new file mode 100644 index 000000000..2ed7e6d0f --- /dev/null +++ b/lab6/kern/linker.ld @@ -0,0 +1,44 @@ +SECTIONS +{ + . = 0xffff000000000000; + . += 0x80000; + __kernel_start = .; + .text : { + KEEP(*(.text.entry)) + *(.text .text.* .gnu.linkonce.t.*) + } + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + . = ALIGN(0x1000); + + /* The data segment */ + .data : { + *(.data) + } + + .bss ALIGN(16) (NOLOAD) : { + PROVIDE(__bss_start = .); + *(.bss) + PROVIDE(__bss_end = .); + BYTE(0) + } + + . = ALIGN(0x1000); + __kernel_pgd = .; + .data.kpgd : { + . += (515 * 0x1000); + } + + __heap_start = .; + + /DISCARD/ : { + *(.eh_frame .note.GNU-stack) + } +} + +__stack_kernel_top = 0x20000000; +__stack_user_top = 0x30000000; +__bss_size = (__bss_end - __bss_start) >> 3; \ No newline at end of file diff --git a/lab6/kern/main.c b/lab6/kern/main.c new file mode 100644 index 000000000..f4fd0aa8f --- /dev/null +++ b/lab6/kern/main.c @@ -0,0 +1,127 @@ +#include "peripheral/mailbox.h" +#include "kern/shell.h" +#include "kern/timer.h" +#include "kern/irq.h" +#include "kern/sched.h" +#include "kern/kio.h" +#include "kern/cpio.h" +#include "kern/mm.h" +#include "dtb.h" +#include "startup_alloc.h" +#include "syscall.h" +#include "string.h" + +void hw_info() { + unsigned int result[2]; + kputs("##########################################\n"); + get_board_revision(result); + kprintf("Board revision:\t\t\t0x%x\n", result[0]); + get_ARM_memory(result); + kprintf("ARM memory base address:\t0x%x\n", result[0]); + kprintf("ARM memory size:\t\t0x%x\n", result[1]); + kputs("##########################################\n"); +} + +void rootfs_init() { + if (fdt_init() < 0) { + kputs("dtb: Bad magic\n"); + return; + } + if (fdt_traverse(initramfs_callback) < 0) + kputs("dtb: Unknown token\n"); + if (fdt_traverse(mm_callback) < 0) + kputs("dtb: Unknown token\n"); + kputs("dtb: init success\n"); +} + +extern unsigned int __stack_kernel_top; + +void reserve_memory() { + kprintf("page used by startup allocator\n"); + reserved_kern_startup(); + kprintf("device tree\n"); + fdt_reserve(); + kprintf("initramfs\n"); + cpio_reserve(); + kprintf("initial kernel stack\n"); + mm_reserve(PHY_2_VIRT((void *)&__stack_kernel_top - 0x2000), PHY_2_VIRT((void *)&__stack_kernel_top)); +} + +void delay(int times) { + while(times--) { + asm volatile("nop"); + } +} + +#include "user_lib.h" + +void fork_test() { + printf("\nFork Test, pid %d\n", getpid()); + int cnt = 1; + int ret = 0; + if ((ret = fork()) == 0) { // child + long long cur_sp; + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", getpid(), cnt, &cnt, cur_sp); + ++cnt; + + if ((ret = fork()) != 0){ + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", getpid(), cnt, &cnt, cur_sp); + } + else{ + while (cnt < 5) { + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("second child pid: %d, cnt: %d, ptr: %x, sp : %x\n", getpid(), cnt, &cnt, cur_sp); + delay(1000000); + ++cnt; + } + } + exit(); + } + else { + printf("parent here, pid %d, child %d\n", getpid(), ret); + } + exit(); +} + +char *user_code; + +void user_prog() { + user_code = cpio_find("vm.img"); + if (user_code) + __exec(user_code, ""); + exit(); +} + +void idle_task() { + while(1) { + schedule(); + } +} + +void kern_main() { + kio_init(); + runqueue_init(); + task_init(); + int_init(); + core_timer_enable(); + unsigned long tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); + timer_sched_latency(); + + kputs("press any key to continue..."); + kscanc(); + kputs("\n"); + rootfs_init(); + hw_info(); + + mm_init(); + reserve_memory(); + + thread_create(user_prog); + // privilege_task_create(kill_zombies, 10); + idle_task(); +} \ No newline at end of file diff --git a/lab6/kern/mm.c b/lab6/kern/mm.c new file mode 100644 index 000000000..0ecd897dc --- /dev/null +++ b/lab6/kern/mm.c @@ -0,0 +1,242 @@ +#include "kern/mm.h" +#include "kern/kio.h" +#include "startup_alloc.h" + +#include "string.h" +#include "byteswap.h" + +unsigned int phy_address_start = 0; +unsigned int phy_address_limit = 0x3C000000; + +void mm_callback(char *node_name, char *prop_name, void *prop_value) { + if (!strncmp(node_name, "memory", 6) && !strncmp(prop_name, "reg", 3)) { + kputs("mm: Find!\n"); + phy_address_start = __bswap_32(*((unsigned int *)(prop_value))); + phy_address_limit = __bswap_32(*((unsigned int *)(prop_value+4))); + kprintf("physical start address: 0x%x\n", phy_address_start); + kprintf("physical address limit: 0x%x\n", phy_address_limit); + } +} + +struct free_area *free_area; +struct page *frames; + +struct page *get_page_from_addr(void *addr) { + int pfn = PHY_2_PFN(addr); + return &frames[pfn]; +} + +void buddy_alloc_ds() { + frames = (struct page *)sumalloc(sizeof(struct page) * PHY_FRAMES_NUM); + free_area = (struct free_area *)sumalloc(sizeof(struct free_area) * (MAX_ORDER+1)); +} + +void add_to_free_area(struct page *page, struct free_area *free_area) { + free_area->nr_free++; + // kprintf("------add_to_free_area %d(%x) %d %x %d\n", page->pg_index, PFN_2_PHY(page->pg_index), page->compound_order, free_area, free_area->nr_free); + list_add_tail(&page->list, &free_area->free_list); +} + +void del_page_from_free_area(struct page *page, struct free_area *free_area) { + free_area->nr_free--; + // kprintf("------del_page_from_free_area %d(%x) %d %x %d\n", page->pg_index, PFN_2_PHY(page->pg_index), page->compound_order, free_area, free_area->nr_free); + list_del(&page->list); +} + +struct page* expand(struct page *page, unsigned int order) { + struct page *redundant; + unsigned int porder = page->compound_order; + + if (porder > order) { + // kprintf("Release %d, ask for, %d\n", porder, order); + porder--; + redundant = page + (1 << porder); + page->compound_order = porder; + redundant->flags = PG_HEAD; + redundant->compound_order = porder; + add_to_free_area(redundant, &free_area[redundant->compound_order]); + return expand(page, order); + } + page->flags = PG_USED; + return page; +} + +struct page* rmqueue(struct free_area *free_area, unsigned int order) { + struct page *hpage; + if (list_empty(&free_area->free_list)) + return 0; + hpage = list_entry(free_area->free_list.next, struct page, list); + del_page_from_free_area(hpage, free_area); + return expand(hpage, order); +} + +struct page* alloc_pages(unsigned int order) { + struct page *page; + if (order >= MAX_ORDER) + return 0; + for (int i=order ; i 0) { + page = rmqueue(&free_area[i], order); + if (page) { + // kprintf("Alloc new buddy: %d, %x, %d\n", page->pg_index, page->pg_index*PAGE_SIZE, page->compound_order); + return page; + } + } + } + return 0; +} + +/* +You can use the block’s index xor with its exponent to find its buddy. +If its buddy is in the page frame array, then you can merge them to a larger block. +*/ +struct page* find_buddy(struct page *page) { + int buddy_index = page->pg_index ^ (1 << page->compound_order); + if (buddy_index >= PHY_FRAMES_NUM) + return 0; + return &frames[buddy_index]; +} + +void free_pages(void *addr) { + struct page *page = get_page_from_addr(addr); + struct page *buddy; + int order = page->compound_order; + + // kprintf("\tFree buddy: %d, %x, %d\n", page->pg_index, page->pg_index*PAGE_SIZE, page->compound_order); + while(order < MAX_ORDER) { + buddy = find_buddy(page); + // kprintf("\tBuddy page: %d, %x, %d\n", buddy->pg_index, buddy->pg_index*PAGE_SIZE, buddy->compound_order); + if (!buddy || buddy->flags != PG_HEAD || buddy->compound_order != order) { + page->flags = PG_HEAD; + add_to_free_area(page, &free_area[page->compound_order]); + break; + } + // kprintf("\tBuddy page: %d, %x, %d\n", buddy->pg_index, buddy->pg_index*PAGE_SIZE, buddy->compound_order); + // kprintf("\tMerge %d to %d\n", order, order+1); + + // order == buddy->compound_order + del_page_from_free_area(buddy, &free_area[order]); + if (buddy > page) { // | page | buddy | + page->compound_order = order+1; + buddy->flags = PG_TAIL; + } else { // | buddy | page | + buddy->compound_order = order+1; + page->flags = PG_TAIL; + page = buddy; + } + order = page->compound_order; + } +} + +// start of kernel frame +extern unsigned int __heap_start; + +void mm_init() { + int i; + int cnt = 0; + int order = MAX_ORDER - 1; + + int kernel_data_end = (long)(&__heap_start) / PAGE_SIZE; + int mem_end = phy_address_limit / PAGE_SIZE - 50; + + buddy_alloc_ds(); + + + for (i=0 ; i= mem_end) + order--; + frames[i].flags = PG_HEAD; + frames[i].compound_order = order; + add_to_free_area(&frames[i], &free_area[order]); + cnt = (1 << order) - 1; + } else { + frames[i].flags = PG_TAIL; + frames[i].compound_order = 0; + cnt--; + } + } + + for ( ; icompound_order; + unsigned int cl = page->pg_index; + unsigned int cr = cl + (1 << porder) - 1; + unsigned int mid; + + if (cl > r || cr < l) { + add_to_free_area(page, &free_area[porder]); + return; + } + // no need to split + if (cl >= l && cr <= r) { + // kprintf("\tReserved range: %d-%d\n", cl, cr); + page->flags = PG_USED; + return; + } + // split + mid = (cl + cr) >> 1; + porder--; + buddy = &frames[mid+1]; + page->compound_order = porder; + buddy->flags = PG_HEAD; + buddy->compound_order = porder; + expand_reserve(page, l, r); + expand_reserve(buddy, l, r); +} + +// Mark the page from start to end as used +void mm_reserve(void *start, void *end) { + unsigned int ps = PHY_2_PFN(VIRT_2_PHY(start)); + unsigned int pe = PHY_2_PFN(VIRT_2_PHY(end)); + unsigned int pi = ps; + struct page page; + int i; + + kprintf("\tReserve 0x%x-0x%x\n", VIRT_2_PHY(start), VIRT_2_PHY(end)); + for (i=ps ; i<=pe ; i++) if (frames[i].flags == PG_USED) { + kputs("\tTry to reserved page that are already been used...\n"); + return; + } + + do { + // find the header page of start address, linear search for now + while(pi >= 0) { + page = frames[pi--]; + if (page.flags == PG_HEAD) + break; + } + pi = page.pg_index + (1<pgd, pgd_index(vaddr)); + pmd = pgtable_walk(pud, pud_index(vaddr)); + pte = pgtable_walk(pmd, pmd_index(vaddr)); + return pgtable_walk_pte(pte, pte_index(vaddr), paddr) + (vaddr & (PAGE_SIZE-1)); +} + +void *mappages(struct mm_struct *mm, unsigned long vaddr, unsigned long size, unsigned long paddr) { + if (!mm->pgd) + return 0; + for (int i=0 ; ipgd) + return 0; + void *pud; + pud = pgtable_walk(mm->pgd, pgd_index(vaddr)); + pgtable_walk_block(pud, pud_index(vaddr), paddr); +} + +void create_pgd(struct mm_struct *mm) { + void *new_page = kmalloc(PAGE_SIZE); + if (!new_page) + return; + memset(new_page, 0, PAGE_SIZE); + mm->pgd = new_page; +} + +void free_pgtable(unsigned long *table, int level) { + void *next; + for(int i=0 ; i<512 ; i++) { + if (table[i]) { + next = PHY_2_VIRT(table[i] & PAGE_MASK); + if (level != 4) + free_pgtable(next, level+1); + // if device memory + if (level == 4 && VIRT_2_PHY(next) >= 0x3C000000) + continue; + kfree(next); + } + } +} + +void free_pgd(struct mm_struct *mm) { + unsigned long *pgd = mm->pgd; + void *pud; + for(int i=0 ; i<512 ; i++) { + if (pgd[i]) { + pud = PHY_2_VIRT(pgd[i] & PAGE_MASK); + free_pgtable(pud, 2); + kfree(pud); + } + } + kfree(pgd); +} + +/* + level + pgd 1 + pud 2 + pmd 3 + pte 4 +*/ +void fork_pgtable(unsigned long *ptable, unsigned long *ctable, int level) { + void *pnext; + void *cnext; + + for(int i=0 ; i<512 ; i++) { + if (ptable[i]) { + pnext = PHY_2_VIRT(ptable[i] & PAGE_MASK); + if (level == 4) { + cnext = pgtable_walk_pte(ctable, i, 0); + memcpy(cnext, pnext, PAGE_SIZE); + } else { + cnext = pgtable_walk(ctable, i); + fork_pgtable(pnext, cnext, level+1); + } + } + } +} + +void fork_pgd(struct mm_struct *parent_mm, struct mm_struct *child_mm) { + unsigned long *ppgd = parent_mm->pgd; + unsigned long *cpgd = child_mm->pgd; + void *ppud; + void *cpud; + + if (!ppgd || !cpgd) + return; + + for(int i=0 ; i<512 ; i++) { + if (ppgd[i]) { + ppud = PHY_2_VIRT(ppgd[i] & PAGE_MASK); + cpud = pgtable_walk(cpgd, i); + fork_pgtable(ppud, cpud, 2); + } + } +} \ No newline at end of file diff --git a/lab6/kern/sched.S b/lab6/kern/sched.S new file mode 100644 index 000000000..fb7019ca6 --- /dev/null +++ b/lab6/kern/sched.S @@ -0,0 +1,41 @@ + + +.global switch_to +switch_to: + stp x19, x20, [x0, 16 * 0] + stp x21, x22, [x0, 16 * 1] + stp x23, x24, [x0, 16 * 2] + stp x25, x26, [x0, 16 * 3] + stp x27, x28, [x0, 16 * 4] + stp fp, lr, [x0, 16 * 5] + mov x9, sp + str x9, [x0, 16 * 6] + + ldp x19, x20, [x1, 16 * 0] + ldp x21, x22, [x1, 16 * 1] + ldp x23, x24, [x1, 16 * 2] + ldp x25, x26, [x1, 16 * 3] + ldp x27, x28, [x1, 16 * 4] + ldp fp, lr, [x1, 16 * 5] + ldr x9, [x1, 16 * 6] + mov sp, x9 + ret + +.global update_current +update_current: + msr tpidr_el1, x0 + ret + +.global get_current +get_current: + mrs x0, tpidr_el1 + ret + +.global update_pgd +update_pgd: + 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 + ret \ No newline at end of file diff --git a/lab6/kern/sched.c b/lab6/kern/sched.c new file mode 100644 index 000000000..6aad073c5 --- /dev/null +++ b/lab6/kern/sched.c @@ -0,0 +1,324 @@ +#include "kern/sched.h" +#include "kern/irq.h" +#include "kern/slab.h" +#include "kern/kio.h" +#include "string.h" + +#define ROUND_UP(n,d) (((n) + (d-1)) & (-d)) +#define ROUND_DOWN(n,d) ((n) & (-d)) + +// ############## runqueue ################## + +struct prio_array { + DECLARE_BITMAP(bitmap, MAX_PRIO); + struct list_head queue[MAX_PRIO]; +}; + +struct runqueue { + unsigned long nr_running; + struct prio_array array; +}; + +struct runqueue runqueue; +struct list_head zombie_queue; +char kernel_stack[MAX_PRIV_TASK_NUM][STACKSIZE]; +char user_stack[MAX_PRIV_TASK_NUM][STACKSIZE]; + +void runqueue_init() { + int i; + struct prio_array *array = &runqueue.array; + runqueue.nr_running = 0; + for(i=0 ; iqueue[i]); + } + bitmap_zero(array->bitmap, MAX_PRIO); + INIT_LIST_HEAD(&zombie_queue); +} + +void runqueue_push(struct task_struct *new_task) { + struct prio_array *array = &runqueue.array; + + runqueue.nr_running += 1; + __set_bit(new_task->prio, array->bitmap); + list_add_tail(&new_task->list, &array->queue[new_task->prio]); +} + +struct task_struct* runqueue_pop() { + int highest_prio; + struct task_struct *next_task; + struct prio_array *array = &runqueue.array; + + runqueue.nr_running -= 1; + highest_prio = sched_find_first_bit(array->bitmap); + // no task in queue + if (highest_prio == MAX_PRIO) + return 0; + next_task = list_entry(array->queue[highest_prio].next, struct task_struct, list); + list_del(&next_task->list); + if (list_empty(&array->queue[highest_prio])) + __clear_bit(highest_prio, array->bitmap); + return next_task; +} + +// ############## priv task ################## + +struct task_struct task_pool[MAX_PRIV_TASK_NUM]; +struct task_struct *utask[1000]; +int pid; // start from 1000 + +inline int get_priv_tid() { + int i; + for(i=0 ; i 20 || prio < 1) + return 0; + + tid = get_priv_tid(); + if (tid == -1) + return 0; + + + new_task = &task_pool[tid]; + new_task->used = 1; + new_task->prio = prio; + new_task->state = RUNNING; + new_task->ctime = TASK_CTIME; + new_task->resched = 0; + create_pgd(&new_task->mm); + INIT_LIST_HEAD(&new_task->signal_list); + INIT_LIST_HEAD(&new_task->signal_pend_list); + + // kernel stack + stk_addr = (unsigned long)&kernel_stack[tid][4095]; + stk_addr = ROUND_DOWN(stk_addr, 16); + new_task->task_context.lr = (unsigned long)func; + new_task->task_context.fp = stk_addr; + new_task->task_context.sp = stk_addr; + new_task->stk_addr = (void*)stk_addr; + + runqueue_push(new_task); + return new_task; +} + +// ############## normal task ################## + +struct task_struct *task_create(void (*func)(), int prio) { + unsigned long stk_addr; + struct task_struct *new_task; + + if (prio <= 20) + return 0; + + new_task = kmalloc(STACKSIZE); + if (!new_task) + return 0; + + int_disable(); + + utask[pid-1000] = new_task; + new_task->tid = pid++; + new_task->prio = prio; + new_task->state = RUNNING; + new_task->ctime = TASK_CTIME; + new_task->resched = 0; + create_pgd(&new_task->mm); + INIT_LIST_HEAD(&new_task->signal_list); + INIT_LIST_HEAD(&new_task->signal_pend_list); + + // kernel stack + stk_addr = (unsigned long)kmalloc(STACKSIZE); + stk_addr = stk_addr + STACKSIZE; + stk_addr = ROUND_DOWN(stk_addr, 16); + new_task->task_context.lr = (unsigned long)func; + new_task->task_context.fp = stk_addr; + new_task->task_context.sp = stk_addr; + new_task->stk_addr = (void*)stk_addr; + + runqueue_push(new_task); + + int_enable(); + + return new_task; +} + +int task_fork(void (*func)(), struct task_struct *parent, void *trapframe) { + int i; + unsigned long offset; + char *pptr; + char *cptr; + struct trapframe* child_trapframe; + struct trapframe* parent_trapframe; + struct task_struct *child = task_create(func, parent->prio); + + if (!child) + return -1; + + int_disable(); + + // setup kernel stack + cptr = (char *)child->stk_addr; + pptr = (char *)parent->stk_addr; + offset = pptr - (char*)trapframe; + for (i=0 ; itask_context.sp = (unsigned long)child->stk_addr - offset; + + // setup user stack + fork_pgd(&parent->mm, &child->mm); + mappages(&child->mm, 0x3C000000, 0x3000000, 0x3C000000); + child_trapframe = (struct trapframe *)child->task_context.sp; + parent_trapframe = (struct trapframe *)trapframe; + child_trapframe->sp_el0 = parent_trapframe->sp_el0; + child_trapframe->x[0] = 0; + + int_enable(); + + if (list_empty(&parent->signal_list)) + goto out; + // signal copy + struct list_head *ptr; + struct signal_t *signal; + struct signal_t *new_signal; + list_for_each(ptr, &parent->signal_list) { + signal = list_entry(ptr, struct signal_t, list); + new_signal = signal_create(signal->num, signal->handler); + list_add_tail(&new_signal->list, &child->signal_list); + } +out: + return child->tid; +} + +// ############################################# + +void context_switch(struct task_struct *next) { + struct task_struct *prev = get_current(); + if (prev->state == RUNNING) { + runqueue_push(prev); + } else if (prev->state == DEAD) { + kprintf("Process %d dead...\n", prev->tid); + if (prev->tid >= 1000) + list_add_tail(&prev->list, &zombie_queue); + else + prev->used = 0; + } + // kprintf("context switch %d ~ %d\n", prev->tid, next->tid); + update_pgd(VIRT_2_PHY(next->mm.pgd)); + update_current(next); + switch_to(&prev->task_context, &next->task_context); +} + +void schedule() { + struct task_struct *next = runqueue_pop(); + if (next != 0) { + context_switch(next); + } +} + +void kill_zombies() { + struct task_struct *to_release; + struct list_head *itr; + struct list_head *tmp; + + while(1) { + list_for_each_safe(itr, tmp, &zombie_queue) { + to_release = list_entry(itr, struct task_struct, list); + kprintf("Kill zombie %d\n", to_release->tid); + kfree(to_release->stk_addr); + kfree(to_release->ustk_addr); + free_pgd(&to_release->mm); + kfree(to_release); + list_del(itr); + } + } +} + +extern void run_el1_to_el0(void *, void *); + +void do_exec(void (*func)()) { + struct task_struct *current = get_current(); + // should use user stack + run_el1_to_el0(func, current->ustk_addr); +} + +struct task_struct* get_task_struct(int pid) { + if (pid < 1000) + return &task_pool[pid]; + else { + return utask[pid-1000]; + } +} + +// ############## sys call ################## + +int __getpid() { + struct task_struct *current = get_current(); + return current->tid; +} + +void __exec(const char *user_code, char *const argv[]) { + void *pc; + void *stk; + + struct task_struct *current = get_current(); + char *user_prog1 = kmalloc(250000); + memcpy(user_prog1, user_code, 250000); + + pc = mappages(¤t->mm, 0x0, 250000, VIRT_2_PHY(user_prog1)); + stk = mappages(¤t->mm, USER_STK_LOW, STACKSIZE, 0); + + asm volatile("msr sp_el0, %0" : : "r"(USER_STK_HIGH)); + asm volatile("msr elr_el1, %0": : "r"(0x0)); + asm volatile("msr spsr_el1, %0" : : "r"(0b0)); + asm volatile("eret"); +} + +extern void return_from_fork(); + +int __fork(void *trapframe) { + struct task_struct *parent = get_current(); + return task_fork(return_from_fork, parent, trapframe); +} + +void __exit() { + struct task_struct *current = get_current(); + current->state = DEAD; + schedule(); +} + +void __kill(int pid) { + if (pid <= 0) + return; + struct task_struct* target = get_task_struct(pid); + target->state = DEAD; +} \ No newline at end of file diff --git a/lab6/kern/shell.c b/lab6/kern/shell.c new file mode 100644 index 000000000..a25e3709a --- /dev/null +++ b/lab6/kern/shell.c @@ -0,0 +1,79 @@ +#include "kern/kio.h" +#include "kern/shell.h" +#include "kern/timer.h" +#include "kern/sched.h" +#include "kern/cpio.h" +#include "kern/mm.h" +#include "string.h" +#include "reset.h" + +void shell_input(char *cmd) { + char c; + unsigned int len = 0; + + while((c = kscanc()) != '\n') { + if (c == BACKSPACE || c == DELETE) { + if (!len) + continue; + LEFT_SHIFT + kputc(' '); + LEFT_SHIFT + --len; + } else if (c == ESC) { + kscanc(); + kscanc(); + } else { // regular letter + kputc(c); + cmd[len++] = c; + } + } + kputs("\n"); + cmd[len] = '\0'; +} + +void shell_help() { + kputs("help\t\t: print this help menu\n"); + kputs("hello\t\t: print Hello World!\n"); + kputs("ls\t\t: list file\n"); + kputs("cat\t\t: print file content\n"); + kputs("exec\t\t: execute a file\n"); + kputs("setTimeout\t: MESSAGE SECONDS\n"); + kputs("reboot\t\t: reboot the device\n"); +} + +void shell_parse(char *cmd) { + char args[MAX_INPUT_LEN]; + if (!strcmp(cmd, "help")) { + shell_help(); + } else if (!strcmp(cmd, "hello")) { + kputs("Hello World!\n"); + } else if (!strcmp(cmd, "ls")) { + cpio_ls(); + } else if (!strcmp(cmd, "cat")) { + kputs("FileName: "); + shell_input(args); + cpio_cat(args); + } else if (!strcmp(cmd, "exec")) { + kputs("FileName: "); + shell_input(args); + cpio_exec(args); + } else if (!strcmp(cmd, "setTimeout")) { + shell_input(args); + set_timeout(args); + } else if (!strcmp(cmd, "reboot")) { + kputs("About to reboot...\n"); + reset(1000); + } else { + kputs(cmd); + kputs(": command not found\n"); + } +} + +void shell_start() { + char cmd[128]; + while (1) { + kputs("raspi3> "); + shell_input(cmd); + shell_parse(cmd); + } +} \ No newline at end of file diff --git a/lab6/kern/signal.c b/lab6/kern/signal.c new file mode 100644 index 000000000..1b11b9193 --- /dev/null +++ b/lab6/kern/signal.c @@ -0,0 +1,113 @@ +#include "kern/signal.h" +#include "kern/sched.h" +#include "kern/slab.h" +#include "kern/kio.h" +#include "kern/irq.h" +#include "string.h" + +struct signal_t *signal_create(int SIGNAL, void (*handler)()) { + struct signal_t *new_signal = kmalloc(sizeof(struct signal_t)); + new_signal->num = SIGNAL; + new_signal->handler = handler; + INIT_LIST_HEAD(&new_signal->list); + return new_signal; +} + +void signal_default(int pid, int SIGNAL) { + switch(SIGNAL) { + case SIGKILL: + __kill(pid); + break; + default: + kprintf("Undefined signal number...\n"); + } +} + +void signal_return() { + asm volatile( + "mov x8, #10 \n\t" + "svc #0 \n\t" + ); +} + +void signal_jump(void *trapframe, void (*handler)()) { + struct trapframe *tf = trapframe; + struct task_struct *current = get_current(); + struct signal_context_t *signal_context = kmalloc(sizeof(struct signal_context_t)); + signal_context->stk_addr = kmalloc(4096); + signal_context->trapframe = kmalloc(sizeof(struct trapframe)); + // kprintf("Ready to jump %x %x %x\n", signal_context, signal_context->stk_addr, signal_context->trapframe); + memcpy(signal_context->trapframe, trapframe, sizeof(struct trapframe)); + + current->signal_context = signal_context; + + // return address save in x30 in ARM + tf->x[30] = (long)signal_return; + tf->elr_el1 = (long)handler; + tf->sp_el0 = (long)signal_context->stk_addr; +} + +void signal_back(void *trapframe) { + struct task_struct *current = get_current(); + // kprintf("Back %x %x\n", current->signal_context, current->signal_context->trapframe); + memcpy(trapframe, current->signal_context->trapframe, sizeof(struct trapframe)); + kfree(current->signal_context->trapframe); + kfree(current->signal_context->stk_addr); + kfree(current->signal_context); +} + + +void __signal(int SIGNAL, void (*handler)()) { + struct list_head *ptr; + struct signal_t *signal; + struct task_struct *current = get_current(); + + if (list_empty(¤t->signal_list)) + goto regis; + list_for_each(ptr, ¤t->signal_list) { + signal = list_entry(ptr, struct signal_t, list); + if (signal->num == SIGNAL) { + kprintf("Overwite existing registed signal(%d)\n", SIGNAL); + list_del(&signal->list); + break; + } + } +regis: + signal = signal_create(SIGNAL, handler); + list_add_tail(&signal->list, ¤t->signal_list); +} + +void __sigkill(int pid, int SIGNAL, void *trapframe) { + struct signal_pend_t *signal_pend; + struct task_struct *target = get_task_struct(pid); + if (list_empty(&target->signal_list)) + goto default_sig; + + signal_pend = kmalloc(sizeof(struct signal_pend_t)); + signal_pend->num = SIGNAL; + INIT_LIST_HEAD(&signal_pend->list); + + list_add_tail(&signal_pend->list, &target->signal_pend_list); + return; +default_sig: + signal_default(pid, SIGNAL); +} + +void signal_run(void *trapframe) { + struct task_struct *current = get_current(); + if (list_empty(¤t->signal_pend_list)) + return; + + struct list_head *ptr; + struct signal_t *signal; + struct signal_pend_t *signal_pend; + signal_pend = list_entry(current->signal_pend_list.next, struct signal_pend_t, list); + list_del(&signal_pend->list); + list_for_each(ptr, ¤t->signal_list) { + signal = list_entry(ptr, struct signal_t, list); + if (signal->num == signal_pend->num) { + signal_jump(trapframe, signal->handler); + return; + } + } +} \ No newline at end of file diff --git a/lab6/kern/slab.c b/lab6/kern/slab.c new file mode 100644 index 000000000..4d831d87f --- /dev/null +++ b/lab6/kern/slab.c @@ -0,0 +1,169 @@ +#include "kern/mm.h" +#include "kern/kio.h" +#include "startup_alloc.h" + +#define PREALLOC_SIZE 100 + +/* + slab_t +*/ +struct slab_t* pmalloc_slab() { + struct slab_t *ret; + ret = (struct slab_t *)sumalloc(sizeof(struct slab_t)); + return ret; +} + + +struct kmem_pool *kmalloc_pools; + +void slab_alloc_ds() { + kmalloc_pools = (struct kmem_pool *)sumalloc(sizeof(struct kmem_pool) * MAX_OBJ_CACHE_NUM); +} + +struct kmem_pool* kmalloc_slab(unsigned int size) { + unsigned int rounded_size; + int pool_id; + + if (size <= SMALL_OBJ_SIZE) { + rounded_size = (size + 7) & -8; + pool_id = rounded_size / 8 - 1; + } else if (size <= MEDIUM_OBJ_SIZE) { + size -= SMALL_OBJ_SIZE; + pool_id = 15 + (size + 11) / 12; + } else { + for(pool_id=24 ; pool_id= MAX_OBJ_CACHE_NUM) + return 0; + kmalloc_pools[pool_id].object_size = size; + kmalloc_pools[pool_id].num = PAGE_SIZE*4 / size; + } + return &kmalloc_pools[pool_id]; +} + +struct slab_t* slab_create(struct kmem_pool *pool) { + struct slab_t *slab; + struct page *page; + + page = alloc_pages(pool->gfporder); + page->flags = PG_SLAB; + + slab = pmalloc_slab(); + slab->inuse = 0; + slab->nr_free = pool->num; + slab->head_addr = (void*)PFN_2_PHY(page->pg_index); + INIT_LIST_HEAD(&slab->free_list); + INIT_LIST_HEAD(&slab->list); + + page->slab = slab; + + return slab; +} + +void* slab_alloc(struct kmem_pool *pool) { + struct slab_t *slab; + struct list_head *ptr; + void *ret; + + if (list_empty(&pool->slab_list)) + goto new_slab; + + list_for_each(ptr, &pool->slab_list) { + slab = list_entry(ptr, struct slab_t, list); + if (slab->nr_free > 0) + break; + } + + if (slab->nr_free == 0) { +new_slab: + slab = slab_create(pool); + list_add_tail(&slab->list, &pool->slab_list); + } + + slab->inuse++; + slab->nr_free--; + if (!list_empty(&slab->free_list)) { + ptr = slab->free_list.next; + list_del(ptr); + return (void*)ptr; + } + ret = slab->head_addr + (slab->inuse-1) * pool->object_size; + return ret; +} + +void* __do_kmalloc(unsigned int size) { + struct kmem_pool *cachep; + void *ret; + + cachep = kmalloc_slab(size); + if (!cachep) { + kputs("Unable to find kmem_pool...\n"); + return 0; + } + ret = slab_alloc(cachep); + return ret; +} + +void* kmalloc(unsigned int size) { + int i; + void *ret; + struct page *page; + + if (size >= PAGE_SIZE) { + for (i=0 ; ipg_index); + // kprintf("kmalloc: buddy %x\n", ret); + } else { + ret = __do_kmalloc(size); + // kprintf("kmalloc: slab %x\n", ret); + } + return PHY_2_VIRT(ret); +} + +void kfree(void *addr) { + struct slab_t *slab; + struct page *page = get_page_from_addr(addr); + + if (page->flags == PG_SLAB) { + slab = page->slab; + list_add_tail((struct list_head*)addr, &slab->free_list); + slab->inuse--; + slab->nr_free++; + } else { + free_pages(addr); + } +} + + +void slab_init() { + int i; + + slab_alloc_ds(); + + for (i=0 ; ix[0] = __getpid(); +} + +inline void sys_uart_read(struct trapframe *trapframe) { + int i; + int size = trapframe->x[1]; + char *buf = (char *)trapframe->x[0]; + for(i=0 ; ix[0] = i; +} + +inline void sys_uart_write(struct trapframe *trapframe) { + int i; + char *buf = (char *)trapframe->x[0]; + int size = trapframe->x[1]; + for(i=0 ; ix[0] = i; +} + +inline void sys_exec(struct trapframe *trapframe) { + const char *name = (const char *)trapframe->x[0]; + char *user_code = cpio_find(name); + __exec(user_code, trapframe->x[1]); + trapframe->x[0] = 0; +} + +inline void sys_fork(struct trapframe *trapframe) { + trapframe->x[0] = __fork(trapframe); +} + +inline void sys_exit(struct trapframe *trapframe) { + __exit(); +} + +inline void sys_mbox_call(struct trapframe *trapframe) { + unsigned char ch = trapframe->x[0]; + unsigned int *mailbox = (unsigned int *)trapframe->x[1]; + unsigned int *kernel_addr = walk(&(get_current()->mm.pgd), mailbox, 0); + trapframe->x[0] = mailbox_call(ch, kernel_addr); +} + +inline void sys_kill(struct trapframe *trapframe) { + __kill(trapframe->x[0]); +} + +inline void sys_signal(struct trapframe *trapframe) { + __signal(trapframe->x[0], trapframe->x[1]); +} + +inline void sys_sigkill(struct trapframe *trapframe) { + __sigkill(trapframe->x[0], trapframe->x[1], trapframe); +} + +inline void sys_sigreturn(struct trapframe *trapframe) { + signal_back(trapframe); +} + +void syscall_main(struct trapframe *trapframe) { + int_enable(); + long syscall_num = trapframe->x[8]; + switch(syscall_num) { + case SYS_GET_PID: + sys_getpid(trapframe); + break; + case SYS_UART_READ: + sys_uart_read(trapframe); + break; + case SYS_UART_WRITE: + sys_uart_write(trapframe); + break; + case SYS_EXEC: + sys_exec(trapframe); + break; + case SYS_FORK: + sys_fork(trapframe); + break; + case SYS_EXIT: + sys_exit(trapframe); + break; + case SYS_MBOX_CALL: + sys_mbox_call(trapframe); + break; + case SYS_KILL: + sys_kill(trapframe); + break; + case SYS_SIGNAL: + sys_signal(trapframe); + break; + case SYS_SIGKILL: + sys_sigkill(trapframe); + break; + case 10: + sys_sigreturn(trapframe); + break; + default: + uart_sync_puts("Undefined syscall number, about to reboot...\n"); + reset(1000); + while(1); + } + int_disable(); +} + +void svc_main(unsigned long spsr, unsigned long elr, unsigned long esr, struct trapframe *trapframe) { + unsigned int svc_num; + svc_num = esr & 0xFFFFFF; + + switch(svc_num) { + case 0: + syscall_main(trapframe); + break; + case 1: + kputs("svc 1\n"); + core_timer_enable(); + break; + case 2: + /* + bits [31:26] 0b010101 SVC instruction execution in AArch64 state. + */ + kprintf("\nspsr_el1: \t%x\n", spsr); + kprintf("elr_el1: \t%x\n", elr); + kprintf("esr_el1: \t%x\n", esr); + break; + default: + uart_sync_printNum(svc_num, 10); + uart_sync_puts(": Undefined svc number, about to reboot...\n"); + reset(1000); + while(1); + } +} + +void fault_parse(unsigned long sc) { + unsigned long far; + if (sc & 0b110000) { + kprintf("Others fault...\n"); + return; + } + + switch((sc & 0b1100) >> 2) { + case 0: + kprintf("Address size fault,"); + break; + case 1: + kprintf("Translation fault,"); + break; + case 2: + kprintf("Access flag fault,"); + break; + case 3: + kprintf("Permission fault,"); + break; + } + + kprintf(" level %d\n", sc & 0b11); + asm volatile("mrs %0, far_el1":"=r"(far)); + kprintf("Address: \t0x%x\n", far); +} + +void sync_main(unsigned long spsr, unsigned long elr, unsigned long esr, struct trapframe *trapframe) { + switch(EC_BITS(esr)) { + case EC_SVC_64: + svc_main(spsr, elr, esr, trapframe); + break; + case EC_IA_EL0: + kprintf("(EL0)"); + case EC_IA_EL1: + kprintf("Instruction Abort\n"); + fault_parse(IFSC(esr)); + kprintf("spsr_el0: \t0x%x\n", trapframe->sp_el0); + __exit(); + break; + case EC_DA_EL0: + kprintf("(EL0)"); + case EC_DA_EL1: + kprintf("Data Abort\n"); + fault_parse(DFSC(esr)); + kprintf("spsr_el0: \t0x%x\n", trapframe->sp_el0); + __exit(); + break; + default: + uart_sync_printNum(EC_BITS(esr), 10); + uart_sync_puts(": Unknown ec bit, about to reboot...\n"); + reset(1000); + while(1); + } +} \ No newline at end of file diff --git a/lab6/kern/syscall.S b/lab6/kern/syscall.S new file mode 100644 index 000000000..c50653b0f --- /dev/null +++ b/lab6/kern/syscall.S @@ -0,0 +1,60 @@ + +.global getpid +getpid: + mov x8, #0 + svc #0 + ret + +.global uart_read +uart_read: + mov x8, #1 + svc #0 + ret + +.global uart_write +uart_write: + mov x8, #2 + svc #0 + ret + +.global exec +exec: + mov x8, #3 + svc #0 + ret + +.global fork +fork: + mov x8, #4 + svc #0 + ret + +.global exit +exit: + mov x8, #5 + svc #0 + +.global mbox_call +mbox_call: + mov x8, #6 + svc #0 + ret + +.global kill +kill: + mov x8, #7 + svc #0 + ret + +.global signal +signal: + mov x8, #8 + svc #0 + ret + +.global sigkill +sigkill: + mov x8, #9 + svc #0 + ret + diff --git a/lab6/kern/timer.S b/lab6/kern/timer.S new file mode 100644 index 000000000..f8ad2a60e --- /dev/null +++ b/lab6/kern/timer.S @@ -0,0 +1,44 @@ +.section ".text" + +#include "peripheral/arm.h" + +.global core_timer_enable +core_timer_enable: + mov x0, 1 + msr cntp_ctl_el0, x0 // enable + mrs x0, cntfrq_el0 + msr cntp_tval_el0, x0 // set expired time + mov x0, 2 + ldr x1, =CORE0_TIMER_IRQ_CTRL + str w0, [x1] // unmask timer interrupt + ret + +.global core_timer_disable +core_timer_disable: + mov x0, 0 + msr cntp_ctl_el0, x0 // disable + mov x0, 0 + ldr x1, =CORE0_TIMER_IRQ_CTRL + str x0, [x1] // disable timer interrupt + ret + +.global timer_enable_int +timer_enable_int: + mov x0, 2 + ldr x1, =CORE0_TIMER_IRQ_CTRL + str w0, [x1] // unmask timer interrupt + ret + +.global timer_disable_int +timer_disable_int: + mov x0, 0 + ldr x1, =CORE0_TIMER_IRQ_CTRL + str x0, [x1] // disable timer interrupt + ret + +.global timer_sched_latency +timer_sched_latency: + mrs x0, cntfrq_el0 + asr x0, x0, 7 // 1/2 secs + msr cntp_tval_el0, x0 + ret \ No newline at end of file diff --git a/lab6/kern/timer.c b/lab6/kern/timer.c new file mode 100644 index 000000000..7f76e5b35 --- /dev/null +++ b/lab6/kern/timer.c @@ -0,0 +1,130 @@ +#include "kern/timer.h" +#include "kern/kio.h" +#include "startup_alloc.h" +#include "string.h" + +struct timer_queue *timer_head; +struct timer_queue *timer_tail; + +unsigned long get_current_time() { + unsigned long cntpct; + unsigned long cntfrq; + asm volatile("mrs %0, cntpct_el0" : "=r"(cntpct)); + asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq)); + return cntpct/cntfrq; +} + +void set_expired(unsigned int seconds) { + unsigned long cntfrq; + asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq)); + asm volatile("msr cntp_tval_el0, %0" : : "r"(cntfrq * seconds)); +} + +void timer_el0_handler() { + kprintf("Seconds after booting: %d\n", get_current_time()); + set_expired(2); + timer_enable_int(); +} + +void timer_el1_handler() { + struct timer_queue *next; + unsigned long timeout; + + timer_head->callback(timer_head->message, timer_head->register_time); + next = timer_head->next; + if (next) { + next->prev = 0; + timer_head = next; + timeout = next->register_time + next->duration - get_current_time(); + set_expired(timeout); + timer_enable_int(); + } else { + timer_head = 0; + timer_tail = 0; + } +} + +void timer_unknown_handler() { + kputs("Timer interrupt: unknown source EL, delay one seconds...\n"); + set_expired(1); + timer_enable_int(); +} + + +void timer_init() { + timer_head = 0; + timer_tail = 0; +} + +void add_timer(void (*callback)(char *, unsigned long), char *message, unsigned int duration) { + struct timer_queue *new_timer = (struct timer_queue *)sumalloc(sizeof(struct timer_queue)); + struct timer_queue *itr; + unsigned long timeout; + int i; + + new_timer->register_time = get_current_time(); + new_timer->duration = duration; + new_timer->callback = callback; + for(i=0 ; message[i]!='\0' ; i++) + new_timer->message[i] = message[i]; + new_timer->message[i] = '\0'; + new_timer->prev = 0; + new_timer->next = 0; + + if (!timer_head) { + timer_head = new_timer; + timer_tail = new_timer; + core_timer_enable(); + set_expired(duration); + } else { + timeout = new_timer->register_time + new_timer->duration; + for(itr=timer_head ; itr ; itr=itr->next) { + if(itr->register_time + itr->duration > timeout) + break; + } + + if (!itr) { // tail + new_timer->prev = timer_tail; + timer_tail->next = new_timer; + timer_tail = new_timer; + } else if (!itr->prev) { // head + new_timer->next = timer_head; + timer_head->prev = new_timer; + timer_head = new_timer; + set_expired(duration); + } else { // middle + new_timer->prev = itr->prev; + new_timer->next = itr; + itr->prev->next = new_timer; + itr->prev = new_timer; + } + } +} + +void timer_callback(char *msg, unsigned long register_time) { + kprintf("\nSeconds after booting: %d\n", get_current_time()); + kprintf("%s, register at: %d\n", msg, register_time); +} + +void set_timeout(char *args) { + int i; + int duration; + int message_end = -1; + + for(i=0 ; args[i]!='\0' ; i++) if (args[i] == ' ') { + message_end = i; + break; + } + if (message_end == -1) { + kputs("setTimeout: MESSAGE SECONDS\n"); + return; + } + args[message_end] = '\0'; + duration = atoi(args+message_end+1, 10, strlen(args+message_end+1)); + if (duration <= 0 || duration >= 35) { + kputs("setTimeout: time error\n"); + return; + } + kprintf("Timeout: %ds\n", duration); + add_timer(timer_callback, args, duration); +} \ No newline at end of file diff --git a/lab6/lib/dtb.c b/lab6/lib/dtb.c new file mode 100644 index 000000000..905348585 --- /dev/null +++ b/lab6/lib/dtb.c @@ -0,0 +1,60 @@ +#include "dtb.h" +#include "string.h" +#include "byteswap.h" +#include "kern/mm.h" + +#define align4(num) ((num + 3) & (-4)) + +char FDT_HEADER_MAGIC[4] = {0xd0, 0x0d, 0xfe, 0xed}; + +void *DTB_ADDRESS = 0; +void *DTB_END_ADR = 0; + +int fdt_init() { + asm volatile("MOV %0, x23" : "=r"(DTB_ADDRESS)); + DTB_ADDRESS = (void*)PHY_2_VIRT(DTB_ADDRESS); + if (strncmp((char*)DTB_ADDRESS, FDT_HEADER_MAGIC, 4)) + return -1; + return 0; +} + +int fdt_traverse(void (*cb)(char *, char *, void *)) { + unsigned int token; + void *ptr; + void *struct_block; + void *string_block; + char *node_name = 0; + char *prop_name = 0; + struct fdt_prop *prop; + struct fdt_header *header = DTB_ADDRESS; + + struct_block = DTB_ADDRESS + __bswap_32(header->off_dt_struct); + string_block = DTB_ADDRESS + __bswap_32(header->off_dt_strings); + + for (ptr=struct_block ; ; ptr+=4) { + token = __bswap_32(*((unsigned int*)ptr)); + if (token == FDT_BEGIN_NODE) { + node_name = ptr + 4; + ptr += align4(strlen(node_name) + 1); + } else if (token == FDT_END_NODE) { + } else if (token == FDT_PROP) { + prop = ptr + 4; + prop_name = string_block + __bswap_32(prop->nameoff); + cb(node_name, prop_name, ptr + 12); + ptr += align4(8 + __bswap_32(prop->len)); + } else if (token == FDT_NOP) { + } else if (token == FDT_END) { + break; + } else { + return -1; + } + } + DTB_END_ADR = ptr; + return 0; +} + +void fdt_reserve() { + if (!DTB_END_ADR) + return; + mm_reserve(DTB_ADDRESS, DTB_END_ADR); +} \ No newline at end of file diff --git a/lab6/lib/mailbox.c b/lab6/lib/mailbox.c new file mode 100644 index 000000000..bb7a13927 --- /dev/null +++ b/lab6/lib/mailbox.c @@ -0,0 +1,89 @@ +#include "peripheral/mailbox.h" +#include "string.h" +#include "kern/mm_types.h" + +unsigned int mailbox_call(unsigned char ch, unsigned int* mailbox) { + unsigned int message; + unsigned int data; + + // Combine the message address (upper 28 bits) with channel number (lower 4 bits) + message = ((unsigned long)VIRT_2_PHY(mailbox) & 0xfffffff0) | (ch & 0xf); + // Check if Mailbox 0 status register’s full flag is set + while((*MAILBOX_STATUS & MAILBOX_FULL)) asm volatile("nop"); + // write to Mailbox 1 Read/Write register + *MAILBOX_WRITE = message; + while(1) { + // Check if Mailbox 0 status register’s empty flag is set + while((*MAILBOX_STATUS & MAILBOX_EMPTY)) asm volatile("nop"); + // read from Mailbox 0 Read/Write register + data = (unsigned int)(*MAILBOX_READ); + // Check if the value is the same as you wrote + if (data == message) { + return mailbox[1] == REQUEST_SUCCEED; + } + } + return 0; +} + +/* +https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface +Get board revision + Tag: 0x00010002 + Request: + Length: 0 + Response: + Length: 4 + Value: + u32: board revision +*/ +void get_board_revision(unsigned int *result){ + unsigned int mailbox[7]; + + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = END_TAG; + + // message passing procedure call + if (mailbox_call(0x8, mailbox)) { + // it should be 0xa020d3 for rpi3 b+ + result[0] = mailbox[5]; + } +} + +/* +Get ARM memory + Tag: 0x00010005 + Request: + Length: 0 + Response: + Length: 8 + Value: + u32: base address in bytes + u32: size in bytes +*/ +void get_ARM_memory(unsigned int *result) { + unsigned int mailbox[8]; + + mailbox[0] = 8 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_ARM_MEMORY; // tag identifier + mailbox[3] = 8; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + mailbox[6] = 0; // value buffer + // tags end + mailbox[7] = END_TAG; + + // message passing procedure call + if (mailbox_call(0x8, mailbox)) { + result[0] = mailbox[5]; + result[1] = mailbox[6]; + } +} \ No newline at end of file diff --git a/lab6/lib/reset.c b/lab6/lib/reset.c new file mode 100644 index 000000000..933c7d00d --- /dev/null +++ b/lab6/lib/reset.c @@ -0,0 +1,16 @@ +#include "reset.h" + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +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 +} + +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} diff --git a/lab6/lib/startup_alloc.c b/lab6/lib/startup_alloc.c new file mode 100644 index 000000000..96e423fa2 --- /dev/null +++ b/lab6/lib/startup_alloc.c @@ -0,0 +1,22 @@ +#include "kern/mm.h" + +extern unsigned int __heap_start; + +void *heap_start = (void *)&__heap_start; +void *heap_cur = (void *)&__heap_start; + +int startup = 1; + +void* sumalloc(unsigned int size) { + void *ret = (void*)0; + if (!startup) + goto out; + ret = heap_cur; + heap_cur += size; +out: + return ret; +} + +void reserved_kern_startup() { + mm_reserve(heap_start, heap_cur + 8192); +} \ No newline at end of file diff --git a/lab6/lib/string.c b/lab6/lib/string.c new file mode 100644 index 000000000..7517fafa2 --- /dev/null +++ b/lab6/lib/string.c @@ -0,0 +1,114 @@ + +unsigned int strlen(const char *str) { + const char *c; + for (c=str ; *c ; ++c); + return c - str; +} + +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 int n) { + unsigned char c1 = '\0'; + unsigned char c2 = '\0'; + + // if (n >= 4) { + // unsigned int 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; +} + +void strrev(char* str, unsigned int len) { + int i; + int j; + char a; + for (i = 0, j = len - 1; i < j; i++, j--) { + a = str[i]; + str[i] = str[j]; + str[j] = a; + } +} + +int itoa(long num, char* str, int base) { + long sum = num; + int i = 0; + int digit; + do { + digit = sum % base; + if (digit < 0xA) + str[i++] = '0' + digit; + else + str[i++] = 'A' + digit - 0xA; + sum /= base; + } while(sum); + if (sum) + return -1; + str[i] = '\0'; + strrev(str, i); + return 0; +} + +long atoi(char* str, int base, unsigned int len) { + long num = 0; + int i; + for (i=0 ; i= 'A') + num += str[i] - 'A' + 10; + else + num += str[i] - '0'; + } + return num; +} + +void* memcpy (void* dest, const void* src, unsigned int len) { + char *d = dest; + const char *s = src; + while (len--) + *d++ = *s++; + return dest; +} + +void* memset (void *dest, int val, unsigned int len) { + unsigned char *ptr = dest; + while (len-- > 0) + *ptr++ = val; + return dest; +} \ No newline at end of file diff --git a/lab6/lib/uart.c b/lab6/lib/uart.c new file mode 100644 index 000000000..7233d24e1 --- /dev/null +++ b/lab6/lib/uart.c @@ -0,0 +1,176 @@ +#include "peripheral/aux.h" +#include "peripheral/gpio.h" +#include "peripheral/uart.h" +#include "peripheral/interrupt.h" +#include "string.h" + +#define MAX_BUFFER_SIZE 1024 + +// If this bit is set the interrupt line is asserted whenever the transmit FIFO is empty. +#define ENABLE_TX_INT (*AUX_MU_IER |= 2) +#define DISABLE_TX_INT (*AUX_MU_IER &= ~(2)) + +char read_buffer[MAX_BUFFER_SIZE]; +char write_buffer[MAX_BUFFER_SIZE]; + +int read_start, + read_end; +int write_start, + write_end; + +void uart_init() { + + // Mini UART initialization + *AUX_ENABLES |= 1; // Enable mini UART + *AUX_MU_CNTL = 0; // Disable transmitter and receiver during configuration + *AUX_MU_IER = 0; // Disable interrupt + *AUX_MU_LCR = 3; // Set the data size to 8 bit + *AUX_MU_MCR = 0; // Don’t need auto flow control + *AUX_MU_BAUD = 270; // Set baud rate to 115200 + *AUX_MU_IIR = 6; // No FIFO + + // configure GPIO pin + // 1. configure GPFSELn register to change alternate function + // spec p.92 p.102 + register unsigned int r = *GPFSEL1; + r &= ~((7 << 12) | (7 << 15)); // Reset GPIO 14, 15 ex: RRP19P18P17P16P15P14P13P12P11P10 + // 000000 + r |= (2 << 12) | (2 << 15); // Set to ALT5 (010 = GPIO Pin xx takes alternate function 5) + *GPFSEL1 = r; + + // 2. configure pull up/down register to disable GPIO pull up/down + // spec p.101 + *GPPUD = 0; // Write to GPPUD to set the required control signal + r = 150; // Wait 150 cycles + while(r--) asm volatile("nop"); + *GPPUDCLK0 = (1<<14) | (1<<15); // Write to GPPUDCLK0/1 to clock the control signal into the GPIO pads you wish to modify + r = 150; // Wait 150 cycles + while(r--) asm volatile("nop"); + *GPPUDCLK0 = 0; // Write to GPPUDCLK0/1 to remove the clock + + *AUX_MU_CNTL = 3; // Enable the transmitter and receiver + + read_start = read_end = 0; + write_start = write_end = 0; + + // spec p.12, enable rx interrupt + *AUX_MU_IER |= 1; + + uart_sync_puts("UART initialized successfully!\n"); +} + +inline void uart_enable_int() { + ENABLE_IRQS_1_AUX; +} + +inline void uart_disable_int() { + DISABLE_IRQS_1_AUX; +} + + +void uart_int_handler() { + char r; + int tx = *AUX_MU_IIR & 0b10; + int rx = *AUX_MU_IIR & 0b100; + if (rx) { + r = (char)(*AUX_MU_IO); + read_buffer[read_end] = r; + read_end = (read_end + 1) % MAX_BUFFER_SIZE; + } + if (tx) { + while(*AUX_MU_LSR & 0x20) { + if (write_start == write_end) { + DISABLE_TX_INT; + break; + } + *AUX_MU_IO = write_buffer[write_start]; + write_start = (write_start + 1) % MAX_BUFFER_SIZE; + } + } + uart_enable_int(); +} + +void uart_flush() { + while(*AUX_MU_LSR & 0x01) + *AUX_MU_IO; +} + +/* sync */ + +char uart_sync_read() { + char r; + // Check AUX_MU_LSR_REG’s data ready field (Bit 0) + do { + asm volatile("nop"); + } while(!(*AUX_MU_LSR & 0x01)); + r = (char)(*AUX_MU_IO); + return r == '\r' ? '\n' : r; +} + +char uart_sync_read_raw() { + do { + asm volatile("nop"); + } while(!(*AUX_MU_LSR & 0x01)); + return (char)(*AUX_MU_IO); +} + +void uart_sync_write(unsigned int c) { + // Check AUX_MU_LSR_REG’s Transmitter empty field (Bit 5) + do { + asm volatile("nop"); + } while(!(*AUX_MU_LSR & 0x20)); + *AUX_MU_IO = c; +} + +void uart_sync_puts(char *s) { + while(*s) { + if (*s == '\n') + uart_sync_write('\r'); + uart_sync_write(*s++); + } +} + +void uart_sync_printNum(long num, int base) { + char buffer[64]; + if (itoa(num, buffer, base) == -1) + uart_sync_puts("@"); + else + uart_sync_puts(buffer); +} + +/* async */ + +char uart_async_read() { + char r; + while (read_start == read_end) { + asm volatile("nop"); + } + r = read_buffer[read_start]; + read_start = (read_start + 1) % MAX_BUFFER_SIZE; + return r == '\r' ? '\n' : r; +} + +void uart_async_write(unsigned int c) { + write_buffer[write_end] = c; + write_end = (write_end + 1) % MAX_BUFFER_SIZE; + ENABLE_TX_INT; +} + +void uart_async_write_buffer(unsigned int c) { + write_buffer[write_end] = c; + write_end = (write_end + 1) % MAX_BUFFER_SIZE; +} + +void uart_async_puts(char *s) { + while(*s) { + if (*s == '\n') + uart_async_write_buffer('\r'); + uart_async_write_buffer(*s++); + } + ENABLE_TX_INT; +} + +void uart_write_flush() { + if (write_start != write_end) + ENABLE_TX_INT; +} \ No newline at end of file diff --git a/lab6/lib/user_lib.c b/lab6/lib/user_lib.c new file mode 100644 index 000000000..2b8e0d955 --- /dev/null +++ b/lab6/lib/user_lib.c @@ -0,0 +1,65 @@ +#include "string.h" +#include "syscall.h" +#include "kern/slab.h" + +void printf(char *fmt, ...) { + char s[128]; + char buffer[64]; + char *dst = s; + char *p; + + __builtin_va_list args; + __builtin_va_start(args, fmt); + + while (*fmt) { + if (*fmt == '%') { + fmt++; + // escape + if (*fmt == '%') { + goto put; + } + // string + else if (*fmt == 's') { + p = __builtin_va_arg(args, char *); + while (*p) + *dst++ = *p++; + } + // char + else if (*fmt == 'c') { + char c = __builtin_va_arg(args, int); + *dst++ = c; + } + // decimal + else if (*fmt == 'd') { + int arg = __builtin_va_arg(args, int); + if (itoa(arg, buffer, 10) != -1) { + p = buffer; + while(*p) + *dst++ = *p++; + } else { + *dst++ = '@'; + } + + } + // hex + else if (*fmt == 'x') { + long arg = __builtin_va_arg(args, long); + if (itoa(arg, buffer, 16) != -1) { + p = buffer; + while(*p) + *dst++ = *p++; + } else { + *dst++ = '@'; + } + } + } + else { + put: + *dst++ = *fmt; + } + *fmt++; + } + *dst = '\0'; + __builtin_va_end(args); + uart_write(s, dst-s); +} \ No newline at end of file diff --git a/lab6/raspi3/bcm2710-rpi-3-b-plus.dtb b/lab6/raspi3/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/raspi3/config.txt b/lab6/raspi3/config.txt new file mode 100644 index 000000000..e82fa85fa --- /dev/null +++ b/lab6/raspi3/config.txt @@ -0,0 +1,3 @@ +kernel=bootloader.img +arm_64bit=1 +initramfs initramfs.cpio 0x8000000 \ No newline at end of file diff --git a/lab6/rootfs/Makefile b/lab6/rootfs/Makefile new file mode 100644 index 000000000..d864058e8 --- /dev/null +++ b/lab6/rootfs/Makefile @@ -0,0 +1,20 @@ +# OSC 2022 +CC = aarch64-linux-gnu-gcc +LD = aarch64-linux-gnu-ld +OBJCOPY = aarch64-linux-gnu-objcopy + +LINKER_FILE = linker.ld + +# -fno-stack-protector: to disable stack protection +# -fno-builtin is required to avoid refs to undefined functions in the kernel. +# Only optimize to -O1 to discourage inlining, which complicates backtraces. +CFLAGS := -O1 -fno-builtin -nostdinc +CFLAGS += -Wall -c -fno-stack-protector + +user_prog: user_prog.S $(LINKER_FILE) + $(CC) $(CFLAGS) $< -o $@.o + $(LD) -T $(LINKER_FILE) -o $@ $@.o + $(OBJCOPY) $@ -O binary $@ + +archv: + find . | cpio -o -H newc > ../initramfs.cpio \ No newline at end of file diff --git a/lab6/rootfs/file1 b/lab6/rootfs/file1 new file mode 100644 index 000000000..d88c464a9 --- /dev/null +++ b/lab6/rootfs/file1 @@ -0,0 +1 @@ +This is file1 \ No newline at end of file diff --git a/lab6/rootfs/file2.txt b/lab6/rootfs/file2.txt new file mode 100644 index 000000000..d9a0c4d55 --- /dev/null +++ b/lab6/rootfs/file2.txt @@ -0,0 +1 @@ +This is file2 \ No newline at end of file diff --git a/lab6/rootfs/linker.ld b/lab6/rootfs/linker.ld new file mode 100644 index 000000000..05132105e --- /dev/null +++ b/lab6/rootfs/linker.ld @@ -0,0 +1,31 @@ +SECTIONS +{ + . = 0x0; + .text : { + *(.text .text.* .gnu.linkonce.t.*) + } + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + . = ALIGN(0x1000); + + /* The data segment */ + .data : { + *(.data) + } + + .bss ALIGN(16) (NOLOAD) : { + PROVIDE(__bss_start = .); + *(.bss) + PROVIDE(__bss_end = .); + BYTE(0) + } + + . = ALIGN(0x1000); + + /DISCARD/ : { + *(.eh_frame .note.GNU-stack) + } +} \ No newline at end of file diff --git a/lab6/rootfs/user_prog.S b/lab6/rootfs/user_prog.S new file mode 100644 index 000000000..ad2655ba4 --- /dev/null +++ b/lab6/rootfs/user_prog.S @@ -0,0 +1,14 @@ +.section ".text" + +.global _start +_start: + mov x0, 0 + svc 1 +1: + add x0, x0, 1 + svc 0 + cmp x0, 5 + blt 1b + svc 4 +1: + b 1b \ No newline at end of file diff --git a/lab7/Makefile b/lab7/Makefile new file mode 100644 index 000000000..64e8b48cf --- /dev/null +++ b/lab7/Makefile @@ -0,0 +1,58 @@ +# OSC 2022 +CC = aarch64-linux-gnu-gcc +LD = aarch64-linux-gnu-ld +OBJCOPY = aarch64-linux-gnu-objcopy + + +IMG = kernel8.img +ELF = kernel8.elf +LINKER_FILE = kern/linker.ld + +OUT_DIR = out +INC_DIR = include + +SRCS := $(wildcard kern/*.S) +SRCS += $(wildcard kern/*.c) +SRCS += $(wildcard lib/*.c) +SRCS += $(wildcard fs/*.c) +SRCS := $(notdir $(SRCS)) +OBJS := $(patsubst %.c, $(OUT_DIR)/%_c.o, $(SRCS)) +OBJS := $(patsubst %.S, $(OUT_DIR)/%_s.o, $(OBJS)) + +# -fno-stack-protector: to disable stack protection +# -fno-builtin is required to avoid refs to undefined functions in the kernel. +# Only optimize to -O1 to discourage inlining, which complicates backtraces. +CFLAGS := -O1 -fno-builtin -nostdinc +CFLAGS += -Wall -I$(INC_DIR) -c -fno-stack-protector + +.PHONY: asm debug clean run + + +$(IMG): $(ELF) + $(OBJCOPY) -O binary $(ELF) $(IMG) +$(ELF): $(OBJS) $(LINKER_FILE) + $(LD) -T $(LINKER_FILE) -o $(ELF) $(OBJS) + +$(OUT_DIR)/%_s.o: kern/%.S $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ +$(OUT_DIR)/%_c.o: kern/%.c $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ +$(OUT_DIR)/%_c.o: fs/%.c $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ +$(OUT_DIR)/%_c.o: lib/%.c $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ + +$(OUT_DIR): + @mkdir -p $(OUT_DIR) + + +asm: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -d in_asm +debug: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -serial null -serial stdio -initrd initramfs.cpio -S -s +run: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -serial null -serial stdio -initrd initramfs.cpio +run-display: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -serial null -serial stdio -initrd initramfs.cpio +clean: + rm -rf $(OUT_DIR) $(ELF) $(IMG) \ No newline at end of file diff --git a/lab7/boot/Makefile b/lab7/boot/Makefile new file mode 100644 index 000000000..888903976 --- /dev/null +++ b/lab7/boot/Makefile @@ -0,0 +1,54 @@ +# bootloader +CC = aarch64-linux-gnu-gcc +LD = aarch64-linux-gnu-ld +OBJCOPY = aarch64-linux-gnu-objcopy + + +IMG = bootloader.img +ELF = bootloader.elf + +OUT_DIR = out +INC_DIR = ../include + +SRCS := boot.S \ + relocate.c \ + main.c \ + ../lib/uart.c \ + ../lib/string.c +SRCS := $(notdir $(SRCS)) +OBJS := $(patsubst %.c, $(OUT_DIR)/%.o, $(SRCS)) +OBJS := $(patsubst %.S, $(OUT_DIR)/%.o, $(OBJS)) + +# -fno-stack-protector: to disable stack protection +CFLAGS := -O1 -fno-builtin -nostdinc -DBOOT_LOADER +CFLAGS += -Wall -I$(INC_DIR) -c -fno-stack-protector + +.PHONY: asm debug clean run pty + + +$(IMG): $(ELF) + $(OBJCOPY) -O binary $(ELF) $(IMG) +$(ELF): $(OBJS) linker.ld $(OUT_DIR)/boot.o + $(LD) -T linker.ld -o $(ELF) $(OBJS) + +$(OUT_DIR)/boot.o: boot.S $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ +$(OUT_DIR)/%.o: %.c $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ +$(OUT_DIR)/%.o: ../lib/%.c $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ + +$(OUT_DIR): + @mkdir -p $(OUT_DIR) + + +asm: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -d in_asm +debug: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -S -s +run: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -serial null -serial stdio +pty: + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -serial null -serial pty -initrd ../initramfs.cpio -dtb ../raspi3/bcm2710-rpi-3-b-plus.dtb +clean: + rm -rf $(OUT_DIR) $(ELF) $(IMG) \ No newline at end of file diff --git a/lab7/boot/boot.S b/lab7/boot/boot.S new file mode 100644 index 000000000..e26a31ce3 --- /dev/null +++ b/lab7/boot/boot.S @@ -0,0 +1,30 @@ +.section ".text.relocate" + +.global _relocate +_relocate: + // save dtb address + mov x23, x0 +2: + ldr x0, = __stack_top + mov sp, x0 + + // clear bss + ldr x0, =__bss_start + ldr x1, =__bss_size +3: cbz x1, 4f + // [x0] = 0, x0 = x0 + 8 + str xzr, [x0], #8 + // x1 = x1 - 1 + sub x1, x1, #1 + cbnz x1, 3b +4: bl relocate + + + +.section ".text.boot" + +.global _start +_start: + bl main +1: wfe + b 1b diff --git a/lab7/boot/linker.ld b/lab7/boot/linker.ld new file mode 100644 index 000000000..723384a45 --- /dev/null +++ b/lab7/boot/linker.ld @@ -0,0 +1,43 @@ +SECTIONS +{ + . = 0x80000; + .relocate : { + KEEP(*(.text.relocate)) + } + + /* Adjust the address for the data segment to the next page */ + . = ALIGN(0x1000); + + __begin = .; + .text : { + KEEP(*(.text.boot)) + *(.text .text.* .gnu.linkonce.t.*) + } + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + . = ALIGN(0x1000); + + /* The data segment */ + .data : { + *(.data) + } + + .bss ALIGN(16) (NOLOAD) : { + PROVIDE(__bss_start = .); + *(.bss) + PROVIDE(__bss_end = .); + BYTE(0) + } + __end = .; + + /DISCARD/ : { + *(.eh_frame .note.GNU-stack) + } +} + +__stack_top = 0x20000000; +__bss_size = (__bss_end - __bss_start) >> 3; +__bootloader = 0x60000; \ No newline at end of file diff --git a/lab7/boot/main.c b/lab7/boot/main.c new file mode 100644 index 000000000..139ba2ec1 --- /dev/null +++ b/lab7/boot/main.c @@ -0,0 +1,42 @@ +#include "peripheral/uart.h" + +#define KERNEL_ADDR 0x80000 +#define READ_INT(var) \ + var = 0; \ + for (i=0 ; i<4 ; i++) {\ + var <<= 8; \ + var |= (int)uart_sync_read_raw(); \ + } \ + +int main() { + int img_size; + int img_checksum; + int i; + + uart_init(); + uart_flush(); + + READ_INT(img_size); + READ_INT(img_checksum); + + uart_sync_printNum(img_size, 10); + uart_sync_puts("\n"); + uart_sync_printNum(img_checksum, 10); + uart_sync_puts("\n"); + + for (i=0 ; ii_dentry->d_subdirs)) + return -1; + list_for_each(ptr, &dir_node->i_dentry->d_subdirs) { + dentry = list_entry(ptr, struct dentry, d_child); + if (!strcmp(dentry->d_name, component_name) && dentry->d_inode->i_type == I_FILE) { + *target = dentry->d_inode; + return 0; + } + } + return -1; +} + +int tmpfs_create(struct inode* dir_node, struct inode** target, const char* component_name) { + struct tmpfs_inode *tmpfs_internal = (struct tmpfs_inode *)kmalloc(sizeof(struct tmpfs_inode)); + struct dentry *new_dentry = tmpfs_create_dentry(dir_node->i_dentry, component_name, I_FILE, I_FRW); + new_dentry->d_inode->internal = (void*)tmpfs_internal; + *target = new_dentry->d_inode; + return 0; +} + +int tmpfs_mkdir(struct inode* dir_node, struct inode** target, const char* component_name) { + struct dentry *new_dentry = tmpfs_create_dentry(dir_node->i_dentry, component_name, I_DIRECTORY, I_FRW); + *target = new_dentry->d_inode; + return 0; +} + +int initramfs_create(struct inode* dir_node, struct inode** target, const char* component_name) { + return -1; +} + +int initramfs_mkdir(struct inode* dir_node, struct inode** target, const char* component_name) { + return -1; +} + +/* + file operation +*/ +int tmpfs_open(struct inode* file_node, struct file** target) { + return 0; +} + +int tmpfs_close(struct file *file) { + return 0; +} + +int tmpfs_write(struct file *file, const void *buf, long len) { + struct tmpfs_inode *tmpfs_internal = (struct tmpfs_inode *)file->inode->internal; + unsigned long size = file->inode->i_size; + unsigned long i = file->f_pos; + unsigned long bi = 0; + char *src = (char*)buf; + for ( ; bidata[i] = src[bi]; + bi++; + } + file->f_pos = i; + if (i > size) + file->inode->i_size = i; + return bi; +} + +int tmpfs_read(struct file *file, void *buf, long len) { + struct tmpfs_inode *tmpfs_internal = (struct tmpfs_inode *)file->inode->internal; + unsigned long size = file->inode->i_size; + unsigned long i = file->f_pos; + unsigned long bi = 0; + char *dest = (char*)buf; + for ( ; bidata[i]; + bi++; + } + file->f_pos = i; + return bi; +} + +long tmpfs_lseek64(struct file* file, long offset, int whence) { + unsigned long size = file->inode->i_size; + if (whence == SEEK_SET) { + file->f_pos = offset > size ? size : offset; + } else if (whence == SEEK_END) { + file->f_pos = size + offset; + } + return file->f_pos; +} + +int initramfs_write(struct file *file, const void *buf, long len) { + return 0; +} + +int initramfs_read(struct file *file, void *buf, long len) { + struct initramfs_inode *initramfs_internal = (struct initramfs_inode *)file->inode->internal; + unsigned long size = file->inode->i_size; + unsigned long i = file->f_pos; + unsigned long bi = 0; + char *dest = (char*)buf; + for ( ; bidata[i]; + bi++; + } + file->f_pos = i; + return bi; +} + + +int tmpfs_register() { + tmpfs_iop = (struct inode_operations *)kmalloc(sizeof(struct inode_operations)); + tmpfs_iop->lookup = tmpfs_lookup; + tmpfs_iop->create = tmpfs_create; + tmpfs_iop->mkdir = tmpfs_mkdir; + tmpfs_fop = (struct file_operations *)kmalloc(sizeof(struct file_operations)); + tmpfs_fop->write = tmpfs_write; + tmpfs_fop->read = tmpfs_read; + tmpfs_fop->open = tmpfs_open; + tmpfs_fop->close = tmpfs_close; + tmpfs_fop->lseek64 = tmpfs_lseek64; + tmpfs_dop = 0; + + initramfs_iop = (struct inode_operations *)kmalloc(sizeof(struct inode_operations)); + initramfs_iop->lookup = tmpfs_lookup; + initramfs_iop->create = initramfs_create; + initramfs_iop->mkdir = initramfs_mkdir; + initramfs_fop = (struct file_operations *)kmalloc(sizeof(struct file_operations)); + initramfs_fop->write = initramfs_write; + initramfs_fop->read = initramfs_read; + initramfs_fop->open = tmpfs_open; + initramfs_fop->close = tmpfs_close; + initramfs_fop->lseek64 = tmpfs_lseek64; + return 0; +} + +int tmpfs_setup_mount(struct filesystem *fs, struct mount *mount) { + mount->fs = fs; + mount->root = tmpfs_create_dentry(0, "/", I_DIRECTORY, I_FRW); + return 0; +} + +struct filesystem *tmpfs = 0; +struct filesystem* tmpfs_get_filesystem() { + if (tmpfs == 0) { + tmpfs = (struct filesystem *)kmalloc(sizeof(struct filesystem)); + strcpy(tmpfs->name, "tmpfs"); + tmpfs->setup_mount = tmpfs_setup_mount; + } + return tmpfs; +} + +struct inode* tmpfs_create_inode(struct dentry *dentry, unsigned int type, unsigned int flags) { + struct inode *inode = (struct inode *)kmalloc(sizeof(struct inode)); + inode->i_op = tmpfs_iop; + inode->i_fop = tmpfs_fop; + inode->i_dentry = dentry; + inode->i_flags = flags; + inode->i_type = type; + inode->i_size = 0; + return inode; +} + +struct dentry* tmpfs_create_dentry(struct dentry *parent, const char *name, unsigned int type, unsigned int flags) { + struct dentry *dentry = (struct dentry *)kmalloc(sizeof(struct dentry)); + strcpy(dentry->d_name, name); + dentry->d_parent = parent; + dentry->d_inode = tmpfs_create_inode(dentry, type, flags); + // dentry->d_op = tmpfs_dop; + dentry->d_mount = 0; + INIT_LIST_HEAD(&dentry->d_child); + INIT_LIST_HEAD(&dentry->d_subdirs); + if (parent) + list_add_tail(&dentry->d_child, &parent->d_subdirs); + return dentry; +} + +#include "kern/cpio.h" + +/* + Used to create initramfs' file + 1. point directly to data + 2. RO +*/ +void initramfs_init_create(struct inode *root_node, const char *pathname, char *data, int filesize) { + struct inode *dir_node; + struct dentry *new_dentry; + struct initramfs_inode *initramfs_internal; + char filename[32]; + + vfs_walk_recursive(root_node, pathname, &dir_node, filename); + initramfs_internal = (struct initramfs_inode *)kmalloc(sizeof(struct initramfs_inode)); + initramfs_internal->data = data; + new_dentry = tmpfs_create_dentry(dir_node->i_dentry, filename, I_FILE, I_FRO); + new_dentry->d_inode->internal = initramfs_internal; + new_dentry->d_inode->i_size = filesize; + new_dentry->d_inode->i_fop = initramfs_fop; + new_dentry->d_inode->i_op = initramfs_iop; +} + +void initramfs_init_mkdir(struct inode *root_node, const char *pathname) { + struct inode *dir_node; + struct dentry *new_dentry; + char dirname[32]; + + vfs_walk_recursive(root_node, pathname, &dir_node, dirname); + new_dentry = tmpfs_create_dentry(dir_node->i_dentry, dirname, I_DIRECTORY, I_FRO); + new_dentry->d_inode->i_fop = initramfs_fop; + new_dentry->d_inode->i_op = initramfs_iop; +} + +int initramfs_setup_mount(struct filesystem *fs, struct mount *mount) { + int i = 0; + int filesize = 0; + int namesize = 0; + int mode = 0; + struct cpio_newc_header *header; + + mount->fs = fs; + mount->root = tmpfs_create_dentry(0, "/", I_DIRECTORY, I_FRO); + mount->root->d_inode->i_fop = initramfs_fop; + mount->root->d_inode->i_op = initramfs_iop; + + for ( ; ; i+=namesize+filesize) { + header = ((struct cpio_newc_header *)(CPIO_ADDRESS + i)); + if (strncmp(header->c_magic, CPIO_MAGIC, 6)) { + break; + } + filesize = (atoi(header->c_filesize, 16, 8) + 3) & -4; + namesize = ((atoi(header->c_namesize, 16, 8) + 6 + 3) & -4) - 6; + i += sizeof(struct cpio_newc_header); + if (!strncmp((char *)(CPIO_ADDRESS + i), CPIO_END, 10)) + break; + if (!strncmp((char *)(CPIO_ADDRESS + i), ".", 1)) { + continue; + } + mode = atoi(header->c_mode, 16, 8); + if ((mode & 00170000) == 0100000) { + initramfs_init_create(mount->root->d_inode, (char *)(CPIO_ADDRESS + i), (char *)(CPIO_ADDRESS + i + namesize), atoi(header->c_filesize, 16, 8)); + } + if ((mode & 00170000) == 0040000) { + initramfs_init_mkdir(mount->root->d_inode, (char *)(CPIO_ADDRESS + i)); + } + } + + return 0; +} + +struct filesystem *initramfs = 0; +struct filesystem* initramfs_get_filesystem() { + if (initramfs == 0) { + initramfs = (struct filesystem *)kmalloc(sizeof(struct filesystem)); + strcpy(initramfs->name, "initramfs"); + initramfs->setup_mount = initramfs_setup_mount; + } + return initramfs; +} diff --git a/lab7/fs/uartfs.c b/lab7/fs/uartfs.c new file mode 100644 index 000000000..eda7847cb --- /dev/null +++ b/lab7/fs/uartfs.c @@ -0,0 +1,49 @@ +/* + Used to register uart as device file, not a filesystem. +*/ +#include "fs/vfs.h" +#include "kern/slab.h" +#include "peripheral/uart.h" + +int uartfs_read(struct file *file, void *buffer, long len) { + int i; + char *buf = (char *)buffer; + for(i=0 ; iread = uartfs_read; + fop->write = uartfs_write; + fop->open = uartfs_open; + fop->close = uartfs_close; + fop->lseek64 = uartfs_lseek64; + dev = vfs_register_device(fop); + vfs_mknod("/dev/uart", 0, dev); +} \ No newline at end of file diff --git a/lab7/fs/vfs.c b/lab7/fs/vfs.c new file mode 100644 index 000000000..9db28c478 --- /dev/null +++ b/lab7/fs/vfs.c @@ -0,0 +1,258 @@ +#include "fs/vfs.h" +#include "fs/tmpfs.h" +#include "fs/uartfs.h" +#include "string.h" +#include "kern/kio.h" +#include "kern/sched.h" +#include "kern/slab.h" + +struct mount* rootfs; + +/* + device file +*/ +#define MAX_DEVICE_FILE 10 + +int device_id; +struct file_operations *device_files[MAX_DEVICE_FILE]; + + +int register_filesystem(struct filesystem* fs) { + if (!strcmp(fs->name, "tmpfs")) { + return tmpfs_register(); + } + return -1; +} + +void rootfs_init() { + struct filesystem *tmpfs = tmpfs_get_filesystem(); + register_filesystem(tmpfs); + + rootfs = (struct mount *)kmalloc(sizeof(struct mount)); + tmpfs->setup_mount(tmpfs, rootfs); + + // device file init + device_id = 0; + memset(device_files, 0, MAX_DEVICE_FILE); + vfs_mkdir("/dev"); + uartfs_register(); +} + +void vfs_walk_recursive(struct inode *dir_node, const char *pathname, struct inode **target, char *target_name) { + struct list_head *ptr; + struct dentry *dentry; + int i = 0; + while(pathname[i]) { + if (pathname[i] == '/') + break; + target_name[i] = pathname[i]; + i++; + } + target_name[i] = '\0'; + + *target = dir_node; + if (i == 0) + return; + if (!strcmp(target_name, ".")) { + vfs_walk_recursive(dir_node, pathname+i+1, target, target_name); + return; + } + if (!strcmp(target_name, "..")) { + if (dir_node->i_dentry->d_parent == 0) + vfs_walk_recursive(dir_node, pathname+i+1, target, target_name); + else + vfs_walk_recursive(dir_node->i_dentry->d_parent->d_inode, pathname+i+1, target, target_name); + return; + } + + if (list_empty(&dir_node->i_dentry->d_subdirs)) + return; + list_for_each(ptr, &dir_node->i_dentry->d_subdirs) { + dentry = list_entry(ptr, struct dentry, d_child); + if (!strcmp(dentry->d_name, target_name)) { + if (dentry->d_mount != 0) { + vfs_walk_recursive(dentry->d_mount->root->d_inode, pathname+i+1, target, target_name); + return; + } + if (dentry->d_inode->i_type == I_DIRECTORY) + vfs_walk_recursive(dentry->d_inode, pathname+i+1, target, target_name); + return; + } + } +} + +void vfs_walk(const char *pathname, struct inode **target, char *target_name) { + struct inode *root; + if (pathname[0] == '/') { + root = rootfs->root->d_inode; + vfs_walk_recursive(root, pathname+1, target, target_name); + } else { + root = get_current()->cwd->d_inode; + vfs_walk_recursive(root, pathname, target, target_name); + } +} + +struct file* create_fh(struct inode *file_node) { + struct file *fh = (struct file*)kmalloc(sizeof(struct file)); + fh->inode = file_node; + fh->f_pos = 0; + fh->fop = file_node->i_fop; + return fh; +} + + +int vfs_open(const char *pathname, int flags, struct file **target) { + // 1. Lookup pathname + // 2. Create a new file handle for this vnode if found. + // 3. Create a new file if O_CREAT is specified in flags and vnode not found + // lookup error code shows if file exist or not or other error occurs + // 4. Return error code if fails + struct inode *dir_node; + struct inode *file_node; + char filename[32]; + vfs_walk(pathname, &dir_node, filename); + + if (dir_node->i_op->lookup(dir_node, &file_node, filename) >= 0) { + *target = create_fh(file_node); + return 0; + } + // kprintf("%s not found under %s\n", pathname, dir_node->i_dentry->d_name); + + if (flags & O_CREAT) { + if (dir_node->i_flags == I_FRO) + return -3; + if (dir_node->i_op->create(dir_node, &file_node, filename) < 0) + return -1; + *target = create_fh(file_node); + return 0; + } + return -1; +} + +int vfs_close(struct file *file) { + // 1. release the file handle + // 2. Return error code if fails + if (file == 0) + return -1; + kfree(file); + return 0; +} + +int vfs_write(struct file* file, const void* buf, long len) { + // 1. write len byte from buf to the opened file. + // 2. return written size or error code if an error occurs. + if (file == 0) + return -1; + if (file->inode->i_type != I_FILE) { + kprintf("vfs_write: not a regular file %d\n", file->inode->i_type); + return -1; + } + if (file->inode->i_flags == I_FRO) { + return -3; + } + return file->fop->write(file, buf, len); +} + +int vfs_read(struct file* file, void* buf, long len) { + // 1. read min(len, readable size) byte to buf from the opened file. + // 2. block if nothing to read for FIFO type + // 2. return read size or error code if an error occurs. + if (file == 0) + return -1; + if (file->inode->i_type != I_FILE) { + kprintf("vfs_read: not a regular file %d\n", file->inode->i_type); + return -1; + } + return file->fop->read(file, buf, len); +} + +int vfs_mkdir(const char* pathname) { + struct inode *dir_node; + struct inode *new_dir_node; + char dirname[32]; + vfs_walk(pathname, &dir_node, dirname); + if (dir_node->i_type != I_DIRECTORY) { + kprintf("vfs_mkdir: not a directory %d\n", dir_node->i_type); + return -1; + } + if (dir_node->i_flags == I_FRO) { + return -3; + } + return dir_node->i_op->mkdir(dir_node, &new_dir_node, dirname); +} + +int vfs_mount(const char* target, const char* filesystem) { + struct inode *mountpoint; + struct mount *mt; + struct filesystem *fs; + char remain[32]; + vfs_walk(target, &mountpoint, remain); + + if (mountpoint->i_type != I_DIRECTORY) + return -1; + if (!strcmp(mountpoint->i_dentry->d_name, "/")) { + kprintf("%s already been mounted\n", target); + return -2; + } + + if (!strcmp(filesystem, "tmpfs")) { + mt = (struct mount *)kmalloc(sizeof(struct mount)); + fs = tmpfs_get_filesystem(); + fs->setup_mount(fs, mt); + mountpoint->i_dentry->d_mount = mt; + mt->root->d_parent = mountpoint->i_dentry->d_parent; + } else if (!strcmp(filesystem, "initramfs")) { + mt = (struct mount *)kmalloc(sizeof(struct mount)); + fs = initramfs_get_filesystem(); + fs->setup_mount(fs, mt); + mountpoint->i_dentry->d_mount = mt; + mt->root->d_parent = mountpoint->i_dentry->d_parent; + } + return 0; +} + +int vfs_chdir(const char *pathname) { + struct inode *dir_node; + char remain[32]; + vfs_walk(pathname, &dir_node, remain); + get_current()->cwd = dir_node->i_dentry; + return 0; +} + +long vfs_lseek64(struct file *file, long offset, int whence) { + if (file == 0) + return -1; + if (file->inode->i_type != I_FILE) { + kprintf("vfs_lseek64: not a regular file %d\n", file->inode->i_type); + return -1; + } + return file->fop->lseek64(file, offset, whence); +} + +int vfs_mknod(const char* pathname, int mode, int dev) { + // 1. create special file + // 2. change special file's operation to dev operation + struct inode *dir_node; + struct inode *file_node; + char filename[32]; + vfs_walk(pathname, &dir_node, filename); + + if (dir_node->i_op->lookup(dir_node, &file_node, filename) >= 0) { + kprintf("vfs_mknod: %s already exist\n", pathname); + return -1; + } + if (dir_node->i_flags == I_FRO) + return -3; + if (dir_node->i_op->create(dir_node, &file_node, filename) < 0) + return -1; + file_node->i_fop = device_files[dev]; + return 0; +} + +int vfs_register_device(struct file_operations *device_fop) { + // register device operation and return device id + if (device_id == MAX_DEVICE_FILE) + return -1; + device_files[device_id] = device_fop; + return device_id++; +} \ No newline at end of file diff --git a/lab7/include/bitmap.h b/lab7/include/bitmap.h new file mode 100644 index 000000000..4654a3df0 --- /dev/null +++ b/lab7/include/bitmap.h @@ -0,0 +1,66 @@ +#ifndef BITMAP_H +#define BITMAP_H + +#define BITS_PER_BYTE 8 +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) +#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) + +#define DECLARE_BITMAP(name,bits) \ + unsigned long name[BITS_TO_LONGS(bits)] + +static inline void bitmap_zero(unsigned long *dst, unsigned int nbits) { + int i; + for(i=0 ; i>= 32; + } +#endif + if ((word & 0xffff) == 0) { + num += 16; + word >>= 16; + } + if ((word & 0xff) == 0) { + num += 8; + word >>= 8; + } + if ((word & 0xf) == 0) { + num += 4; + word >>= 4; + } + if ((word & 0x3) == 0) { + num += 2; + word >>= 2; + } + if ((word & 0x1) == 0) + num += 1; + return num; +} + +/* +bitops +*/ +static inline void __set_bit(int nr, volatile unsigned long *addr) { + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *) addr) + BIT_WORD(nr); + *p |= mask; +} + +static inline void __clear_bit(int nr, volatile unsigned long *addr) { + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *) addr) + BIT_WORD(nr); + *p &= ~mask; +} + +#endif \ No newline at end of file diff --git a/lab7/include/byteswap.h b/lab7/include/byteswap.h new file mode 100644 index 000000000..b58305de9 --- /dev/null +++ b/lab7/include/byteswap.h @@ -0,0 +1,9 @@ +#ifndef BYTESWAP_H +#define BYTESWAP_H + +/* Swap bytes in 32-bit value. */ +#define __bswap_32(x) \ + ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) \ + | (((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24)) + +#endif \ No newline at end of file diff --git a/lab7/include/dtb.h b/lab7/include/dtb.h new file mode 100644 index 000000000..921ef309b --- /dev/null +++ b/lab7/include/dtb.h @@ -0,0 +1,40 @@ +#ifndef DTB_H +#define DTB_H + +// #define FDT_HEADER_MAGIC 0xd00dfeed +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + +// All the header fields are stored in big-endian format +struct fdt_header { + unsigned int magic; + unsigned int totalsize; + unsigned int off_dt_struct; + unsigned int off_dt_strings; + unsigned int off_mem_rsvmap; + unsigned int version; + unsigned int last_comp_version; + unsigned int boot_cpuid_phys; + unsigned int size_dt_strings; + unsigned int size_dt_struct; +}; + +struct fdt_reserve_entry { + unsigned long long address; + unsigned long long size; +}; + +struct fdt_prop { + unsigned int len; + unsigned int nameoff; +}; + +int fdt_init(); +int fdt_traverse(void (*cb)(char *, char *, void *)); + +void fdt_reserve(); + +#endif \ No newline at end of file diff --git a/lab7/include/fs/tmpfs.h b/lab7/include/fs/tmpfs.h new file mode 100644 index 000000000..d19d21b61 --- /dev/null +++ b/lab7/include/fs/tmpfs.h @@ -0,0 +1,17 @@ +#ifndef TMPFS_H +#define TMPFS_H + +struct tmpfs_inode { + char data[4096]; +}; + +struct initramfs_inode { + char *data; +}; + +int tmpfs_register(); +struct filesystem* tmpfs_get_filesystem(); +struct filesystem* initramfs_get_filesystem(); +struct dentry* tmpfs_create_dentry(struct dentry *parent, const char *name, unsigned int type, unsigned int flags); + +#endif \ No newline at end of file diff --git a/lab7/include/fs/uartfs.h b/lab7/include/fs/uartfs.h new file mode 100644 index 000000000..19e80adb7 --- /dev/null +++ b/lab7/include/fs/uartfs.h @@ -0,0 +1,6 @@ +#ifndef UARTFS_H +#define UARTFS_H + +void uartfs_register(); + +#endif \ No newline at end of file diff --git a/lab7/include/fs/vfs.h b/lab7/include/fs/vfs.h new file mode 100644 index 000000000..5dd3b152f --- /dev/null +++ b/lab7/include/fs/vfs.h @@ -0,0 +1,97 @@ +#ifndef VFS_H +#define VFS_H + +#include "list.h" + +// syscall para +#define O_CREAT 00000100 + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +// i_type +#define I_FILE 1 +#define I_DIRECTORY 2 + +// i_flags +#define I_FRO 1 +#define I_FRW 2 + +struct inode { + struct inode_operations *i_op; + struct file_operations *i_fop; + struct dentry *i_dentry; + unsigned int i_flags; + unsigned int i_type; + unsigned long i_size; + void* internal; +}; + +struct dentry { + char d_name[32]; + struct dentry *d_parent; + struct inode *d_inode; + struct dentry_operations *d_op; + struct mount *d_mount; + struct list_head d_child; + struct list_head d_subdirs; +}; + +struct file { + struct inode* inode; + long f_pos; // RW position of this file handle + struct file_operations* fop; + int flags; +}; + + +struct mount { + struct dentry* root; + struct filesystem* fs; +}; + +struct filesystem { + char name[32]; + int (*setup_mount)(struct filesystem* fs, struct mount* mount); +}; + +struct file_operations { + int (*write)(struct file* file, const void* buf, long len); + int (*read)(struct file* file, void* buf, long len); + int (*open)(struct inode* file_node, struct file** target); + int (*close)(struct file* file); + long (*lseek64)(struct file* file, long offset, int whence); +}; + +struct inode_operations { + int (*lookup)(struct inode* dir_node, struct inode** target, + const char* component_name); + int (*create)(struct inode* dir_node, struct inode** target, + const char* component_name); + int (*mkdir)(struct inode* dir_node, struct inode** target, + const char* component_name); +}; + +struct dentry_operations { +}; + +extern struct mount* rootfs; + +void rootfs_init(); + +int vfs_open(const char* pathname, int flags, struct file** target); +int vfs_close(struct file *file); +int vfs_write(struct file* file, const void* buf, long len); +int vfs_read(struct file* file, void* buf, long len); +int vfs_mkdir(const char* pathname); +int vfs_mount(const char* target, const char* filesystem); +int vfs_chdir(const char *pathname); +long vfs_lseek64(struct file *file, long offset, int whence); + +int vfs_mknod(const char* pathname, int mode, int dev); +int vfs_register_device(struct file_operations *device_fop); + +void vfs_walk_recursive(struct inode *dir_node, const char *pathname, struct inode **target, char *target_name); + +#endif \ No newline at end of file diff --git a/lab7/include/kern/cpio.h b/lab7/include/kern/cpio.h new file mode 100644 index 000000000..20b6c0883 --- /dev/null +++ b/lab7/include/kern/cpio.h @@ -0,0 +1,37 @@ +#ifndef CPIO_H +#define CPIO_H + +// #define CPIO_ADDRESS (void*)0x8000000 +extern void *CPIO_ADDRESS; + +#define CPIO_MAGIC "070701" +#define CPIO_END "TRAILER!!!" + +// New ASCII Format +struct cpio_newc_header { + char c_magic[6]; + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[8]; + char c_filesize[8]; + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char sc_rdevminor[8]; + char c_namesize[8]; + char c_check[8]; +}; + +void initramfs_callback(char *node_name, char *prop_name, void *prop_value); +void initramfs_init(); + +void cpio_ls(); +void cpio_cat(const char *filename); +char* cpio_find(const char *filename); + +void cpio_reserve(); + +#endif \ No newline at end of file diff --git a/lab7/include/kern/fdtable.h b/lab7/include/kern/fdtable.h new file mode 100644 index 000000000..de9a06304 --- /dev/null +++ b/lab7/include/kern/fdtable.h @@ -0,0 +1,19 @@ +#ifndef FDTABLE_H +#define FDTABLE_H + +#include "bitmap.h" +#include "fs/vfs.h" + +#define MAX_OPEN_FD 16 + +struct files_struct { + DECLARE_BITMAP(fd_bitmap, MAX_OPEN_FD); + struct file *fd_array[MAX_OPEN_FD]; +}; + +void fd_init(struct files_struct *files_struct); +int fd_open(struct files_struct *files_struct, struct file *fh); +struct file* fd_close(struct files_struct *files_struct, int fd); +struct file *fd_get(struct files_struct *files_struct, int fd); + +#endif \ No newline at end of file diff --git a/lab7/include/kern/irq.h b/lab7/include/kern/irq.h new file mode 100644 index 000000000..6be242108 --- /dev/null +++ b/lab7/include/kern/irq.h @@ -0,0 +1,16 @@ +#ifndef IRQ_H +#define IRQ_H + +struct trapframe { + long x[31]; + long sp_el0; + long spsr_el1; + long elr_el1; +}; + +void int_enable(); +void int_disable(); + +void int_init(); + +#endif \ No newline at end of file diff --git a/lab7/include/kern/kio.h b/lab7/include/kern/kio.h new file mode 100644 index 000000000..e2d90fcb9 --- /dev/null +++ b/lab7/include/kern/kio.h @@ -0,0 +1,32 @@ +#ifndef KIO_H +#define KIO_H + +#include "peripheral/uart.h" + +static inline void kio_init() { + uart_init(); + uart_flush(); + uart_enable_int(); +} + +static inline void kputc(char c) +{ + uart_async_write(c); +} + +static inline void kputs(char *s) +{ + uart_async_puts(s); +} + +static inline void kflush() { + uart_write_flush(); +} + +static inline char kscanc() { + return uart_async_read(); +} + +void kprintf(char* fmt, ...); + +#endif \ No newline at end of file diff --git a/lab7/include/kern/mm.h b/lab7/include/kern/mm.h new file mode 100644 index 000000000..7e1b7035c --- /dev/null +++ b/lab7/include/kern/mm.h @@ -0,0 +1,17 @@ +#ifndef MM_H +#define MM_H + +#include "kern/mm_types.h" +#include "kern/slab.h" + +void mm_reserve(void *start, void *end); + +void mm_callback(char *node_name, char *prop_name, void *prop_value); + +void mm_init(); + +struct page* get_page_from_addr(void *addr); +struct page* alloc_pages(unsigned int order); +void free_pages(void *addr); + +#endif \ No newline at end of file diff --git a/lab7/include/kern/mm_types.h b/lab7/include/kern/mm_types.h new file mode 100644 index 000000000..e021fcfbf --- /dev/null +++ b/lab7/include/kern/mm_types.h @@ -0,0 +1,48 @@ +#ifndef MM_TYPES_H +#define MM_TYPES_H + +#include "list.h" + +#define MEM_TOTAL 0x40000000 +#define MEM_LIMIT 0x3B400000 + +struct free_area { + struct list_head free_list; + unsigned int nr_free; + unsigned int order; +}; + +#define PG_USED 0 +#define PG_HEAD 1 +#define PG_TAIL 2 +#define PG_SLAB 3 + +struct page { + unsigned int flags; + unsigned int pg_index; + unsigned int compound_order; + + struct slab_t *slab; + + struct list_head list; +}; + +struct mm_struct { + unsigned long *pgd; +}; + + +#include "kern/page.h" + +#define MAX_ORDER 10 + +#define PHY_FRAMES_NUM (MEM_TOTAL / PAGE_SIZE) + +#define PFN_2_PHY(pfn) (long)((pfn) << PAGE_SHIFT) +#define PHY_2_PFN(adr) ((long)(adr) >> PAGE_SHIFT) + +// kernel space address translation +#define VIRT_2_PHY(vaddr) ((long)(vaddr) & 0x0000ffffffffffff) +#define PHY_2_VIRT(vaddr) ((long)(vaddr) | 0xffff000000000000) + +#endif \ No newline at end of file diff --git a/lab7/include/kern/page.h b/lab7/include/kern/page.h new file mode 100644 index 000000000..495336d84 --- /dev/null +++ b/lab7/include/kern/page.h @@ -0,0 +1,36 @@ +#ifndef PAGE_H +#define PAGE_H + +#define PAGE_SIZE 4096 +#define PAGE_SHIFT 12 +#define PAGE_MASK (~(PAGE_SIZE-1)) + + +#define PGD_SHIFT 39 +#define PUD_SHIFT 30 +#define PMD_SHIFT 21 + +#define PTRS_PER_PGD 512 +#define PTRS_PER_PUD 512 +#define PTRS_PER_PMD 512 +#define PTRS_PER_PTE 512 + +#define pgd_index(vaddr) (((vaddr) >> PGD_SHIFT) & (PTRS_PER_PGD - 1)) +#define pgd_offset(mm, vaddr) ((mm)->pgd + pgd_index(vaddr)) + +#define pud_index(vaddr) (((vaddr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)) + +#define pmd_index(vaddr) (((vaddr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) + +#define pte_index(vaddr) (((vaddr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) + +void create_pgd(struct mm_struct *mm); +void free_pgd(struct mm_struct *mm); +void fork_pgd(struct mm_struct *parent_mm, struct mm_struct *child_mm); + +void *walk(struct mm_struct *mm, unsigned long vaddr, unsigned long paddr); +void *mappages(struct mm_struct *mm, unsigned long vaddr, unsigned long size, unsigned long paddr); + +void identity_paging(struct mm_struct *mm, unsigned long vaddr, unsigned long paddr); + +#endif \ No newline at end of file diff --git a/lab7/include/kern/sched.h b/lab7/include/kern/sched.h new file mode 100644 index 000000000..4b0bd52e3 --- /dev/null +++ b/lab7/include/kern/sched.h @@ -0,0 +1,104 @@ +#ifndef SCHED_H +#define SCHED_H + +#include "list.h" +#include "bitmap.h" +#include "kern/signal.h" +#include "kern/mm_types.h" +#include "kern/fdtable.h" +#include "fs/vfs.h" + +#define MAX_PRIV_TASK_NUM 50 +#define TASK_CTIME 1 + +enum task_state { + RUNNING, READY, WAITING, INT, DEAD +}; + +struct task_context { + long x19; + long x20; + long x21; + long x22; + long x23; + long x24; + long x25; + long x26; + long x27; + long x28; + long fp; + long lr; + long sp; +}; + +struct task_struct { + + int tid; + int used; + + enum task_state state; + + int prio; + + int ctime; + int resched; + + void *stk_addr; + void *ustk_addr; + + struct dentry *cwd; + struct dentry *croot; + struct files_struct files; + + struct list_head signal_list; + struct list_head signal_pend_list; + struct signal_context_t *signal_context; + struct task_context task_context; + + struct mm_struct mm; + + struct list_head list; +}; + +#define MAX_PRIO 128 + +static inline int sched_find_first_bit(const unsigned long *b) { + if (b[0]) + return __ffs(b[0]); + if (b[1]) + return __ffs(b[1]) + 64; + return 128; +} + +void task_init(); +void runqueue_init(); +struct task_struct *privilege_task_create(void (*func)(), int prio); +struct task_struct *task_create(void (*func)(), int prio); + +void schedule(); +void kill_zombies(); + +void switch_to(struct task_context *prev, struct task_context *next); +void update_current(struct task_struct *task); +void update_pgd(unsigned long pgd); +struct task_struct* get_current(); +struct task_struct* get_task_struct(int pid); + +int __getpid(); +void __exec(const char *name, char *const argv[]); +int __fork(void *trapframe); +void __exit(); +void __kill(int pid); + +void do_exec(void (*func)()); + +static inline void thread_create(void (*func)()) { + task_create(func, 100); +} + +#define USER_STK_HIGH 0xfffffffff000 +#define USER_STK_LOW 0xffffffffb000 + +#define STACKSIZE 16384 // 4096 * 4 + +#endif \ No newline at end of file diff --git a/lab7/include/kern/shell.h b/lab7/include/kern/shell.h new file mode 100644 index 000000000..398dc84b8 --- /dev/null +++ b/lab7/include/kern/shell.h @@ -0,0 +1,22 @@ +#ifndef SHELL_H +#define SHELL_H + +#define BACKSPACE 8 +#define ESC 27 +#define DELETE 127 + +#define LEFT_SHIFT kputc(ESC); \ + kputc('['); \ + kputc('D'); + +#define RIGHT_SHIFT kputc(ESC); \ + kputc('['); \ + kputc('C'); + +#define MAX_INPUT_LEN 128 + +void shell_input(char *cmd); +void shell_parse(char *cmd); +void shell_start(); + +#endif \ No newline at end of file diff --git a/lab7/include/kern/signal.h b/lab7/include/kern/signal.h new file mode 100644 index 000000000..23c25504f --- /dev/null +++ b/lab7/include/kern/signal.h @@ -0,0 +1,31 @@ +#ifndef SIGNAL_H +#define SIGNAL_H + +#include "list.h" + +#define SIGKILL 9 + +struct signal_t { + int num; + void (*handler)(); + struct list_head list; +}; + +struct signal_pend_t { + int num; + struct list_head list; +}; + +struct signal_context_t { + void *trapframe; + void *stk_addr; +}; + +struct signal_t *signal_create(int SIGNAL, void (*handler)()); +void signal_back(void *trapframe); +void signal_run(); + +void __signal(int SIGNAL, void (*handler)()); +void __sigkill(int pid, int SIGNAL, void *trapframe); + +#endif \ No newline at end of file diff --git a/lab7/include/kern/slab.h b/lab7/include/kern/slab.h new file mode 100644 index 000000000..24c5bba6d --- /dev/null +++ b/lab7/include/kern/slab.h @@ -0,0 +1,37 @@ +#ifndef SLAB_H +#define SLAB_H + +#include "list.h" + +/* + Fixed object size to multiple of 8 if object size less than 128. (16 pools) + Fixed object size to multiple of 12 for next 8 pools. + The remaining pool contain arbitrary size object. (224 bytes ~ 4096 bytes) +*/ +#define MAX_OBJ_CACHE_NUM 40 +#define SMALL_OBJ_SIZE 128 +#define MEDIUM_OBJ_SIZE 224 + +struct kmem_pool { + int object_size; // -1 indicate free + unsigned int gfporder; + unsigned int num; // object per slab + + struct list_head slab_list; +}; + +struct slab_t { + unsigned int inuse; + unsigned int nr_free; + void *head_addr; + struct list_head free_list; + + struct list_head list; +}; + +void slab_init(); + +void* kmalloc(unsigned int size); +void kfree(void *addr); + +#endif \ No newline at end of file diff --git a/lab7/include/kern/softirq.h b/lab7/include/kern/softirq.h new file mode 100644 index 000000000..b840fd690 --- /dev/null +++ b/lab7/include/kern/softirq.h @@ -0,0 +1,18 @@ +#ifndef SOFTIRQ_H +#define SOFTIRQ_H + +#define SOFTIRQ_NUM 64 + +#define SOFTIRQ_TIMER 1 +#define SOFTIRQ_UART 2 + +enum irq_state { + IRQ_RUNNING, IRQ_READY, IRQ_IDLE +}; + +void softirq_init(); +void softirq_register(void (*cb)(), int num); +void softirq_active(int num); +void softirq_run(); + +#endif diff --git a/lab7/include/kern/sync.h b/lab7/include/kern/sync.h new file mode 100644 index 000000000..0e6cee841 --- /dev/null +++ b/lab7/include/kern/sync.h @@ -0,0 +1,20 @@ +#ifndef SYNC_H +#define SYNC_H + +/* + ESR-EL1 +*/ +#define EC_BITS(esr_el1) ((esr_el1 >> 26) & 0b111111) +#define EC_SVC_32 0b010001 +#define EC_SVC_64 0b010101 +#define EC_IA_EL0 0b100000 +#define EC_IA_EL1 0b100001 +#define EC_DA_EL0 0b100100 +#define EC_DA_EL1 0b100101 + +#define IFSC(esr_el1) (esr_el1 & 0b111111) +#define DFSC(esr_el1) (esr_el1 & 0b111111) + +#define TRANS_FAULT_0 0b000100 + +#endif diff --git a/lab7/include/kern/timer.h b/lab7/include/kern/timer.h new file mode 100644 index 000000000..c33f0e1df --- /dev/null +++ b/lab7/include/kern/timer.h @@ -0,0 +1,25 @@ +#ifndef TIMER_H +#define TIMER_H + +struct timer_queue { + unsigned long register_time; + unsigned int duration; + char message[128]; + struct timer_queue *prev; + struct timer_queue *next; + void (*callback)(char *, unsigned long); +}; + +void timer_el0_handler(); +void timer_el1_handler(); +void timer_unknown_handler(); +void timer_init(); +void set_timeout(char *args); + +extern void core_timer_enable(); +extern void core_timer_disable(); +extern void timer_enable_int(); +extern void timer_disable_int(); +extern void timer_sched_latency(); + +#endif \ No newline at end of file diff --git a/lab7/include/list.h b/lab7/include/list.h new file mode 100644 index 000000000..4cc825c8a --- /dev/null +++ b/lab7/include/list.h @@ -0,0 +1,134 @@ +#ifndef LIST_H +#define LIST_H + +struct list_head { + struct list_head *prev; + struct list_head *next; +}; + +#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; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +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; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = entry; + entry->prev = entry; +} + +/** + * 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; pos != (head); pos = pos->next) + +#define list_for_each_back(pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + + +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define list_entry(ptr,type,member) \ + container_of(ptr, type, member) + +#endif \ No newline at end of file diff --git a/lab7/include/mmu.h b/lab7/include/mmu.h new file mode 100644 index 000000000..69b68e35f --- /dev/null +++ b/lab7/include/mmu.h @@ -0,0 +1,46 @@ +#ifndef MMU_H +#define MMU_H + + +#define KERNEL_VA_BASE 0xffff000000000000 + +/* + TCR +*/ +#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) + +/* + MAIR + Device memory 0b0000dd00 + Normal memory 0booooiiii, (oooo != 0000 and iiii != 0000) + oooo == 0b0100 Outer Non-cacheable (L2) + iiii == 0b0100 Inner Non-cacheable (L1) +*/ +#define MAIR_DEVICE_nGnRnE 0b00000000 +#define MAIR_NORMAL_NOCACHE 0b01000100 +#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_NORMAL_NOCACHE 1 +#define MAIR_CONFIG_DEFAULT ((MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8))) + +/* + Page’s Descriptor +*/ +#define PD_TABLE 0b11 +#define PD_BLOCK 0b01 +#define PD_PAGE 0b11 + +#define PD_USER_RW (0b01 << 6) + +#define PD_ACCESS (1 << 10) + +#define PGD0_ATTR PD_TABLE +#define PUD0_ATTR PD_TABLE +#define PUD1_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK) +#define PMD0_ATTR PD_TABLE +#define PTE_DEVICE_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_PAGE) +#define PTE_NORMAL_ATTR (PD_ACCESS | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_PAGE) +#define PTE_NORMAL_LAZY_ATTR ((MAIR_IDX_NORMAL_NOCACHE << 2) | PD_PAGE) + +#endif \ No newline at end of file diff --git a/lab7/include/peripheral/arm.h b/lab7/include/peripheral/arm.h new file mode 100644 index 000000000..ed2784ae7 --- /dev/null +++ b/lab7/include/peripheral/arm.h @@ -0,0 +1,13 @@ +#ifndef ARM_H +#define ARM_H + +#include "mmu.h" + +#define ARM_PERI_BASE (KERNEL_VA_BASE | 0x40000000) + +#define CORE0_TIMER_IRQ_CTRL (ARM_PERI_BASE + 0x40) + +// QA7_rev3.4 p.7 +#define CORE0_IRQ_SRC ((volatile unsigned int*)(ARM_PERI_BASE + 0x60)) + +#endif \ No newline at end of file diff --git a/lab7/include/peripheral/aux.h b/lab7/include/peripheral/aux.h new file mode 100644 index 000000000..a854b68f8 --- /dev/null +++ b/lab7/include/peripheral/aux.h @@ -0,0 +1,36 @@ +#ifndef AUX_H +#define AUX_H + +#include "mmio.h" + +// spec p.8 +// start at 0x7E21,5000 +#define AUX_BASE (MMIO_BASE + 0x215000) + +#define AUX_IRQ ((volatile unsigned int*)(AUX_BASE + 0x00)) +#define AUX_ENABLES ((volatile unsigned int*)(AUX_BASE + 0x04)) +#define AUX_MU_IO ((volatile unsigned int*)(AUX_BASE + 0x40)) +#define AUX_MU_IER ((volatile unsigned int*)(AUX_BASE + 0x44)) +#define AUX_MU_IIR ((volatile unsigned int*)(AUX_BASE + 0x48)) +#define AUX_MU_LCR ((volatile unsigned int*)(AUX_BASE + 0x4C)) +#define AUX_MU_MCR ((volatile unsigned int*)(AUX_BASE + 0x50)) +#define AUX_MU_LSR ((volatile unsigned int*)(AUX_BASE + 0x54)) +#define AUX_MU_MSR ((volatile unsigned int*)(AUX_BASE + 0x58)) +#define AUX_MU_SCRATCH ((volatile unsigned int*)(AUX_BASE + 0x5C)) +#define AUX_MU_CNTL ((volatile unsigned int*)(AUX_BASE + 0x60)) +#define AUX_MU_STAT ((volatile unsigned int*)(AUX_BASE + 0x64)) +#define AUX_MU_BAUD ((volatile unsigned int*)(AUX_BASE + 0x68)) +#define AUX_SPI0_CNTL0 ((volatile unsigned int*)(AUX_BASE + 0x80)) +#define AUX_SPI0_CNTL1 ((volatile unsigned int*)(AUX_BASE + 0x84)) +#define AUX_SPI0_STAT ((volatile unsigned int*)(AUX_BASE + 0x88)) +#define AUX_SPI0_IO ((volatile unsigned int*)(AUX_BASE + 0x90)) +#define AUX_SPI0_PEEK ((volatile unsigned int*)(AUX_BASE + 0x94)) +#define AUX_SPI1_CNTL0 ((volatile unsigned int*)(AUX_BASE + 0xC0)) +#define AUX_SPI1_CNTL1 ((volatile unsigned int*)(AUX_BASE + 0xC4)) +#define AUX_SPI1_STAT ((volatile unsigned int*)(AUX_BASE + 0xC8)) +#define AUX_SPI1_IO ((volatile unsigned int*)(AUX_BASE + 0xD0)) +#define AUX_SPI1_PEEK ((volatile unsigned int*)(AUX_BASE + 0xD4)) + +#define AUX_INT (1 << 29) + +#endif \ No newline at end of file diff --git a/lab7/include/peripheral/gpio.h b/lab7/include/peripheral/gpio.h new file mode 100644 index 000000000..596db3d74 --- /dev/null +++ b/lab7/include/peripheral/gpio.h @@ -0,0 +1,51 @@ +#ifndef GPIO_H +#define GPIO_H + +#include "mmio.h" + +// spec p.90 +// start at 0x7E20,0000 +#define GPIO_BASE (MMIO_BASE + 0x200000) + +#define GPFSEL0 ((volatile unsigned int*)(GPIO_BASE + 0x00)) +#define GPFSEL1 ((volatile unsigned int*)(GPIO_BASE + 0x04)) +#define GPFSEL2 ((volatile unsigned int*)(GPIO_BASE + 0x08)) +#define GPFSEL3 ((volatile unsigned int*)(GPIO_BASE + 0x0C)) +#define GPFSEL4 ((volatile unsigned int*)(GPIO_BASE + 0x10)) +#define GPFSEL5 ((volatile unsigned int*)(GPIO_BASE + 0x14)) +// 0x18 Reserved +#define GPSET0 ((volatile unsigned int*)(GPIO_BASE + 0x1C)) +#define GPSET1 ((volatile unsigned int*)(GPIO_BASE + 0x20)) +// 0x24 Reserved +#define GPCLR0 ((volatile unsigned int*)(GPIO_BASE + 0x28)) +#define GPCLR1 ((volatile unsigned int*)(GPIO_BASE + 0x2C)) +// 0x30 Reserved +#define GPLEV0 ((volatile unsigned int*)(GPIO_BASE + 0x34)) +#define GPLEV1 ((volatile unsigned int*)(GPIO_BASE + 0x38)) +// 0x3C Reserved +#define GPEDS0 ((volatile unsigned int*)(GPIO_BASE + 0x40)) +#define GPEDS1 ((volatile unsigned int*)(GPIO_BASE + 0x44)) +// 0x48 Reserved +#define GPREN0 ((volatile unsigned int*)(GPIO_BASE + 0x4C)) +#define GPREN1 ((volatile unsigned int*)(GPIO_BASE + 0x50)) +// 0x54 Reserved +#define GPFEN0 ((volatile unsigned int*)(GPIO_BASE + 0x58)) +#define GPFEN1 ((volatile unsigned int*)(GPIO_BASE + 0x5C)) +// 0x60 Reserved +#define GPHEN0 ((volatile unsigned int*)(GPIO_BASE + 0x64)) +#define GPHEN1 ((volatile unsigned int*)(GPIO_BASE + 0x68)) +// 0x6C Reserved +#define GPLEN0 ((volatile unsigned int*)(GPIO_BASE + 0x70)) +#define GPLEN1 ((volatile unsigned int*)(GPIO_BASE + 0x74)) +// 0x78 Reserved +#define GPAREN0 ((volatile unsigned int*)(GPIO_BASE + 0x7C)) +#define GPAREN1 ((volatile unsigned int*)(GPIO_BASE + 0x80)) +// 0x84 Reserved +#define GPAFEN0 ((volatile unsigned int*)(GPIO_BASE + 0x88)) +#define GPAFEN1 ((volatile unsigned int*)(GPIO_BASE + 0x8C)) +// 0x90 Reserved +#define GPPUD ((volatile unsigned int*)(GPIO_BASE + 0x94)) +#define GPPUDCLK0 ((volatile unsigned int*)(GPIO_BASE + 0x98)) +#define GPPUDCLK1 ((volatile unsigned int*)(GPIO_BASE + 0x9C)) + +#endif \ No newline at end of file diff --git a/lab7/include/peripheral/interrupt.h b/lab7/include/peripheral/interrupt.h new file mode 100644 index 000000000..5bcfd69da --- /dev/null +++ b/lab7/include/peripheral/interrupt.h @@ -0,0 +1,19 @@ +#ifndef IRQ_H +#define IRQ_H + +#include "mmio.h" + +// spec p.112 +// start at 0x7E00,B000 +#define INT_BASE (MMIO_BASE + 0xB000) + +#define IRQ_PENDING_1 ((volatile unsigned int*)(INT_BASE + 0x204)) +#define IRQ_PENDING_2 ((volatile unsigned int*)(INT_BASE + 0x208)) +#define ENABLE_IRQS_1 ((volatile unsigned int*)(INT_BASE + 0x210)) +#define ENABLE_IRQS_2 ((volatile unsigned int*)(INT_BASE + 0x214)) +#define ENABLE_BASIC_IRQS ((volatile unsigned int*)(INT_BASE + 0x218)) +#define DISABLE_IRQS_1 ((volatile unsigned int*)(INT_BASE + 0x21C)) +#define DISABLE_IRQS_2 ((volatile unsigned int*)(INT_BASE + 0x220)) +#define DISABLE_BASIC_IRQS ((volatile unsigned int*)(INT_BASE + 0x224)) + +#endif \ No newline at end of file diff --git a/lab7/include/peripheral/mailbox.h b/lab7/include/peripheral/mailbox.h new file mode 100644 index 000000000..26333553f --- /dev/null +++ b/lab7/include/peripheral/mailbox.h @@ -0,0 +1,53 @@ +#ifndef MAILBOX_H +#define MAILBOX_H + +#include "mmio.h" + +#define MAILBOX_BASE (MMIO_BASE + 0xb880) + +#define MAILBOX_READ ((volatile unsigned int*)(MAILBOX_BASE)) +#define MAILBOX_STATUS ((volatile unsigned int*)(MAILBOX_BASE + 0x18)) +#define MAILBOX_WRITE ((volatile unsigned int*)(MAILBOX_BASE + 0x20)) + +#define MAILBOX_EMPTY 0x40000000 +#define MAILBOX_FULL 0x80000000 + +// Tag +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_MEMORY 0x00010005 +#define REQUEST_CODE 0x00000000 +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +/* +Mailbox 0 defines the following channels: + +0: Power management +1: Framebuffer +2: Virtual UART +3: VCHIQ +4: LEDs +5: Buttons +6: Touch screen +7: +8: Property tags (ARM -> VC) +9: Property tags (VC -> ARM) +*/ +#define MAILBOX_CH_PM 0 +#define MAILBOX_CH_FB 1 +#define MAILBOX_CH_VUART 2 +#define MAILBOX_CH_VCHIQ 3 +#define MAILBOX_CH_LEDS 4 +#define MAILBOX_CH_BTNS 5 +#define MAILBOX_CH_TS 6 +// 7 +#define MAILBOX_CH_ARM2VC 8 +#define MAILBOX_CH_VC2ARM 9 + +unsigned int mailbox_call(unsigned char ch, unsigned int* mailbox); +void get_board_revision(unsigned int *result); +void get_ARM_memory(unsigned int *result); + +#endif \ No newline at end of file diff --git a/lab7/include/peripheral/mmio.h b/lab7/include/peripheral/mmio.h new file mode 100644 index 000000000..6730a2ec7 --- /dev/null +++ b/lab7/include/peripheral/mmio.h @@ -0,0 +1,12 @@ +#ifndef MMIO_H +#define MMIO_H + +#include "mmu.h" + +#ifdef BOOT_LOADER +#define MMIO_BASE 0x3F000000 +#else +#define MMIO_BASE (KERNEL_VA_BASE | 0x3F000000) // -> 0x7E00,0000 +#endif + +#endif \ No newline at end of file diff --git a/lab7/include/peripheral/uart.h b/lab7/include/peripheral/uart.h new file mode 100644 index 000000000..174f8e6ee --- /dev/null +++ b/lab7/include/peripheral/uart.h @@ -0,0 +1,27 @@ +#ifndef UART_H +#define UART_H + +void uart_init(); + +void uart_enable_int(); +void uart_disable_int(); +void uart_int_handler(); + +char uart_sync_read(); +char uart_sync_read_raw(); +void uart_sync_write(unsigned int c); +void uart_sync_puts(char *s); +void uart_sync_printNum(long num, int base); + +char uart_async_read(); +void uart_async_write(unsigned int c); +void uart_async_puts(char *s); + +void uart_flush(); +void uart_write_flush(); + + +#define ENABLE_IRQS_1_AUX (*ENABLE_IRQS_1 |= AUX_INT) +#define DISABLE_IRQS_1_AUX (*DISABLE_IRQS_1 |= AUX_INT) + +#endif \ No newline at end of file diff --git a/lab7/include/reset.h b/lab7/include/reset.h new file mode 100644 index 000000000..122fca62a --- /dev/null +++ b/lab7/include/reset.h @@ -0,0 +1,12 @@ +#ifndef RESET_H +#define RESET_H + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +void set(long addr, unsigned int value); +void reset(int tick); +void cancel_reset(); + +#endif \ No newline at end of file diff --git a/lab7/include/startup_alloc.h b/lab7/include/startup_alloc.h new file mode 100644 index 000000000..f62ce6003 --- /dev/null +++ b/lab7/include/startup_alloc.h @@ -0,0 +1,8 @@ +#ifndef STARTUP_ALLOC +#define STARTUP_ALLOC + +void* sumalloc(unsigned int size); + +void reserved_kern_startup(); + +#endif \ No newline at end of file diff --git a/lab7/include/string.h b/lab7/include/string.h new file mode 100644 index 000000000..d7a9d078f --- /dev/null +++ b/lab7/include/string.h @@ -0,0 +1,15 @@ +#ifndef STRING_H +#define STRING_H + +unsigned int strlen (const char *str); +int strcmp (const char *p1, const char *p2); +int strncmp (const char *s1, const char *s2, unsigned int len); +char *strcpy(char *dest, const char *src); + +int itoa(long num, char* str, int base); +long atoi(char* str, int base, unsigned int len); + +void* memcpy (void* dest, const void* src, unsigned int len); +void* memset (void* dest, int val, unsigned int len); + +#endif \ No newline at end of file diff --git a/lab7/include/syscall.h b/lab7/include/syscall.h new file mode 100644 index 000000000..a5bc509fe --- /dev/null +++ b/lab7/include/syscall.h @@ -0,0 +1,51 @@ +#ifndef SYSCALL_H +#define SYSCALL_H + +#define SYS_GET_PID 0 +#define SYS_UART_READ 1 +#define SYS_UART_WRITE 2 +#define SYS_EXEC 3 +#define SYS_FORK 4 +#define SYS_EXIT 5 +#define SYS_MBOX_CALL 6 +#define SYS_KILL 7 +#define SYS_SIGNAL 8 +#define SYS_SIGKILL 9 + +int getpid(); +int uart_read(char buf[], int size); +int uart_write(const char buf[], int size); +int exec(const char *name, char *const argv[]); +int fork(); +void exit(); +int mbox_call(unsigned char ch, unsigned int *mbox); +void kill(int pid); +void signal(int SIGNAL, void (*handler)()); +void sigkill(int pid, int SIGNAL); + +#define SYS_OPEN 11 +#define SYS_CLOSE 12 +#define SYS_WRITE 13 +#define SYS_READ 14 +#define SYS_MKDIR 15 +#define SYS_MOUNT 16 +#define SYS_CHDIR 17 +#define SYS_LSEEK64 18 + +#define O_CREAT 00000100 + +int open(const char *pathname, int flags); +int close(int fd); +long write(int fd, const void *buf, unsigned long count); +long read(int fd, void *buf, unsigned long count); +int mkdir(const char *pathname, unsigned mode); +int mount(const char *src, const char *target, const char *filesystem, unsigned long flags, const void *data); +int chdir(const char *path); + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +long lseek64(int fd, long offset, int whence); + +#endif \ No newline at end of file diff --git a/lab7/include/test_func.h b/lab7/include/test_func.h new file mode 100644 index 000000000..b0f61e15b --- /dev/null +++ b/lab7/include/test_func.h @@ -0,0 +1,9 @@ +#ifndef TEST_FUNC_H +#define TEST_FUNC_H + +void fork_test(); +void fs_test(); +void fs_uart_test(); +void initramfs_test(); + +#endif \ No newline at end of file diff --git a/lab7/include/user_lib.h b/lab7/include/user_lib.h new file mode 100644 index 000000000..d8ec88fdf --- /dev/null +++ b/lab7/include/user_lib.h @@ -0,0 +1,6 @@ +#ifndef USER_LIB_H +#define USER_LIB_H + +void printf(char *fmt, ...); + +#endif \ No newline at end of file diff --git a/lab7/kern/cpio.c b/lab7/kern/cpio.c new file mode 100644 index 000000000..30312ee82 --- /dev/null +++ b/lab7/kern/cpio.c @@ -0,0 +1,113 @@ +#include "kern/kio.h" +#include "kern/mm.h" +#include "kern/cpio.h" +#include "kern/sched.h" +#include "string.h" +#include "byteswap.h" +#include "syscall.h" + +// qemu default address +void *CPIO_ADDRESS = (void*)PHY_2_VIRT(0x8000000); +void *CPIO_END_ADR = 0; // weird bugs in physical machine + +void initramfs_callback(char *node_name, char *prop_name, void *prop_value) { + if (!strncmp(node_name, "chosen", 6) && !strncmp(prop_name, "linux,initrd-start", 18)) { + kputs("cpio: Find!\n"); + CPIO_ADDRESS = (void*)(__bswap_32(*((unsigned int *)(prop_value)))); + CPIO_ADDRESS = (void*)PHY_2_VIRT(CPIO_ADDRESS); + } +} + +void cpio_ls() { + int i = 0; + int filesize = 0; + int namesize = 0; + struct cpio_newc_header *header; + + for ( ; ; i+=namesize+filesize) { + header = ((struct cpio_newc_header *)(CPIO_ADDRESS + i)); + if (strncmp(header->c_magic, CPIO_MAGIC, 6)) { + kputs("cpio: Bad magic\n"); + break; + } + filesize = (atoi(header->c_filesize, 16, 8) + 3) & -4; + namesize = ((atoi(header->c_namesize, 16, 8) + 6 + 3) & -4) - 6; + i += sizeof(struct cpio_newc_header); + if (!strncmp((char *)(CPIO_ADDRESS + i), CPIO_END, 10)) + break; + kprintf("%s\n", (char *)(CPIO_ADDRESS + i)); + } +} + +void cpio_cat(const char *filename) { + int i = 0; + int filesize = 0; + int namesize = 0; + struct cpio_newc_header *header; + + for ( ; ; i+=namesize+filesize) { + header = ((struct cpio_newc_header *)(CPIO_ADDRESS + i)); + if (strncmp(header->c_magic, CPIO_MAGIC, 6)) { + kputs("cpio: Bad magic\n"); + break; + } + filesize = (atoi(header->c_filesize, 16, 8) + 3) & -4; + namesize = ((atoi(header->c_namesize, 16, 8) + 6 + 3) & -4) - 6; + i += sizeof(struct cpio_newc_header); + if (!strcmp((char *)(CPIO_ADDRESS + i), filename)) { + kprintf("%s\n", (char *)(CPIO_ADDRESS + i + namesize)); + return; + } + if (!strncmp((char *)(CPIO_ADDRESS + i), CPIO_END, 10)) + break; + } + kputs("File not exists...\n"); +} + +char* cpio_find(const char *filename) { + int i = 0; + int filesize = 0; + int namesize = 0; + struct cpio_newc_header *header; + + for ( ; ; i+=namesize+filesize) { + header = ((struct cpio_newc_header *)(CPIO_ADDRESS + i)); + if (strncmp(header->c_magic, CPIO_MAGIC, 6)) { + kputs("cpio: Bad magic\n"); + break; + } + filesize = (atoi(header->c_filesize, 16, 8) + 3) & -4; + namesize = ((atoi(header->c_namesize, 16, 8) + 6 + 3) & -4) - 6; + i += sizeof(struct cpio_newc_header); + if (!strcmp((char *)(CPIO_ADDRESS + i), filename)) + break; + if (!strncmp((char *)(CPIO_ADDRESS + i), CPIO_END, 10)) { + kputs("File not exists...\n"); + return 0; + } + } + i += namesize; + + return CPIO_ADDRESS + i; +} + +void cpio_reserve() { + int i = 0; + int filesize = 0; + int namesize = 0; + struct cpio_newc_header *header; + + for ( ; ; i+=namesize+filesize) { + header = ((struct cpio_newc_header *)(CPIO_ADDRESS + i)); + if (strncmp(header->c_magic, CPIO_MAGIC, 6)) { + kputs("cpio: Bad magic\n"); + break; + } + filesize = (atoi(header->c_filesize, 16, 8) + 3) & -4; + namesize = ((atoi(header->c_namesize, 16, 8) + 6 + 3) & -4) - 6; + i += sizeof(struct cpio_newc_header); + if (!strncmp((char *)(CPIO_ADDRESS + i), CPIO_END, 10)) + break; + } + mm_reserve(CPIO_ADDRESS, CPIO_ADDRESS+i); +} \ No newline at end of file diff --git a/lab7/kern/entry.S b/lab7/kern/entry.S new file mode 100644 index 000000000..abff6c254 --- /dev/null +++ b/lab7/kern/entry.S @@ -0,0 +1,135 @@ +#include "mmu.h" + +.section ".text.entry" + +.global _start +_start: + bl from_el2_to_el1 + +el1_start: + // Set up TCR_EL1 + ldr x0, =TCR_CONFIG_DEFAULT + msr tcr_el1, x0 + + // Set up mair_el1 + ldr x0, =MAIR_CONFIG_DEFAULT + msr mair_el1, x0 + + bl pgtable_create + + mrs x2, sctlr_el1 + orr x2, x2, #1 + msr sctlr_el1, x2 // enable MMU, cache remains disabled + + // indirect branch + ldr x0, =mmu_open + br x0 + +mmu_open: + // clear bss + ldr x0, =__bss_start + ldr x1, =__bss_size +bss_loop: + cbz x1, ready + str xzr, [x0], #8 // [x0] = 0, x0 = x0 + 8 + sub x1, x1, #1 // x1 = x1 - 1 + cbnz x1, bss_loop + +ready: + // set_exception_vector_table + adr x0, exception_vector_table + msr vbar_el1, x0 + + // change sp to virtual address + ldr x1, =KERNEL_VA_BASE + add sp, sp, x1 + + bl kern_main + +spin: + wfe + b spin + + +from_el2_to_el1: + mov x0, (1 << 31) + msr hcr_el2, x0 + mov x0, 0b1111000101 + msr spsr_el2, x0 + msr elr_el2, lr + ldr x0, = __stack_kernel_top + msr sp_el1, x0 + eret + +.global run_el1_to_el0 +run_el1_to_el0: + msr elr_el1, x0 + mov x0, 0b0 // enable interrupt in EL0 + msr spsr_el1, x0 + msr sp_el0, x1 + eret + +pgtable_create: + ldr x0, =__kernel_pgd // PGD + lsl x0, x0, #16 // omit first 16 bit (using physical address) + lsr x0, x0, #16 + add x1, x0, #4096 // PUD + add x2, x1, #4096 // PMD + add x3, x2, #4096 // PTE + + // Set up PGD + ldr x4, =PGD0_ATTR + orr x4, x1, x4 + str x4, [x0] + + // Set up PUD + ldr x4, =PUD0_ATTR + orr x4, x2, x4 + str x4, [x1] + + ldr x4, =PUD1_ATTR + mov x5, 0x40000000 + orr x4, x5, x4 + str x4, [x1, #8] + + // Set up PMD + mov x5, x3 + mov x6, xzr // i = 0 + mov x7, #512 +pmd_loop: + ldr x4, =PMD0_ATTR + orr x4, x5, x4 + str x4, [x2, x6, lsl #3] // i * 8 + add x6, x6, #1 // i++ + add x5, x5, #4096 + cmp x6, x7 + b.ls pmd_loop + + // Set up normal PTE + mov x4, xzr // physical address + mov x5, xzr // i = 0 + mov x6, #258048 +pte_nloop: + ldr x7, =PTE_NORMAL_ATTR + orr x7, x4, x7 + str x7, [x3, x5, lsl #3] // (i * 8) + add x5, x5, #1 + add x4, x4, #4096 + cmp x5, x6 + b.ls pte_nloop + + // Set up device PTE + add x6, x6, #4096 // 262144 +pte_dloop: + ldr x7, =PTE_DEVICE_ATTR + orr x7, x4, x7 + str x7, [x3, x5, lsl #3] // (i * 8) + add x5, x5, #1 + add x4, x4, #4096 + cmp x5, x6 + b.ls pte_dloop + + msr ttbr0_el1, x0 + msr ttbr1_el1, x0 + + ret \ No newline at end of file diff --git a/lab7/kern/exception_vector_table.S b/lab7/kern/exception_vector_table.S new file mode 100644 index 000000000..556b3d939 --- /dev/null +++ b/lab7/kern/exception_vector_table.S @@ -0,0 +1,136 @@ +.section ".text" + +// save general registers to stack +.macro save_all + sub sp, sp, 32 * 18 + 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] + + mrs x20, sp_el0 + stp x30, x20, [sp, 16 * 15] + + mrs x20, spsr_el1 + mrs x21, elr_el1 + stp x20, x21, [sp ,16 * 16] +.endm + +// load general registers from stack +.macro load_all + ldp x20, x21, [sp ,16 * 16] + msr spsr_el1, x20 + msr elr_el1, x21 + + ldp x30, x20, [sp, 16 * 15] + msr sp_el0, x20 + + 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] + add sp, sp, 32 * 18 +.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 + b exception_handler + .align 7 // entry size is 0x80, .align will pad 0 + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + // Exception from the current EL while using SP_ELx + b sync_handler + .align 7 + b irq_el1_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + // Exception from a lower EL and at least one lower EL is AArch64 + b sync_handler + .align 7 + b irq_el0_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + // Exception from a lower EL and all lower ELs are AArch32 + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + +exception_handler: + b exception_handler + +sync_handler: + save_all + mrs x0, spsr_el1 + mrs x1, elr_el1 + mrs x2, esr_el1 + mov x3, sp + bl sync_main + load_all + eret + +irq_el1_handler: + save_all + bl irq_main + bl irq_resched + mov x0, sp + bl signal_run + load_all + eret + +irq_el0_handler: + save_all + bl irq_main + bl irq_resched + mov x0, sp + bl signal_run + load_all + eret + +.global return_from_fork +return_from_fork: + load_all + eret diff --git a/lab7/kern/fdtable.c b/lab7/kern/fdtable.c new file mode 100644 index 000000000..118788936 --- /dev/null +++ b/lab7/kern/fdtable.c @@ -0,0 +1,35 @@ +#include "kern/fdtable.h" +#include "fs/vfs.h" + +void fd_init(struct files_struct *files_struct) { + struct file *stdio_fh; + bitmap_zero(files_struct->fd_bitmap, MAX_OPEN_FD); + + // open /dev/uart as stdin (fd 0), stdout (fd 1), and stderr (fd 2) + vfs_open("/dev/uart", 0, &stdio_fh); + files_struct->fd_array[0] = stdio_fh; + files_struct->fd_array[1] = stdio_fh; + files_struct->fd_array[2] = stdio_fh; + + for (int i=3 ; ifd_bitmap); +} + +int fd_open(struct files_struct *files_struct, struct file *fh) { + int fd = __ffs(files_struct->fd_bitmap[0]); + __clear_bit(fd, files_struct->fd_bitmap); + files_struct->fd_array[fd] = fh; + return fd; +} + +struct file* fd_close(struct files_struct *files_struct, int fd) { + struct file *fh; + __set_bit(fd, files_struct->fd_bitmap); + fh = files_struct->fd_array[fd]; + files_struct->fd_array[fd] = 0; + return fh; +} + +struct file *fd_get(struct files_struct *files_struct, int fd) { + return files_struct->fd_array[fd]; +} \ No newline at end of file diff --git a/lab7/kern/irq.c b/lab7/kern/irq.c new file mode 100644 index 000000000..39ef2a1ba --- /dev/null +++ b/lab7/kern/irq.c @@ -0,0 +1,76 @@ +#include "peripheral/aux.h" +#include "peripheral/uart.h" +#include "peripheral/interrupt.h" +#include "peripheral/arm.h" +#include "kern/timer.h" +#include "kern/irq.h" +#include "kern/sched.h" +#include "kern/softirq.h" + +// QA7_rev3.4 p.16 +#define CNTPNSIRQ_INT 1 +#define GPU_INT 8 + +char int_stack[4096]; + +void int_enable() { + asm volatile("msr DAIFClr, 0xf"); +} + +void int_disable() { + asm volatile("msr DAIFSet, 0xf"); +} + +void timer_int_handler() { + struct task_struct *current = get_current(); + if (--current->ctime <= 0) { + current->resched = 1; + } + timer_sched_latency(); + timer_enable_int(); +} + +void int_init() { + softirq_init(); + softirq_register(timer_int_handler, SOFTIRQ_TIMER); + softirq_register(uart_int_handler, SOFTIRQ_UART); + int_enable(); +} + +void irq_router() { + int_disable(); + if (*CORE0_IRQ_SRC & (1 << CNTPNSIRQ_INT)) { + timer_disable_int(); + softirq_active(SOFTIRQ_TIMER); + } else if (*CORE0_IRQ_SRC & (1 << GPU_INT)) { + if (*IRQ_PENDING_1 & AUX_INT) { + uart_disable_int(); + softirq_active(SOFTIRQ_UART); + } + } + int_enable(); + softirq_run(); +} + +void irq_main() { + register char *sp; + asm volatile("mov %0, sp": "=r"(sp)); + if (!(sp <= &int_stack[4095] && sp >= &int_stack[0])) { + asm volatile("mov sp, %0" : : "r"(&int_stack[4080])); + } + + irq_router(); + + if (!(sp <= &int_stack[4095] && sp >= &int_stack[0])) { + asm volatile("mov sp, %0" : : "r"(sp)); + } +} + +void irq_resched() { + struct task_struct *current = get_current(); + if (current->resched) { + current->ctime = 1; + current->resched = 0; + schedule(); + } +} \ No newline at end of file diff --git a/lab7/kern/kio.c b/lab7/kern/kio.c new file mode 100644 index 000000000..b83deafbf --- /dev/null +++ b/lab7/kern/kio.c @@ -0,0 +1,65 @@ +#include "string.h" +#include "kern/kio.h" + +void kprintf(char* fmt, ...) { + char s[124]; + char buffer[64]; + char *dst = s; + char *p; + + __builtin_va_list args; + __builtin_va_start(args, fmt); + + while (*fmt) { + if (*fmt == '%') { + fmt++; + // escape + if (*fmt == '%') { + goto put; + } + // string + else if (*fmt == 's') { + p = __builtin_va_arg(args, char *); + while (*p) + *dst++ = *p++; + } + // char + else if (*fmt == 'c') { + char c = __builtin_va_arg(args, int); + *dst++ = c; + } + // decimal + else if (*fmt == 'd') { + int arg = __builtin_va_arg(args, int); + if (itoa(arg, buffer, 10) != -1) { + p = buffer; + while(*p) + *dst++ = *p++; + } else { + *dst++ = '@'; + } + + } + // hex + else if (*fmt == 'x') { + long arg = __builtin_va_arg(args, long); + if (itoa(arg, buffer, 16) != -1) { + p = buffer; + while(*p) + *dst++ = *p++; + } else { + *dst++ = '@'; + } + } + } + else { + put: + *dst++ = *fmt; + } + *fmt++; + } + *dst = '\0'; + __builtin_va_end(args); + + uart_async_puts(s); +} diff --git a/lab7/kern/linker.ld b/lab7/kern/linker.ld new file mode 100644 index 000000000..2ed7e6d0f --- /dev/null +++ b/lab7/kern/linker.ld @@ -0,0 +1,44 @@ +SECTIONS +{ + . = 0xffff000000000000; + . += 0x80000; + __kernel_start = .; + .text : { + KEEP(*(.text.entry)) + *(.text .text.* .gnu.linkonce.t.*) + } + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + . = ALIGN(0x1000); + + /* The data segment */ + .data : { + *(.data) + } + + .bss ALIGN(16) (NOLOAD) : { + PROVIDE(__bss_start = .); + *(.bss) + PROVIDE(__bss_end = .); + BYTE(0) + } + + . = ALIGN(0x1000); + __kernel_pgd = .; + .data.kpgd : { + . += (515 * 0x1000); + } + + __heap_start = .; + + /DISCARD/ : { + *(.eh_frame .note.GNU-stack) + } +} + +__stack_kernel_top = 0x20000000; +__stack_user_top = 0x30000000; +__bss_size = (__bss_end - __bss_start) >> 3; \ No newline at end of file diff --git a/lab7/kern/main.c b/lab7/kern/main.c new file mode 100644 index 000000000..92a1d0b66 --- /dev/null +++ b/lab7/kern/main.c @@ -0,0 +1,95 @@ +#include "peripheral/mailbox.h" +#include "kern/shell.h" +#include "kern/timer.h" +#include "kern/irq.h" +#include "kern/sched.h" +#include "kern/kio.h" +#include "kern/cpio.h" +#include "kern/mm.h" +#include "dtb.h" +#include "startup_alloc.h" +#include "syscall.h" +#include "string.h" + +void hw_info() { + unsigned int result[2]; + kputs("##########################################\n"); + get_board_revision(result); + kprintf("Board revision:\t\t\t0x%x\n", result[0]); + get_ARM_memory(result); + kprintf("ARM memory base address:\t0x%x\n", result[0]); + kprintf("ARM memory size:\t\t0x%x\n", result[1]); + kputs("##########################################\n"); +} + +void dtb_init() { + if (fdt_init() < 0) { + kputs("dtb: Bad magic\n"); + return; + } + if (fdt_traverse(initramfs_callback) < 0) + kputs("dtb: Unknown token\n"); + if (fdt_traverse(mm_callback) < 0) + kputs("dtb: Unknown token\n"); + kputs("dtb: init success\n"); +} + +extern unsigned int __stack_kernel_top; + +void reserve_memory() { + kprintf("page used by startup allocator\n"); + reserved_kern_startup(); + kprintf("device tree\n"); + fdt_reserve(); + kprintf("initramfs\n"); + cpio_reserve(); + kprintf("initial kernel stack\n"); + mm_reserve((void *)PHY_2_VIRT((void *)&__stack_kernel_top - 0x2000), (void *)PHY_2_VIRT((void *)&__stack_kernel_top)); +} + +void user_prog() { + exec("/initramfs/vfs1.img", 0); + exit(); +} + +void idle_task() { + while(1) { + schedule(); + } +} + +void initramfs_init() { + mkdir("/initramfs", 0); + mount(0, "/initramfs", "initramfs", 0, 0); +} + +#include "test_func.h" + +void kern_main() { + kio_init(); + mm_init(); + rootfs_init(); + runqueue_init(); + task_init(); + int_init(); + core_timer_enable(); + unsigned long tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); + timer_sched_latency(); + + kputs("press any key to continue..."); + kscanc(); + kputs("\n"); + dtb_init(); + hw_info(); + + reserve_memory(); + + initramfs_init(); + + thread_create(user_prog); + // privilege_task_create(kill_zombies, 10); + idle_task(); +} \ No newline at end of file diff --git a/lab7/kern/mm.c b/lab7/kern/mm.c new file mode 100644 index 000000000..0ecd897dc --- /dev/null +++ b/lab7/kern/mm.c @@ -0,0 +1,242 @@ +#include "kern/mm.h" +#include "kern/kio.h" +#include "startup_alloc.h" + +#include "string.h" +#include "byteswap.h" + +unsigned int phy_address_start = 0; +unsigned int phy_address_limit = 0x3C000000; + +void mm_callback(char *node_name, char *prop_name, void *prop_value) { + if (!strncmp(node_name, "memory", 6) && !strncmp(prop_name, "reg", 3)) { + kputs("mm: Find!\n"); + phy_address_start = __bswap_32(*((unsigned int *)(prop_value))); + phy_address_limit = __bswap_32(*((unsigned int *)(prop_value+4))); + kprintf("physical start address: 0x%x\n", phy_address_start); + kprintf("physical address limit: 0x%x\n", phy_address_limit); + } +} + +struct free_area *free_area; +struct page *frames; + +struct page *get_page_from_addr(void *addr) { + int pfn = PHY_2_PFN(addr); + return &frames[pfn]; +} + +void buddy_alloc_ds() { + frames = (struct page *)sumalloc(sizeof(struct page) * PHY_FRAMES_NUM); + free_area = (struct free_area *)sumalloc(sizeof(struct free_area) * (MAX_ORDER+1)); +} + +void add_to_free_area(struct page *page, struct free_area *free_area) { + free_area->nr_free++; + // kprintf("------add_to_free_area %d(%x) %d %x %d\n", page->pg_index, PFN_2_PHY(page->pg_index), page->compound_order, free_area, free_area->nr_free); + list_add_tail(&page->list, &free_area->free_list); +} + +void del_page_from_free_area(struct page *page, struct free_area *free_area) { + free_area->nr_free--; + // kprintf("------del_page_from_free_area %d(%x) %d %x %d\n", page->pg_index, PFN_2_PHY(page->pg_index), page->compound_order, free_area, free_area->nr_free); + list_del(&page->list); +} + +struct page* expand(struct page *page, unsigned int order) { + struct page *redundant; + unsigned int porder = page->compound_order; + + if (porder > order) { + // kprintf("Release %d, ask for, %d\n", porder, order); + porder--; + redundant = page + (1 << porder); + page->compound_order = porder; + redundant->flags = PG_HEAD; + redundant->compound_order = porder; + add_to_free_area(redundant, &free_area[redundant->compound_order]); + return expand(page, order); + } + page->flags = PG_USED; + return page; +} + +struct page* rmqueue(struct free_area *free_area, unsigned int order) { + struct page *hpage; + if (list_empty(&free_area->free_list)) + return 0; + hpage = list_entry(free_area->free_list.next, struct page, list); + del_page_from_free_area(hpage, free_area); + return expand(hpage, order); +} + +struct page* alloc_pages(unsigned int order) { + struct page *page; + if (order >= MAX_ORDER) + return 0; + for (int i=order ; i 0) { + page = rmqueue(&free_area[i], order); + if (page) { + // kprintf("Alloc new buddy: %d, %x, %d\n", page->pg_index, page->pg_index*PAGE_SIZE, page->compound_order); + return page; + } + } + } + return 0; +} + +/* +You can use the block’s index xor with its exponent to find its buddy. +If its buddy is in the page frame array, then you can merge them to a larger block. +*/ +struct page* find_buddy(struct page *page) { + int buddy_index = page->pg_index ^ (1 << page->compound_order); + if (buddy_index >= PHY_FRAMES_NUM) + return 0; + return &frames[buddy_index]; +} + +void free_pages(void *addr) { + struct page *page = get_page_from_addr(addr); + struct page *buddy; + int order = page->compound_order; + + // kprintf("\tFree buddy: %d, %x, %d\n", page->pg_index, page->pg_index*PAGE_SIZE, page->compound_order); + while(order < MAX_ORDER) { + buddy = find_buddy(page); + // kprintf("\tBuddy page: %d, %x, %d\n", buddy->pg_index, buddy->pg_index*PAGE_SIZE, buddy->compound_order); + if (!buddy || buddy->flags != PG_HEAD || buddy->compound_order != order) { + page->flags = PG_HEAD; + add_to_free_area(page, &free_area[page->compound_order]); + break; + } + // kprintf("\tBuddy page: %d, %x, %d\n", buddy->pg_index, buddy->pg_index*PAGE_SIZE, buddy->compound_order); + // kprintf("\tMerge %d to %d\n", order, order+1); + + // order == buddy->compound_order + del_page_from_free_area(buddy, &free_area[order]); + if (buddy > page) { // | page | buddy | + page->compound_order = order+1; + buddy->flags = PG_TAIL; + } else { // | buddy | page | + buddy->compound_order = order+1; + page->flags = PG_TAIL; + page = buddy; + } + order = page->compound_order; + } +} + +// start of kernel frame +extern unsigned int __heap_start; + +void mm_init() { + int i; + int cnt = 0; + int order = MAX_ORDER - 1; + + int kernel_data_end = (long)(&__heap_start) / PAGE_SIZE; + int mem_end = phy_address_limit / PAGE_SIZE - 50; + + buddy_alloc_ds(); + + + for (i=0 ; i= mem_end) + order--; + frames[i].flags = PG_HEAD; + frames[i].compound_order = order; + add_to_free_area(&frames[i], &free_area[order]); + cnt = (1 << order) - 1; + } else { + frames[i].flags = PG_TAIL; + frames[i].compound_order = 0; + cnt--; + } + } + + for ( ; icompound_order; + unsigned int cl = page->pg_index; + unsigned int cr = cl + (1 << porder) - 1; + unsigned int mid; + + if (cl > r || cr < l) { + add_to_free_area(page, &free_area[porder]); + return; + } + // no need to split + if (cl >= l && cr <= r) { + // kprintf("\tReserved range: %d-%d\n", cl, cr); + page->flags = PG_USED; + return; + } + // split + mid = (cl + cr) >> 1; + porder--; + buddy = &frames[mid+1]; + page->compound_order = porder; + buddy->flags = PG_HEAD; + buddy->compound_order = porder; + expand_reserve(page, l, r); + expand_reserve(buddy, l, r); +} + +// Mark the page from start to end as used +void mm_reserve(void *start, void *end) { + unsigned int ps = PHY_2_PFN(VIRT_2_PHY(start)); + unsigned int pe = PHY_2_PFN(VIRT_2_PHY(end)); + unsigned int pi = ps; + struct page page; + int i; + + kprintf("\tReserve 0x%x-0x%x\n", VIRT_2_PHY(start), VIRT_2_PHY(end)); + for (i=ps ; i<=pe ; i++) if (frames[i].flags == PG_USED) { + kputs("\tTry to reserved page that are already been used...\n"); + return; + } + + do { + // find the header page of start address, linear search for now + while(pi >= 0) { + page = frames[pi--]; + if (page.flags == PG_HEAD) + break; + } + pi = page.pg_index + (1<pgd, pgd_index(vaddr)); + pmd = pgtable_walk(pud, pud_index(vaddr)); + pte = pgtable_walk(pmd, pmd_index(vaddr)); + return pgtable_walk_pte(pte, pte_index(vaddr), paddr) + (vaddr & (PAGE_SIZE-1)); +} + +void *mappages(struct mm_struct *mm, unsigned long vaddr, unsigned long size, unsigned long paddr) { + if (!mm->pgd) + return 0; + for (int i=0 ; ipgd) + return; + void *pud; + pud = pgtable_walk(mm->pgd, pgd_index(vaddr)); + pgtable_walk_block(pud, pud_index(vaddr), paddr); +} + +void create_pgd(struct mm_struct *mm) { + void *new_page = kmalloc(PAGE_SIZE); + if (!new_page) + return; + memset(new_page, 0, PAGE_SIZE); + mm->pgd = new_page; +} + +void free_pgtable(unsigned long *table, int level) { + void *next; + for(int i=0 ; i<512 ; i++) { + if (table[i]) { + next = (void*)PHY_2_VIRT(table[i] & PAGE_MASK); + if (level != 4) + free_pgtable(next, level+1); + // if device memory + if (level == 4 && VIRT_2_PHY(next) >= 0x3C000000) + continue; + kfree(next); + } + } +} + +void free_pgd(struct mm_struct *mm) { + unsigned long *pgd = mm->pgd; + void *pud; + for(int i=0 ; i<512 ; i++) { + if (pgd[i]) { + pud = (void*)PHY_2_VIRT(pgd[i] & PAGE_MASK); + free_pgtable(pud, 2); + kfree(pud); + } + } + kfree(pgd); +} + +/* + level + pgd 1 + pud 2 + pmd 3 + pte 4 +*/ +void fork_pgtable(unsigned long *ptable, unsigned long *ctable, int level) { + void *pnext; + void *cnext; + + for(int i=0 ; i<512 ; i++) { + if (ptable[i]) { + pnext = (void*)PHY_2_VIRT(ptable[i] & PAGE_MASK); + if (level == 4) { + cnext = pgtable_walk_pte(ctable, i, 0); + memcpy(cnext, pnext, PAGE_SIZE); + } else { + cnext = pgtable_walk(ctable, i); + fork_pgtable(pnext, cnext, level+1); + } + } + } +} + +void fork_pgd(struct mm_struct *parent_mm, struct mm_struct *child_mm) { + unsigned long *ppgd = parent_mm->pgd; + unsigned long *cpgd = child_mm->pgd; + void *ppud; + void *cpud; + + if (!ppgd || !cpgd) + return; + + for(int i=0 ; i<512 ; i++) { + if (ppgd[i]) { + ppud = (void*)PHY_2_VIRT(ppgd[i] & PAGE_MASK); + cpud = pgtable_walk(cpgd, i); + fork_pgtable(ppud, cpud, 2); + } + } +} \ No newline at end of file diff --git a/lab7/kern/sched.S b/lab7/kern/sched.S new file mode 100644 index 000000000..fb7019ca6 --- /dev/null +++ b/lab7/kern/sched.S @@ -0,0 +1,41 @@ + + +.global switch_to +switch_to: + stp x19, x20, [x0, 16 * 0] + stp x21, x22, [x0, 16 * 1] + stp x23, x24, [x0, 16 * 2] + stp x25, x26, [x0, 16 * 3] + stp x27, x28, [x0, 16 * 4] + stp fp, lr, [x0, 16 * 5] + mov x9, sp + str x9, [x0, 16 * 6] + + ldp x19, x20, [x1, 16 * 0] + ldp x21, x22, [x1, 16 * 1] + ldp x23, x24, [x1, 16 * 2] + ldp x25, x26, [x1, 16 * 3] + ldp x27, x28, [x1, 16 * 4] + ldp fp, lr, [x1, 16 * 5] + ldr x9, [x1, 16 * 6] + mov sp, x9 + ret + +.global update_current +update_current: + msr tpidr_el1, x0 + ret + +.global get_current +get_current: + mrs x0, tpidr_el1 + ret + +.global update_pgd +update_pgd: + 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 + ret \ No newline at end of file diff --git a/lab7/kern/sched.c b/lab7/kern/sched.c new file mode 100644 index 000000000..1f7c18e4e --- /dev/null +++ b/lab7/kern/sched.c @@ -0,0 +1,334 @@ +#include "kern/sched.h" +#include "kern/irq.h" +#include "kern/slab.h" +#include "kern/kio.h" +#include "string.h" +#include "fs/vfs.h" + +#define ROUND_UP(n,d) (((n) + (d-1)) & (-d)) +#define ROUND_DOWN(n,d) ((n) & (-d)) + +// ############## runqueue ################## + +struct prio_array { + DECLARE_BITMAP(bitmap, MAX_PRIO); + struct list_head queue[MAX_PRIO]; +}; + +struct runqueue { + unsigned long nr_running; + struct prio_array array; +}; + +struct runqueue runqueue; +struct list_head zombie_queue; +char kernel_stack[MAX_PRIV_TASK_NUM][STACKSIZE]; +char user_stack[MAX_PRIV_TASK_NUM][STACKSIZE]; + +void runqueue_init() { + int i; + struct prio_array *array = &runqueue.array; + runqueue.nr_running = 0; + for(i=0 ; iqueue[i]); + } + bitmap_zero(array->bitmap, MAX_PRIO); + INIT_LIST_HEAD(&zombie_queue); +} + +void runqueue_push(struct task_struct *new_task) { + struct prio_array *array = &runqueue.array; + + runqueue.nr_running += 1; + __set_bit(new_task->prio, array->bitmap); + list_add_tail(&new_task->list, &array->queue[new_task->prio]); +} + +struct task_struct* runqueue_pop() { + int highest_prio; + struct task_struct *next_task; + struct prio_array *array = &runqueue.array; + + runqueue.nr_running -= 1; + highest_prio = sched_find_first_bit(array->bitmap); + // no task in queue + if (highest_prio == MAX_PRIO) + return 0; + next_task = list_entry(array->queue[highest_prio].next, struct task_struct, list); + list_del(&next_task->list); + if (list_empty(&array->queue[highest_prio])) + __clear_bit(highest_prio, array->bitmap); + return next_task; +} + +// ############## priv task ################## + +struct task_struct task_pool[MAX_PRIV_TASK_NUM]; +struct task_struct *utask[1000]; +int pid; // start from 1000 + +inline int get_priv_tid() { + int i; + for(i=0 ; iroot; + task_pool[0].croot = rootfs->root; + fd_init(&task_pool[0].files); + task_pool[0].mm.pgd = (unsigned long *)&__kernel_pgd; + INIT_LIST_HEAD(&task_pool[0].signal_pend_list); + update_current(&task_pool[0]); + pid = 1000; +} + +struct task_struct *privilege_task_create(void (*func)(), int prio) { + struct task_struct *new_task; + unsigned long stk_addr; + int tid = -1; + + if (prio > 20 || prio < 1) + return 0; + + tid = get_priv_tid(); + if (tid == -1) + return 0; + + + new_task = &task_pool[tid]; + new_task->used = 1; + new_task->prio = prio; + new_task->state = RUNNING; + new_task->ctime = TASK_CTIME; + new_task->resched = 0; + new_task->cwd = rootfs->root; + new_task->croot = rootfs->root; + fd_init(&new_task->files); + create_pgd(&new_task->mm); + INIT_LIST_HEAD(&new_task->signal_list); + INIT_LIST_HEAD(&new_task->signal_pend_list); + + // kernel stack + stk_addr = (unsigned long)&kernel_stack[tid][4095]; + stk_addr = ROUND_DOWN(stk_addr, 16); + new_task->task_context.lr = (unsigned long)func; + new_task->task_context.fp = stk_addr; + new_task->task_context.sp = stk_addr; + new_task->stk_addr = (void*)stk_addr; + + runqueue_push(new_task); + return new_task; +} + +// ############## normal task ################## + +struct task_struct *task_create(void (*func)(), int prio) { + unsigned long stk_addr; + struct task_struct *new_task; + + if (prio <= 20) + return 0; + + new_task = kmalloc(STACKSIZE); + if (!new_task) + return 0; + + int_disable(); + + utask[pid-1000] = new_task; + new_task->tid = pid++; + new_task->prio = prio; + new_task->state = RUNNING; + new_task->ctime = TASK_CTIME; + new_task->resched = 0; + new_task->cwd = rootfs->root; + new_task->croot = rootfs->root; + fd_init(&new_task->files); + create_pgd(&new_task->mm); + INIT_LIST_HEAD(&new_task->signal_list); + INIT_LIST_HEAD(&new_task->signal_pend_list); + + // kernel stack + stk_addr = (unsigned long)kmalloc(STACKSIZE); + stk_addr = stk_addr + STACKSIZE; + stk_addr = ROUND_DOWN(stk_addr, 16); + new_task->task_context.lr = (unsigned long)func; + new_task->task_context.fp = stk_addr; + new_task->task_context.sp = stk_addr; + new_task->stk_addr = (void*)stk_addr; + + runqueue_push(new_task); + + int_enable(); + + return new_task; +} + +int task_fork(void (*func)(), struct task_struct *parent, void *trapframe) { + int i; + unsigned long offset; + char *pptr; + char *cptr; + struct trapframe* child_trapframe; + struct trapframe* parent_trapframe; + struct task_struct *child = task_create(func, parent->prio); + + if (!child) + return -1; + + int_disable(); + + // setup kernel stack + cptr = (char *)child->stk_addr; + pptr = (char *)parent->stk_addr; + offset = pptr - (char*)trapframe; + for (i=0 ; itask_context.sp = (unsigned long)child->stk_addr - offset; + + // setup user stack + fork_pgd(&parent->mm, &child->mm); + mappages(&child->mm, 0x3C000000, 0x3000000, 0x3C000000); + child_trapframe = (struct trapframe *)child->task_context.sp; + parent_trapframe = (struct trapframe *)trapframe; + child_trapframe->sp_el0 = parent_trapframe->sp_el0; + child_trapframe->x[0] = 0; + + int_enable(); + + if (list_empty(&parent->signal_list)) + goto out; + // signal copy + struct list_head *ptr; + struct signal_t *signal; + struct signal_t *new_signal; + list_for_each(ptr, &parent->signal_list) { + signal = list_entry(ptr, struct signal_t, list); + new_signal = signal_create(signal->num, signal->handler); + list_add_tail(&new_signal->list, &child->signal_list); + } +out: + return child->tid; +} + +// ############################################# + +void context_switch(struct task_struct *next) { + struct task_struct *prev = get_current(); + if (prev->state == RUNNING) { + runqueue_push(prev); + } else if (prev->state == DEAD) { + kprintf("Process %d dead...\n", prev->tid); + if (prev->tid >= 1000) + list_add_tail(&prev->list, &zombie_queue); + else + prev->used = 0; + } + // kprintf("context switch %d ~ %d\n", prev->tid, next->tid); + update_pgd(VIRT_2_PHY(next->mm.pgd)); + update_current(next); + switch_to(&prev->task_context, &next->task_context); +} + +void schedule() { + struct task_struct *next = runqueue_pop(); + if (next != 0) { + context_switch(next); + } +} + +void kill_zombies() { + struct task_struct *to_release; + struct list_head *itr; + struct list_head *tmp; + + while(1) { + list_for_each_safe(itr, tmp, &zombie_queue) { + to_release = list_entry(itr, struct task_struct, list); + kprintf("Kill zombie %d\n", to_release->tid); + kfree(to_release->stk_addr); + kfree(to_release->ustk_addr); + free_pgd(&to_release->mm); + kfree(to_release); + list_del(itr); + } + } +} + +struct task_struct* get_task_struct(int pid) { + if (pid < 1000) + return &task_pool[pid]; + else { + return utask[pid-1000]; + } +} + +// ############## sys call ################## + +int __getpid() { + struct task_struct *current = get_current(); + return current->tid; +} + +void __exec(const char *name, char *const argv[]) { + struct task_struct *current = get_current(); + struct file *file_node; + long filesize; + char *user_prog; + + if (vfs_open(name, 0, &file_node) < 0) { + kprintf("Failed to exec %s", name); + return; + } + + filesize = vfs_lseek64(file_node, 0, SEEK_END); + vfs_lseek64(file_node, 0, SEEK_SET); + user_prog = kmalloc(filesize); + vfs_read(file_node, user_prog, filesize); + + mappages(¤t->mm, 0x0, 250000, VIRT_2_PHY(user_prog)); + mappages(¤t->mm, USER_STK_LOW, STACKSIZE, 0); + + asm volatile("msr sp_el0, %0" : : "r"(USER_STK_HIGH)); + asm volatile("msr elr_el1, %0": : "r"(0x0)); + asm volatile("msr spsr_el1, %0" : : "r"(0b0)); + asm volatile("eret"); +} + +extern void return_from_fork(); + +int __fork(void *trapframe) { + struct task_struct *parent = get_current(); + return task_fork(return_from_fork, parent, trapframe); +} + +void __exit() { + struct task_struct *current = get_current(); + current->state = DEAD; + schedule(); +} + +void __kill(int pid) { + if (pid <= 0) + return; + struct task_struct* target = get_task_struct(pid); + target->state = DEAD; +} \ No newline at end of file diff --git a/lab7/kern/shell.c b/lab7/kern/shell.c new file mode 100644 index 000000000..0b8b58e63 --- /dev/null +++ b/lab7/kern/shell.c @@ -0,0 +1,75 @@ +#include "kern/kio.h" +#include "kern/shell.h" +#include "kern/timer.h" +#include "kern/sched.h" +#include "kern/cpio.h" +#include "kern/mm.h" +#include "string.h" +#include "reset.h" + +void shell_input(char *cmd) { + char c; + unsigned int len = 0; + + while((c = kscanc()) != '\n') { + if (c == BACKSPACE || c == DELETE) { + if (!len) + continue; + LEFT_SHIFT + kputc(' '); + LEFT_SHIFT + --len; + } else if (c == ESC) { + kscanc(); + kscanc(); + } else { // regular letter + kputc(c); + cmd[len++] = c; + } + } + kputs("\n"); + cmd[len] = '\0'; +} + +void shell_help() { + kputs("help\t\t: print this help menu\n"); + kputs("hello\t\t: print Hello World!\n"); + kputs("ls\t\t: list file\n"); + kputs("cat\t\t: print file content\n"); + kputs("exec\t\t: execute a file\n"); + kputs("setTimeout\t: MESSAGE SECONDS\n"); + kputs("reboot\t\t: reboot the device\n"); +} + +void shell_parse(char *cmd) { + char args[MAX_INPUT_LEN]; + if (!strcmp(cmd, "help")) { + shell_help(); + } else if (!strcmp(cmd, "hello")) { + kputs("Hello World!\n"); + } else if (!strcmp(cmd, "ls")) { + cpio_ls(); + } else if (!strcmp(cmd, "cat")) { + kputs("FileName: "); + shell_input(args); + cpio_cat(args); + } else if (!strcmp(cmd, "setTimeout")) { + shell_input(args); + set_timeout(args); + } else if (!strcmp(cmd, "reboot")) { + kputs("About to reboot...\n"); + reset(1000); + } else { + kputs(cmd); + kputs(": command not found\n"); + } +} + +void shell_start() { + char cmd[128]; + while (1) { + kputs("raspi3> "); + shell_input(cmd); + shell_parse(cmd); + } +} \ No newline at end of file diff --git a/lab7/kern/signal.c b/lab7/kern/signal.c new file mode 100644 index 000000000..62d0dfe2a --- /dev/null +++ b/lab7/kern/signal.c @@ -0,0 +1,113 @@ +#include "kern/signal.h" +#include "kern/sched.h" +#include "kern/slab.h" +#include "kern/kio.h" +#include "kern/irq.h" +#include "string.h" + +struct signal_t *signal_create(int SIGNAL, void (*handler)()) { + struct signal_t *new_signal = kmalloc(sizeof(struct signal_t)); + new_signal->num = SIGNAL; + new_signal->handler = handler; + INIT_LIST_HEAD(&new_signal->list); + return new_signal; +} + +void signal_default(int pid, int SIGNAL) { + switch(SIGNAL) { + case SIGKILL: + __kill(pid); + break; + default: + kprintf("Undefined signal number...\n"); + } +} + +void signal_return() { + asm volatile( + "mov x8, #30 \n\t" + "svc #0 \n\t" + ); +} + +void signal_jump(void *trapframe, void (*handler)()) { + struct trapframe *tf = trapframe; + struct task_struct *current = get_current(); + struct signal_context_t *signal_context = kmalloc(sizeof(struct signal_context_t)); + signal_context->stk_addr = kmalloc(4096); + signal_context->trapframe = kmalloc(sizeof(struct trapframe)); + // kprintf("Ready to jump %x %x %x\n", signal_context, signal_context->stk_addr, signal_context->trapframe); + memcpy(signal_context->trapframe, trapframe, sizeof(struct trapframe)); + + current->signal_context = signal_context; + + // return address save in x30 in ARM + tf->x[30] = (long)signal_return; + tf->elr_el1 = (long)handler; + tf->sp_el0 = (long)signal_context->stk_addr; +} + +void signal_back(void *trapframe) { + struct task_struct *current = get_current(); + // kprintf("Back %x %x\n", current->signal_context, current->signal_context->trapframe); + memcpy(trapframe, current->signal_context->trapframe, sizeof(struct trapframe)); + kfree(current->signal_context->trapframe); + kfree(current->signal_context->stk_addr); + kfree(current->signal_context); +} + + +void __signal(int SIGNAL, void (*handler)()) { + struct list_head *ptr; + struct signal_t *signal; + struct task_struct *current = get_current(); + + if (list_empty(¤t->signal_list)) + goto regis; + list_for_each(ptr, ¤t->signal_list) { + signal = list_entry(ptr, struct signal_t, list); + if (signal->num == SIGNAL) { + kprintf("Overwite existing registed signal(%d)\n", SIGNAL); + list_del(&signal->list); + break; + } + } +regis: + signal = signal_create(SIGNAL, handler); + list_add_tail(&signal->list, ¤t->signal_list); +} + +void __sigkill(int pid, int SIGNAL, void *trapframe) { + struct signal_pend_t *signal_pend; + struct task_struct *target = get_task_struct(pid); + if (list_empty(&target->signal_list)) + goto default_sig; + + signal_pend = kmalloc(sizeof(struct signal_pend_t)); + signal_pend->num = SIGNAL; + INIT_LIST_HEAD(&signal_pend->list); + + list_add_tail(&signal_pend->list, &target->signal_pend_list); + return; +default_sig: + signal_default(pid, SIGNAL); +} + +void signal_run(void *trapframe) { + struct task_struct *current = get_current(); + if (list_empty(¤t->signal_pend_list)) + return; + + struct list_head *ptr; + struct signal_t *signal; + struct signal_pend_t *signal_pend; + signal_pend = list_entry(current->signal_pend_list.next, struct signal_pend_t, list); + list_del(&signal_pend->list); + list_for_each(ptr, ¤t->signal_list) { + signal = list_entry(ptr, struct signal_t, list); + if (signal->num == signal_pend->num) { + signal_jump(trapframe, signal->handler); + return; + } + } +} \ No newline at end of file diff --git a/lab7/kern/slab.c b/lab7/kern/slab.c new file mode 100644 index 000000000..666e5d243 --- /dev/null +++ b/lab7/kern/slab.c @@ -0,0 +1,169 @@ +#include "kern/mm.h" +#include "kern/kio.h" +#include "startup_alloc.h" + +#define PREALLOC_SIZE 100 + +/* + slab_t +*/ +struct slab_t* pmalloc_slab() { + struct slab_t *ret; + ret = (struct slab_t *)sumalloc(sizeof(struct slab_t)); + return ret; +} + + +struct kmem_pool *kmalloc_pools; + +void slab_alloc_ds() { + kmalloc_pools = (struct kmem_pool *)sumalloc(sizeof(struct kmem_pool) * MAX_OBJ_CACHE_NUM); +} + +struct kmem_pool* kmalloc_slab(unsigned int size) { + unsigned int rounded_size; + int pool_id; + + if (size <= SMALL_OBJ_SIZE) { + rounded_size = (size + 7) & -8; + pool_id = rounded_size / 8 - 1; + } else if (size <= MEDIUM_OBJ_SIZE) { + size -= SMALL_OBJ_SIZE; + pool_id = 15 + (size + 11) / 12; + } else { + for(pool_id=24 ; pool_id= MAX_OBJ_CACHE_NUM) + return 0; + kmalloc_pools[pool_id].object_size = size; + kmalloc_pools[pool_id].num = PAGE_SIZE*4 / size; + } + return &kmalloc_pools[pool_id]; +} + +struct slab_t* slab_create(struct kmem_pool *pool) { + struct slab_t *slab; + struct page *page; + + page = alloc_pages(pool->gfporder); + page->flags = PG_SLAB; + + slab = pmalloc_slab(); + slab->inuse = 0; + slab->nr_free = pool->num; + slab->head_addr = (void*)PFN_2_PHY(page->pg_index); + INIT_LIST_HEAD(&slab->free_list); + INIT_LIST_HEAD(&slab->list); + + page->slab = slab; + + return slab; +} + +void* slab_alloc(struct kmem_pool *pool) { + struct slab_t *slab; + struct list_head *ptr; + void *ret; + + if (list_empty(&pool->slab_list)) + goto new_slab; + + list_for_each(ptr, &pool->slab_list) { + slab = list_entry(ptr, struct slab_t, list); + if (slab->nr_free > 0) + break; + } + + if (slab->nr_free == 0) { +new_slab: + slab = slab_create(pool); + list_add_tail(&slab->list, &pool->slab_list); + } + + slab->inuse++; + slab->nr_free--; + if (!list_empty(&slab->free_list)) { + ptr = slab->free_list.next; + list_del(ptr); + return (void*)ptr; + } + ret = slab->head_addr + (slab->inuse-1) * pool->object_size; + return ret; +} + +void* __do_kmalloc(unsigned int size) { + struct kmem_pool *cachep; + void *ret; + + cachep = kmalloc_slab(size); + if (!cachep) { + kputs("Unable to find kmem_pool...\n"); + return 0; + } + ret = slab_alloc(cachep); + return ret; +} + +void* kmalloc(unsigned int size) { + int i; + void *ret; + struct page *page; + + if (size >= PAGE_SIZE) { + for (i=0 ; ipg_index); + // kprintf("kmalloc: buddy %x\n", ret); + } else { + ret = __do_kmalloc(size); + // kprintf("kmalloc: slab %x\n", ret); + } + return (void*)PHY_2_VIRT(ret); +} + +void kfree(void *addr) { + struct slab_t *slab; + struct page *page = get_page_from_addr(addr); + + if (page->flags == PG_SLAB) { + slab = page->slab; + list_add_tail((struct list_head*)addr, &slab->free_list); + slab->inuse--; + slab->nr_free++; + } else { + free_pages(addr); + } +} + + +void slab_init() { + int i; + + slab_alloc_ds(); + + for (i=0 ; ix[0] = __getpid(); +} + +inline void sys_uart_read(struct trapframe *trapframe) { + int i; + int size = trapframe->x[1]; + char *buf = (char *)trapframe->x[0]; + for(i=0 ; ix[0] = i; +} + +inline void sys_uart_write(struct trapframe *trapframe) { + int i; + char *buf = (char *)trapframe->x[0]; + int size = trapframe->x[1]; + for(i=0 ; ix[0] = i; +} + +inline void sys_exec(struct trapframe *trapframe) { + const char *name = (const char *)trapframe->x[0]; + __exec(name, (void*)trapframe->x[1]); + trapframe->x[0] = 0; +} + +inline void sys_fork(struct trapframe *trapframe) { + trapframe->x[0] = __fork(trapframe); +} + +inline void sys_exit(struct trapframe *trapframe) { + __exit(); +} + +inline void sys_mbox_call(struct trapframe *trapframe) { + unsigned char ch = trapframe->x[0]; + unsigned int *mailbox = (unsigned int *)trapframe->x[1]; + unsigned int *kernel_addr = walk((struct mm_struct *)&(get_current()->mm.pgd), (unsigned long)mailbox, 0); + trapframe->x[0] = mailbox_call(ch, kernel_addr); +} + +inline void sys_kill(struct trapframe *trapframe) { + __kill(trapframe->x[0]); +} + +inline void sys_signal(struct trapframe *trapframe) { + __signal(trapframe->x[0], (void*)trapframe->x[1]); +} + +inline void sys_sigkill(struct trapframe *trapframe) { + __sigkill(trapframe->x[0], trapframe->x[1], trapframe); +} + +inline void sys_sigreturn(struct trapframe *trapframe) { + signal_back(trapframe); +} + +inline void sys_open(struct trapframe *trapframe) { + int fd; + struct file *fh; + const char *pathname = (char *)trapframe->x[0]; + int flags = trapframe->x[1]; + int ret = vfs_open(pathname, flags, &fh); +#ifdef DEBUG_FS + kprintf("open(%s, %d)\n", pathname, flags); +#endif + if (ret < 0) { + trapframe->x[0] = ret; + return; + } + fd = fd_open(&(get_current()->files), fh); + trapframe->x[0] = fd; +} + +inline void sys_close(struct trapframe *trapframe) { + struct file *fh; + int fd = trapframe->x[0]; +#ifdef DEBUG_FS + kprintf("close(%d)\n", fd); +#endif + if (fd < 0) { + trapframe->x[0] = -1; + return; + } + fh = fd_close(&(get_current()->files), fd); + trapframe->x[0] = vfs_close(fh); +} + +inline void sys_write(struct trapframe *trapframe) { + struct file *fh; + int fd = trapframe->x[0]; + const char *buf = (char *)trapframe->x[1]; + unsigned long count = trapframe->x[2]; +#ifdef DEBUG_FS + kprintf("write(%d, %s, %d)\n", fd, buf, count); +#endif + if (fd < 0) { + trapframe->x[0] = -1; + return; + } + fh = fd_get(&(get_current()->files), fd); + if (fh == 0) { + trapframe->x[0] = -1; + return; + } + trapframe->x[0] = vfs_write(fh, buf, count); +} + +inline void sys_read(struct trapframe *trapframe) { + struct file *fh; + int fd = trapframe->x[0]; + char *buf = (char *)trapframe->x[1]; + unsigned long count = trapframe->x[2]; +#ifdef DEBUG_FS + kprintf("read(%d, %d)\n", fd, count); +#endif + if (fd < 0) { + trapframe->x[0] = -1; + return; + } + fh = fd_get(&(get_current()->files), fd); + if (fh == 0) { + trapframe->x[0] = -1; + return; + } + trapframe->x[0] = vfs_read(fh, buf, count); +} + +inline void sys_mkdir(struct trapframe *trapframe) { + const char *pathname = (char *)trapframe->x[0]; +#ifdef DEBUG_FS + kprintf("mkdir(%s)\n", pathname); +#endif + // unsigned mode = trapframe->x[1]; + trapframe->x[0] = vfs_mkdir(pathname); +} + +inline void sys_mount(struct trapframe *trapframe) { + const char *target = (char *)trapframe->x[1]; + const char *filesystem = (char *)trapframe->x[2]; +#ifdef DEBUG_FS + kprintf("mount(%s, %s)\n", target, filesystem); +#endif + trapframe->x[0] = vfs_mount(target, filesystem); +} + +inline void sys_chdir(struct trapframe *trapframe) { + const char *path = (char *)trapframe->x[0]; +#ifdef DEBUG_FS + kprintf("chdir(%s)\n", path); +#endif + trapframe->x[0] = vfs_chdir(path); +} + +inline void sys_lseek64(struct trapframe *trapframe) { + struct file *fh; + int fd = trapframe->x[0]; + long offset = trapframe->x[1]; + int whence = trapframe->x[2]; + + if (fd < 0) { + trapframe->x[0] = -1; + return; + } + fh = fd_get(&(get_current()->files), fd); + if (fh == 0) { + trapframe->x[0] = -1; + return; + } + trapframe->x[0] = vfs_lseek64(fh, offset, whence); +} + +void syscall_main(struct trapframe *trapframe) { + int_enable(); + long syscall_num = trapframe->x[8]; + switch(syscall_num) { + case SYS_GET_PID: + sys_getpid(trapframe); + break; + case SYS_UART_READ: + sys_uart_read(trapframe); + break; + case SYS_UART_WRITE: + sys_uart_write(trapframe); + break; + case SYS_EXEC: + sys_exec(trapframe); + break; + case SYS_FORK: + sys_fork(trapframe); + break; + case SYS_EXIT: + sys_exit(trapframe); + break; + case SYS_MBOX_CALL: + sys_mbox_call(trapframe); + break; + case SYS_KILL: + sys_kill(trapframe); + break; + case SYS_SIGNAL: + sys_signal(trapframe); + break; + case SYS_SIGKILL: + sys_sigkill(trapframe); + break; + case SYS_OPEN: + sys_open(trapframe); + break; + case SYS_CLOSE: + sys_close(trapframe); + break; + case SYS_WRITE: + sys_write(trapframe); + break; + case SYS_READ: + sys_read(trapframe); + break; + case SYS_MKDIR: + sys_mkdir(trapframe); + break; + case SYS_MOUNT: + sys_mount(trapframe); + break; + case SYS_CHDIR: + sys_chdir(trapframe); + break; + case SYS_LSEEK64: + sys_lseek64(trapframe); + break; + case 30: + sys_sigreturn(trapframe); + break; + default: + uart_sync_puts("Undefined syscall number, about to reboot...\n"); + reset(1000); + while(1); + } + int_disable(); +} + +void svc_main(unsigned long spsr, unsigned long elr, unsigned long esr, struct trapframe *trapframe) { + unsigned int svc_num; + svc_num = esr & 0xFFFFFF; + + switch(svc_num) { + case 0: + syscall_main(trapframe); + break; + case 1: + kputs("svc 1\n"); + core_timer_enable(); + break; + case 2: + /* + bits [31:26] 0b010101 SVC instruction execution in AArch64 state. + */ + kprintf("\nspsr_el1: \t%x\n", spsr); + kprintf("elr_el1: \t%x\n", elr); + kprintf("esr_el1: \t%x\n", esr); + break; + default: + uart_sync_printNum(svc_num, 10); + uart_sync_puts(": Undefined svc number, about to reboot...\n"); + reset(1000); + while(1); + } +} + +void fault_parse(unsigned long sc) { + unsigned long far; + if (sc & 0b110000) { + kprintf("Others fault...\n"); + return; + } + + switch((sc & 0b1100) >> 2) { + case 0: + kprintf("Address size fault,"); + break; + case 1: + kprintf("Translation fault,"); + break; + case 2: + kprintf("Access flag fault,"); + break; + case 3: + kprintf("Permission fault,"); + break; + } + + kprintf(" level %d\n", sc & 0b11); + asm volatile("mrs %0, far_el1":"=r"(far)); + kprintf("Address: \t0x%x\n", far); +} + +void sync_main(unsigned long spsr, unsigned long elr, unsigned long esr, struct trapframe *trapframe) { + switch(EC_BITS(esr)) { + case EC_SVC_64: + svc_main(spsr, elr, esr, trapframe); + break; + case EC_IA_EL0: + kprintf("(EL0)"); + case EC_IA_EL1: + kprintf("Instruction Abort\n"); + fault_parse(IFSC(esr)); + kprintf("spsr_el0: \t0x%x\n", trapframe->sp_el0); + __exit(); + break; + case EC_DA_EL0: + kprintf("(EL0)"); + case EC_DA_EL1: + kprintf("Data Abort\n"); + fault_parse(DFSC(esr)); + kprintf("spsr_el0: \t0x%x\n", trapframe->sp_el0); + __exit(); + break; + default: + uart_sync_printNum(EC_BITS(esr), 10); + uart_sync_puts(": Unknown ec bit, about to reboot...\n"); + reset(1000); + while(1); + } +} \ No newline at end of file diff --git a/lab7/kern/syscall.S b/lab7/kern/syscall.S new file mode 100644 index 000000000..4df0f6dc9 --- /dev/null +++ b/lab7/kern/syscall.S @@ -0,0 +1,107 @@ + +.global getpid +getpid: + mov x8, #0 + svc #0 + ret + +.global uart_read +uart_read: + mov x8, #1 + svc #0 + ret + +.global uart_write +uart_write: + mov x8, #2 + svc #0 + ret + +.global exec +exec: + mov x8, #3 + svc #0 + ret + +.global fork +fork: + mov x8, #4 + svc #0 + ret + +.global exit +exit: + mov x8, #5 + svc #0 + +.global mbox_call +mbox_call: + mov x8, #6 + svc #0 + ret + +.global kill +kill: + mov x8, #7 + svc #0 + ret + +.global signal +signal: + mov x8, #8 + svc #0 + ret + +.global sigkill +sigkill: + mov x8, #9 + svc #0 + ret + +.global open +open: + mov x8, #11 + svc #0 + ret + +.global close +close: + mov x8, #12 + svc #0 + ret + +.global write +write: + mov x8, #13 + svc #0 + ret + +.global read +read: + mov x8, #14 + svc #0 + ret + +.global mkdir +mkdir: + mov x8, #15 + svc #0 + ret + +.global mount +mount: + mov x8, #16 + svc #0 + ret + +.global chdir +chdir: + mov x8, #17 + svc #0 + ret + +.global lseek64 +lseek64: + mov x8, #18 + svc #0 + ret \ No newline at end of file diff --git a/lab7/kern/timer.S b/lab7/kern/timer.S new file mode 100644 index 000000000..f8ad2a60e --- /dev/null +++ b/lab7/kern/timer.S @@ -0,0 +1,44 @@ +.section ".text" + +#include "peripheral/arm.h" + +.global core_timer_enable +core_timer_enable: + mov x0, 1 + msr cntp_ctl_el0, x0 // enable + mrs x0, cntfrq_el0 + msr cntp_tval_el0, x0 // set expired time + mov x0, 2 + ldr x1, =CORE0_TIMER_IRQ_CTRL + str w0, [x1] // unmask timer interrupt + ret + +.global core_timer_disable +core_timer_disable: + mov x0, 0 + msr cntp_ctl_el0, x0 // disable + mov x0, 0 + ldr x1, =CORE0_TIMER_IRQ_CTRL + str x0, [x1] // disable timer interrupt + ret + +.global timer_enable_int +timer_enable_int: + mov x0, 2 + ldr x1, =CORE0_TIMER_IRQ_CTRL + str w0, [x1] // unmask timer interrupt + ret + +.global timer_disable_int +timer_disable_int: + mov x0, 0 + ldr x1, =CORE0_TIMER_IRQ_CTRL + str x0, [x1] // disable timer interrupt + ret + +.global timer_sched_latency +timer_sched_latency: + mrs x0, cntfrq_el0 + asr x0, x0, 7 // 1/2 secs + msr cntp_tval_el0, x0 + ret \ No newline at end of file diff --git a/lab7/kern/timer.c b/lab7/kern/timer.c new file mode 100644 index 000000000..7f76e5b35 --- /dev/null +++ b/lab7/kern/timer.c @@ -0,0 +1,130 @@ +#include "kern/timer.h" +#include "kern/kio.h" +#include "startup_alloc.h" +#include "string.h" + +struct timer_queue *timer_head; +struct timer_queue *timer_tail; + +unsigned long get_current_time() { + unsigned long cntpct; + unsigned long cntfrq; + asm volatile("mrs %0, cntpct_el0" : "=r"(cntpct)); + asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq)); + return cntpct/cntfrq; +} + +void set_expired(unsigned int seconds) { + unsigned long cntfrq; + asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq)); + asm volatile("msr cntp_tval_el0, %0" : : "r"(cntfrq * seconds)); +} + +void timer_el0_handler() { + kprintf("Seconds after booting: %d\n", get_current_time()); + set_expired(2); + timer_enable_int(); +} + +void timer_el1_handler() { + struct timer_queue *next; + unsigned long timeout; + + timer_head->callback(timer_head->message, timer_head->register_time); + next = timer_head->next; + if (next) { + next->prev = 0; + timer_head = next; + timeout = next->register_time + next->duration - get_current_time(); + set_expired(timeout); + timer_enable_int(); + } else { + timer_head = 0; + timer_tail = 0; + } +} + +void timer_unknown_handler() { + kputs("Timer interrupt: unknown source EL, delay one seconds...\n"); + set_expired(1); + timer_enable_int(); +} + + +void timer_init() { + timer_head = 0; + timer_tail = 0; +} + +void add_timer(void (*callback)(char *, unsigned long), char *message, unsigned int duration) { + struct timer_queue *new_timer = (struct timer_queue *)sumalloc(sizeof(struct timer_queue)); + struct timer_queue *itr; + unsigned long timeout; + int i; + + new_timer->register_time = get_current_time(); + new_timer->duration = duration; + new_timer->callback = callback; + for(i=0 ; message[i]!='\0' ; i++) + new_timer->message[i] = message[i]; + new_timer->message[i] = '\0'; + new_timer->prev = 0; + new_timer->next = 0; + + if (!timer_head) { + timer_head = new_timer; + timer_tail = new_timer; + core_timer_enable(); + set_expired(duration); + } else { + timeout = new_timer->register_time + new_timer->duration; + for(itr=timer_head ; itr ; itr=itr->next) { + if(itr->register_time + itr->duration > timeout) + break; + } + + if (!itr) { // tail + new_timer->prev = timer_tail; + timer_tail->next = new_timer; + timer_tail = new_timer; + } else if (!itr->prev) { // head + new_timer->next = timer_head; + timer_head->prev = new_timer; + timer_head = new_timer; + set_expired(duration); + } else { // middle + new_timer->prev = itr->prev; + new_timer->next = itr; + itr->prev->next = new_timer; + itr->prev = new_timer; + } + } +} + +void timer_callback(char *msg, unsigned long register_time) { + kprintf("\nSeconds after booting: %d\n", get_current_time()); + kprintf("%s, register at: %d\n", msg, register_time); +} + +void set_timeout(char *args) { + int i; + int duration; + int message_end = -1; + + for(i=0 ; args[i]!='\0' ; i++) if (args[i] == ' ') { + message_end = i; + break; + } + if (message_end == -1) { + kputs("setTimeout: MESSAGE SECONDS\n"); + return; + } + args[message_end] = '\0'; + duration = atoi(args+message_end+1, 10, strlen(args+message_end+1)); + if (duration <= 0 || duration >= 35) { + kputs("setTimeout: time error\n"); + return; + } + kprintf("Timeout: %ds\n", duration); + add_timer(timer_callback, args, duration); +} \ No newline at end of file diff --git a/lab7/lib/dtb.c b/lab7/lib/dtb.c new file mode 100644 index 000000000..905348585 --- /dev/null +++ b/lab7/lib/dtb.c @@ -0,0 +1,60 @@ +#include "dtb.h" +#include "string.h" +#include "byteswap.h" +#include "kern/mm.h" + +#define align4(num) ((num + 3) & (-4)) + +char FDT_HEADER_MAGIC[4] = {0xd0, 0x0d, 0xfe, 0xed}; + +void *DTB_ADDRESS = 0; +void *DTB_END_ADR = 0; + +int fdt_init() { + asm volatile("MOV %0, x23" : "=r"(DTB_ADDRESS)); + DTB_ADDRESS = (void*)PHY_2_VIRT(DTB_ADDRESS); + if (strncmp((char*)DTB_ADDRESS, FDT_HEADER_MAGIC, 4)) + return -1; + return 0; +} + +int fdt_traverse(void (*cb)(char *, char *, void *)) { + unsigned int token; + void *ptr; + void *struct_block; + void *string_block; + char *node_name = 0; + char *prop_name = 0; + struct fdt_prop *prop; + struct fdt_header *header = DTB_ADDRESS; + + struct_block = DTB_ADDRESS + __bswap_32(header->off_dt_struct); + string_block = DTB_ADDRESS + __bswap_32(header->off_dt_strings); + + for (ptr=struct_block ; ; ptr+=4) { + token = __bswap_32(*((unsigned int*)ptr)); + if (token == FDT_BEGIN_NODE) { + node_name = ptr + 4; + ptr += align4(strlen(node_name) + 1); + } else if (token == FDT_END_NODE) { + } else if (token == FDT_PROP) { + prop = ptr + 4; + prop_name = string_block + __bswap_32(prop->nameoff); + cb(node_name, prop_name, ptr + 12); + ptr += align4(8 + __bswap_32(prop->len)); + } else if (token == FDT_NOP) { + } else if (token == FDT_END) { + break; + } else { + return -1; + } + } + DTB_END_ADR = ptr; + return 0; +} + +void fdt_reserve() { + if (!DTB_END_ADR) + return; + mm_reserve(DTB_ADDRESS, DTB_END_ADR); +} \ No newline at end of file diff --git a/lab7/lib/mailbox.c b/lab7/lib/mailbox.c new file mode 100644 index 000000000..bb7a13927 --- /dev/null +++ b/lab7/lib/mailbox.c @@ -0,0 +1,89 @@ +#include "peripheral/mailbox.h" +#include "string.h" +#include "kern/mm_types.h" + +unsigned int mailbox_call(unsigned char ch, unsigned int* mailbox) { + unsigned int message; + unsigned int data; + + // Combine the message address (upper 28 bits) with channel number (lower 4 bits) + message = ((unsigned long)VIRT_2_PHY(mailbox) & 0xfffffff0) | (ch & 0xf); + // Check if Mailbox 0 status register’s full flag is set + while((*MAILBOX_STATUS & MAILBOX_FULL)) asm volatile("nop"); + // write to Mailbox 1 Read/Write register + *MAILBOX_WRITE = message; + while(1) { + // Check if Mailbox 0 status register’s empty flag is set + while((*MAILBOX_STATUS & MAILBOX_EMPTY)) asm volatile("nop"); + // read from Mailbox 0 Read/Write register + data = (unsigned int)(*MAILBOX_READ); + // Check if the value is the same as you wrote + if (data == message) { + return mailbox[1] == REQUEST_SUCCEED; + } + } + return 0; +} + +/* +https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface +Get board revision + Tag: 0x00010002 + Request: + Length: 0 + Response: + Length: 4 + Value: + u32: board revision +*/ +void get_board_revision(unsigned int *result){ + unsigned int mailbox[7]; + + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = END_TAG; + + // message passing procedure call + if (mailbox_call(0x8, mailbox)) { + // it should be 0xa020d3 for rpi3 b+ + result[0] = mailbox[5]; + } +} + +/* +Get ARM memory + Tag: 0x00010005 + Request: + Length: 0 + Response: + Length: 8 + Value: + u32: base address in bytes + u32: size in bytes +*/ +void get_ARM_memory(unsigned int *result) { + unsigned int mailbox[8]; + + mailbox[0] = 8 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_ARM_MEMORY; // tag identifier + mailbox[3] = 8; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + mailbox[6] = 0; // value buffer + // tags end + mailbox[7] = END_TAG; + + // message passing procedure call + if (mailbox_call(0x8, mailbox)) { + result[0] = mailbox[5]; + result[1] = mailbox[6]; + } +} \ No newline at end of file diff --git a/lab7/lib/reset.c b/lab7/lib/reset.c new file mode 100644 index 000000000..933c7d00d --- /dev/null +++ b/lab7/lib/reset.c @@ -0,0 +1,16 @@ +#include "reset.h" + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +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 +} + +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} diff --git a/lab7/lib/startup_alloc.c b/lab7/lib/startup_alloc.c new file mode 100644 index 000000000..96e423fa2 --- /dev/null +++ b/lab7/lib/startup_alloc.c @@ -0,0 +1,22 @@ +#include "kern/mm.h" + +extern unsigned int __heap_start; + +void *heap_start = (void *)&__heap_start; +void *heap_cur = (void *)&__heap_start; + +int startup = 1; + +void* sumalloc(unsigned int size) { + void *ret = (void*)0; + if (!startup) + goto out; + ret = heap_cur; + heap_cur += size; +out: + return ret; +} + +void reserved_kern_startup() { + mm_reserve(heap_start, heap_cur + 8192); +} \ No newline at end of file diff --git a/lab7/lib/string.c b/lab7/lib/string.c new file mode 100644 index 000000000..f1b62666c --- /dev/null +++ b/lab7/lib/string.c @@ -0,0 +1,118 @@ + +unsigned int strlen(const char *str) { + const char *c; + for (c=str ; *c ; ++c); + return c - str; +} + +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 int n) { + unsigned char c1 = '\0'; + unsigned char c2 = '\0'; + + // if (n >= 4) { + // unsigned int 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; +} + +void strrev(char* str, unsigned int len) { + int i; + int j; + char a; + for (i = 0, j = len - 1; i < j; i++, j--) { + a = str[i]; + str[i] = str[j]; + str[j] = a; + } +} + +int itoa(long num, char* str, int base) { + long sum = num; + int i = 0; + int digit; + do { + digit = sum % base; + if (digit < 0xA) + str[i++] = '0' + digit; + else + str[i++] = 'A' + digit - 0xA; + sum /= base; + } while(sum); + if (sum) + return -1; + str[i] = '\0'; + strrev(str, i); + return 0; +} + +long atoi(char* str, int base, unsigned int len) { + long num = 0; + int i; + for (i=0 ; i= 'A') + num += str[i] - 'A' + 10; + else + num += str[i] - '0'; + } + return num; +} + +void* memcpy (void* dest, const void* src, unsigned int len) { + char *d = dest; + const char *s = src; + while (len--) + *d++ = *s++; + return dest; +} + +void* memset (void *dest, int val, unsigned int len) { + unsigned char *ptr = dest; + while (len-- > 0) + *ptr++ = val; + return dest; +} + +char *strcpy(char *dest, const char *src) { + return memcpy(dest, src, strlen(src)+1); +} \ No newline at end of file diff --git a/lab7/lib/test_func.c b/lab7/lib/test_func.c new file mode 100644 index 000000000..50ff84d70 --- /dev/null +++ b/lab7/lib/test_func.c @@ -0,0 +1,89 @@ + + +#include "syscall.h" +#include "string.h" +#include "user_lib.h" + +void delay(int times) { + while(times--) { + asm volatile("nop"); + } +} + +void fork_test() { + printf("\nFork Test, pid %d\n", getpid()); + int cnt = 1; + int ret = 0; + if ((ret = fork()) == 0) { // child + long long cur_sp; + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", getpid(), cnt, &cnt, cur_sp); + ++cnt; + + if ((ret = fork()) != 0){ + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", getpid(), cnt, &cnt, cur_sp); + } + else{ + while (cnt < 5) { + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("second child pid: %d, cnt: %d, ptr: %x, sp : %x\n", getpid(), cnt, &cnt, cur_sp); + delay(1000000); + ++cnt; + } + } + exit(); + } + else { + printf("parent here, pid %d, child %d\n", getpid(), ret); + } + exit(); +} + +void fs_test() { + char buf[100]; + mkdir("mnt", 0); + int fd = open("/mnt/a.txt", O_CREAT); + write(fd, "Hi", 2); + close(fd); + chdir("mnt"); + fd = open("./a.txt", 0); + if (fd < 0) { + printf("error1\n"); + return; + } + read(fd, buf, 2); + if (strncmp(buf, "Hi", 2) != 0) { + printf("error2\n"); + return; + } + close(fd); + + chdir(".."); + mount("", "mnt", "tmpfs", 0, 0); + mount("", "mnt", "tmpfs", 0, 0); + fd = open("mnt/a.txt", 0); + if (fd > 0) { + printf("error3\n"); + return; + } +} + +void fs_uart_test() { + int fd = open("/dev/uart", 0); + write(fd, "Hi", 2); + write(fd, "Hi l\n", 5); +} + +void initramfs_test() { + char buf[8]; + int fd = open("/initramfs/dir1/file3.txt", 0); + read(fd, buf, 100); + printf("%s\n", buf); + close(fd); + fd = open("/initramfs/file1", 0); + printf("%d\n", lseek64(fd, 0, SEEK_END)); + read(fd, buf, 100); + printf("%s\n", buf); + close(fd); +} \ No newline at end of file diff --git a/lab7/lib/uart.c b/lab7/lib/uart.c new file mode 100644 index 000000000..027601d12 --- /dev/null +++ b/lab7/lib/uart.c @@ -0,0 +1,184 @@ +#include "peripheral/aux.h" +#include "peripheral/gpio.h" +#include "peripheral/uart.h" +#include "peripheral/interrupt.h" +#include "string.h" + +#define MAX_BUFFER_SIZE 4096 + +// If this bit is set the interrupt line is asserted whenever the transmit FIFO is empty. +#define ENABLE_TX_INT (*AUX_MU_IER |= 2) +#define DISABLE_TX_INT (*AUX_MU_IER &= ~(2)) + +char read_buffer[MAX_BUFFER_SIZE]; +char write_buffer[MAX_BUFFER_SIZE]; + +int read_start, + read_end; +int write_start, + write_end; + +void uart_init() { + + // Mini UART initialization + *AUX_ENABLES |= 1; // Enable mini UART + *AUX_MU_CNTL = 0; // Disable transmitter and receiver during configuration + *AUX_MU_IER = 0; // Disable interrupt + *AUX_MU_LCR = 3; // Set the data size to 8 bit + *AUX_MU_MCR = 0; // Don’t need auto flow control + *AUX_MU_BAUD = 270; // Set baud rate to 115200 + *AUX_MU_IIR = 6; // No FIFO + + // configure GPIO pin + // 1. configure GPFSELn register to change alternate function + // spec p.92 p.102 + register unsigned int r = *GPFSEL1; + r &= ~((7 << 12) | (7 << 15)); // Reset GPIO 14, 15 ex: RRP19P18P17P16P15P14P13P12P11P10 + // 000000 + r |= (2 << 12) | (2 << 15); // Set to ALT5 (010 = GPIO Pin xx takes alternate function 5) + *GPFSEL1 = r; + + // 2. configure pull up/down register to disable GPIO pull up/down + // spec p.101 + *GPPUD = 0; // Write to GPPUD to set the required control signal + r = 150; // Wait 150 cycles + while(r--) asm volatile("nop"); + *GPPUDCLK0 = (1<<14) | (1<<15); // Write to GPPUDCLK0/1 to clock the control signal into the GPIO pads you wish to modify + r = 150; // Wait 150 cycles + while(r--) asm volatile("nop"); + *GPPUDCLK0 = 0; // Write to GPPUDCLK0/1 to remove the clock + + *AUX_MU_CNTL = 3; // Enable the transmitter and receiver + + read_start = read_end = 0; + write_start = write_end = 0; + + // spec p.12, enable rx interrupt + *AUX_MU_IER |= 1; + + memset(read_buffer, 0, MAX_BUFFER_SIZE); + memset(write_buffer, 0, MAX_BUFFER_SIZE); + uart_sync_puts("UART initialized successfully!\n"); +} + +inline void uart_enable_int() { + ENABLE_IRQS_1_AUX; +} + +inline void uart_disable_int() { + DISABLE_IRQS_1_AUX; +} + + +void uart_int_handler() { + char r; + int tx = *AUX_MU_IIR & 0b10; + int rx = *AUX_MU_IIR & 0b100; + if (rx) { + while(*AUX_MU_LSR & 0x01) { + r = (char)(*AUX_MU_IO); + read_buffer[read_end] = r; + read_end = (read_end + 1) % MAX_BUFFER_SIZE; + } + } + if (tx) { + while(*AUX_MU_LSR & 0x20) { + if (write_start == write_end) { + DISABLE_TX_INT; + break; + } + *AUX_MU_IO = write_buffer[write_start]; + write_start = (write_start + 1) % MAX_BUFFER_SIZE; + // To ensure finished shifting out the last bit. + while(!(*AUX_MU_LSR & 0b1000000)) { + asm volatile("nop"); + } + } + } + uart_enable_int(); +} + +void uart_flush() { + while(*AUX_MU_LSR & 0x01) + *AUX_MU_IO; +} + +/* sync */ + +char uart_sync_read() { + char r; + // Check AUX_MU_LSR_REG’s data ready field (Bit 0) + do { + asm volatile("nop"); + } while(!(*AUX_MU_LSR & 0x01)); + r = (char)(*AUX_MU_IO); + return r == '\r' ? '\n' : r; +} + +char uart_sync_read_raw() { + do { + asm volatile("nop"); + } while(!(*AUX_MU_LSR & 0x01)); + return (char)(*AUX_MU_IO); +} + +void uart_sync_write(unsigned int c) { + // Check AUX_MU_LSR_REG’s Transmitter empty field (Bit 5) + do { + asm volatile("nop"); + } while(!(*AUX_MU_LSR & 0x20)); + *AUX_MU_IO = c; +} + +void uart_sync_puts(char *s) { + while(*s) { + if (*s == '\n') + uart_sync_write('\r'); + uart_sync_write(*s++); + } +} + +void uart_sync_printNum(long num, int base) { + char buffer[64]; + if (itoa(num, buffer, base) == -1) + uart_sync_puts("@"); + else + uart_sync_puts(buffer); +} + +/* async */ + +char uart_async_read() { + char r; + while (read_start == read_end) { + asm volatile("nop"); + } + r = read_buffer[read_start]; + read_start = (read_start + 1) % MAX_BUFFER_SIZE; + return r == '\r' ? '\n' : r; +} + +void uart_async_write(unsigned int c) { + write_buffer[write_end] = c; + write_end = (write_end + 1) % MAX_BUFFER_SIZE; + ENABLE_TX_INT; +} + +void uart_async_write_buffer(unsigned int c) { + write_buffer[write_end] = c; + write_end = (write_end + 1) % MAX_BUFFER_SIZE; +} + +void uart_async_puts(char *s) { + while(*s) { + if (*s == '\n') + uart_async_write_buffer('\r'); + uart_async_write_buffer(*s++); + } + ENABLE_TX_INT; +} + +void uart_write_flush() { + if (write_start != write_end) + ENABLE_TX_INT; +} \ No newline at end of file diff --git a/lab7/lib/user_lib.c b/lab7/lib/user_lib.c new file mode 100644 index 000000000..2b8e0d955 --- /dev/null +++ b/lab7/lib/user_lib.c @@ -0,0 +1,65 @@ +#include "string.h" +#include "syscall.h" +#include "kern/slab.h" + +void printf(char *fmt, ...) { + char s[128]; + char buffer[64]; + char *dst = s; + char *p; + + __builtin_va_list args; + __builtin_va_start(args, fmt); + + while (*fmt) { + if (*fmt == '%') { + fmt++; + // escape + if (*fmt == '%') { + goto put; + } + // string + else if (*fmt == 's') { + p = __builtin_va_arg(args, char *); + while (*p) + *dst++ = *p++; + } + // char + else if (*fmt == 'c') { + char c = __builtin_va_arg(args, int); + *dst++ = c; + } + // decimal + else if (*fmt == 'd') { + int arg = __builtin_va_arg(args, int); + if (itoa(arg, buffer, 10) != -1) { + p = buffer; + while(*p) + *dst++ = *p++; + } else { + *dst++ = '@'; + } + + } + // hex + else if (*fmt == 'x') { + long arg = __builtin_va_arg(args, long); + if (itoa(arg, buffer, 16) != -1) { + p = buffer; + while(*p) + *dst++ = *p++; + } else { + *dst++ = '@'; + } + } + } + else { + put: + *dst++ = *fmt; + } + *fmt++; + } + *dst = '\0'; + __builtin_va_end(args); + uart_write(s, dst-s); +} \ No newline at end of file diff --git a/lab7/raspi3/bcm2710-rpi-3-b-plus.dtb b/lab7/raspi3/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/lab7/raspi3/config.txt b/lab7/raspi3/config.txt new file mode 100644 index 000000000..e82fa85fa --- /dev/null +++ b/lab7/raspi3/config.txt @@ -0,0 +1,3 @@ +kernel=bootloader.img +arm_64bit=1 +initramfs initramfs.cpio 0x8000000 \ No newline at end of file diff --git a/lab7/rootfs/Makefile b/lab7/rootfs/Makefile new file mode 100644 index 000000000..d864058e8 --- /dev/null +++ b/lab7/rootfs/Makefile @@ -0,0 +1,20 @@ +# OSC 2022 +CC = aarch64-linux-gnu-gcc +LD = aarch64-linux-gnu-ld +OBJCOPY = aarch64-linux-gnu-objcopy + +LINKER_FILE = linker.ld + +# -fno-stack-protector: to disable stack protection +# -fno-builtin is required to avoid refs to undefined functions in the kernel. +# Only optimize to -O1 to discourage inlining, which complicates backtraces. +CFLAGS := -O1 -fno-builtin -nostdinc +CFLAGS += -Wall -c -fno-stack-protector + +user_prog: user_prog.S $(LINKER_FILE) + $(CC) $(CFLAGS) $< -o $@.o + $(LD) -T $(LINKER_FILE) -o $@ $@.o + $(OBJCOPY) $@ -O binary $@ + +archv: + find . | cpio -o -H newc > ../initramfs.cpio \ No newline at end of file diff --git a/lab7/rootfs/dir1/file3.txt b/lab7/rootfs/dir1/file3.txt new file mode 100644 index 000000000..873fb8d66 --- /dev/null +++ b/lab7/rootfs/dir1/file3.txt @@ -0,0 +1 @@ +file3 \ No newline at end of file diff --git a/lab7/rootfs/dir1/file5.txt b/lab7/rootfs/dir1/file5.txt new file mode 100644 index 000000000..d92b9c318 --- /dev/null +++ b/lab7/rootfs/dir1/file5.txt @@ -0,0 +1 @@ +file5 \ No newline at end of file diff --git a/lab7/rootfs/file1 b/lab7/rootfs/file1 new file mode 100644 index 000000000..d88c464a9 --- /dev/null +++ b/lab7/rootfs/file1 @@ -0,0 +1 @@ +This is file1 \ No newline at end of file diff --git a/lab7/rootfs/file2.txt b/lab7/rootfs/file2.txt new file mode 100644 index 000000000..d9a0c4d55 --- /dev/null +++ b/lab7/rootfs/file2.txt @@ -0,0 +1 @@ +This is file2 \ No newline at end of file diff --git a/lab7/rootfs/linker.ld b/lab7/rootfs/linker.ld new file mode 100644 index 000000000..05132105e --- /dev/null +++ b/lab7/rootfs/linker.ld @@ -0,0 +1,31 @@ +SECTIONS +{ + . = 0x0; + .text : { + *(.text .text.* .gnu.linkonce.t.*) + } + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + . = ALIGN(0x1000); + + /* The data segment */ + .data : { + *(.data) + } + + .bss ALIGN(16) (NOLOAD) : { + PROVIDE(__bss_start = .); + *(.bss) + PROVIDE(__bss_end = .); + BYTE(0) + } + + . = ALIGN(0x1000); + + /DISCARD/ : { + *(.eh_frame .note.GNU-stack) + } +} \ No newline at end of file diff --git a/lab7/rootfs/user_prog.S b/lab7/rootfs/user_prog.S new file mode 100644 index 000000000..ad2655ba4 --- /dev/null +++ b/lab7/rootfs/user_prog.S @@ -0,0 +1,14 @@ +.section ".text" + +.global _start +_start: + mov x0, 0 + svc 1 +1: + add x0, x0, 1 + svc 0 + cmp x0, 5 + blt 1b + svc 4 +1: + b 1b \ No newline at end of file From d66fbec465dfd3b257cdfaa087309f22c1f90ed2 Mon Sep 17 00:00:00 2001 From: eugenechouy Date: Thu, 16 Jun 2022 17:04:55 +0800 Subject: [PATCH 2/2] lab8 --- lab8/Makefile | 64 ++++ lab8/boot/Makefile | 54 ++++ lab8/boot/boot.S | 30 ++ lab8/boot/linker.ld | 43 +++ lab8/boot/main.c | 42 +++ lab8/boot/relocate.c | 17 + lab8/documentation/fat32.md | 77 +++++ lab8/documentation/mm.md | 29 ++ lab8/documentation/sched.md | 5 + lab8/drivers/sdhost.c | 243 ++++++++++++++ lab8/fs/fat32.c | 453 +++++++++++++++++++++++++++ lab8/fs/tmpfs.c | 281 +++++++++++++++++ lab8/fs/uartfs.c | 49 +++ lab8/fs/vfs.c | 263 ++++++++++++++++ lab8/include/bitmap.h | 66 ++++ lab8/include/byteswap.h | 9 + lab8/include/drivers/mbr.h | 46 +++ lab8/include/drivers/sdhost.h | 10 + lab8/include/dtb.h | 40 +++ lab8/include/fs/fat32.h | 137 ++++++++ lab8/include/fs/tmpfs.h | 15 + lab8/include/fs/uartfs.h | 6 + lab8/include/fs/vfs.h | 104 ++++++ lab8/include/kern/cpio.h | 37 +++ lab8/include/kern/fdtable.h | 19 ++ lab8/include/kern/irq.h | 16 + lab8/include/kern/kio.h | 32 ++ lab8/include/kern/mm.h | 17 + lab8/include/kern/mm_types.h | 50 +++ lab8/include/kern/page.h | 36 +++ lab8/include/kern/pagecache.h | 12 + lab8/include/kern/sched.h | 100 ++++++ lab8/include/kern/shell.h | 22 ++ lab8/include/kern/signal.h | 31 ++ lab8/include/kern/slab.h | 37 +++ lab8/include/kern/softirq.h | 18 ++ lab8/include/kern/sync.h | 20 ++ lab8/include/kern/timer.h | 25 ++ lab8/include/list.h | 134 ++++++++ lab8/include/mmu.h | 46 +++ lab8/include/peripheral/arm.h | 13 + lab8/include/peripheral/aux.h | 36 +++ lab8/include/peripheral/gpio.h | 51 +++ lab8/include/peripheral/interrupt.h | 19 ++ lab8/include/peripheral/mailbox.h | 53 ++++ lab8/include/peripheral/mmio.h | 12 + lab8/include/peripheral/uart.h | 27 ++ lab8/include/reset.h | 12 + lab8/include/startup_alloc.h | 8 + lab8/include/string.h | 15 + lab8/include/syscall.h | 54 ++++ lab8/include/test_func.h | 10 + lab8/include/user_lib.h | 6 + lab8/kern/cpio.c | 113 +++++++ lab8/kern/entry.S | 135 ++++++++ lab8/kern/exception_vector_table.S | 136 ++++++++ lab8/kern/fdtable.c | 35 +++ lab8/kern/irq.c | 78 +++++ lab8/kern/kio.c | 65 ++++ lab8/kern/linker.ld | 44 +++ lab8/kern/main.c | 142 +++++++++ lab8/kern/mm.c | 242 ++++++++++++++ lab8/kern/page.c | 158 ++++++++++ lab8/kern/pagecache.c | 69 ++++ lab8/kern/sched.S | 41 +++ lab8/kern/sched.c | 344 ++++++++++++++++++++ lab8/kern/shell.c | 75 +++++ lab8/kern/signal.c | 113 +++++++ lab8/kern/slab.c | 177 +++++++++++ lab8/kern/softirq.c | 45 +++ lab8/kern/sync.c | 353 +++++++++++++++++++++ lab8/kern/syscall.S | 113 +++++++ lab8/kern/timer.S | 44 +++ lab8/kern/timer.c | 130 ++++++++ lab8/lib/dtb.c | 60 ++++ lab8/lib/mailbox.c | 89 ++++++ lab8/lib/reset.c | 16 + lab8/lib/startup_alloc.c | 22 ++ lab8/lib/string.c | 118 +++++++ lab8/lib/test_func.c | 102 ++++++ lab8/lib/uart.c | 184 +++++++++++ lab8/lib/user_lib.c | 65 ++++ lab8/raspi3/bcm2710-rpi-3-b-plus.dtb | Bin 0 -> 31790 bytes lab8/raspi3/config.txt | 3 + lab8/rootfs/Makefile | 20 ++ lab8/rootfs/dir1/file3.txt | 1 + lab8/rootfs/dir1/file5.txt | 1 + lab8/rootfs/file1 | 1 + lab8/rootfs/file2.txt | 1 + lab8/rootfs/linker.ld | 31 ++ lab8/rootfs/user_prog.S | 14 + 91 files changed, 6431 insertions(+) create mode 100644 lab8/Makefile create mode 100644 lab8/boot/Makefile create mode 100644 lab8/boot/boot.S create mode 100644 lab8/boot/linker.ld create mode 100644 lab8/boot/main.c create mode 100644 lab8/boot/relocate.c create mode 100644 lab8/documentation/fat32.md create mode 100644 lab8/documentation/mm.md create mode 100644 lab8/documentation/sched.md create mode 100644 lab8/drivers/sdhost.c create mode 100644 lab8/fs/fat32.c create mode 100644 lab8/fs/tmpfs.c create mode 100644 lab8/fs/uartfs.c create mode 100644 lab8/fs/vfs.c create mode 100644 lab8/include/bitmap.h create mode 100644 lab8/include/byteswap.h create mode 100644 lab8/include/drivers/mbr.h create mode 100644 lab8/include/drivers/sdhost.h create mode 100644 lab8/include/dtb.h create mode 100644 lab8/include/fs/fat32.h create mode 100644 lab8/include/fs/tmpfs.h create mode 100644 lab8/include/fs/uartfs.h create mode 100644 lab8/include/fs/vfs.h create mode 100644 lab8/include/kern/cpio.h create mode 100644 lab8/include/kern/fdtable.h create mode 100644 lab8/include/kern/irq.h create mode 100644 lab8/include/kern/kio.h create mode 100644 lab8/include/kern/mm.h create mode 100644 lab8/include/kern/mm_types.h create mode 100644 lab8/include/kern/page.h create mode 100644 lab8/include/kern/pagecache.h create mode 100644 lab8/include/kern/sched.h create mode 100644 lab8/include/kern/shell.h create mode 100644 lab8/include/kern/signal.h create mode 100644 lab8/include/kern/slab.h create mode 100644 lab8/include/kern/softirq.h create mode 100644 lab8/include/kern/sync.h create mode 100644 lab8/include/kern/timer.h create mode 100644 lab8/include/list.h create mode 100644 lab8/include/mmu.h create mode 100644 lab8/include/peripheral/arm.h create mode 100644 lab8/include/peripheral/aux.h create mode 100644 lab8/include/peripheral/gpio.h create mode 100644 lab8/include/peripheral/interrupt.h create mode 100644 lab8/include/peripheral/mailbox.h create mode 100644 lab8/include/peripheral/mmio.h create mode 100644 lab8/include/peripheral/uart.h create mode 100644 lab8/include/reset.h create mode 100644 lab8/include/startup_alloc.h create mode 100644 lab8/include/string.h create mode 100644 lab8/include/syscall.h create mode 100644 lab8/include/test_func.h create mode 100644 lab8/include/user_lib.h create mode 100644 lab8/kern/cpio.c create mode 100644 lab8/kern/entry.S create mode 100644 lab8/kern/exception_vector_table.S create mode 100644 lab8/kern/fdtable.c create mode 100644 lab8/kern/irq.c create mode 100644 lab8/kern/kio.c create mode 100644 lab8/kern/linker.ld create mode 100644 lab8/kern/main.c create mode 100644 lab8/kern/mm.c create mode 100644 lab8/kern/page.c create mode 100644 lab8/kern/pagecache.c create mode 100644 lab8/kern/sched.S create mode 100644 lab8/kern/sched.c create mode 100644 lab8/kern/shell.c create mode 100644 lab8/kern/signal.c create mode 100644 lab8/kern/slab.c create mode 100644 lab8/kern/softirq.c create mode 100644 lab8/kern/sync.c create mode 100644 lab8/kern/syscall.S create mode 100644 lab8/kern/timer.S create mode 100644 lab8/kern/timer.c create mode 100644 lab8/lib/dtb.c create mode 100644 lab8/lib/mailbox.c create mode 100644 lab8/lib/reset.c create mode 100644 lab8/lib/startup_alloc.c create mode 100644 lab8/lib/string.c create mode 100644 lab8/lib/test_func.c create mode 100644 lab8/lib/uart.c create mode 100644 lab8/lib/user_lib.c create mode 100644 lab8/raspi3/bcm2710-rpi-3-b-plus.dtb create mode 100644 lab8/raspi3/config.txt create mode 100644 lab8/rootfs/Makefile create mode 100644 lab8/rootfs/dir1/file3.txt create mode 100644 lab8/rootfs/dir1/file5.txt create mode 100644 lab8/rootfs/file1 create mode 100644 lab8/rootfs/file2.txt create mode 100644 lab8/rootfs/linker.ld create mode 100644 lab8/rootfs/user_prog.S diff --git a/lab8/Makefile b/lab8/Makefile new file mode 100644 index 000000000..15a72444d --- /dev/null +++ b/lab8/Makefile @@ -0,0 +1,64 @@ +# OSC 2022 +CC = aarch64-linux-gnu-gcc +LD = aarch64-linux-gnu-ld +OBJCOPY = aarch64-linux-gnu-objcopy + + +IMG = kernel8.img +ELF = kernel8.elf +LINKER_FILE = kern/linker.ld + +OUT_DIR = out +INC_DIR = include + +SRCS := $(wildcard kern/*.S) +SRCS += $(wildcard kern/*.c) +SRCS += $(wildcard lib/*.c) +SRCS += $(wildcard fs/*.c) +SRCS += $(wildcard drivers/*.c) +SRCS := $(notdir $(SRCS)) +OBJS := $(patsubst %.c, $(OUT_DIR)/%_c.o, $(SRCS)) +OBJS := $(patsubst %.S, $(OUT_DIR)/%_s.o, $(OBJS)) + +# -fno-stack-protector: to disable stack protection +# -fno-builtin is required to avoid refs to undefined functions in the kernel. +# Only optimize to -O1 to discourage inlining, which complicates backtraces. +CFLAGS := -O1 -fno-builtin -nostdinc +CFLAGS += -Wall -I$(INC_DIR) -c -fno-stack-protector + +.PHONY: asm debug clean run + + +$(IMG): $(ELF) + $(OBJCOPY) -O binary $(ELF) $(IMG) +$(ELF): $(OBJS) $(LINKER_FILE) + $(LD) -T $(LINKER_FILE) -o $(ELF) $(OBJS) + +$(OUT_DIR)/%_s.o: kern/%.S $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ +$(OUT_DIR)/%_c.o: kern/%.c $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ +$(OUT_DIR)/%_c.o: fs/%.c $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ +$(OUT_DIR)/%_c.o: drivers/%.c $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ +$(OUT_DIR)/%_c.o: lib/%.c $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ + + +$(OUT_DIR): + @mkdir -p $(OUT_DIR) + + +asm: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -d in_asm +debug: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -serial null -serial stdio -initrd initramfs.cpio -S -s +run: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -serial null -serial stdio -initrd initramfs.cpio +run-sd: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -serial null -serial stdio -initrd initramfs.cpio -drive if=sd,file=sfn_nctuos.img,format=raw +run-display: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -serial null -serial stdio -initrd initramfs.cpio +clean: + rm -rf $(OUT_DIR) $(ELF) $(IMG) \ No newline at end of file diff --git a/lab8/boot/Makefile b/lab8/boot/Makefile new file mode 100644 index 000000000..888903976 --- /dev/null +++ b/lab8/boot/Makefile @@ -0,0 +1,54 @@ +# bootloader +CC = aarch64-linux-gnu-gcc +LD = aarch64-linux-gnu-ld +OBJCOPY = aarch64-linux-gnu-objcopy + + +IMG = bootloader.img +ELF = bootloader.elf + +OUT_DIR = out +INC_DIR = ../include + +SRCS := boot.S \ + relocate.c \ + main.c \ + ../lib/uart.c \ + ../lib/string.c +SRCS := $(notdir $(SRCS)) +OBJS := $(patsubst %.c, $(OUT_DIR)/%.o, $(SRCS)) +OBJS := $(patsubst %.S, $(OUT_DIR)/%.o, $(OBJS)) + +# -fno-stack-protector: to disable stack protection +CFLAGS := -O1 -fno-builtin -nostdinc -DBOOT_LOADER +CFLAGS += -Wall -I$(INC_DIR) -c -fno-stack-protector + +.PHONY: asm debug clean run pty + + +$(IMG): $(ELF) + $(OBJCOPY) -O binary $(ELF) $(IMG) +$(ELF): $(OBJS) linker.ld $(OUT_DIR)/boot.o + $(LD) -T linker.ld -o $(ELF) $(OBJS) + +$(OUT_DIR)/boot.o: boot.S $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ +$(OUT_DIR)/%.o: %.c $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ +$(OUT_DIR)/%.o: ../lib/%.c $(OUT_DIR) + $(CC) $(CFLAGS) $< -o $@ + +$(OUT_DIR): + @mkdir -p $(OUT_DIR) + + +asm: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -d in_asm +debug: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -S -s +run: $(IMG) + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -serial null -serial stdio +pty: + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -display none -serial null -serial pty -initrd ../initramfs.cpio -dtb ../raspi3/bcm2710-rpi-3-b-plus.dtb +clean: + rm -rf $(OUT_DIR) $(ELF) $(IMG) \ No newline at end of file diff --git a/lab8/boot/boot.S b/lab8/boot/boot.S new file mode 100644 index 000000000..e26a31ce3 --- /dev/null +++ b/lab8/boot/boot.S @@ -0,0 +1,30 @@ +.section ".text.relocate" + +.global _relocate +_relocate: + // save dtb address + mov x23, x0 +2: + ldr x0, = __stack_top + mov sp, x0 + + // clear bss + ldr x0, =__bss_start + ldr x1, =__bss_size +3: cbz x1, 4f + // [x0] = 0, x0 = x0 + 8 + str xzr, [x0], #8 + // x1 = x1 - 1 + sub x1, x1, #1 + cbnz x1, 3b +4: bl relocate + + + +.section ".text.boot" + +.global _start +_start: + bl main +1: wfe + b 1b diff --git a/lab8/boot/linker.ld b/lab8/boot/linker.ld new file mode 100644 index 000000000..723384a45 --- /dev/null +++ b/lab8/boot/linker.ld @@ -0,0 +1,43 @@ +SECTIONS +{ + . = 0x80000; + .relocate : { + KEEP(*(.text.relocate)) + } + + /* Adjust the address for the data segment to the next page */ + . = ALIGN(0x1000); + + __begin = .; + .text : { + KEEP(*(.text.boot)) + *(.text .text.* .gnu.linkonce.t.*) + } + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + . = ALIGN(0x1000); + + /* The data segment */ + .data : { + *(.data) + } + + .bss ALIGN(16) (NOLOAD) : { + PROVIDE(__bss_start = .); + *(.bss) + PROVIDE(__bss_end = .); + BYTE(0) + } + __end = .; + + /DISCARD/ : { + *(.eh_frame .note.GNU-stack) + } +} + +__stack_top = 0x20000000; +__bss_size = (__bss_end - __bss_start) >> 3; +__bootloader = 0x60000; \ No newline at end of file diff --git a/lab8/boot/main.c b/lab8/boot/main.c new file mode 100644 index 000000000..139ba2ec1 --- /dev/null +++ b/lab8/boot/main.c @@ -0,0 +1,42 @@ +#include "peripheral/uart.h" + +#define KERNEL_ADDR 0x80000 +#define READ_INT(var) \ + var = 0; \ + for (i=0 ; i<4 ; i++) {\ + var <<= 8; \ + var |= (int)uart_sync_read_raw(); \ + } \ + +int main() { + int img_size; + int img_checksum; + int i; + + uart_init(); + uart_flush(); + + READ_INT(img_size); + READ_INT(img_checksum); + + uart_sync_printNum(img_size, 10); + uart_sync_puts("\n"); + uart_sync_printNum(img_checksum, 10); + uart_sync_puts("\n"); + + for (i=0 ; i= FAT_ENTRY_RESERVED_TO_END`, the cluster is used, which also be the last cluster in the file. +* `FAT[cluster] == FAT_ENTRY_DEFECTIVE_CLUSTER`, indicate defective cluster. +* Otherwise, the cluster is used, it contains the next cluster number in the file. + +> When writing the FAT entry for the last cluster in a file, use the value 0x0fffffff + +### Data Region + +* The first file in the data region is the root directory + +#### Directory + +The first byte in a directory entry determines if the entry is either: +1. unused (DIR_ENTRY_UNUSED) +2. unused and marks the end of the directory (DIR_ENTRY_LAST_AND_UNUSED) +3. used + +If the entry is used, then the attribute byte is examined to determine if the entry is for a short filename or for a long filename. + +Short Filename +* The first short filename character may not be a space (0x20) +* No lowercase characters may be in the short filename +* Terminate and fill both the main filename part and the extension name field with spaces(0x20) + +Long Filename +* **Each long filename has an associated short filename entry** and that short filename entry must be the last entry for that group (continus directory entries) + +To create a new entry in directory +1. Read through the directory to ensure name conflict doesn't exist. +2. Find either an unused directory entry or extend the directory. + * To extend the directory: use the last entry and tag the next entry as FAT32_DIR_ENTRY_LAST_AND_UNUSED + * If there is no more space in this cluster, then we need to find a free cluster, and update FAT + +#### File + +Files are allocated in units of clusters, which may be unused bytes(sectors) at the end of the last sector(cluster). + +To extend a file +* DIR_FileSize must be update +* If the current cluster is full, an additional cluster needs to be allocated ... diff --git a/lab8/documentation/mm.md b/lab8/documentation/mm.md new file mode 100644 index 000000000..120879173 --- /dev/null +++ b/lab8/documentation/mm.md @@ -0,0 +1,29 @@ + +## memory layout + +``` ++------------------+ +| Arm Peripherals | ++------------------+ <- 0x40000000 +| GPU Peripherals | ++------------------+ <- 0x3f000000 +| reserved | ++------------------+ <- 0x3C000000 +| . | +| User stack | +| . | ++------------------+ +| Kernel frame[n] | <- statically declared ++------------------+ +| . | +| . | ++------------------+ +| Kernel frame[0] | ++------------------+ +| Int stack | <- statically declared ++------------------+ +| kernel/user data | ++------------------+ +| kernel/user text | ++------------------+ <- kernel_base +``` \ No newline at end of file diff --git a/lab8/documentation/sched.md b/lab8/documentation/sched.md new file mode 100644 index 000000000..814def8ff --- /dev/null +++ b/lab8/documentation/sched.md @@ -0,0 +1,5 @@ + +## priority + +* privilege task: 1 ~ 20 +* user task: 21 ~ 127 \ No newline at end of file diff --git a/lab8/drivers/sdhost.c b/lab8/drivers/sdhost.c new file mode 100644 index 000000000..9ee3b6ebe --- /dev/null +++ b/lab8/drivers/sdhost.c @@ -0,0 +1,243 @@ +// mmio +#define KVA 0xffff000000000000 +#define MMIO_BASE (KVA + 0x3f000000) + +// SD card command +#define GO_IDLE_STATE 0 +#define SEND_OP_CMD 1 +#define ALL_SEND_CID 2 +#define SEND_RELATIVE_ADDR 3 +#define SELECT_CARD 7 +#define SEND_IF_COND 8 + #define VOLTAGE_CHECK_PATTERN 0x1aa +#define STOP_TRANSMISSION 12 +#define SET_BLOCKLEN 16 +#define READ_SINGLE_BLOCK 17 +#define WRITE_SINGLE_BLOCK 24 +#define SD_APP_OP_COND 41 + #define SDCARD_3_3V (1 << 21) + #define SDCARD_ISHCS (1 << 30) + #define SDCARD_READY (1 << 31) +#define APP_CMD 55 + +// gpio +#define GPIO_BASE (MMIO_BASE + 0x200000) +#define GPIO_GPFSEL4 (GPIO_BASE + 0x10) +#define GPIO_GPFSEL5 (GPIO_BASE + 0x14) +#define GPIO_GPPUD (GPIO_BASE + 0x94) +#define GPIO_GPPUDCLK1 (GPIO_BASE + 0x9c) + +// sdhost +#define SDHOST_BASE (MMIO_BASE + 0x202000) +#define SDHOST_CMD (SDHOST_BASE + 0) + #define SDHOST_READ 0x40 + #define SDHOST_WRITE 0x80 + #define SDHOST_LONG_RESPONSE 0x200 + #define SDHOST_NO_REPONSE 0x400 + #define SDHOST_BUSY 0x800 + #define SDHOST_NEW_CMD 0x8000 +#define SDHOST_ARG (SDHOST_BASE + 0x4) +#define SDHOST_TOUT (SDHOST_BASE + 0x8) + #define SDHOST_TOUT_DEFAULT 0xf00000 +#define SDHOST_CDIV (SDHOST_BASE + 0xc) + #define SDHOST_CDIV_MAXDIV 0x7ff + #define SDHOST_CDIV_DEFAULT 0x148 +#define SDHOST_RESP0 (SDHOST_BASE + 0x10) +#define SDHOST_RESP1 (SDHOST_BASE + 0x14) +#define SDHOST_RESP2 (SDHOST_BASE + 0x18) +#define SDHOST_RESP3 (SDHOST_BASE + 0x1c) +#define SDHOST_HSTS (SDHOST_BASE + 0x20) + #define SDHOST_HSTS_MASK (0x7f8) + #define SDHOST_HSTS_ERR_MASK (0xf8) + #define SDHOST_HSTS_DATA (1 << 0) +#define SDHOST_PWR (SDHOST_BASE + 0x30) +#define SDHOST_DBG (SDHOST_BASE + 0x34) + #define SDHOST_DBG_FSM_DATA 1 + #define SDHOST_DBG_FSM_MASK 0xf + #define SDHOST_DBG_MASK (0x1f << 14 | 0x1f << 9) + #define SDHOST_DBG_FIFO (0x4 << 14 | 0x4 << 9) +#define SDHOST_CFG (SDHOST_BASE + 0x38) + #define SDHOST_CFG_DATA_EN (1 << 4) + #define SDHOST_CFG_SLOW (1 << 3) + #define SDHOST_CFG_INTBUS (1 << 1) +#define SDHOST_SIZE (SDHOST_BASE + 0x3c) +#define SDHOST_DATA (SDHOST_BASE + 0x40) +#define SDHOST_CNT (SDHOST_BASE + 0x50) + +// helper +#define set(io_addr, val) \ + asm volatile("str %w1, [%0]" ::"r"(io_addr), "r"(val) : "memory"); + +#define get(io_addr, val) \ + asm volatile("ldr %w0, [%1]" : "=r"(val) : "r"(io_addr) : "memory"); + +static inline void delay(unsigned long tick) { + while (tick--) { + asm volatile("nop"); + } +} + +static int is_hcs; // high capcacity(SDHC) + +static void pin_setup() { + set(GPIO_GPFSEL4, 0x24000000); + set(GPIO_GPFSEL5, 0x924); + set(GPIO_GPPUD, 0); + delay(15000); + set(GPIO_GPPUDCLK1, 0xffffffff); + delay(15000); + set(GPIO_GPPUDCLK1, 0); +} + +static void sdhost_setup() { + unsigned int tmp; + set(SDHOST_PWR, 0); + set(SDHOST_CMD, 0); + set(SDHOST_ARG, 0); + set(SDHOST_TOUT, SDHOST_TOUT_DEFAULT); + set(SDHOST_CDIV, 0); + set(SDHOST_HSTS, SDHOST_HSTS_MASK); + set(SDHOST_CFG, 0); + set(SDHOST_CNT, 0); + set(SDHOST_SIZE, 0); + get(SDHOST_DBG, tmp); + tmp &= ~SDHOST_DBG_MASK; + tmp |= SDHOST_DBG_FIFO; + set(SDHOST_DBG, tmp); + delay(250000); + set(SDHOST_PWR, 1); + delay(250000); + set(SDHOST_CFG, SDHOST_CFG_SLOW | SDHOST_CFG_INTBUS | SDHOST_CFG_DATA_EN); + set(SDHOST_CDIV, SDHOST_CDIV_DEFAULT); +} + +static int wait_sd() { + int cnt = 1000000; + unsigned int cmd; + do { + if (cnt == 0) { + return -1; + } + get(SDHOST_CMD, cmd); + --cnt; + } while (cmd & SDHOST_NEW_CMD); + return 0; +} + +static int sd_cmd(unsigned cmd, unsigned int arg) { + set(SDHOST_ARG, arg); + set(SDHOST_CMD, cmd | SDHOST_NEW_CMD); + return wait_sd(); +} + +static int sdcard_setup() { + unsigned int tmp; + sd_cmd(GO_IDLE_STATE | SDHOST_NO_REPONSE, 0); + sd_cmd(SEND_IF_COND, VOLTAGE_CHECK_PATTERN); + get(SDHOST_RESP0, tmp); + if (tmp != VOLTAGE_CHECK_PATTERN) { + return -1; + } + while (1) { + if (sd_cmd(APP_CMD, 0) == -1) { + // MMC card or invalid card status + // currently not support + continue; + } + sd_cmd(SD_APP_OP_COND, SDCARD_3_3V | SDCARD_ISHCS); + get(SDHOST_RESP0, tmp); + if (tmp & SDCARD_READY) { + break; + } + delay(1000000); + } + + is_hcs = tmp & SDCARD_ISHCS; + sd_cmd(ALL_SEND_CID | SDHOST_LONG_RESPONSE, 0); + sd_cmd(SEND_RELATIVE_ADDR, 0); + get(SDHOST_RESP0, tmp); + sd_cmd(SELECT_CARD, tmp); + sd_cmd(SET_BLOCKLEN, 512); + return 0; +} + +static int wait_fifo() { + int cnt = 1000000; + unsigned int hsts; + do { + if (cnt == 0) { + return -1; + } + get(SDHOST_HSTS, hsts); + --cnt; + } while ((hsts & SDHOST_HSTS_DATA) == 0); + return 0; +} + +static void set_block(int size, int cnt) { + set(SDHOST_SIZE, size); + set(SDHOST_CNT, cnt); +} + +static void wait_finish() { + unsigned int dbg; + do { + get(SDHOST_DBG, dbg); + } while ((dbg & SDHOST_DBG_FSM_MASK) != SDHOST_HSTS_DATA); +} + +void readblock(int block_idx, void* buf) { + unsigned int* buf_u = (unsigned int*)buf; + int succ = 0; + if (!is_hcs) { + block_idx <<= 9; + } + do{ + set_block(512, 1); + sd_cmd(READ_SINGLE_BLOCK | SDHOST_READ, block_idx); + for (int i = 0; i < 128; ++i) { + wait_fifo(); + get(SDHOST_DATA, buf_u[i]); + } + unsigned int hsts; + get(SDHOST_HSTS, hsts); + if (hsts & SDHOST_HSTS_ERR_MASK) { + set(SDHOST_HSTS, SDHOST_HSTS_ERR_MASK); + sd_cmd(STOP_TRANSMISSION | SDHOST_BUSY, 0); + } else { + succ = 1; + } + } while(!succ); + wait_finish(); +} + +void writeblock(int block_idx, void* buf) { + unsigned int* buf_u = (unsigned int*)buf; + int succ = 0; + if (!is_hcs) { + block_idx <<= 9; + } + do{ + set_block(512, 1); + sd_cmd(WRITE_SINGLE_BLOCK | SDHOST_WRITE, block_idx); + for (int i = 0; i < 128; ++i) { + wait_fifo(); + set(SDHOST_DATA, buf_u[i]); + } + unsigned int hsts; + get(SDHOST_HSTS, hsts); + if (hsts & SDHOST_HSTS_ERR_MASK) { + set(SDHOST_HSTS, SDHOST_HSTS_ERR_MASK); + sd_cmd(STOP_TRANSMISSION | SDHOST_BUSY, 0); + } else { + succ = 1; + } + } while(!succ); + wait_finish(); +} + +void sd_init() { + pin_setup(); + sdhost_setup(); + sdcard_setup(); +} \ No newline at end of file diff --git a/lab8/fs/fat32.c b/lab8/fs/fat32.c new file mode 100644 index 000000000..0d9860b78 --- /dev/null +++ b/lab8/fs/fat32.c @@ -0,0 +1,453 @@ +#include "fs/vfs.h" +#include "fs/fat32.h" +#include "kern/slab.h" +#include "kern/kio.h" +#include "kern/pagecache.h" +#include "string.h" + +#define MIN(a,b) ((a) > (b) ? (b) : (a)) + +struct fat32_info fat32_info = {0}; + +#define clus_2_lba(cluster) (fat32_info.data_lba + (cluster - fat32_info.root_clus) * fat32_info.clus_size) +#define fat_lba(cluster) (fat32_info.fat_lba + (cluster / FAT32_ENTRY_PER_SECT)) +#define fat_idx(cluster) (cluster / FAT32_ENTRY_PER_SECT) + +void get_sfn(unsigned char *name, unsigned char *ext, char *target) { + int i; + int t = 0; + char c; + for(i=0 ; i<8 ; i++) { + c = name[i]; + if (c == ' ') + break; + target[t++] = c; + } + target[t++] = '.'; + for(i=0 ; i<3 ; i++) { + c = ext[i]; + if (c == ' ') + break; + target[t++] = c; + } + target[t++] = '\0'; +} + +void to_sfn(unsigned char *name, unsigned char *ext, const char *source) { + int i; + int t = 0; + + i = 0; + while(source[t] != '\0' && i < 8) { + if (source[t] == '.') { + t++; + break; + } + name[i++] = (unsigned char)source[t]; + t++; + } + while (i < 8) name[i++] = ' '; + + i = 0; + while(source[t] != '\0' && i < 3) { + ext[i++] = (unsigned char)source[t]; + t++; + } + while (i < 3) ext[i++] = ' '; +} + +unsigned int fat_allocate_free() { + unsigned int *fat; + unsigned int i; + unsigned int file_first_clus = 1; + unsigned int clus = fat32_info.fsi_next_free; + while(file_first_clus == 1) { + fat = pagecache_read(fat_lba(clus)); + for (i=(clus%FAT32_ENTRY_PER_SECT) ; ii_dentry->d_subdirs)) + return -1; + list_for_each(ptr, &dir_node->i_dentry->d_subdirs) { + dentry = list_entry(ptr, struct dentry, d_child); + if (!strcmp(dentry->d_name, component_name) && dentry->d_inode->i_type == I_FILE) { + *target = dentry->d_inode; + return 0; + } + } + return -1; +} + +/* + 1. Find an empty entry in the FAT table. + 2. Find an empty directory entry in the target directory. +*/ +int fat32_create(struct inode* dir_node, struct inode** target, const char* component_name) { + char filename[13]; + unsigned int *fat; + unsigned int i; + unsigned int file_first_clus; + unsigned int unused_entry; + unsigned int clus; + struct fat32_dir_entry *dentry_list = 0; + struct fat32_inode *fat32_internal = (struct fat32_inode*)dir_node->internal; + + struct dentry *new_dentry; + + // Find an empty entry in the FAT table. + file_first_clus = fat_allocate_free(); + + // Find an empty directory entry in the target directory. + unused_entry = -1; + clus = fat32_internal->cluster; + if (!FAT32_VALID_CLUS_NUM(clus)) { + kprintf("fat32_create: directory cluster number error\n"); + return -3; + } + while(FAT32_VALID_CLUS_NUM(clus)) { + dentry_list = (struct fat32_dir_entry *)pagecache_read(clus_2_lba(clus)); + for(i=0 ; i= FAT32_DIR_ENTRY_PRT_SEC) { + kprintf("fat32_create: directory entry fulled!\n"); + return -3; + } + if (dentry_list == 0) { + kprintf("fat32_create: directory entry not found!\n"); + return -3; + } + dentry_list[i+1].DIR_Name[0] = FAT32_DIR_ENTRY_LAST_AND_UNUSED; + unused_entry = i; + } + to_sfn(dentry_list[unused_entry].DIR_Name, dentry_list[unused_entry].DIR_Ext, component_name); + dentry_list[unused_entry].DIR_Attr = FAT32_DIR_ENTRY_ATTR_ARCHIVE; + dentry_list[unused_entry].DIR_FstClusHI = file_first_clus & 0xffff0000; + dentry_list[unused_entry].DIR_FstClusLO = file_first_clus & 0x0000ffff; + dentry_list[unused_entry].DIR_FileSize = 0; + pagecache_dirty(clus_2_lba(clus)); + + // in-memory inode tree + fat32_internal = (struct fat32_inode*)kmalloc(sizeof(struct fat32_inode)); + fat32_internal->cluster = file_first_clus; + new_dentry = fat32_create_dentry(dir_node->i_dentry, component_name, I_FILE, I_FRW); + new_dentry->d_inode->internal = fat32_internal; + *target = new_dentry->d_inode; + + return 0; +} + +int fat32_mkdir(struct inode* dir_node, struct inode** target, const char* component_name) { + return -1; +} + +struct inode_operations fat32_iop = { + .lookup = fat32_lookup, + .create = fat32_create, + .mkdir = fat32_mkdir, +}; + + +/* + dentry operation +*/ +int fat32_read_dentry(struct dentry *dentry) { + int i; + char filename[13]; + struct dentry *new_dentry; + struct fat32_dir_entry *dentry_list; + struct fat32_inode *fat32_internal = (struct fat32_inode*)dentry->d_inode->internal; + unsigned int *fat; + unsigned int cur_clus = fat32_internal->cluster; + + if (!FAT32_VALID_CLUS_NUM(cur_clus)) { + kprintf("fat32_read_dentry: directory cluster number error\n"); + return -3; + } + while(FAT32_VALID_CLUS_NUM(cur_clus)) { + dentry_list = (struct fat32_dir_entry *)pagecache_read(clus_2_lba(cur_clus)); + for(i=0 ; icluster = ((dentry_list[i].DIR_FstClusHI << 16) | (dentry_list[i].DIR_FstClusLO)); + new_dentry->d_inode->i_size = dentry_list[i].DIR_FileSize; + new_dentry->d_inode->internal = fat32_internal; + } + if (i < FAT32_DIR_ENTRY_PRT_SEC) + break; + fat = pagecache_read(fat_lba(cur_clus)); + cur_clus = fat[cur_clus % FAT32_ENTRY_PER_SECT]; + } + dentry->d_cached = 1; + return 0; +} + +int fat32_update_dentry(struct dentry *dentry, const char *component_name, unsigned int filesize, unsigned int file_first_clus) { + int i; + char filename[13]; + struct fat32_dir_entry *dentry_list; + struct fat32_inode *fat32_internal = (struct fat32_inode*)dentry->d_inode->internal; + unsigned int *fat; + unsigned int cur_clus = fat32_internal->cluster; + + while(FAT32_VALID_CLUS_NUM(cur_clus)) { + dentry_list = (struct fat32_dir_entry *)pagecache_read(clus_2_lba(cur_clus)); + for(i=0 ; i %d\n", dentry_list[i].DIR_FileSize, filesize); + dentry_list[i].DIR_FileSize = filesize; + } else { + dentry_list[i].DIR_FstClusHI = file_first_clus & 0xffff0000; + dentry_list[i].DIR_FstClusLO = file_first_clus & 0x0000ffff; + } + pagecache_dirty(clus_2_lba(cur_clus)); + return 0; + } + } + if (i < FAT32_DIR_ENTRY_PRT_SEC) + break; + fat = pagecache_read(fat_lba(cur_clus)); + cur_clus = fat[cur_clus % FAT32_ENTRY_PER_SECT]; + } + kprintf("dentry lookup not found\n"); + return -1; +} + +struct dentry_operations fat32_dop = { + .read = fat32_read_dentry, +}; + + +/* + file operation +*/ +int fat32_open(struct inode* file_node, struct file** target) { + return 0; +} + +int fat32_close(struct file *file) { + return 0; +} + +int fat32_write(struct file *file, const void *buf, long len) { + struct fat32_inode *fat32_internal = (struct fat32_inode*)file->inode->internal; + unsigned long bi = 0; + unsigned long j; + unsigned long offset; + unsigned long end; + unsigned int cur_clus; + unsigned int *fat; + unsigned char *buffer; + char *src = (char*)buf; + + if (file->cur_clus == 1) + cur_clus = fat32_internal->cluster; + else + cur_clus = file->cur_clus; + + // file is empty, need to allocate new cluster, happens when you create this file manually, i.e. touch. + if (file->inode->i_size == 0 && cur_clus == 0) { + cur_clus = fat_allocate_free(); + fat32_internal->cluster = cur_clus; + fat32_update_dentry(file->inode->i_dentry->d_parent, file->inode->i_dentry->d_name, 0, cur_clus); + } + + while(len > 0 && FAT32_VALID_CLUS_NUM(cur_clus)) { + buffer = pagecache_read(clus_2_lba(cur_clus)); + // data range in this block + offset = file->f_pos % BLOCK_SIZE; + end = MIN(BLOCK_SIZE, offset + len); + for(j=offset ; jf_pos += (end - offset); + len -= (end - offset); + if (len) { + // allocate new cluster + fat = pagecache_read(fat_lba(cur_clus)); + fat[cur_clus % FAT32_ENTRY_PER_SECT] = fat_allocate_free(); + cur_clus = fat[cur_clus % FAT32_ENTRY_PER_SECT]; + } + } + file->cur_clus = cur_clus; + if (file->f_pos > file->inode->i_size) { + file->inode->i_size = file->f_pos; + fat32_update_dentry(file->inode->i_dentry->d_parent, file->inode->i_dentry->d_name, file->inode->i_size, 0); + } + return bi; +} + +int fat32_read(struct file *file, void *buf, long len) { + struct fat32_inode *fat32_internal = (struct fat32_inode*)file->inode->internal; + unsigned long size = file->inode->i_size; + unsigned long i = 0; + unsigned long bi = 0; + unsigned long j; + unsigned long offset; + unsigned long end; + unsigned int cur_clus; + unsigned int *fat; + unsigned char *buffer; + char *dest = (char*)buf; + + if (file->cur_clus == 1) + cur_clus = fat32_internal->cluster; + else + cur_clus = file->cur_clus; + + i = (file->f_pos / BLOCK_SIZE) * BLOCK_SIZE; + while(len > 0 && i < size && FAT32_VALID_CLUS_NUM(cur_clus)) { + buffer = pagecache_read(clus_2_lba(cur_clus)); + // data range in this block + offset = file->f_pos % BLOCK_SIZE; + end = MIN(BLOCK_SIZE, offset + len); + if (i + (end-offset) > size) { + end = size % BLOCK_SIZE; + len = 0; + } else + len -= (end - offset); + for(j=offset ; jf_pos += (end - offset); + i += BLOCK_SIZE; + if (len) { + // lookup FAT + fat = pagecache_read(fat_lba(cur_clus)); + cur_clus = fat[cur_clus % FAT32_ENTRY_PER_SECT]; + } + } + file->cur_clus = cur_clus; + + return bi; +} + +long fat32_lseek64(struct file* file, long offset, int whence) { + return -1; +} + +struct file_operations fat32_fop = { + .write = fat32_write, + .read = fat32_read, + .open = fat32_open, + .close = fat32_close, + .lseek64 = fat32_lseek64, +}; + + +int fat32_setup_mount(struct filesystem *fs, struct mount *mount) { + struct fat32_inode *fat32_internal = (struct fat32_inode*)kmalloc(sizeof(struct fat32_inode)); + + mount->fs = fs; + mount->root = fat32_create_dentry(0, "/", I_DIRECTORY, I_FRW); + + if (fat32_info.root_clus != 2) + kprintf("Warning: fat32 root cluster number differed.\n"); + + fat32_internal->cluster = fat32_info.root_clus; + mount->root->d_inode->internal = fat32_internal; + return 0; +} + +struct filesystem *fat32 = 0; +struct filesystem* fat32_get_filesystem() { + if (fat32 == 0) { + fat32 = (struct filesystem *)kmalloc(sizeof(struct filesystem)); + strcpy(fat32->name, "fat32"); + fat32->setup_mount = fat32_setup_mount; + } + return fat32; +} + +struct inode* fat32_create_inode(struct dentry *dentry, unsigned int type, unsigned int flags) { + struct inode *inode = (struct inode *)kmalloc(sizeof(struct inode)); + inode->i_op = &fat32_iop; + inode->i_fop = &fat32_fop; + inode->i_dentry = dentry; + inode->i_flags = flags; + inode->i_type = type; + inode->i_size = 0; + return inode; +} + +struct dentry* fat32_create_dentry(struct dentry *parent, const char *name, unsigned int type, unsigned int flags) { + struct dentry *dentry = (struct dentry *)kmalloc(sizeof(struct dentry)); + strcpy(dentry->d_name, name); + dentry->d_cached = 0; + dentry->d_parent = parent; + dentry->d_inode = fat32_create_inode(dentry, type, flags); + dentry->d_op = &fat32_dop; + dentry->d_mount = 0; + INIT_LIST_HEAD(&dentry->d_child); + INIT_LIST_HEAD(&dentry->d_subdirs); + if (parent) + list_add_tail(&dentry->d_child, &parent->d_subdirs); + return dentry; +} \ No newline at end of file diff --git a/lab8/fs/tmpfs.c b/lab8/fs/tmpfs.c new file mode 100644 index 000000000..6b08fe424 --- /dev/null +++ b/lab8/fs/tmpfs.c @@ -0,0 +1,281 @@ +#include "fs/vfs.h" +#include "fs/tmpfs.h" +#include "kern/slab.h" +#include "string.h" + +struct inode* tmpfs_create_inode(struct dentry *dentry, unsigned int type, unsigned int flags); +struct dentry* tmpfs_create_dentry(struct dentry *parent, const char *name, unsigned int type, unsigned int flags); + +/* + inode operation +*/ +int tmpfs_lookup(struct inode* dir_node, struct inode** target, const char* component_name) { + struct list_head *ptr; + struct dentry *dentry; + if (list_empty(&dir_node->i_dentry->d_subdirs)) + return -1; + list_for_each(ptr, &dir_node->i_dentry->d_subdirs) { + dentry = list_entry(ptr, struct dentry, d_child); + if (!strcmp(dentry->d_name, component_name) && dentry->d_inode->i_type == I_FILE) { + *target = dentry->d_inode; + return 0; + } + } + return -1; +} + +int tmpfs_create(struct inode* dir_node, struct inode** target, const char* component_name) { + struct tmpfs_inode *tmpfs_internal = (struct tmpfs_inode *)kmalloc(sizeof(struct tmpfs_inode)); + struct dentry *new_dentry = tmpfs_create_dentry(dir_node->i_dentry, component_name, I_FILE, I_FRW); + new_dentry->d_inode->internal = (void*)tmpfs_internal; + *target = new_dentry->d_inode; + return 0; +} + +int tmpfs_mkdir(struct inode* dir_node, struct inode** target, const char* component_name) { + struct dentry *new_dentry = tmpfs_create_dentry(dir_node->i_dentry, component_name, I_DIRECTORY, I_FRW); + *target = new_dentry->d_inode; + return 0; +} + +struct inode_operations tmpfs_iop = { + .lookup = tmpfs_lookup, + .create = tmpfs_create, + .mkdir = tmpfs_mkdir, +}; + + +int initramfs_create(struct inode* dir_node, struct inode** target, const char* component_name) { + return -1; +} + +int initramfs_mkdir(struct inode* dir_node, struct inode** target, const char* component_name) { + return -1; +} + +struct inode_operations initramfs_iop = { + .lookup = tmpfs_lookup, + .create = initramfs_create, + .mkdir = initramfs_mkdir, +}; + + +/* + dentry operation +*/ +int tmpfs_read_dentry(struct dentry *dentry) { + return 0; +} + +struct dentry_operations tmpfs_dop = { + .read = tmpfs_read_dentry, +}; + + +/* + file operation +*/ +int tmpfs_open(struct inode* file_node, struct file** target) { + return 0; +} + +int tmpfs_close(struct file *file) { + return 0; +} + +int tmpfs_write(struct file *file, const void *buf, long len) { + struct tmpfs_inode *tmpfs_internal = (struct tmpfs_inode *)file->inode->internal; + unsigned long i = file->f_pos; + unsigned long bi = 0; + char *src = (char*)buf; + for ( ; bidata[i] = src[bi]; + bi++; + } + file->f_pos = i; + if (file->f_pos > file->inode->i_size) + file->inode->i_size = file->f_pos; + return bi; +} + +int tmpfs_read(struct file *file, void *buf, long len) { + struct tmpfs_inode *tmpfs_internal = (struct tmpfs_inode *)file->inode->internal; + unsigned long size = file->inode->i_size; + unsigned long i = file->f_pos; + unsigned long bi = 0; + char *dest = (char*)buf; + for ( ; bidata[i]; + bi++; + } + file->f_pos = i; + return bi; +} + +long tmpfs_lseek64(struct file* file, long offset, int whence) { + unsigned long size = file->inode->i_size; + if (whence == SEEK_SET) { + file->f_pos = offset > size ? size : offset; + } else if (whence == SEEK_END) { + file->f_pos = size + offset; + } + return file->f_pos; +} + +struct file_operations tmpfs_fop = { + .write = tmpfs_write, + .read = tmpfs_read, + .open = tmpfs_open, + .close = tmpfs_close, + .lseek64 = tmpfs_lseek64, +}; + +int initramfs_write(struct file *file, const void *buf, long len) { + return 0; +} + +int initramfs_read(struct file *file, void *buf, long len) { + struct initramfs_inode *initramfs_internal = (struct initramfs_inode *)file->inode->internal; + unsigned long size = file->inode->i_size; + unsigned long i = file->f_pos; + unsigned long bi = 0; + char *dest = (char*)buf; + for ( ; bidata[i]; + bi++; + } + file->f_pos = i; + return bi; +} + +struct file_operations initramfs_fop = { + .write = initramfs_write, + .read = initramfs_read, + .open = tmpfs_open, + .close = tmpfs_close, + .lseek64 = tmpfs_lseek64, +}; + + +int tmpfs_setup_mount(struct filesystem *fs, struct mount *mount) { + mount->fs = fs; + mount->root = tmpfs_create_dentry(0, "/", I_DIRECTORY, I_FRW); + return 0; +} + +struct filesystem *tmpfs = 0; +struct filesystem* tmpfs_get_filesystem() { + if (tmpfs == 0) { + tmpfs = (struct filesystem *)kmalloc(sizeof(struct filesystem)); + strcpy(tmpfs->name, "tmpfs"); + tmpfs->setup_mount = tmpfs_setup_mount; + } + return tmpfs; +} + +struct inode* tmpfs_create_inode(struct dentry *dentry, unsigned int type, unsigned int flags) { + struct inode *inode = (struct inode *)kmalloc(sizeof(struct inode)); + inode->i_op = &tmpfs_iop; + inode->i_fop = &tmpfs_fop; + inode->i_dentry = dentry; + inode->i_flags = flags; + inode->i_type = type; + inode->i_size = 0; + return inode; +} + +struct dentry* tmpfs_create_dentry(struct dentry *parent, const char *name, unsigned int type, unsigned int flags) { + struct dentry *dentry = (struct dentry *)kmalloc(sizeof(struct dentry)); + strcpy(dentry->d_name, name); + dentry->d_cached = 1; // always true for tmpfs + dentry->d_parent = parent; + dentry->d_inode = tmpfs_create_inode(dentry, type, flags); + dentry->d_op = &tmpfs_dop; + dentry->d_mount = 0; + INIT_LIST_HEAD(&dentry->d_child); + INIT_LIST_HEAD(&dentry->d_subdirs); + if (parent) + list_add_tail(&dentry->d_child, &parent->d_subdirs); + return dentry; +} + +#include "kern/cpio.h" + +/* + Used to create initramfs' file + 1. point directly to data + 2. RO +*/ +void initramfs_init_create(struct inode *root_node, const char *pathname, char *data, int filesize) { + struct inode *dir_node; + struct dentry *new_dentry; + struct initramfs_inode *initramfs_internal; + char filename[32]; + + vfs_walk_recursive(root_node, pathname, &dir_node, filename); + initramfs_internal = (struct initramfs_inode *)kmalloc(sizeof(struct initramfs_inode)); + initramfs_internal->data = data; + new_dentry = tmpfs_create_dentry(dir_node->i_dentry, filename, I_FILE, I_FRO); + new_dentry->d_inode->internal = initramfs_internal; + new_dentry->d_inode->i_size = filesize; + new_dentry->d_inode->i_fop = &initramfs_fop; + new_dentry->d_inode->i_op = &initramfs_iop; +} + +void initramfs_init_mkdir(struct inode *root_node, const char *pathname) { + struct inode *dir_node; + struct dentry *new_dentry; + char dirname[32]; + + vfs_walk_recursive(root_node, pathname, &dir_node, dirname); + new_dentry = tmpfs_create_dentry(dir_node->i_dentry, dirname, I_DIRECTORY, I_FRO); + new_dentry->d_inode->i_fop = &initramfs_fop; + new_dentry->d_inode->i_op = &initramfs_iop; +} + +int initramfs_setup_mount(struct filesystem *fs, struct mount *mount) { + int i = 0; + int filesize = 0; + int namesize = 0; + int mode = 0; + struct cpio_newc_header *header; + + mount->fs = fs; + mount->root = tmpfs_create_dentry(0, "/", I_DIRECTORY, I_FRO); + mount->root->d_inode->i_fop = &initramfs_fop; + mount->root->d_inode->i_op = &initramfs_iop; + + for ( ; ; i+=namesize+filesize) { + header = ((struct cpio_newc_header *)(CPIO_ADDRESS + i)); + if (strncmp(header->c_magic, CPIO_MAGIC, 6)) { + break; + } + filesize = (atoi(header->c_filesize, 16, 8) + 3) & -4; + namesize = ((atoi(header->c_namesize, 16, 8) + 6 + 3) & -4) - 6; + i += sizeof(struct cpio_newc_header); + if (!strncmp((char *)(CPIO_ADDRESS + i), CPIO_END, 10)) + break; + if (!strncmp((char *)(CPIO_ADDRESS + i), ".", 1)) { + continue; + } + mode = atoi(header->c_mode, 16, 8); + if ((mode & 00170000) == 0100000) { + initramfs_init_create(mount->root->d_inode, (char *)(CPIO_ADDRESS + i), (char *)(CPIO_ADDRESS + i + namesize), atoi(header->c_filesize, 16, 8)); + } + if ((mode & 00170000) == 0040000) { + initramfs_init_mkdir(mount->root->d_inode, (char *)(CPIO_ADDRESS + i)); + } + } + + return 0; +} + +struct filesystem *initramfs = 0; +struct filesystem* initramfs_get_filesystem() { + if (initramfs == 0) { + initramfs = (struct filesystem *)kmalloc(sizeof(struct filesystem)); + strcpy(initramfs->name, "initramfs"); + initramfs->setup_mount = initramfs_setup_mount; + } + return initramfs; +} diff --git a/lab8/fs/uartfs.c b/lab8/fs/uartfs.c new file mode 100644 index 000000000..eda7847cb --- /dev/null +++ b/lab8/fs/uartfs.c @@ -0,0 +1,49 @@ +/* + Used to register uart as device file, not a filesystem. +*/ +#include "fs/vfs.h" +#include "kern/slab.h" +#include "peripheral/uart.h" + +int uartfs_read(struct file *file, void *buffer, long len) { + int i; + char *buf = (char *)buffer; + for(i=0 ; iread = uartfs_read; + fop->write = uartfs_write; + fop->open = uartfs_open; + fop->close = uartfs_close; + fop->lseek64 = uartfs_lseek64; + dev = vfs_register_device(fop); + vfs_mknod("/dev/uart", 0, dev); +} \ No newline at end of file diff --git a/lab8/fs/vfs.c b/lab8/fs/vfs.c new file mode 100644 index 000000000..a04f85374 --- /dev/null +++ b/lab8/fs/vfs.c @@ -0,0 +1,263 @@ +#include "fs/vfs.h" +#include "fs/tmpfs.h" +#include "fs/uartfs.h" +#include "fs/fat32.h" +#include "string.h" +#include "kern/kio.h" +#include "kern/sched.h" +#include "kern/slab.h" +#include "kern/pagecache.h" + +struct mount* rootfs; + +/* + device file +*/ +#define MAX_DEVICE_FILE 10 + +int device_id; +struct file_operations *device_files[MAX_DEVICE_FILE]; + + +void rootfs_init() { + struct filesystem *tmpfs = tmpfs_get_filesystem(); + + rootfs = (struct mount *)kmalloc(sizeof(struct mount)); + tmpfs->setup_mount(tmpfs, rootfs); + + // device file init + device_id = 0; + memset(device_files, 0, MAX_DEVICE_FILE); + vfs_mkdir("/dev"); + uartfs_register(); +} + +void vfs_walk_recursive(struct inode *dir_node, const char *pathname, struct inode **target, char *target_name) { + struct list_head *ptr; + struct dentry *dentry; + int i = 0; + + if (dir_node->i_dentry->d_cached == 0) { + dir_node->i_dentry->d_op->read(dir_node->i_dentry); + } + + while(pathname[i]) { + if (pathname[i] == '/') + break; + target_name[i] = pathname[i]; + i++; + } + target_name[i] = '\0'; + + *target = dir_node; + if (i == 0) + return; + if (!strcmp(target_name, ".")) { + vfs_walk_recursive(dir_node, pathname+i+1, target, target_name); + return; + } + if (!strcmp(target_name, "..")) { + if (dir_node->i_dentry->d_parent == 0) + vfs_walk_recursive(dir_node, pathname+i+1, target, target_name); + else + vfs_walk_recursive(dir_node->i_dentry->d_parent->d_inode, pathname+i+1, target, target_name); + return; + } + + if (list_empty(&dir_node->i_dentry->d_subdirs)) + return; + list_for_each(ptr, &dir_node->i_dentry->d_subdirs) { + dentry = list_entry(ptr, struct dentry, d_child); + if (!strcmp(dentry->d_name, target_name)) { + if (dentry->d_mount != 0) { + vfs_walk_recursive(dentry->d_mount->root->d_inode, pathname+i+1, target, target_name); + return; + } + if (dentry->d_inode->i_type == I_DIRECTORY) + vfs_walk_recursive(dentry->d_inode, pathname+i+1, target, target_name); + return; + } + } +} + +void vfs_walk(const char *pathname, struct inode **target, char *target_name) { + struct inode *root; + if (pathname[0] == '/') { + root = rootfs->root->d_inode; + vfs_walk_recursive(root, pathname+1, target, target_name); + } else { + root = get_current()->cwd->d_inode; + vfs_walk_recursive(root, pathname, target, target_name); + } +} + +struct file* create_fh(struct inode *file_node) { + struct file *fh = (struct file*)kmalloc(sizeof(struct file)); + fh->inode = file_node; + fh->f_pos = 0; + fh->fop = file_node->i_fop; + fh->cur_clus = 1; // cluster number normally start with 2 + return fh; +} + + +int vfs_open(const char *pathname, int flags, struct file **target) { + // 1. Lookup pathname + // 2. Create a new file handle for this vnode if found. + // 3. Create a new file if O_CREAT is specified in flags and vnode not found + // lookup error code shows if file exist or not or other error occurs + // 4. Return error code if fails + struct inode *dir_node; + struct inode *file_node; + char filename[32]; + vfs_walk(pathname, &dir_node, filename); + + if (dir_node->i_op->lookup(dir_node, &file_node, filename) >= 0) { + *target = create_fh(file_node); + return 0; + } + // kprintf("%s not found under %s\n", pathname, dir_node->i_dentry->d_name); + + if (flags & O_CREAT) { + if (dir_node->i_flags == I_FRO) + return -3; + if (dir_node->i_op->create(dir_node, &file_node, filename) < 0) + return -1; + *target = create_fh(file_node); + return 0; + } + return -1; +} + +int vfs_close(struct file *file) { + // 1. release the file handle + // 2. Return error code if fails + if (file == 0) + return -1; + kfree(file); + return 0; +} + +int vfs_write(struct file* file, const void* buf, long len) { + // 1. write len byte from buf to the opened file. + // 2. return written size or error code if an error occurs. + if (file == 0) + return -1; + if (file->inode->i_type != I_FILE) { + kprintf("vfs_write: not a regular file %d\n", file->inode->i_type); + return -1; + } + if (file->inode->i_flags == I_FRO) { + return -3; + } + return file->fop->write(file, buf, len); +} + +int vfs_read(struct file* file, void* buf, long len) { + // 1. read min(len, readable size) byte to buf from the opened file. + // 2. block if nothing to read for FIFO type + // 2. return read size or error code if an error occurs. + if (file == 0) + return -1; + if (file->inode->i_type != I_FILE) { + kprintf("vfs_read: not a regular file %d\n", file->inode->i_type); + return -1; + } + return file->fop->read(file, buf, len); +} + +int vfs_mkdir(const char* pathname) { + struct inode *dir_node; + struct inode *new_dir_node; + char dirname[32]; + vfs_walk(pathname, &dir_node, dirname); + if (dir_node->i_type != I_DIRECTORY) { + kprintf("vfs_mkdir: not a directory %d\n", dir_node->i_type); + return -1; + } + if (dir_node->i_flags == I_FRO) { + return -3; + } + return dir_node->i_op->mkdir(dir_node, &new_dir_node, dirname); +} + +int vfs_mount(const char* target, const char* filesystem) { + struct inode *mountpoint; + struct mount *mt; + struct filesystem *fs; + char remain[32]; + vfs_walk(target, &mountpoint, remain); + + if (mountpoint->i_type != I_DIRECTORY) + return -1; + if (!strcmp(mountpoint->i_dentry->d_name, "/")) { + kprintf("%s already been mounted\n", target); + return -2; + } + + if (!strcmp(filesystem, "tmpfs")) { + fs = tmpfs_get_filesystem(); + } else if (!strcmp(filesystem, "initramfs")) { + fs = initramfs_get_filesystem(); + } else if (!strcmp(filesystem, "fat32")) { + fs = fat32_get_filesystem(); + } else { + kprintf("Unsupported filesystem: %s\n", filesystem); + return -3; + } + mt = (struct mount *)kmalloc(sizeof(struct mount)); + fs->setup_mount(fs, mt); + mountpoint->i_dentry->d_mount = mt; + mt->root->d_parent = mountpoint->i_dentry->d_parent; + return 0; +} + +int vfs_chdir(const char *pathname) { + struct inode *dir_node; + char remain[32]; + vfs_walk(pathname, &dir_node, remain); + get_current()->cwd = dir_node->i_dentry; + return 0; +} + +long vfs_lseek64(struct file *file, long offset, int whence) { + if (file == 0) + return -1; + if (file->inode->i_type != I_FILE) { + kprintf("vfs_lseek64: not a regular file %d\n", file->inode->i_type); + return -1; + } + return file->fop->lseek64(file, offset, whence); +} + +int vfs_mknod(const char* pathname, int mode, int dev) { + // 1. create special file + // 2. change special file's operation to dev operation + struct inode *dir_node; + struct inode *file_node; + char filename[32]; + vfs_walk(pathname, &dir_node, filename); + + if (dir_node->i_op->lookup(dir_node, &file_node, filename) >= 0) { + kprintf("vfs_mknod: %s already exist\n", pathname); + return -1; + } + if (dir_node->i_flags == I_FRO) + return -3; + if (dir_node->i_op->create(dir_node, &file_node, filename) < 0) + return -1; + file_node->i_fop = device_files[dev]; + return 0; +} + +int vfs_register_device(struct file_operations *device_fop) { + // register device operation and return device id + if (device_id == MAX_DEVICE_FILE) + return -1; + device_files[device_id] = device_fop; + return device_id++; +} + +void vfs_sync() { + pagecache_write_back(); +} \ No newline at end of file diff --git a/lab8/include/bitmap.h b/lab8/include/bitmap.h new file mode 100644 index 000000000..4654a3df0 --- /dev/null +++ b/lab8/include/bitmap.h @@ -0,0 +1,66 @@ +#ifndef BITMAP_H +#define BITMAP_H + +#define BITS_PER_BYTE 8 +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) +#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) + +#define DECLARE_BITMAP(name,bits) \ + unsigned long name[BITS_TO_LONGS(bits)] + +static inline void bitmap_zero(unsigned long *dst, unsigned int nbits) { + int i; + for(i=0 ; i>= 32; + } +#endif + if ((word & 0xffff) == 0) { + num += 16; + word >>= 16; + } + if ((word & 0xff) == 0) { + num += 8; + word >>= 8; + } + if ((word & 0xf) == 0) { + num += 4; + word >>= 4; + } + if ((word & 0x3) == 0) { + num += 2; + word >>= 2; + } + if ((word & 0x1) == 0) + num += 1; + return num; +} + +/* +bitops +*/ +static inline void __set_bit(int nr, volatile unsigned long *addr) { + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *) addr) + BIT_WORD(nr); + *p |= mask; +} + +static inline void __clear_bit(int nr, volatile unsigned long *addr) { + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *) addr) + BIT_WORD(nr); + *p &= ~mask; +} + +#endif \ No newline at end of file diff --git a/lab8/include/byteswap.h b/lab8/include/byteswap.h new file mode 100644 index 000000000..b58305de9 --- /dev/null +++ b/lab8/include/byteswap.h @@ -0,0 +1,9 @@ +#ifndef BYTESWAP_H +#define BYTESWAP_H + +/* Swap bytes in 32-bit value. */ +#define __bswap_32(x) \ + ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) \ + | (((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24)) + +#endif \ No newline at end of file diff --git a/lab8/include/drivers/mbr.h b/lab8/include/drivers/mbr.h new file mode 100644 index 000000000..da2b802e3 --- /dev/null +++ b/lab8/include/drivers/mbr.h @@ -0,0 +1,46 @@ +#ifndef MBR_H +#define MBR_H + +struct chs { + unsigned char cylinder; + unsigned char head; + unsigned char sector; +}; + +/* + MBR structure + 000 ~ 1BD 446 Code Area + 1BE ~ 1FD 64 Master Partition Table + 1BE ~ 1CD 16 Table entry for primary partition #1 + 1CE ~ 1DD 16 Table entry for primary partition #2 + 1DE ~ 1ED 16 Table entry for primary partition #3 + 1EE ~ 1FD 16 Table entry for primary partition #4 + 1FE ~ 1FF 2 Boot Record Signature + + Partition Types + 0x00 Empty partition entry + 0x07 NTFS + 0x0B FAT32 with CHS (Cylinder, Head, Sector) Addressing + 0x0C FAT32 with LBA + 0x0F Extended Partition with LBA + 0x82 Linux Swap Space + 0x83 Linux File System +*/ +struct mbr { + unsigned char code[446]; + struct mbr_partition { + unsigned char status; + struct chs first_sector; + unsigned char partition_type; + struct chs last_sector; + unsigned int first_sector_lba; + unsigned int sectors; + } partition[4]; + unsigned short mbr_signature; +} __attribute__((packed)); + +#define MBR_SIGNATURE 0xAA55 +#define MBR_STATUS_BOOTABLE 0x80 + + +#endif \ No newline at end of file diff --git a/lab8/include/drivers/sdhost.h b/lab8/include/drivers/sdhost.h new file mode 100644 index 000000000..b840ff2d1 --- /dev/null +++ b/lab8/include/drivers/sdhost.h @@ -0,0 +1,10 @@ +#ifndef SDHOST_H +#define SDHOST_H + +void readblock(int block_idx, void* buf); +void writeblock(int block_idx, void* buf); +void sd_init(); + +#define BLOCK_SIZE 512 + +#endif \ No newline at end of file diff --git a/lab8/include/dtb.h b/lab8/include/dtb.h new file mode 100644 index 000000000..921ef309b --- /dev/null +++ b/lab8/include/dtb.h @@ -0,0 +1,40 @@ +#ifndef DTB_H +#define DTB_H + +// #define FDT_HEADER_MAGIC 0xd00dfeed +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + +// All the header fields are stored in big-endian format +struct fdt_header { + unsigned int magic; + unsigned int totalsize; + unsigned int off_dt_struct; + unsigned int off_dt_strings; + unsigned int off_mem_rsvmap; + unsigned int version; + unsigned int last_comp_version; + unsigned int boot_cpuid_phys; + unsigned int size_dt_strings; + unsigned int size_dt_struct; +}; + +struct fdt_reserve_entry { + unsigned long long address; + unsigned long long size; +}; + +struct fdt_prop { + unsigned int len; + unsigned int nameoff; +}; + +int fdt_init(); +int fdt_traverse(void (*cb)(char *, char *, void *)); + +void fdt_reserve(); + +#endif \ No newline at end of file diff --git a/lab8/include/fs/fat32.h b/lab8/include/fs/fat32.h new file mode 100644 index 000000000..599eaf3d7 --- /dev/null +++ b/lab8/include/fs/fat32.h @@ -0,0 +1,137 @@ +#ifndef FAT32_H +#define FAT32_H + +#include "drivers/sdhost.h" + +struct fat32_boot_sector { + char BS_jmpBoot[3]; + char BS_OEMName[8]; + unsigned short BPB_BytsPerSec; + unsigned char BPB_SecPerClus; + unsigned short BPB_RsvdSecCnt; + unsigned char BPB_NumFATs; + unsigned short BPB_RootEntCnt; // Maximum number of FAT12 or FAT16 root directory entries. 0 for FAT32, where the root directory is stored in ordinary data clusters + unsigned short BPB_TotSec16; + char BPB_Media; + unsigned short BPB_FATSz16; + + unsigned short BPB_SecPerTrk; + unsigned short NumHeads; + unsigned int BPB_HiddSec; + unsigned int BPB_TotSec32; + + unsigned int BPB_FATSz32; + unsigned short BPB_flags; + unsigned short BPB_FSVer; + unsigned int BPB_RootClus; // Cluster number of root directory start, typically 2 (first cluster[37]) if it contains no bad sector. + unsigned short BPB_FSInfo; // Logical sector number of FS Information Sector, typically 1 + unsigned short BPB_BkBootSec; + char BPB_Reserved[12]; + unsigned char BS_DrvNum; + unsigned char BS_Reserved1; + char BS_BootSig; + unsigned int BS_VolID; + char BS_VolLAB[11]; + char BS_FilSysType[8]; + char code[420]; + char bootsig[2]; +} __attribute__((packed)); + + +#define FSI_LEAD_SIG 0x41615252 +#define FSI_STRUCT_SIG 0x61417272 +#define FSI_NXT_FREE_UNKNOWN 0xffffffff + +struct fat32_fsinfo_sector { + unsigned int FSI_LeadSig; + char FSI_Reserved1[480]; + unsigned int FSI_StrucSig; + unsigned int FSI_Free_Count; + unsigned int FSI_Nxt_Free; + char FSI_Reserved2[12]; +} __attribute__((packed)); + + +// in-memory cache for important metadata +struct fat32_info { + unsigned short sec_size; + unsigned char clus_size; // number of sector + + unsigned int first_lba; + unsigned int fat_lba; + unsigned char fat_num; + unsigned int fat_size; + unsigned int data_lba; + + unsigned int root_clus; + + unsigned int fsi_next_free; + unsigned int total_sec; +}; + +// store first cluster number of file/directory +struct fat32_inode { + unsigned int cluster; +}; + +// file allocation table +#define FAT32_ENTRY_PER_SECT (BLOCK_SIZE / sizeof(unsigned int)) +#define FAT32_ENTRY_FREE 0 +#define FAT32_ENTRY_RESERVED_TO_END 0x0ffffff8 +#define FAT32_ENTRY_DEFECTIVE_CLUSTER 0x0ffffff7 +#define FAT32_ENTRY_ALLOCATED_AND_END_OF_FILE 0x0fffffff + +// cluster number typically start with 2 +#define FAT32_VALID_CLUS_NUM(clus) ((clus > 1) && (clus < FAT32_ENTRY_DEFECTIVE_CLUSTER)) + +#define FAT32_DIR_ENTRY_LAST_AND_UNUSED 0x0 +#define FAT32_DIR_ENTRY_UNUSED 0xE5 + +#define FAT32_DIR_ENTRY_ATTR_READ_ONLY 0x01 +#define FAT32_DIR_ENTRY_ATTR_HIDDEN 0x02 +#define FAT32_DIR_ENTRY_ATTR_SYSTEM 0x04 +#define FAT32_DIR_ENTRY_ATTR_VOLUME_ID 0x08 +#define FAT32_DIR_ENTRY_ATTR_DIRECTORY 0x10 +#define FAT32_DIR_ENTRY_ATTR_ARCHIVE 0x20 +#define FAT32_DIR_ENTRY_ATTR_LONG_NAME ( FAT32_DIR_ENTRY_ATTR_READ_ONLY | \ + FAT32_DIR_ENTRY_ATTR_HIDDEN | \ + FAT32_DIR_ENTRY_ATTR_SYSTEM | \ + FAT32_DIR_ENTRY_ATTR_VOLUME_ID ) +#define FAT32_DIR_ENTRY_ATTR_LONG_NAME_MASK 0b111111 + + +struct fat32_dir_entry { + unsigned char DIR_Name[8]; /* Offset 0 */ + unsigned char DIR_Ext[3]; + unsigned char DIR_Attr; /* Offset 11 */ + unsigned char DIR_NTRes; /* Offset 12, Reserved */ + unsigned char DIR_CTimeHundth; /* Creation time, centiseconds (0-199) */ + unsigned short DIR_CTime; /* Creation time */ + unsigned short DIR_CDate; /* Creation date */ + unsigned short DIR_LstAccDate; /* Offset 18, Last access date */ + unsigned short DIR_FstClusHI; /* First cluster number high two bytes */ + unsigned short DIR_WrtTime; /* Write Time */ + unsigned short DIR_WrtDate; /* Write Date */ + unsigned short DIR_FstClusLO; /* First cluster number low two bytes */ + unsigned int DIR_FileSize; /* file size (in bytes) */ +} __attribute__((packed)); + +#define FAT32_DIR_ENTRY_PRT_SEC (BLOCK_SIZE / sizeof(struct fat32_dir_entry)) // 16 + +struct fat32_dir_long_entry { + unsigned char id; /* sequence number for slot */ + unsigned char name0_4[10]; /* first 5 characters in name */ + unsigned char attr; /* attribute byte */ + unsigned char reserved; /* always 0 */ + unsigned char alias_checksum; /* checksum for 8.3 alias */ + unsigned char name5_10[12]; /* 6 more characters in name */ + unsigned short start; /* starting cluster number, 0 in long slots */ + unsigned char name11_12[4]; /* last 2 characters in name */ +} __attribute__((packed)); + + +extern struct fat32_info fat32_info; + +struct filesystem* fat32_get_filesystem(); + +#endif \ No newline at end of file diff --git a/lab8/include/fs/tmpfs.h b/lab8/include/fs/tmpfs.h new file mode 100644 index 000000000..6b4a2ce0c --- /dev/null +++ b/lab8/include/fs/tmpfs.h @@ -0,0 +1,15 @@ +#ifndef TMPFS_H +#define TMPFS_H + +struct tmpfs_inode { + char data[4096]; +}; + +struct initramfs_inode { + char *data; +}; + +struct filesystem* tmpfs_get_filesystem(); +struct filesystem* initramfs_get_filesystem(); + +#endif \ No newline at end of file diff --git a/lab8/include/fs/uartfs.h b/lab8/include/fs/uartfs.h new file mode 100644 index 000000000..19e80adb7 --- /dev/null +++ b/lab8/include/fs/uartfs.h @@ -0,0 +1,6 @@ +#ifndef UARTFS_H +#define UARTFS_H + +void uartfs_register(); + +#endif \ No newline at end of file diff --git a/lab8/include/fs/vfs.h b/lab8/include/fs/vfs.h new file mode 100644 index 000000000..6e6445ae7 --- /dev/null +++ b/lab8/include/fs/vfs.h @@ -0,0 +1,104 @@ +#ifndef VFS_H +#define VFS_H + +#include "list.h" + +// syscall para +#define O_CREAT 00000100 + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +// i_type +#define I_FILE 1 +#define I_DIRECTORY 2 + +// i_flags +#define I_FRO 1 +#define I_FRW 2 + +struct inode { + struct inode_operations *i_op; + struct file_operations *i_fop; + struct dentry *i_dentry; + unsigned int i_flags; + unsigned int i_type; + unsigned long i_size; + void* internal; +}; + +struct dentry { + char d_name[32]; + char d_cached; // whether the contents of directory is in memory + struct dentry *d_parent; + struct inode *d_inode; + struct dentry_operations *d_op; + struct mount *d_mount; + struct list_head d_child; + struct list_head d_subdirs; +}; + +/* + f_pos and cur_clus should be sync +*/ +struct file { + struct inode* inode; + long f_pos; // RW position of this file handle + struct file_operations* fop; + int flags; + unsigned int cur_clus; // current cluster number (FAT) +}; + + +struct mount { + struct dentry* root; + struct filesystem* fs; +}; + +struct filesystem { + char name[32]; + int (*setup_mount)(struct filesystem* fs, struct mount* mount); +}; + +struct file_operations { + int (*write)(struct file* file, const void* buf, long len); + int (*read)(struct file* file, void* buf, long len); + int (*open)(struct inode* file_node, struct file** target); + int (*close)(struct file* file); + long (*lseek64)(struct file* file, long offset, int whence); +}; + +struct inode_operations { + int (*lookup)(struct inode* dir_node, struct inode** target, + const char* component_name); + int (*create)(struct inode* dir_node, struct inode** target, + const char* component_name); + int (*mkdir)(struct inode* dir_node, struct inode** target, + const char* component_name); +}; + +struct dentry_operations { + int (*read)(struct dentry *dentry); +}; + +extern struct mount* rootfs; + +void rootfs_init(); + +int vfs_open(const char* pathname, int flags, struct file** target); +int vfs_close(struct file *file); +int vfs_write(struct file* file, const void* buf, long len); +int vfs_read(struct file* file, void* buf, long len); +int vfs_mkdir(const char* pathname); +int vfs_mount(const char* target, const char* filesystem); +int vfs_chdir(const char *pathname); +long vfs_lseek64(struct file *file, long offset, int whence); +void vfs_sync(); + +int vfs_mknod(const char* pathname, int mode, int dev); +int vfs_register_device(struct file_operations *device_fop); + +void vfs_walk_recursive(struct inode *dir_node, const char *pathname, struct inode **target, char *target_name); + +#endif \ No newline at end of file diff --git a/lab8/include/kern/cpio.h b/lab8/include/kern/cpio.h new file mode 100644 index 000000000..20b6c0883 --- /dev/null +++ b/lab8/include/kern/cpio.h @@ -0,0 +1,37 @@ +#ifndef CPIO_H +#define CPIO_H + +// #define CPIO_ADDRESS (void*)0x8000000 +extern void *CPIO_ADDRESS; + +#define CPIO_MAGIC "070701" +#define CPIO_END "TRAILER!!!" + +// New ASCII Format +struct cpio_newc_header { + char c_magic[6]; + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[8]; + char c_filesize[8]; + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char sc_rdevminor[8]; + char c_namesize[8]; + char c_check[8]; +}; + +void initramfs_callback(char *node_name, char *prop_name, void *prop_value); +void initramfs_init(); + +void cpio_ls(); +void cpio_cat(const char *filename); +char* cpio_find(const char *filename); + +void cpio_reserve(); + +#endif \ No newline at end of file diff --git a/lab8/include/kern/fdtable.h b/lab8/include/kern/fdtable.h new file mode 100644 index 000000000..de9a06304 --- /dev/null +++ b/lab8/include/kern/fdtable.h @@ -0,0 +1,19 @@ +#ifndef FDTABLE_H +#define FDTABLE_H + +#include "bitmap.h" +#include "fs/vfs.h" + +#define MAX_OPEN_FD 16 + +struct files_struct { + DECLARE_BITMAP(fd_bitmap, MAX_OPEN_FD); + struct file *fd_array[MAX_OPEN_FD]; +}; + +void fd_init(struct files_struct *files_struct); +int fd_open(struct files_struct *files_struct, struct file *fh); +struct file* fd_close(struct files_struct *files_struct, int fd); +struct file *fd_get(struct files_struct *files_struct, int fd); + +#endif \ No newline at end of file diff --git a/lab8/include/kern/irq.h b/lab8/include/kern/irq.h new file mode 100644 index 000000000..6be242108 --- /dev/null +++ b/lab8/include/kern/irq.h @@ -0,0 +1,16 @@ +#ifndef IRQ_H +#define IRQ_H + +struct trapframe { + long x[31]; + long sp_el0; + long spsr_el1; + long elr_el1; +}; + +void int_enable(); +void int_disable(); + +void int_init(); + +#endif \ No newline at end of file diff --git a/lab8/include/kern/kio.h b/lab8/include/kern/kio.h new file mode 100644 index 000000000..e2d90fcb9 --- /dev/null +++ b/lab8/include/kern/kio.h @@ -0,0 +1,32 @@ +#ifndef KIO_H +#define KIO_H + +#include "peripheral/uart.h" + +static inline void kio_init() { + uart_init(); + uart_flush(); + uart_enable_int(); +} + +static inline void kputc(char c) +{ + uart_async_write(c); +} + +static inline void kputs(char *s) +{ + uart_async_puts(s); +} + +static inline void kflush() { + uart_write_flush(); +} + +static inline char kscanc() { + return uart_async_read(); +} + +void kprintf(char* fmt, ...); + +#endif \ No newline at end of file diff --git a/lab8/include/kern/mm.h b/lab8/include/kern/mm.h new file mode 100644 index 000000000..7e1b7035c --- /dev/null +++ b/lab8/include/kern/mm.h @@ -0,0 +1,17 @@ +#ifndef MM_H +#define MM_H + +#include "kern/mm_types.h" +#include "kern/slab.h" + +void mm_reserve(void *start, void *end); + +void mm_callback(char *node_name, char *prop_name, void *prop_value); + +void mm_init(); + +struct page* get_page_from_addr(void *addr); +struct page* alloc_pages(unsigned int order); +void free_pages(void *addr); + +#endif \ No newline at end of file diff --git a/lab8/include/kern/mm_types.h b/lab8/include/kern/mm_types.h new file mode 100644 index 000000000..79fcf8526 --- /dev/null +++ b/lab8/include/kern/mm_types.h @@ -0,0 +1,50 @@ +#ifndef MM_TYPES_H +#define MM_TYPES_H + +#include "list.h" + +#define MEM_TOTAL 0x40000000 +#define MEM_LIMIT 0x3B400000 + +struct free_area { + struct list_head free_list; + unsigned int nr_free; + unsigned int order; +}; + +#define PG_USED 0 +#define PG_HEAD 1 +#define PG_TAIL 2 +#define PG_SLAB 3 + +struct page { + unsigned int flags; + unsigned int pg_index; + unsigned int compound_order; + + struct slab_t *slab; + + struct list_head list; +}; + +struct mm_struct { + unsigned long *pgd; +}; + + +#include "kern/page.h" + +#define MAX_ORDER 10 + +#define PHY_FRAMES_NUM (MEM_TOTAL / PAGE_SIZE) + +#define PFN_2_PHY(pfn) (long)((pfn) << PAGE_SHIFT) +#define PHY_2_PFN(adr) ((long)(adr) >> PAGE_SHIFT) + +// kernel space address translation +#define VIRT_2_PHY(vaddr) ((long)(vaddr) & 0x0000ffffffffffff) +#define PHY_2_VIRT(vaddr) ((long)(vaddr) | 0xffff000000000000) + +#define VIRT_CHECK(vaddr) ((long)(vaddr) & 0xffff000000000000) + +#endif \ No newline at end of file diff --git a/lab8/include/kern/page.h b/lab8/include/kern/page.h new file mode 100644 index 000000000..495336d84 --- /dev/null +++ b/lab8/include/kern/page.h @@ -0,0 +1,36 @@ +#ifndef PAGE_H +#define PAGE_H + +#define PAGE_SIZE 4096 +#define PAGE_SHIFT 12 +#define PAGE_MASK (~(PAGE_SIZE-1)) + + +#define PGD_SHIFT 39 +#define PUD_SHIFT 30 +#define PMD_SHIFT 21 + +#define PTRS_PER_PGD 512 +#define PTRS_PER_PUD 512 +#define PTRS_PER_PMD 512 +#define PTRS_PER_PTE 512 + +#define pgd_index(vaddr) (((vaddr) >> PGD_SHIFT) & (PTRS_PER_PGD - 1)) +#define pgd_offset(mm, vaddr) ((mm)->pgd + pgd_index(vaddr)) + +#define pud_index(vaddr) (((vaddr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)) + +#define pmd_index(vaddr) (((vaddr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) + +#define pte_index(vaddr) (((vaddr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) + +void create_pgd(struct mm_struct *mm); +void free_pgd(struct mm_struct *mm); +void fork_pgd(struct mm_struct *parent_mm, struct mm_struct *child_mm); + +void *walk(struct mm_struct *mm, unsigned long vaddr, unsigned long paddr); +void *mappages(struct mm_struct *mm, unsigned long vaddr, unsigned long size, unsigned long paddr); + +void identity_paging(struct mm_struct *mm, unsigned long vaddr, unsigned long paddr); + +#endif \ No newline at end of file diff --git a/lab8/include/kern/pagecache.h b/lab8/include/kern/pagecache.h new file mode 100644 index 000000000..c2eaf26b6 --- /dev/null +++ b/lab8/include/kern/pagecache.h @@ -0,0 +1,12 @@ +#ifndef PAGECACHE_H +#define PAGECACHE_H + +#include "list.h" + +void pagecache_init(); + +void* pagecache_read(int lba); +void pagecache_dirty(int lba); +void pagecache_write_back(); + +#endif \ No newline at end of file diff --git a/lab8/include/kern/sched.h b/lab8/include/kern/sched.h new file mode 100644 index 000000000..6ab9c1613 --- /dev/null +++ b/lab8/include/kern/sched.h @@ -0,0 +1,100 @@ +#ifndef SCHED_H +#define SCHED_H + +#include "list.h" +#include "bitmap.h" +#include "kern/signal.h" +#include "kern/mm_types.h" +#include "kern/fdtable.h" +#include "fs/vfs.h" + +#define MAX_PRIV_TASK_NUM 50 +#define TASK_CTIME 10 + +enum task_state { + RUNNING, READY, WAITING, INT, DEAD +}; + +struct task_context { + long x19; + long x20; + long x21; + long x22; + long x23; + long x24; + long x25; + long x26; + long x27; + long x28; + long fp; + long lr; + long sp; +}; + +struct task_struct { + + int tid; + int used; + + enum task_state state; + + int prio; + + int ctime; + int resched; + + void *stk_addr; + void *ustk_addr; + + struct dentry *cwd; + struct dentry *croot; + struct files_struct files; + + struct list_head signal_list; + struct list_head signal_pend_list; + struct signal_context_t *signal_context; + struct task_context task_context; + + struct mm_struct mm; + + struct list_head list; +}; + +#define MAX_PRIO 128 + +static inline int sched_find_first_bit(const unsigned long *b) { + if (b[0]) + return __ffs(b[0]); + if (b[1]) + return __ffs(b[1]) + 64; + return 128; +} + +void task_init(); +void runqueue_init(); +struct task_struct *privilege_task_create(void (*func)(), int prio); +struct task_struct *task_create(void (*func)(), int prio); + +void schedule(); +void kill_zombies(); + +void switch_to(struct task_context *prev, struct task_context *next); +void update_current(struct task_struct *task); +void update_pgd(unsigned long pgd); +struct task_struct* get_current(); +struct task_struct* get_task_struct(int pid); + +int __getpid(); +void __exec(const char *name, char *const argv[]); +int __fork(void *trapframe); +void __exit(); +void __kill(int pid); + +void thread_create(void (*func)()); + +#define USER_STK_HIGH 0xfffffffff000 +#define USER_STK_LOW 0xffffffffb000 + +#define STACKSIZE 16384 // 4096 * 4 + +#endif \ No newline at end of file diff --git a/lab8/include/kern/shell.h b/lab8/include/kern/shell.h new file mode 100644 index 000000000..398dc84b8 --- /dev/null +++ b/lab8/include/kern/shell.h @@ -0,0 +1,22 @@ +#ifndef SHELL_H +#define SHELL_H + +#define BACKSPACE 8 +#define ESC 27 +#define DELETE 127 + +#define LEFT_SHIFT kputc(ESC); \ + kputc('['); \ + kputc('D'); + +#define RIGHT_SHIFT kputc(ESC); \ + kputc('['); \ + kputc('C'); + +#define MAX_INPUT_LEN 128 + +void shell_input(char *cmd); +void shell_parse(char *cmd); +void shell_start(); + +#endif \ No newline at end of file diff --git a/lab8/include/kern/signal.h b/lab8/include/kern/signal.h new file mode 100644 index 000000000..23c25504f --- /dev/null +++ b/lab8/include/kern/signal.h @@ -0,0 +1,31 @@ +#ifndef SIGNAL_H +#define SIGNAL_H + +#include "list.h" + +#define SIGKILL 9 + +struct signal_t { + int num; + void (*handler)(); + struct list_head list; +}; + +struct signal_pend_t { + int num; + struct list_head list; +}; + +struct signal_context_t { + void *trapframe; + void *stk_addr; +}; + +struct signal_t *signal_create(int SIGNAL, void (*handler)()); +void signal_back(void *trapframe); +void signal_run(); + +void __signal(int SIGNAL, void (*handler)()); +void __sigkill(int pid, int SIGNAL, void *trapframe); + +#endif \ No newline at end of file diff --git a/lab8/include/kern/slab.h b/lab8/include/kern/slab.h new file mode 100644 index 000000000..24c5bba6d --- /dev/null +++ b/lab8/include/kern/slab.h @@ -0,0 +1,37 @@ +#ifndef SLAB_H +#define SLAB_H + +#include "list.h" + +/* + Fixed object size to multiple of 8 if object size less than 128. (16 pools) + Fixed object size to multiple of 12 for next 8 pools. + The remaining pool contain arbitrary size object. (224 bytes ~ 4096 bytes) +*/ +#define MAX_OBJ_CACHE_NUM 40 +#define SMALL_OBJ_SIZE 128 +#define MEDIUM_OBJ_SIZE 224 + +struct kmem_pool { + int object_size; // -1 indicate free + unsigned int gfporder; + unsigned int num; // object per slab + + struct list_head slab_list; +}; + +struct slab_t { + unsigned int inuse; + unsigned int nr_free; + void *head_addr; + struct list_head free_list; + + struct list_head list; +}; + +void slab_init(); + +void* kmalloc(unsigned int size); +void kfree(void *addr); + +#endif \ No newline at end of file diff --git a/lab8/include/kern/softirq.h b/lab8/include/kern/softirq.h new file mode 100644 index 000000000..b840fd690 --- /dev/null +++ b/lab8/include/kern/softirq.h @@ -0,0 +1,18 @@ +#ifndef SOFTIRQ_H +#define SOFTIRQ_H + +#define SOFTIRQ_NUM 64 + +#define SOFTIRQ_TIMER 1 +#define SOFTIRQ_UART 2 + +enum irq_state { + IRQ_RUNNING, IRQ_READY, IRQ_IDLE +}; + +void softirq_init(); +void softirq_register(void (*cb)(), int num); +void softirq_active(int num); +void softirq_run(); + +#endif diff --git a/lab8/include/kern/sync.h b/lab8/include/kern/sync.h new file mode 100644 index 000000000..0e6cee841 --- /dev/null +++ b/lab8/include/kern/sync.h @@ -0,0 +1,20 @@ +#ifndef SYNC_H +#define SYNC_H + +/* + ESR-EL1 +*/ +#define EC_BITS(esr_el1) ((esr_el1 >> 26) & 0b111111) +#define EC_SVC_32 0b010001 +#define EC_SVC_64 0b010101 +#define EC_IA_EL0 0b100000 +#define EC_IA_EL1 0b100001 +#define EC_DA_EL0 0b100100 +#define EC_DA_EL1 0b100101 + +#define IFSC(esr_el1) (esr_el1 & 0b111111) +#define DFSC(esr_el1) (esr_el1 & 0b111111) + +#define TRANS_FAULT_0 0b000100 + +#endif diff --git a/lab8/include/kern/timer.h b/lab8/include/kern/timer.h new file mode 100644 index 000000000..c33f0e1df --- /dev/null +++ b/lab8/include/kern/timer.h @@ -0,0 +1,25 @@ +#ifndef TIMER_H +#define TIMER_H + +struct timer_queue { + unsigned long register_time; + unsigned int duration; + char message[128]; + struct timer_queue *prev; + struct timer_queue *next; + void (*callback)(char *, unsigned long); +}; + +void timer_el0_handler(); +void timer_el1_handler(); +void timer_unknown_handler(); +void timer_init(); +void set_timeout(char *args); + +extern void core_timer_enable(); +extern void core_timer_disable(); +extern void timer_enable_int(); +extern void timer_disable_int(); +extern void timer_sched_latency(); + +#endif \ No newline at end of file diff --git a/lab8/include/list.h b/lab8/include/list.h new file mode 100644 index 000000000..4cc825c8a --- /dev/null +++ b/lab8/include/list.h @@ -0,0 +1,134 @@ +#ifndef LIST_H +#define LIST_H + +struct list_head { + struct list_head *prev; + struct list_head *next; +}; + +#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; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +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; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = entry; + entry->prev = entry; +} + +/** + * 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; pos != (head); pos = pos->next) + +#define list_for_each_back(pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + + +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define list_entry(ptr,type,member) \ + container_of(ptr, type, member) + +#endif \ No newline at end of file diff --git a/lab8/include/mmu.h b/lab8/include/mmu.h new file mode 100644 index 000000000..69b68e35f --- /dev/null +++ b/lab8/include/mmu.h @@ -0,0 +1,46 @@ +#ifndef MMU_H +#define MMU_H + + +#define KERNEL_VA_BASE 0xffff000000000000 + +/* + TCR +*/ +#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) + +/* + MAIR + Device memory 0b0000dd00 + Normal memory 0booooiiii, (oooo != 0000 and iiii != 0000) + oooo == 0b0100 Outer Non-cacheable (L2) + iiii == 0b0100 Inner Non-cacheable (L1) +*/ +#define MAIR_DEVICE_nGnRnE 0b00000000 +#define MAIR_NORMAL_NOCACHE 0b01000100 +#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_NORMAL_NOCACHE 1 +#define MAIR_CONFIG_DEFAULT ((MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8))) + +/* + Page’s Descriptor +*/ +#define PD_TABLE 0b11 +#define PD_BLOCK 0b01 +#define PD_PAGE 0b11 + +#define PD_USER_RW (0b01 << 6) + +#define PD_ACCESS (1 << 10) + +#define PGD0_ATTR PD_TABLE +#define PUD0_ATTR PD_TABLE +#define PUD1_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK) +#define PMD0_ATTR PD_TABLE +#define PTE_DEVICE_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_PAGE) +#define PTE_NORMAL_ATTR (PD_ACCESS | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_PAGE) +#define PTE_NORMAL_LAZY_ATTR ((MAIR_IDX_NORMAL_NOCACHE << 2) | PD_PAGE) + +#endif \ No newline at end of file diff --git a/lab8/include/peripheral/arm.h b/lab8/include/peripheral/arm.h new file mode 100644 index 000000000..ed2784ae7 --- /dev/null +++ b/lab8/include/peripheral/arm.h @@ -0,0 +1,13 @@ +#ifndef ARM_H +#define ARM_H + +#include "mmu.h" + +#define ARM_PERI_BASE (KERNEL_VA_BASE | 0x40000000) + +#define CORE0_TIMER_IRQ_CTRL (ARM_PERI_BASE + 0x40) + +// QA7_rev3.4 p.7 +#define CORE0_IRQ_SRC ((volatile unsigned int*)(ARM_PERI_BASE + 0x60)) + +#endif \ No newline at end of file diff --git a/lab8/include/peripheral/aux.h b/lab8/include/peripheral/aux.h new file mode 100644 index 000000000..a854b68f8 --- /dev/null +++ b/lab8/include/peripheral/aux.h @@ -0,0 +1,36 @@ +#ifndef AUX_H +#define AUX_H + +#include "mmio.h" + +// spec p.8 +// start at 0x7E21,5000 +#define AUX_BASE (MMIO_BASE + 0x215000) + +#define AUX_IRQ ((volatile unsigned int*)(AUX_BASE + 0x00)) +#define AUX_ENABLES ((volatile unsigned int*)(AUX_BASE + 0x04)) +#define AUX_MU_IO ((volatile unsigned int*)(AUX_BASE + 0x40)) +#define AUX_MU_IER ((volatile unsigned int*)(AUX_BASE + 0x44)) +#define AUX_MU_IIR ((volatile unsigned int*)(AUX_BASE + 0x48)) +#define AUX_MU_LCR ((volatile unsigned int*)(AUX_BASE + 0x4C)) +#define AUX_MU_MCR ((volatile unsigned int*)(AUX_BASE + 0x50)) +#define AUX_MU_LSR ((volatile unsigned int*)(AUX_BASE + 0x54)) +#define AUX_MU_MSR ((volatile unsigned int*)(AUX_BASE + 0x58)) +#define AUX_MU_SCRATCH ((volatile unsigned int*)(AUX_BASE + 0x5C)) +#define AUX_MU_CNTL ((volatile unsigned int*)(AUX_BASE + 0x60)) +#define AUX_MU_STAT ((volatile unsigned int*)(AUX_BASE + 0x64)) +#define AUX_MU_BAUD ((volatile unsigned int*)(AUX_BASE + 0x68)) +#define AUX_SPI0_CNTL0 ((volatile unsigned int*)(AUX_BASE + 0x80)) +#define AUX_SPI0_CNTL1 ((volatile unsigned int*)(AUX_BASE + 0x84)) +#define AUX_SPI0_STAT ((volatile unsigned int*)(AUX_BASE + 0x88)) +#define AUX_SPI0_IO ((volatile unsigned int*)(AUX_BASE + 0x90)) +#define AUX_SPI0_PEEK ((volatile unsigned int*)(AUX_BASE + 0x94)) +#define AUX_SPI1_CNTL0 ((volatile unsigned int*)(AUX_BASE + 0xC0)) +#define AUX_SPI1_CNTL1 ((volatile unsigned int*)(AUX_BASE + 0xC4)) +#define AUX_SPI1_STAT ((volatile unsigned int*)(AUX_BASE + 0xC8)) +#define AUX_SPI1_IO ((volatile unsigned int*)(AUX_BASE + 0xD0)) +#define AUX_SPI1_PEEK ((volatile unsigned int*)(AUX_BASE + 0xD4)) + +#define AUX_INT (1 << 29) + +#endif \ No newline at end of file diff --git a/lab8/include/peripheral/gpio.h b/lab8/include/peripheral/gpio.h new file mode 100644 index 000000000..596db3d74 --- /dev/null +++ b/lab8/include/peripheral/gpio.h @@ -0,0 +1,51 @@ +#ifndef GPIO_H +#define GPIO_H + +#include "mmio.h" + +// spec p.90 +// start at 0x7E20,0000 +#define GPIO_BASE (MMIO_BASE + 0x200000) + +#define GPFSEL0 ((volatile unsigned int*)(GPIO_BASE + 0x00)) +#define GPFSEL1 ((volatile unsigned int*)(GPIO_BASE + 0x04)) +#define GPFSEL2 ((volatile unsigned int*)(GPIO_BASE + 0x08)) +#define GPFSEL3 ((volatile unsigned int*)(GPIO_BASE + 0x0C)) +#define GPFSEL4 ((volatile unsigned int*)(GPIO_BASE + 0x10)) +#define GPFSEL5 ((volatile unsigned int*)(GPIO_BASE + 0x14)) +// 0x18 Reserved +#define GPSET0 ((volatile unsigned int*)(GPIO_BASE + 0x1C)) +#define GPSET1 ((volatile unsigned int*)(GPIO_BASE + 0x20)) +// 0x24 Reserved +#define GPCLR0 ((volatile unsigned int*)(GPIO_BASE + 0x28)) +#define GPCLR1 ((volatile unsigned int*)(GPIO_BASE + 0x2C)) +// 0x30 Reserved +#define GPLEV0 ((volatile unsigned int*)(GPIO_BASE + 0x34)) +#define GPLEV1 ((volatile unsigned int*)(GPIO_BASE + 0x38)) +// 0x3C Reserved +#define GPEDS0 ((volatile unsigned int*)(GPIO_BASE + 0x40)) +#define GPEDS1 ((volatile unsigned int*)(GPIO_BASE + 0x44)) +// 0x48 Reserved +#define GPREN0 ((volatile unsigned int*)(GPIO_BASE + 0x4C)) +#define GPREN1 ((volatile unsigned int*)(GPIO_BASE + 0x50)) +// 0x54 Reserved +#define GPFEN0 ((volatile unsigned int*)(GPIO_BASE + 0x58)) +#define GPFEN1 ((volatile unsigned int*)(GPIO_BASE + 0x5C)) +// 0x60 Reserved +#define GPHEN0 ((volatile unsigned int*)(GPIO_BASE + 0x64)) +#define GPHEN1 ((volatile unsigned int*)(GPIO_BASE + 0x68)) +// 0x6C Reserved +#define GPLEN0 ((volatile unsigned int*)(GPIO_BASE + 0x70)) +#define GPLEN1 ((volatile unsigned int*)(GPIO_BASE + 0x74)) +// 0x78 Reserved +#define GPAREN0 ((volatile unsigned int*)(GPIO_BASE + 0x7C)) +#define GPAREN1 ((volatile unsigned int*)(GPIO_BASE + 0x80)) +// 0x84 Reserved +#define GPAFEN0 ((volatile unsigned int*)(GPIO_BASE + 0x88)) +#define GPAFEN1 ((volatile unsigned int*)(GPIO_BASE + 0x8C)) +// 0x90 Reserved +#define GPPUD ((volatile unsigned int*)(GPIO_BASE + 0x94)) +#define GPPUDCLK0 ((volatile unsigned int*)(GPIO_BASE + 0x98)) +#define GPPUDCLK1 ((volatile unsigned int*)(GPIO_BASE + 0x9C)) + +#endif \ No newline at end of file diff --git a/lab8/include/peripheral/interrupt.h b/lab8/include/peripheral/interrupt.h new file mode 100644 index 000000000..5bcfd69da --- /dev/null +++ b/lab8/include/peripheral/interrupt.h @@ -0,0 +1,19 @@ +#ifndef IRQ_H +#define IRQ_H + +#include "mmio.h" + +// spec p.112 +// start at 0x7E00,B000 +#define INT_BASE (MMIO_BASE + 0xB000) + +#define IRQ_PENDING_1 ((volatile unsigned int*)(INT_BASE + 0x204)) +#define IRQ_PENDING_2 ((volatile unsigned int*)(INT_BASE + 0x208)) +#define ENABLE_IRQS_1 ((volatile unsigned int*)(INT_BASE + 0x210)) +#define ENABLE_IRQS_2 ((volatile unsigned int*)(INT_BASE + 0x214)) +#define ENABLE_BASIC_IRQS ((volatile unsigned int*)(INT_BASE + 0x218)) +#define DISABLE_IRQS_1 ((volatile unsigned int*)(INT_BASE + 0x21C)) +#define DISABLE_IRQS_2 ((volatile unsigned int*)(INT_BASE + 0x220)) +#define DISABLE_BASIC_IRQS ((volatile unsigned int*)(INT_BASE + 0x224)) + +#endif \ No newline at end of file diff --git a/lab8/include/peripheral/mailbox.h b/lab8/include/peripheral/mailbox.h new file mode 100644 index 000000000..26333553f --- /dev/null +++ b/lab8/include/peripheral/mailbox.h @@ -0,0 +1,53 @@ +#ifndef MAILBOX_H +#define MAILBOX_H + +#include "mmio.h" + +#define MAILBOX_BASE (MMIO_BASE + 0xb880) + +#define MAILBOX_READ ((volatile unsigned int*)(MAILBOX_BASE)) +#define MAILBOX_STATUS ((volatile unsigned int*)(MAILBOX_BASE + 0x18)) +#define MAILBOX_WRITE ((volatile unsigned int*)(MAILBOX_BASE + 0x20)) + +#define MAILBOX_EMPTY 0x40000000 +#define MAILBOX_FULL 0x80000000 + +// Tag +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_MEMORY 0x00010005 +#define REQUEST_CODE 0x00000000 +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +/* +Mailbox 0 defines the following channels: + +0: Power management +1: Framebuffer +2: Virtual UART +3: VCHIQ +4: LEDs +5: Buttons +6: Touch screen +7: +8: Property tags (ARM -> VC) +9: Property tags (VC -> ARM) +*/ +#define MAILBOX_CH_PM 0 +#define MAILBOX_CH_FB 1 +#define MAILBOX_CH_VUART 2 +#define MAILBOX_CH_VCHIQ 3 +#define MAILBOX_CH_LEDS 4 +#define MAILBOX_CH_BTNS 5 +#define MAILBOX_CH_TS 6 +// 7 +#define MAILBOX_CH_ARM2VC 8 +#define MAILBOX_CH_VC2ARM 9 + +unsigned int mailbox_call(unsigned char ch, unsigned int* mailbox); +void get_board_revision(unsigned int *result); +void get_ARM_memory(unsigned int *result); + +#endif \ No newline at end of file diff --git a/lab8/include/peripheral/mmio.h b/lab8/include/peripheral/mmio.h new file mode 100644 index 000000000..6730a2ec7 --- /dev/null +++ b/lab8/include/peripheral/mmio.h @@ -0,0 +1,12 @@ +#ifndef MMIO_H +#define MMIO_H + +#include "mmu.h" + +#ifdef BOOT_LOADER +#define MMIO_BASE 0x3F000000 +#else +#define MMIO_BASE (KERNEL_VA_BASE | 0x3F000000) // -> 0x7E00,0000 +#endif + +#endif \ No newline at end of file diff --git a/lab8/include/peripheral/uart.h b/lab8/include/peripheral/uart.h new file mode 100644 index 000000000..174f8e6ee --- /dev/null +++ b/lab8/include/peripheral/uart.h @@ -0,0 +1,27 @@ +#ifndef UART_H +#define UART_H + +void uart_init(); + +void uart_enable_int(); +void uart_disable_int(); +void uart_int_handler(); + +char uart_sync_read(); +char uart_sync_read_raw(); +void uart_sync_write(unsigned int c); +void uart_sync_puts(char *s); +void uart_sync_printNum(long num, int base); + +char uart_async_read(); +void uart_async_write(unsigned int c); +void uart_async_puts(char *s); + +void uart_flush(); +void uart_write_flush(); + + +#define ENABLE_IRQS_1_AUX (*ENABLE_IRQS_1 |= AUX_INT) +#define DISABLE_IRQS_1_AUX (*DISABLE_IRQS_1 |= AUX_INT) + +#endif \ No newline at end of file diff --git a/lab8/include/reset.h b/lab8/include/reset.h new file mode 100644 index 000000000..122fca62a --- /dev/null +++ b/lab8/include/reset.h @@ -0,0 +1,12 @@ +#ifndef RESET_H +#define RESET_H + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +void set(long addr, unsigned int value); +void reset(int tick); +void cancel_reset(); + +#endif \ No newline at end of file diff --git a/lab8/include/startup_alloc.h b/lab8/include/startup_alloc.h new file mode 100644 index 000000000..f62ce6003 --- /dev/null +++ b/lab8/include/startup_alloc.h @@ -0,0 +1,8 @@ +#ifndef STARTUP_ALLOC +#define STARTUP_ALLOC + +void* sumalloc(unsigned int size); + +void reserved_kern_startup(); + +#endif \ No newline at end of file diff --git a/lab8/include/string.h b/lab8/include/string.h new file mode 100644 index 000000000..d7a9d078f --- /dev/null +++ b/lab8/include/string.h @@ -0,0 +1,15 @@ +#ifndef STRING_H +#define STRING_H + +unsigned int strlen (const char *str); +int strcmp (const char *p1, const char *p2); +int strncmp (const char *s1, const char *s2, unsigned int len); +char *strcpy(char *dest, const char *src); + +int itoa(long num, char* str, int base); +long atoi(char* str, int base, unsigned int len); + +void* memcpy (void* dest, const void* src, unsigned int len); +void* memset (void* dest, int val, unsigned int len); + +#endif \ No newline at end of file diff --git a/lab8/include/syscall.h b/lab8/include/syscall.h new file mode 100644 index 000000000..bc4539a49 --- /dev/null +++ b/lab8/include/syscall.h @@ -0,0 +1,54 @@ +#ifndef SYSCALL_H +#define SYSCALL_H + +#define SYS_GET_PID 0 +#define SYS_UART_READ 1 +#define SYS_UART_WRITE 2 +#define SYS_EXEC 3 +#define SYS_FORK 4 +#define SYS_EXIT 5 +#define SYS_MBOX_CALL 6 +#define SYS_KILL 7 +#define SYS_SIGNAL 8 +#define SYS_SIGKILL 9 + +int getpid(); +int uart_read(char buf[], int size); +int uart_write(const char buf[], int size); +int exec(const char *name, char *const argv[]); +int fork(); +void exit(); +int mbox_call(unsigned char ch, unsigned int *mbox); +void kill(int pid); +void signal(int SIGNAL, void (*handler)()); +void sigkill(int pid, int SIGNAL); + +#define SYS_OPEN 11 +#define SYS_CLOSE 12 +#define SYS_WRITE 13 +#define SYS_READ 14 +#define SYS_MKDIR 15 +#define SYS_MOUNT 16 +#define SYS_CHDIR 17 +#define SYS_LSEEK64 18 + +#define SYS_SYNC 20 + +#define O_CREAT 00000100 + +int open(const char *pathname, int flags); +int close(int fd); +long write(int fd, const void *buf, unsigned long count); +long read(int fd, void *buf, unsigned long count); +int mkdir(const char *pathname, unsigned mode); +int mount(const char *src, const char *target, const char *filesystem, unsigned long flags, const void *data); +int chdir(const char *path); +void sync(); + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +long lseek64(int fd, long offset, int whence); + +#endif \ No newline at end of file diff --git a/lab8/include/test_func.h b/lab8/include/test_func.h new file mode 100644 index 000000000..4cd35646b --- /dev/null +++ b/lab8/include/test_func.h @@ -0,0 +1,10 @@ +#ifndef TEST_FUNC_H +#define TEST_FUNC_H + +void fork_test(); +void fs_test(); +void fat_test(); +void fs_uart_test(); +void initramfs_test(); + +#endif \ No newline at end of file diff --git a/lab8/include/user_lib.h b/lab8/include/user_lib.h new file mode 100644 index 000000000..d8ec88fdf --- /dev/null +++ b/lab8/include/user_lib.h @@ -0,0 +1,6 @@ +#ifndef USER_LIB_H +#define USER_LIB_H + +void printf(char *fmt, ...); + +#endif \ No newline at end of file diff --git a/lab8/kern/cpio.c b/lab8/kern/cpio.c new file mode 100644 index 000000000..30312ee82 --- /dev/null +++ b/lab8/kern/cpio.c @@ -0,0 +1,113 @@ +#include "kern/kio.h" +#include "kern/mm.h" +#include "kern/cpio.h" +#include "kern/sched.h" +#include "string.h" +#include "byteswap.h" +#include "syscall.h" + +// qemu default address +void *CPIO_ADDRESS = (void*)PHY_2_VIRT(0x8000000); +void *CPIO_END_ADR = 0; // weird bugs in physical machine + +void initramfs_callback(char *node_name, char *prop_name, void *prop_value) { + if (!strncmp(node_name, "chosen", 6) && !strncmp(prop_name, "linux,initrd-start", 18)) { + kputs("cpio: Find!\n"); + CPIO_ADDRESS = (void*)(__bswap_32(*((unsigned int *)(prop_value)))); + CPIO_ADDRESS = (void*)PHY_2_VIRT(CPIO_ADDRESS); + } +} + +void cpio_ls() { + int i = 0; + int filesize = 0; + int namesize = 0; + struct cpio_newc_header *header; + + for ( ; ; i+=namesize+filesize) { + header = ((struct cpio_newc_header *)(CPIO_ADDRESS + i)); + if (strncmp(header->c_magic, CPIO_MAGIC, 6)) { + kputs("cpio: Bad magic\n"); + break; + } + filesize = (atoi(header->c_filesize, 16, 8) + 3) & -4; + namesize = ((atoi(header->c_namesize, 16, 8) + 6 + 3) & -4) - 6; + i += sizeof(struct cpio_newc_header); + if (!strncmp((char *)(CPIO_ADDRESS + i), CPIO_END, 10)) + break; + kprintf("%s\n", (char *)(CPIO_ADDRESS + i)); + } +} + +void cpio_cat(const char *filename) { + int i = 0; + int filesize = 0; + int namesize = 0; + struct cpio_newc_header *header; + + for ( ; ; i+=namesize+filesize) { + header = ((struct cpio_newc_header *)(CPIO_ADDRESS + i)); + if (strncmp(header->c_magic, CPIO_MAGIC, 6)) { + kputs("cpio: Bad magic\n"); + break; + } + filesize = (atoi(header->c_filesize, 16, 8) + 3) & -4; + namesize = ((atoi(header->c_namesize, 16, 8) + 6 + 3) & -4) - 6; + i += sizeof(struct cpio_newc_header); + if (!strcmp((char *)(CPIO_ADDRESS + i), filename)) { + kprintf("%s\n", (char *)(CPIO_ADDRESS + i + namesize)); + return; + } + if (!strncmp((char *)(CPIO_ADDRESS + i), CPIO_END, 10)) + break; + } + kputs("File not exists...\n"); +} + +char* cpio_find(const char *filename) { + int i = 0; + int filesize = 0; + int namesize = 0; + struct cpio_newc_header *header; + + for ( ; ; i+=namesize+filesize) { + header = ((struct cpio_newc_header *)(CPIO_ADDRESS + i)); + if (strncmp(header->c_magic, CPIO_MAGIC, 6)) { + kputs("cpio: Bad magic\n"); + break; + } + filesize = (atoi(header->c_filesize, 16, 8) + 3) & -4; + namesize = ((atoi(header->c_namesize, 16, 8) + 6 + 3) & -4) - 6; + i += sizeof(struct cpio_newc_header); + if (!strcmp((char *)(CPIO_ADDRESS + i), filename)) + break; + if (!strncmp((char *)(CPIO_ADDRESS + i), CPIO_END, 10)) { + kputs("File not exists...\n"); + return 0; + } + } + i += namesize; + + return CPIO_ADDRESS + i; +} + +void cpio_reserve() { + int i = 0; + int filesize = 0; + int namesize = 0; + struct cpio_newc_header *header; + + for ( ; ; i+=namesize+filesize) { + header = ((struct cpio_newc_header *)(CPIO_ADDRESS + i)); + if (strncmp(header->c_magic, CPIO_MAGIC, 6)) { + kputs("cpio: Bad magic\n"); + break; + } + filesize = (atoi(header->c_filesize, 16, 8) + 3) & -4; + namesize = ((atoi(header->c_namesize, 16, 8) + 6 + 3) & -4) - 6; + i += sizeof(struct cpio_newc_header); + if (!strncmp((char *)(CPIO_ADDRESS + i), CPIO_END, 10)) + break; + } + mm_reserve(CPIO_ADDRESS, CPIO_ADDRESS+i); +} \ No newline at end of file diff --git a/lab8/kern/entry.S b/lab8/kern/entry.S new file mode 100644 index 000000000..abff6c254 --- /dev/null +++ b/lab8/kern/entry.S @@ -0,0 +1,135 @@ +#include "mmu.h" + +.section ".text.entry" + +.global _start +_start: + bl from_el2_to_el1 + +el1_start: + // Set up TCR_EL1 + ldr x0, =TCR_CONFIG_DEFAULT + msr tcr_el1, x0 + + // Set up mair_el1 + ldr x0, =MAIR_CONFIG_DEFAULT + msr mair_el1, x0 + + bl pgtable_create + + mrs x2, sctlr_el1 + orr x2, x2, #1 + msr sctlr_el1, x2 // enable MMU, cache remains disabled + + // indirect branch + ldr x0, =mmu_open + br x0 + +mmu_open: + // clear bss + ldr x0, =__bss_start + ldr x1, =__bss_size +bss_loop: + cbz x1, ready + str xzr, [x0], #8 // [x0] = 0, x0 = x0 + 8 + sub x1, x1, #1 // x1 = x1 - 1 + cbnz x1, bss_loop + +ready: + // set_exception_vector_table + adr x0, exception_vector_table + msr vbar_el1, x0 + + // change sp to virtual address + ldr x1, =KERNEL_VA_BASE + add sp, sp, x1 + + bl kern_main + +spin: + wfe + b spin + + +from_el2_to_el1: + mov x0, (1 << 31) + msr hcr_el2, x0 + mov x0, 0b1111000101 + msr spsr_el2, x0 + msr elr_el2, lr + ldr x0, = __stack_kernel_top + msr sp_el1, x0 + eret + +.global run_el1_to_el0 +run_el1_to_el0: + msr elr_el1, x0 + mov x0, 0b0 // enable interrupt in EL0 + msr spsr_el1, x0 + msr sp_el0, x1 + eret + +pgtable_create: + ldr x0, =__kernel_pgd // PGD + lsl x0, x0, #16 // omit first 16 bit (using physical address) + lsr x0, x0, #16 + add x1, x0, #4096 // PUD + add x2, x1, #4096 // PMD + add x3, x2, #4096 // PTE + + // Set up PGD + ldr x4, =PGD0_ATTR + orr x4, x1, x4 + str x4, [x0] + + // Set up PUD + ldr x4, =PUD0_ATTR + orr x4, x2, x4 + str x4, [x1] + + ldr x4, =PUD1_ATTR + mov x5, 0x40000000 + orr x4, x5, x4 + str x4, [x1, #8] + + // Set up PMD + mov x5, x3 + mov x6, xzr // i = 0 + mov x7, #512 +pmd_loop: + ldr x4, =PMD0_ATTR + orr x4, x5, x4 + str x4, [x2, x6, lsl #3] // i * 8 + add x6, x6, #1 // i++ + add x5, x5, #4096 + cmp x6, x7 + b.ls pmd_loop + + // Set up normal PTE + mov x4, xzr // physical address + mov x5, xzr // i = 0 + mov x6, #258048 +pte_nloop: + ldr x7, =PTE_NORMAL_ATTR + orr x7, x4, x7 + str x7, [x3, x5, lsl #3] // (i * 8) + add x5, x5, #1 + add x4, x4, #4096 + cmp x5, x6 + b.ls pte_nloop + + // Set up device PTE + add x6, x6, #4096 // 262144 +pte_dloop: + ldr x7, =PTE_DEVICE_ATTR + orr x7, x4, x7 + str x7, [x3, x5, lsl #3] // (i * 8) + add x5, x5, #1 + add x4, x4, #4096 + cmp x5, x6 + b.ls pte_dloop + + msr ttbr0_el1, x0 + msr ttbr1_el1, x0 + + ret \ No newline at end of file diff --git a/lab8/kern/exception_vector_table.S b/lab8/kern/exception_vector_table.S new file mode 100644 index 000000000..556b3d939 --- /dev/null +++ b/lab8/kern/exception_vector_table.S @@ -0,0 +1,136 @@ +.section ".text" + +// save general registers to stack +.macro save_all + sub sp, sp, 32 * 18 + 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] + + mrs x20, sp_el0 + stp x30, x20, [sp, 16 * 15] + + mrs x20, spsr_el1 + mrs x21, elr_el1 + stp x20, x21, [sp ,16 * 16] +.endm + +// load general registers from stack +.macro load_all + ldp x20, x21, [sp ,16 * 16] + msr spsr_el1, x20 + msr elr_el1, x21 + + ldp x30, x20, [sp, 16 * 15] + msr sp_el0, x20 + + 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] + add sp, sp, 32 * 18 +.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 + b exception_handler + .align 7 // entry size is 0x80, .align will pad 0 + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + // Exception from the current EL while using SP_ELx + b sync_handler + .align 7 + b irq_el1_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + // Exception from a lower EL and at least one lower EL is AArch64 + b sync_handler + .align 7 + b irq_el0_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + // Exception from a lower EL and all lower ELs are AArch32 + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + +exception_handler: + b exception_handler + +sync_handler: + save_all + mrs x0, spsr_el1 + mrs x1, elr_el1 + mrs x2, esr_el1 + mov x3, sp + bl sync_main + load_all + eret + +irq_el1_handler: + save_all + bl irq_main + bl irq_resched + mov x0, sp + bl signal_run + load_all + eret + +irq_el0_handler: + save_all + bl irq_main + bl irq_resched + mov x0, sp + bl signal_run + load_all + eret + +.global return_from_fork +return_from_fork: + load_all + eret diff --git a/lab8/kern/fdtable.c b/lab8/kern/fdtable.c new file mode 100644 index 000000000..118788936 --- /dev/null +++ b/lab8/kern/fdtable.c @@ -0,0 +1,35 @@ +#include "kern/fdtable.h" +#include "fs/vfs.h" + +void fd_init(struct files_struct *files_struct) { + struct file *stdio_fh; + bitmap_zero(files_struct->fd_bitmap, MAX_OPEN_FD); + + // open /dev/uart as stdin (fd 0), stdout (fd 1), and stderr (fd 2) + vfs_open("/dev/uart", 0, &stdio_fh); + files_struct->fd_array[0] = stdio_fh; + files_struct->fd_array[1] = stdio_fh; + files_struct->fd_array[2] = stdio_fh; + + for (int i=3 ; ifd_bitmap); +} + +int fd_open(struct files_struct *files_struct, struct file *fh) { + int fd = __ffs(files_struct->fd_bitmap[0]); + __clear_bit(fd, files_struct->fd_bitmap); + files_struct->fd_array[fd] = fh; + return fd; +} + +struct file* fd_close(struct files_struct *files_struct, int fd) { + struct file *fh; + __set_bit(fd, files_struct->fd_bitmap); + fh = files_struct->fd_array[fd]; + files_struct->fd_array[fd] = 0; + return fh; +} + +struct file *fd_get(struct files_struct *files_struct, int fd) { + return files_struct->fd_array[fd]; +} \ No newline at end of file diff --git a/lab8/kern/irq.c b/lab8/kern/irq.c new file mode 100644 index 000000000..d0d566d51 --- /dev/null +++ b/lab8/kern/irq.c @@ -0,0 +1,78 @@ +#include "peripheral/aux.h" +#include "peripheral/uart.h" +#include "peripheral/interrupt.h" +#include "peripheral/arm.h" +#include "kern/timer.h" +#include "kern/irq.h" +#include "kern/sched.h" +#include "kern/softirq.h" + +// QA7_rev3.4 p.16 +#define CNTPNSIRQ_INT 1 +#define GPU_INT 8 + +#define ROUND_DOWN(n,d) ((n) & (-d)) + +char int_stack[4096]; + +void int_enable() { + asm volatile("msr DAIFClr, 0xf"); +} + +void int_disable() { + asm volatile("msr DAIFSet, 0xf"); +} + +void timer_int_handler() { + struct task_struct *current = get_current(); + if (--current->ctime <= 0) { + current->resched = 1; + } + timer_sched_latency(); + timer_enable_int(); +} + +void int_init() { + softirq_init(); + softirq_register(timer_int_handler, SOFTIRQ_TIMER); + softirq_register(uart_int_handler, SOFTIRQ_UART); + int_enable(); +} + +void irq_router() { + int_disable(); + if (*CORE0_IRQ_SRC & (1 << CNTPNSIRQ_INT)) { + timer_disable_int(); + softirq_active(SOFTIRQ_TIMER); + } else if (*CORE0_IRQ_SRC & (1 << GPU_INT)) { + if (*IRQ_PENDING_1 & AUX_INT) { + uart_disable_int(); + softirq_active(SOFTIRQ_UART); + } + } + int_enable(); + softirq_run(); +} + +void irq_main() { + register char *sp; + asm volatile("mov %0, sp": "=r"(sp)); + if (!(sp <= &int_stack[4095] && sp >= &int_stack[0])) { + asm volatile("mov sp, %0" : : "r"(ROUND_DOWN((unsigned long)&int_stack[4088], 16))); + } + + irq_router(); + + if (!(sp <= &int_stack[4095] && sp >= &int_stack[0])) { + asm volatile("mov sp, %0" : : "r"(sp)); + } +} + +void irq_resched() { + struct task_struct *current = get_current(); + if (current->resched) { + current->ctime = TASK_CTIME; + current->resched = 0; + schedule(); + } +} \ No newline at end of file diff --git a/lab8/kern/kio.c b/lab8/kern/kio.c new file mode 100644 index 000000000..b83deafbf --- /dev/null +++ b/lab8/kern/kio.c @@ -0,0 +1,65 @@ +#include "string.h" +#include "kern/kio.h" + +void kprintf(char* fmt, ...) { + char s[124]; + char buffer[64]; + char *dst = s; + char *p; + + __builtin_va_list args; + __builtin_va_start(args, fmt); + + while (*fmt) { + if (*fmt == '%') { + fmt++; + // escape + if (*fmt == '%') { + goto put; + } + // string + else if (*fmt == 's') { + p = __builtin_va_arg(args, char *); + while (*p) + *dst++ = *p++; + } + // char + else if (*fmt == 'c') { + char c = __builtin_va_arg(args, int); + *dst++ = c; + } + // decimal + else if (*fmt == 'd') { + int arg = __builtin_va_arg(args, int); + if (itoa(arg, buffer, 10) != -1) { + p = buffer; + while(*p) + *dst++ = *p++; + } else { + *dst++ = '@'; + } + + } + // hex + else if (*fmt == 'x') { + long arg = __builtin_va_arg(args, long); + if (itoa(arg, buffer, 16) != -1) { + p = buffer; + while(*p) + *dst++ = *p++; + } else { + *dst++ = '@'; + } + } + } + else { + put: + *dst++ = *fmt; + } + *fmt++; + } + *dst = '\0'; + __builtin_va_end(args); + + uart_async_puts(s); +} diff --git a/lab8/kern/linker.ld b/lab8/kern/linker.ld new file mode 100644 index 000000000..2ed7e6d0f --- /dev/null +++ b/lab8/kern/linker.ld @@ -0,0 +1,44 @@ +SECTIONS +{ + . = 0xffff000000000000; + . += 0x80000; + __kernel_start = .; + .text : { + KEEP(*(.text.entry)) + *(.text .text.* .gnu.linkonce.t.*) + } + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + . = ALIGN(0x1000); + + /* The data segment */ + .data : { + *(.data) + } + + .bss ALIGN(16) (NOLOAD) : { + PROVIDE(__bss_start = .); + *(.bss) + PROVIDE(__bss_end = .); + BYTE(0) + } + + . = ALIGN(0x1000); + __kernel_pgd = .; + .data.kpgd : { + . += (515 * 0x1000); + } + + __heap_start = .; + + /DISCARD/ : { + *(.eh_frame .note.GNU-stack) + } +} + +__stack_kernel_top = 0x20000000; +__stack_user_top = 0x30000000; +__bss_size = (__bss_end - __bss_start) >> 3; \ No newline at end of file diff --git a/lab8/kern/main.c b/lab8/kern/main.c new file mode 100644 index 000000000..dabee2d72 --- /dev/null +++ b/lab8/kern/main.c @@ -0,0 +1,142 @@ +#include "peripheral/mailbox.h" +#include "kern/shell.h" +#include "kern/timer.h" +#include "kern/irq.h" +#include "kern/sched.h" +#include "kern/kio.h" +#include "kern/cpio.h" +#include "kern/mm.h" +#include "kern/pagecache.h" +#include "dtb.h" +#include "startup_alloc.h" +#include "syscall.h" +#include "string.h" +#include "fs/vfs.h" +#include "fs/fat32.h" +#include "drivers/sdhost.h" +#include "drivers/mbr.h" + +void sd_mount() { + struct fat32_boot_sector fat32_bs; + struct fat32_fsinfo_sector fat32_fsinfo; + struct mbr mbr; + + sd_init(); + readblock(0, &mbr); + + if (mbr.mbr_signature != MBR_SIGNATURE) { + kprintf("sdcard mbr signature error: %x\n", mbr.mbr_signature); + return; + } + + if (mbr.partition[0].partition_type == 0xB) { + readblock(mbr.partition[0].first_sector_lba, &fat32_bs); + + fat32_info.sec_size = fat32_bs.BPB_BytsPerSec; + fat32_info.clus_size = fat32_bs.BPB_SecPerClus; + fat32_info.first_lba = mbr.partition[0].first_sector_lba; + fat32_info.fat_lba = mbr.partition[0].first_sector_lba + fat32_bs.BPB_RsvdSecCnt; + fat32_info.fat_num = fat32_bs.BPB_NumFATs; + fat32_info.fat_size = fat32_bs.BPB_FATSz32; + fat32_info.data_lba = mbr.partition[0].first_sector_lba + fat32_bs.BPB_RsvdSecCnt + (fat32_bs.BPB_NumFATs * fat32_bs.BPB_FATSz32); + fat32_info.root_clus = fat32_bs.BPB_RootClus; + fat32_info.total_sec = fat32_bs.BPB_TotSec32; + + readblock(mbr.partition[0].first_sector_lba + fat32_bs.BPB_FSInfo, &fat32_fsinfo); + if (fat32_fsinfo.FSI_LeadSig == FSI_LEAD_SIG && fat32_fsinfo.FSI_StrucSig == FSI_STRUCT_SIG && fat32_fsinfo.FSI_Nxt_Free != FSI_NXT_FREE_UNKNOWN) { + fat32_info.fsi_next_free = fat32_fsinfo.FSI_Nxt_Free; + } else { + fat32_info.fsi_next_free = 2; + } + + vfs_mkdir("/boot"); + vfs_mount("/boot", "fat32"); + } +} + +void hw_info() { + unsigned int result[2]; + kputs("##########################################\n"); + get_board_revision(result); + kprintf("Board revision:\t\t\t0x%x\n", result[0]); + get_ARM_memory(result); + kprintf("ARM memory base address:\t0x%x\n", result[0]); + kprintf("ARM memory size:\t\t0x%x\n", result[1]); + kputs("##########################################\n"); +} + +void dtb_init() { + if (fdt_init() < 0) { + kputs("dtb: Bad magic\n"); + return; + } + if (fdt_traverse(initramfs_callback) < 0) + kputs("dtb: Unknown token\n"); + if (fdt_traverse(mm_callback) < 0) + kputs("dtb: Unknown token\n"); + kputs("dtb: init success\n"); +} + +extern unsigned int __stack_kernel_top; + +void reserve_memory() { + kprintf("page used by startup allocator\n"); + reserved_kern_startup(); + kprintf("device tree\n"); + fdt_reserve(); + kprintf("initramfs\n"); + cpio_reserve(); + kprintf("initial kernel stack\n"); + mm_reserve((void *)PHY_2_VIRT((void *)&__stack_kernel_top - 0x2000), (void *)PHY_2_VIRT((void *)&__stack_kernel_top)); +} + +void user_prog() { + exec("/initramfs/vfs2.img", 0); + exit(); +} + +void idle_task() { + while(1) { + schedule(); + } +} + +void initramfs_init() { + vfs_mkdir("/initramfs"); + vfs_mount("/initramfs", "initramfs"); +} + +#include "test_func.h" + +void kern_main() { + kio_init(); + mm_init(); + rootfs_init(); + runqueue_init(); + task_init(); + int_init(); + core_timer_enable(); + unsigned long tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); + timer_sched_latency(); + + kputs("press any key to continue..."); + kscanc(); + kputs("\n"); + dtb_init(); + hw_info(); + + reserve_memory(); + + initramfs_init(); + pagecache_init(); + sd_mount(); + // fs_test(); + // fat_test(); + + thread_create(user_prog); + privilege_task_create(kill_zombies, 10); + idle_task(); +} \ No newline at end of file diff --git a/lab8/kern/mm.c b/lab8/kern/mm.c new file mode 100644 index 000000000..3f92d707d --- /dev/null +++ b/lab8/kern/mm.c @@ -0,0 +1,242 @@ +#include "kern/mm.h" +#include "kern/kio.h" +#include "startup_alloc.h" + +#include "string.h" +#include "byteswap.h" + +unsigned int phy_address_start = 0; +unsigned int phy_address_limit = 0x3C000000; + +void mm_callback(char *node_name, char *prop_name, void *prop_value) { + if (!strncmp(node_name, "memory", 6) && !strncmp(prop_name, "reg", 3)) { + kputs("mm: Find!\n"); + phy_address_start = __bswap_32(*((unsigned int *)(prop_value))); + phy_address_limit = __bswap_32(*((unsigned int *)(prop_value+4))); + kprintf("physical start address: 0x%x\n", phy_address_start); + kprintf("physical address limit: 0x%x\n", phy_address_limit); + } +} + +struct free_area *free_area; +struct page *frames; + +struct page *get_page_from_addr(void *addr) { + int pfn = PHY_2_PFN(VIRT_2_PHY(addr)); + return &frames[pfn]; +} + +void buddy_alloc_ds() { + frames = (struct page *)sumalloc(sizeof(struct page) * PHY_FRAMES_NUM); + free_area = (struct free_area *)sumalloc(sizeof(struct free_area) * (MAX_ORDER+1)); +} + +void add_to_free_area(struct page *page, struct free_area *free_area) { + free_area->nr_free++; + // kprintf("------add_to_free_area %d(%x) %d %x %d\n", page->pg_index, PFN_2_PHY(page->pg_index), page->compound_order, free_area, free_area->nr_free); + list_add_tail(&page->list, &free_area->free_list); +} + +void del_page_from_free_area(struct page *page, struct free_area *free_area) { + free_area->nr_free--; + // kprintf("------del_page_from_free_area %d(%x) %d %x %d\n", page->pg_index, PFN_2_PHY(page->pg_index), page->compound_order, free_area, free_area->nr_free); + list_del(&page->list); +} + +struct page* expand(struct page *page, unsigned int order) { + struct page *redundant; + unsigned int porder = page->compound_order; + + if (porder > order && porder > 0) { + // kprintf("Release %d, ask for, %d\n", porder, order); + porder--; + redundant = page + (1 << porder); + page->compound_order = porder; + redundant->flags = PG_HEAD; + redundant->compound_order = porder; + add_to_free_area(redundant, &free_area[redundant->compound_order]); + return expand(page, order); + } + page->flags = PG_USED; + return page; +} + +struct page* rmqueue(struct free_area *free_area, unsigned int order) { + struct page *hpage; + if (list_empty(&free_area->free_list)) + return 0; + hpage = list_entry(free_area->free_list.next, struct page, list); + del_page_from_free_area(hpage, free_area); + return expand(hpage, order); +} + +struct page* alloc_pages(unsigned int order) { + struct page *page; + if (order >= MAX_ORDER) + return 0; + for (int i=order ; i 0) { + page = rmqueue(&free_area[i], order); + if (page) { + // kprintf("Alloc new buddy: %d, %x, %d\n", page->pg_index, page->pg_index*PAGE_SIZE, page->compound_order); + return page; + } + } + } + return 0; +} + +/* +You can use the block’s index xor with its exponent to find its buddy. +If its buddy is in the page frame array, then you can merge them to a larger block. +*/ +struct page* find_buddy(struct page *page) { + int buddy_index = page->pg_index ^ (1 << page->compound_order); + if (buddy_index >= PHY_FRAMES_NUM) + return 0; + return &frames[buddy_index]; +} + +void free_pages(void *addr) { + struct page *page = get_page_from_addr(addr); + struct page *buddy; + int order = page->compound_order; + + // kprintf("\tFree buddy: %d, %x, %d\n", page->pg_index, page->pg_index*PAGE_SIZE, page->compound_order); + while(order < MAX_ORDER) { + buddy = find_buddy(page); + // kprintf("\tBuddy page: %d, %x, %d\n", buddy->pg_index, buddy->pg_index*PAGE_SIZE, buddy->compound_order); + if (!buddy || buddy->flags != PG_HEAD || buddy->compound_order != order) { + page->flags = PG_HEAD; + add_to_free_area(page, &free_area[page->compound_order]); + break; + } + // kprintf("\tBuddy page: %d, %x, %d\n", buddy->pg_index, buddy->pg_index*PAGE_SIZE, buddy->compound_order); + // kprintf("\tMerge %d to %d\n", order, order+1); + + // order == buddy->compound_order + del_page_from_free_area(buddy, &free_area[order]); + if (buddy > page) { // | page | buddy | + page->compound_order = order+1; + buddy->flags = PG_TAIL; + } else { // | buddy | page | + buddy->compound_order = order+1; + page->flags = PG_TAIL; + page = buddy; + } + order = page->compound_order; + } +} + +// start of kernel frame +extern unsigned int __heap_start; + +void mm_init() { + int i; + int cnt = 0; + int order = MAX_ORDER - 1; + + int kernel_data_end = (long)(&__heap_start) / PAGE_SIZE; + int mem_end = phy_address_limit / PAGE_SIZE - 50; + + buddy_alloc_ds(); + + + for (i=0 ; i= mem_end) + order--; + frames[i].flags = PG_HEAD; + frames[i].compound_order = order; + add_to_free_area(&frames[i], &free_area[order]); + cnt = (1 << order) - 1; + } else { + frames[i].flags = PG_TAIL; + frames[i].compound_order = 0; + cnt--; + } + } + + for ( ; icompound_order; + unsigned int cl = page->pg_index; + unsigned int cr = cl + (1 << porder) - 1; + unsigned int mid; + + if (cl > r || cr < l) { + add_to_free_area(page, &free_area[porder]); + return; + } + // no need to split + if (cl >= l && cr <= r) { + // kprintf("\tReserved range: %d-%d\n", cl, cr); + page->flags = PG_USED; + return; + } + // split + mid = (cl + cr) >> 1; + porder--; + buddy = &frames[mid+1]; + page->compound_order = porder; + buddy->flags = PG_HEAD; + buddy->compound_order = porder; + expand_reserve(page, l, r); + expand_reserve(buddy, l, r); +} + +// Mark the page from start to end as used +void mm_reserve(void *start, void *end) { + unsigned int ps = PHY_2_PFN(VIRT_2_PHY(start)); + unsigned int pe = PHY_2_PFN(VIRT_2_PHY(end)); + unsigned int pi = ps; + struct page *page; + int i; + + kprintf("\tReserve 0x%x-0x%x\n", VIRT_2_PHY(start), VIRT_2_PHY(end)); + for (i=ps ; i<=pe ; i++) if (frames[i].flags == PG_USED) { + kputs("\tTry to reserved page that are already been used...\n"); + return; + } + + do { + // find the header page of start address, linear search for now + while(pi >= 0) { + page = &frames[pi--]; + if (page->flags == PG_HEAD) + break; + } + pi = page->pg_index + (1<compound_order); + del_page_from_free_area(page, &free_area[page->compound_order]); + expand_reserve(page, ps, pe); + } while(pi <= pe); +} \ No newline at end of file diff --git a/lab8/kern/page.c b/lab8/kern/page.c new file mode 100644 index 000000000..cfcd37e80 --- /dev/null +++ b/lab8/kern/page.c @@ -0,0 +1,158 @@ +#include "mmu.h" +#include "string.h" +#include "kern/slab.h" +#include "kern/kio.h" +#include "kern/mm_types.h" + +void *pgtable_walk(unsigned long *table, unsigned long idx) { + if (!table) { + kprintf("pgtable_walk failed"); + return 0; + } + if (!table[idx]) { + void *new_page = kmalloc(PAGE_SIZE); + if (!new_page) + return 0; + memset(new_page, 0, PAGE_SIZE); + table[idx] = VIRT_2_PHY((unsigned long)new_page) | PD_TABLE; + } + return (void*)PHY_2_VIRT(table[idx] & PAGE_MASK); +} + +void *pgtable_walk_pte(unsigned long *table, unsigned long idx, unsigned long paddr) { + if (!table) { + kprintf("pgtable_walk_pte failed"); + return 0; + } + if (!table[idx]) { + if (paddr == 0) { + void *new_page = kmalloc(PAGE_SIZE); + if (!new_page) + return 0; + memset(new_page, 0, PAGE_SIZE); + table[idx] = VIRT_2_PHY((unsigned long)new_page) | PTE_NORMAL_ATTR | PD_USER_RW; + } else + table[idx] = paddr | PTE_NORMAL_ATTR | PD_USER_RW; + } + return (void*)PHY_2_VIRT(table[idx] & PAGE_MASK); +} + +void pgtable_walk_block(unsigned long *table, unsigned long idx, unsigned long paddr) { + if (!table) { + kprintf("pgtable_walk_block failed"); + return; + } + if (!table[idx]) { + table[idx] = paddr | PUD1_ATTR | PD_USER_RW; + } +} + +void *walk(struct mm_struct *mm, unsigned long vaddr, unsigned long paddr) { + void *pud; + void *pmd; + void *pte; + + pud = pgtable_walk(mm->pgd, pgd_index(vaddr)); + pmd = pgtable_walk(pud, pud_index(vaddr)); + pte = pgtable_walk(pmd, pmd_index(vaddr)); + return pgtable_walk_pte(pte, pte_index(vaddr), paddr) + (vaddr & (PAGE_SIZE-1)); +} + +void *mappages(struct mm_struct *mm, unsigned long vaddr, unsigned long size, unsigned long paddr) { + if (!mm->pgd) + return 0; + for (int i=0 ; ipgd) + return; + void *pud; + pud = pgtable_walk(mm->pgd, pgd_index(vaddr)); + pgtable_walk_block(pud, pud_index(vaddr), paddr); +} + +void create_pgd(struct mm_struct *mm) { + void *new_page = kmalloc(PAGE_SIZE); + if (!new_page) + return; + memset(new_page, 0, PAGE_SIZE); + mm->pgd = new_page; +} + +void free_pgtable(unsigned long *table, int level) { + void *next; + for(int i=0 ; i<512 ; i++) { + if (table[i]) { + next = (void*)PHY_2_VIRT(table[i] & PAGE_MASK); + if (level != 4) + free_pgtable(next, level+1); + // if device memory + if (level == 4 && VIRT_2_PHY(next) >= 0x3C000000) + continue; + kfree(next); + } + } +} + +void free_pgd(struct mm_struct *mm) { + unsigned long *pgd = mm->pgd; + void *pud; + for(int i=0 ; i<512 ; i++) { + if (pgd[i]) { + pud = (void*)PHY_2_VIRT(pgd[i] & PAGE_MASK); + free_pgtable(pud, 2); + kfree(pud); + } + } + kfree(pgd); +} + +/* + level + pgd 1 + pud 2 + pmd 3 + pte 4 +*/ +void fork_pgtable(unsigned long *ptable, unsigned long *ctable, int level) { + void *pnext; + void *cnext; + + for(int i=0 ; i<512 ; i++) { + if (ptable[i]) { + pnext = (void*)PHY_2_VIRT(ptable[i] & PAGE_MASK); + if (level == 4) { + cnext = pgtable_walk_pte(ctable, i, 0); + memcpy(cnext, pnext, PAGE_SIZE); + } else { + cnext = pgtable_walk(ctable, i); + fork_pgtable(pnext, cnext, level+1); + } + } + } +} + +void fork_pgd(struct mm_struct *parent_mm, struct mm_struct *child_mm) { + unsigned long *ppgd = parent_mm->pgd; + unsigned long *cpgd = child_mm->pgd; + void *ppud; + void *cpud; + + if (!ppgd || !cpgd) + return; + + for(int i=0 ; i<512 ; i++) { + if (ppgd[i]) { + ppud = (void*)PHY_2_VIRT(ppgd[i] & PAGE_MASK); + cpud = pgtable_walk(cpgd, i); + fork_pgtable(ppud, cpud, 2); + } + } +} \ No newline at end of file diff --git a/lab8/kern/pagecache.c b/lab8/kern/pagecache.c new file mode 100644 index 000000000..dbbf6465d --- /dev/null +++ b/lab8/kern/pagecache.c @@ -0,0 +1,69 @@ +/* + pagecache used for FAT32 partition only +*/ +#include "kern/kio.h" +#include "kern/slab.h" +#include "kern/pagecache.h" +#include "drivers/sdhost.h" +#include "string.h" + +struct filepage { + unsigned int lba; + void *data; + struct list_head list; +}; + +struct list_head clean_list; +struct list_head dirty_list; + +struct filepage *lba_map; +unsigned int offset; + +#define LBA_MAP_MAX 50000 +#define LBA_OFFSET 2048 + +void pagecache_init() { + INIT_LIST_HEAD(&clean_list); + INIT_LIST_HEAD(&dirty_list); + lba_map = (struct filepage *)kmalloc(sizeof(struct filepage) * LBA_MAP_MAX); + memset(lba_map, 0, sizeof(struct filepage) * LBA_MAP_MAX); +} + +void* pagecache_read(int lba) { + if (lba_map[lba - LBA_OFFSET].data == 0) { + lba_map[lba - LBA_OFFSET].data = kmalloc(BLOCK_SIZE); + lba_map[lba - LBA_OFFSET].lba = lba; + readblock(lba, lba_map[lba - LBA_OFFSET].data); + // add to clean page list + INIT_LIST_HEAD(&lba_map[lba - LBA_OFFSET].list); + list_add_tail(&lba_map[lba - LBA_OFFSET].list, &clean_list); + } +#ifdef DEBUG_PAGECACHE + kprintf("read pagecache %d\n", lba); +#endif + return lba_map[lba - LBA_OFFSET].data; +} + +void pagecache_dirty(int lba) { + if (lba_map[lba - LBA_OFFSET].data == 0) { + kprintf("Warning: try to mark uncached data dirty\n"); + return; + } +#ifdef DEBUG_PAGECACHE + kprintf("write pagecache %d\n", lba); +#endif + list_del(&lba_map[lba - LBA_OFFSET].list); + list_add_tail(&lba_map[lba - LBA_OFFSET].list, &dirty_list); +} + +void pagecache_write_back() { + struct list_head *ptr; + struct list_head *tmp; + struct filepage *dpage; + list_for_each_safe(ptr, tmp, &dirty_list) { + dpage = list_entry(ptr, struct filepage, list); + writeblock(dpage->lba, dpage->data); + list_del(&dpage->list); + list_add_tail(&dpage->list, &clean_list); + } +} diff --git a/lab8/kern/sched.S b/lab8/kern/sched.S new file mode 100644 index 000000000..fb7019ca6 --- /dev/null +++ b/lab8/kern/sched.S @@ -0,0 +1,41 @@ + + +.global switch_to +switch_to: + stp x19, x20, [x0, 16 * 0] + stp x21, x22, [x0, 16 * 1] + stp x23, x24, [x0, 16 * 2] + stp x25, x26, [x0, 16 * 3] + stp x27, x28, [x0, 16 * 4] + stp fp, lr, [x0, 16 * 5] + mov x9, sp + str x9, [x0, 16 * 6] + + ldp x19, x20, [x1, 16 * 0] + ldp x21, x22, [x1, 16 * 1] + ldp x23, x24, [x1, 16 * 2] + ldp x25, x26, [x1, 16 * 3] + ldp x27, x28, [x1, 16 * 4] + ldp fp, lr, [x1, 16 * 5] + ldr x9, [x1, 16 * 6] + mov sp, x9 + ret + +.global update_current +update_current: + msr tpidr_el1, x0 + ret + +.global get_current +get_current: + mrs x0, tpidr_el1 + ret + +.global update_pgd +update_pgd: + 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 + ret \ No newline at end of file diff --git a/lab8/kern/sched.c b/lab8/kern/sched.c new file mode 100644 index 000000000..d410f1013 --- /dev/null +++ b/lab8/kern/sched.c @@ -0,0 +1,344 @@ +#include "kern/sched.h" +#include "kern/irq.h" +#include "kern/slab.h" +#include "kern/kio.h" +#include "string.h" +#include "fs/vfs.h" + +#define ROUND_UP(n,d) (((n) + (d-1)) & (-d)) +#define ROUND_DOWN(n,d) ((n) & (-d)) + +// ############## runqueue ################## + +struct prio_array { + DECLARE_BITMAP(bitmap, MAX_PRIO); + struct list_head queue[MAX_PRIO]; +}; + +struct runqueue { + unsigned long nr_running; + struct prio_array array; +}; + +struct runqueue runqueue; +struct list_head zombie_queue; +char kernel_stack[MAX_PRIV_TASK_NUM][STACKSIZE]; +char user_stack[MAX_PRIV_TASK_NUM][STACKSIZE]; + +void runqueue_init() { + int i; + struct prio_array *array = &runqueue.array; + runqueue.nr_running = 0; + for(i=0 ; iqueue[i]); + } + bitmap_zero(array->bitmap, MAX_PRIO); + INIT_LIST_HEAD(&zombie_queue); +} + +void runqueue_push(struct task_struct *new_task) { + struct prio_array *array = &runqueue.array; + + runqueue.nr_running += 1; + __set_bit(new_task->prio, array->bitmap); + list_add_tail(&new_task->list, &array->queue[new_task->prio]); +} + +struct task_struct* runqueue_pop() { + int highest_prio; + struct task_struct *next_task; + struct prio_array *array = &runqueue.array; + + highest_prio = sched_find_first_bit(array->bitmap); + // no task in queue + if (highest_prio == MAX_PRIO) + return 0; + + runqueue.nr_running -= 1; + next_task = list_entry(array->queue[highest_prio].next, struct task_struct, list); + list_del(&next_task->list); + if (list_empty(&array->queue[highest_prio])) + __clear_bit(highest_prio, array->bitmap); + return next_task; +} + +// ############## priv task ################## + +struct task_struct task_pool[MAX_PRIV_TASK_NUM]; +struct task_struct *utask[1000]; +int pid; // start from 1000 + +inline int get_priv_tid() { + int i; + for(i=0 ; iroot; + task_pool[0].croot = rootfs->root; + fd_init(&task_pool[0].files); + task_pool[0].mm.pgd = (unsigned long *)&__kernel_pgd; + INIT_LIST_HEAD(&task_pool[0].signal_pend_list); + update_current(&task_pool[0]); + pid = 1000; +} + +struct task_struct *privilege_task_create(void (*func)(), int prio) { + struct task_struct *new_task; + unsigned long stk_addr; + int tid = -1; + + if (prio > 20 || prio < 1) + return 0; + + tid = get_priv_tid(); + if (tid == -1) + return 0; + + + new_task = &task_pool[tid]; + new_task->used = 1; + new_task->prio = prio; + new_task->state = RUNNING; + new_task->ctime = TASK_CTIME; + new_task->resched = 0; + new_task->cwd = rootfs->root; + new_task->croot = rootfs->root; + fd_init(&new_task->files); + create_pgd(&new_task->mm); + INIT_LIST_HEAD(&new_task->signal_list); + INIT_LIST_HEAD(&new_task->signal_pend_list); + + // kernel stack + stk_addr = (unsigned long)&kernel_stack[tid][4095]; + stk_addr = ROUND_DOWN(stk_addr, 16); + new_task->task_context.lr = (unsigned long)func; + new_task->task_context.fp = stk_addr; + new_task->task_context.sp = stk_addr; + new_task->stk_addr = (void*)stk_addr; + + runqueue_push(new_task); + return new_task; +} + +// ############## normal task ################## + +struct task_struct *task_create(void (*func)(), int prio) { + unsigned long stk_addr; + struct task_struct *new_task; + + if (prio <= 20) + return 0; + + new_task = kmalloc(sizeof(struct task_struct)); + if (!new_task) + return 0; + + int_disable(); + + utask[pid-1000] = new_task; + new_task->tid = pid++; + new_task->prio = prio; + new_task->state = RUNNING; + new_task->ctime = TASK_CTIME; + new_task->resched = 0; + new_task->cwd = rootfs->root; + new_task->croot = rootfs->root; + fd_init(&new_task->files); + create_pgd(&new_task->mm); + INIT_LIST_HEAD(&new_task->signal_list); + INIT_LIST_HEAD(&new_task->signal_pend_list); + + // kernel stack + stk_addr = (unsigned long)kmalloc(STACKSIZE); + stk_addr = stk_addr + STACKSIZE; + stk_addr = ROUND_DOWN(stk_addr, 16); + new_task->task_context.lr = (unsigned long)func; + new_task->task_context.fp = stk_addr; + new_task->task_context.sp = stk_addr; + new_task->stk_addr = (void*)stk_addr; + + int_enable(); + + return new_task; +} + +int task_fork(void (*func)(), struct task_struct *parent, void *trapframe) { + int i; + unsigned long offset; + char *pptr; + char *cptr; + struct trapframe* child_trapframe; + struct trapframe* parent_trapframe; + struct task_struct *child = task_create(func, parent->prio); + + if (!child) + return -1; + + int_disable(); + + // setup kernel stack + cptr = (char *)child->stk_addr; + pptr = (char *)parent->stk_addr; + offset = pptr - (char*)trapframe; + for (i=0 ; itask_context.sp = (unsigned long)child->stk_addr - offset; + + // setup user stack + fork_pgd(&parent->mm, &child->mm); + mappages(&child->mm, 0x3C000000, 0x3000000, 0x3C000000); + child_trapframe = (struct trapframe *)child->task_context.sp; + parent_trapframe = (struct trapframe *)trapframe; + child_trapframe->sp_el0 = parent_trapframe->sp_el0; + child_trapframe->x[0] = 0; + + if (list_empty(&parent->signal_list)) + goto out; + // signal copy + struct list_head *ptr; + struct signal_t *signal; + struct signal_t *new_signal; + list_for_each(ptr, &parent->signal_list) { + signal = list_entry(ptr, struct signal_t, list); + new_signal = signal_create(signal->num, signal->handler); + list_add_tail(&new_signal->list, &child->signal_list); + } +out: + runqueue_push(child); + int_enable(); + + return child->tid; +} + +void thread_create(void (*func)()) { + struct task_struct *new_taks = task_create(func, 100); + runqueue_push(new_taks); +} + +// ############################################# + +void context_switch(struct task_struct *next) { + struct task_struct *prev = get_current(); + if (prev->state == RUNNING) { + runqueue_push(prev); + } else if (prev->state == DEAD) { + kprintf("Process %d dead...\n", prev->tid); + if (prev->tid >= 1000) + list_add_tail(&prev->list, &zombie_queue); + else + prev->used = 0; + } + // kprintf("context switch %d ~ %d\n", prev->tid, next->tid); + update_pgd(VIRT_2_PHY(next->mm.pgd)); + update_current(next); + switch_to(&prev->task_context, &next->task_context); +} + +void schedule() { + struct task_struct *next = runqueue_pop(); + if (next != 0) { + context_switch(next); + } +} + +void kill_zombies() { + struct task_struct *to_release; + struct list_head *itr; + struct list_head *tmp; + + while(1) { + if (list_empty(&zombie_queue)) { + schedule(); + } + + int_disable(); + list_for_each_safe(itr, tmp, &zombie_queue) { + to_release = list_entry(itr, struct task_struct, list); + kprintf("Kill zombie %d\n", to_release->tid); + kfree(to_release->stk_addr); + // free_pgd(&to_release->mm); + // kfree(to_release); + list_del(itr); + } + int_enable(); + } +} + +struct task_struct* get_task_struct(int pid) { + if (pid < 1000) + return &task_pool[pid]; + else { + return utask[pid-1000]; + } +} + +// ############## sys call ################## + +int __getpid() { + struct task_struct *current = get_current(); + return current->tid; +} + +void __exec(const char *name, char *const argv[]) { + struct task_struct *current = get_current(); + struct file *file_node; + long filesize; + char *user_prog; + + if (vfs_open(name, 0, &file_node) < 0) { + kprintf("Failed to exec %s", name); + return; + } + + filesize = vfs_lseek64(file_node, 0, SEEK_END); + vfs_lseek64(file_node, 0, SEEK_SET); + user_prog = kmalloc(filesize); + vfs_read(file_node, user_prog, filesize); + + mappages(¤t->mm, 0x0, 250000, VIRT_2_PHY(user_prog)); + mappages(¤t->mm, USER_STK_LOW, STACKSIZE, 0); + + asm volatile("msr sp_el0, %0" : : "r"(USER_STK_HIGH)); + asm volatile("msr elr_el1, %0": : "r"(0x0)); + asm volatile("msr spsr_el1, %0" : : "r"(0b0)); + asm volatile("eret"); +} + +extern void return_from_fork(); + +int __fork(void *trapframe) { + struct task_struct *parent = get_current(); + return task_fork(return_from_fork, parent, trapframe); +} + +void __exit() { + struct task_struct *current = get_current(); + current->state = DEAD; + schedule(); +} + +void __kill(int pid) { + if (pid <= 0) + return; + struct task_struct* target = get_task_struct(pid); + target->state = DEAD; +} \ No newline at end of file diff --git a/lab8/kern/shell.c b/lab8/kern/shell.c new file mode 100644 index 000000000..0b8b58e63 --- /dev/null +++ b/lab8/kern/shell.c @@ -0,0 +1,75 @@ +#include "kern/kio.h" +#include "kern/shell.h" +#include "kern/timer.h" +#include "kern/sched.h" +#include "kern/cpio.h" +#include "kern/mm.h" +#include "string.h" +#include "reset.h" + +void shell_input(char *cmd) { + char c; + unsigned int len = 0; + + while((c = kscanc()) != '\n') { + if (c == BACKSPACE || c == DELETE) { + if (!len) + continue; + LEFT_SHIFT + kputc(' '); + LEFT_SHIFT + --len; + } else if (c == ESC) { + kscanc(); + kscanc(); + } else { // regular letter + kputc(c); + cmd[len++] = c; + } + } + kputs("\n"); + cmd[len] = '\0'; +} + +void shell_help() { + kputs("help\t\t: print this help menu\n"); + kputs("hello\t\t: print Hello World!\n"); + kputs("ls\t\t: list file\n"); + kputs("cat\t\t: print file content\n"); + kputs("exec\t\t: execute a file\n"); + kputs("setTimeout\t: MESSAGE SECONDS\n"); + kputs("reboot\t\t: reboot the device\n"); +} + +void shell_parse(char *cmd) { + char args[MAX_INPUT_LEN]; + if (!strcmp(cmd, "help")) { + shell_help(); + } else if (!strcmp(cmd, "hello")) { + kputs("Hello World!\n"); + } else if (!strcmp(cmd, "ls")) { + cpio_ls(); + } else if (!strcmp(cmd, "cat")) { + kputs("FileName: "); + shell_input(args); + cpio_cat(args); + } else if (!strcmp(cmd, "setTimeout")) { + shell_input(args); + set_timeout(args); + } else if (!strcmp(cmd, "reboot")) { + kputs("About to reboot...\n"); + reset(1000); + } else { + kputs(cmd); + kputs(": command not found\n"); + } +} + +void shell_start() { + char cmd[128]; + while (1) { + kputs("raspi3> "); + shell_input(cmd); + shell_parse(cmd); + } +} \ No newline at end of file diff --git a/lab8/kern/signal.c b/lab8/kern/signal.c new file mode 100644 index 000000000..62d0dfe2a --- /dev/null +++ b/lab8/kern/signal.c @@ -0,0 +1,113 @@ +#include "kern/signal.h" +#include "kern/sched.h" +#include "kern/slab.h" +#include "kern/kio.h" +#include "kern/irq.h" +#include "string.h" + +struct signal_t *signal_create(int SIGNAL, void (*handler)()) { + struct signal_t *new_signal = kmalloc(sizeof(struct signal_t)); + new_signal->num = SIGNAL; + new_signal->handler = handler; + INIT_LIST_HEAD(&new_signal->list); + return new_signal; +} + +void signal_default(int pid, int SIGNAL) { + switch(SIGNAL) { + case SIGKILL: + __kill(pid); + break; + default: + kprintf("Undefined signal number...\n"); + } +} + +void signal_return() { + asm volatile( + "mov x8, #30 \n\t" + "svc #0 \n\t" + ); +} + +void signal_jump(void *trapframe, void (*handler)()) { + struct trapframe *tf = trapframe; + struct task_struct *current = get_current(); + struct signal_context_t *signal_context = kmalloc(sizeof(struct signal_context_t)); + signal_context->stk_addr = kmalloc(4096); + signal_context->trapframe = kmalloc(sizeof(struct trapframe)); + // kprintf("Ready to jump %x %x %x\n", signal_context, signal_context->stk_addr, signal_context->trapframe); + memcpy(signal_context->trapframe, trapframe, sizeof(struct trapframe)); + + current->signal_context = signal_context; + + // return address save in x30 in ARM + tf->x[30] = (long)signal_return; + tf->elr_el1 = (long)handler; + tf->sp_el0 = (long)signal_context->stk_addr; +} + +void signal_back(void *trapframe) { + struct task_struct *current = get_current(); + // kprintf("Back %x %x\n", current->signal_context, current->signal_context->trapframe); + memcpy(trapframe, current->signal_context->trapframe, sizeof(struct trapframe)); + kfree(current->signal_context->trapframe); + kfree(current->signal_context->stk_addr); + kfree(current->signal_context); +} + + +void __signal(int SIGNAL, void (*handler)()) { + struct list_head *ptr; + struct signal_t *signal; + struct task_struct *current = get_current(); + + if (list_empty(¤t->signal_list)) + goto regis; + list_for_each(ptr, ¤t->signal_list) { + signal = list_entry(ptr, struct signal_t, list); + if (signal->num == SIGNAL) { + kprintf("Overwite existing registed signal(%d)\n", SIGNAL); + list_del(&signal->list); + break; + } + } +regis: + signal = signal_create(SIGNAL, handler); + list_add_tail(&signal->list, ¤t->signal_list); +} + +void __sigkill(int pid, int SIGNAL, void *trapframe) { + struct signal_pend_t *signal_pend; + struct task_struct *target = get_task_struct(pid); + if (list_empty(&target->signal_list)) + goto default_sig; + + signal_pend = kmalloc(sizeof(struct signal_pend_t)); + signal_pend->num = SIGNAL; + INIT_LIST_HEAD(&signal_pend->list); + + list_add_tail(&signal_pend->list, &target->signal_pend_list); + return; +default_sig: + signal_default(pid, SIGNAL); +} + +void signal_run(void *trapframe) { + struct task_struct *current = get_current(); + if (list_empty(¤t->signal_pend_list)) + return; + + struct list_head *ptr; + struct signal_t *signal; + struct signal_pend_t *signal_pend; + signal_pend = list_entry(current->signal_pend_list.next, struct signal_pend_t, list); + list_del(&signal_pend->list); + list_for_each(ptr, ¤t->signal_list) { + signal = list_entry(ptr, struct signal_t, list); + if (signal->num == signal_pend->num) { + signal_jump(trapframe, signal->handler); + return; + } + } +} \ No newline at end of file diff --git a/lab8/kern/slab.c b/lab8/kern/slab.c new file mode 100644 index 000000000..1114a27f6 --- /dev/null +++ b/lab8/kern/slab.c @@ -0,0 +1,177 @@ +#include "kern/mm.h" +#include "kern/kio.h" +#include "startup_alloc.h" + +#define PREALLOC_SIZE 100 + +/* + slab_t +*/ +struct slab_t* pmalloc_slab() { + struct slab_t *ret; + ret = (struct slab_t *)sumalloc(sizeof(struct slab_t)); + return ret; +} + + +struct kmem_pool *kmalloc_pools; + +void slab_alloc_ds() { + kmalloc_pools = (struct kmem_pool *)sumalloc(sizeof(struct kmem_pool) * MAX_OBJ_CACHE_NUM); +} + +struct kmem_pool* kmalloc_slab(unsigned int size) { + unsigned int rounded_size; + int pool_id; + + if (size <= SMALL_OBJ_SIZE) { + rounded_size = (size + 7) & -8; + pool_id = rounded_size / 8 - 1; + } else if (size <= MEDIUM_OBJ_SIZE) { + size -= SMALL_OBJ_SIZE; + pool_id = 15 + (size + 11) / 12; + } else { + for(pool_id=24 ; pool_id= MAX_OBJ_CACHE_NUM) + return 0; + kmalloc_pools[pool_id].object_size = size; + kmalloc_pools[pool_id].num = PAGE_SIZE*4 / size; + } + return &kmalloc_pools[pool_id]; +} + +struct slab_t* slab_create(struct kmem_pool *pool) { + struct slab_t *slab; + struct page *page; + + page = alloc_pages(pool->gfporder); + page->flags = PG_SLAB; + + slab = pmalloc_slab(); + slab->inuse = 0; + slab->nr_free = pool->num; + slab->head_addr = (void*)PFN_2_PHY(page->pg_index); + INIT_LIST_HEAD(&slab->free_list); + INIT_LIST_HEAD(&slab->list); + + page->slab = slab; + + return slab; +} + +void* slab_alloc(struct kmem_pool *pool) { + struct slab_t *slab; + struct list_head *ptr; + void *ret; + + if (list_empty(&pool->slab_list)) + goto new_slab; + + list_for_each(ptr, &pool->slab_list) { + slab = list_entry(ptr, struct slab_t, list); + if (slab->nr_free > 0) + break; + } + + if (slab->nr_free == 0) { +new_slab: + slab = slab_create(pool); + list_add_tail(&slab->list, &pool->slab_list); + } + + slab->inuse++; + slab->nr_free--; + if (!list_empty(&slab->free_list)) { + ptr = slab->free_list.next; + list_del(ptr); + return (void*)ptr; + } + ret = slab->head_addr + (slab->inuse-1) * pool->object_size; + return ret; +} + +void* __do_kmalloc(unsigned int size) { + struct kmem_pool *cachep; + void *ret; + + cachep = kmalloc_slab(size); + if (!cachep) { + kputs("Unable to find kmem_pool...\n"); + return 0; + } + ret = slab_alloc(cachep); + return ret; +} + +void* kmalloc(unsigned int size) { + int i; + void *ret; + struct page *page; + + if (size == 0) + return 0; + + if (size >= PAGE_SIZE) { + for (i=0 ; ipg_index); + // kprintf("kmalloc: buddy %x\n", ret); + } else { + ret = __do_kmalloc(size); + // kprintf("kmalloc: slab %x\n", ret); + } + return ret == 0 ? 0 : (void*)PHY_2_VIRT(ret); +} + +void kfree(void *addr) { + struct slab_t *slab; + struct page *page = get_page_from_addr(addr); + + if (page->flags == PG_SLAB) { + slab = page->slab; + list_add_tail((struct list_head*)addr, &slab->free_list); + slab->inuse--; + slab->nr_free++; + } else { + free_pages(addr); + } +} + + +void slab_init() { + int i; + + slab_alloc_ds(); + + for (i=0 ; ix[0] = __getpid(); +} + +inline void sys_uart_read(struct trapframe *trapframe) { + int i; + int size = trapframe->x[1]; + char *buf = (char *)trapframe->x[0]; + for(i=0 ; ix[0] = i; +} + +inline void sys_uart_write(struct trapframe *trapframe) { + int i; + char *buf = (char *)trapframe->x[0]; + int size = trapframe->x[1]; + for(i=0 ; ix[0] = i; +} + +inline void sys_exec(struct trapframe *trapframe) { + const char *name = (const char *)trapframe->x[0]; + __exec(name, (void*)trapframe->x[1]); + trapframe->x[0] = 0; +} + +inline void sys_fork(struct trapframe *trapframe) { + trapframe->x[0] = __fork(trapframe); +} + +inline void sys_exit(struct trapframe *trapframe) { + __exit(); +} + +inline void sys_mbox_call(struct trapframe *trapframe) { + unsigned char ch = trapframe->x[0]; + unsigned int *mailbox = (unsigned int *)trapframe->x[1]; + unsigned int *kernel_addr = walk((struct mm_struct *)&(get_current()->mm.pgd), (unsigned long)mailbox, 0); + trapframe->x[0] = mailbox_call(ch, kernel_addr); +} + +inline void sys_kill(struct trapframe *trapframe) { + __kill(trapframe->x[0]); +} + +inline void sys_signal(struct trapframe *trapframe) { + __signal(trapframe->x[0], (void*)trapframe->x[1]); +} + +inline void sys_sigkill(struct trapframe *trapframe) { + __sigkill(trapframe->x[0], trapframe->x[1], trapframe); +} + +inline void sys_sigreturn(struct trapframe *trapframe) { + signal_back(trapframe); +} + +inline void sys_open(struct trapframe *trapframe) { + int fd; + struct file *fh; + const char *pathname = (char *)trapframe->x[0]; + int flags = trapframe->x[1]; + int ret = vfs_open(pathname, flags, &fh); +#ifdef DEBUG_FS + kprintf("open(%s, %d)\n", pathname, flags); +#endif + if (ret < 0) { + trapframe->x[0] = ret; + return; + } + fd = fd_open(&(get_current()->files), fh); + trapframe->x[0] = fd; +} + +inline void sys_close(struct trapframe *trapframe) { + struct file *fh; + int fd = trapframe->x[0]; +#ifdef DEBUG_FS + kprintf("close(%d)\n", fd); +#endif + if (fd < 0) { + trapframe->x[0] = -1; + return; + } + fh = fd_close(&(get_current()->files), fd); + trapframe->x[0] = vfs_close(fh); +} + +inline void sys_write(struct trapframe *trapframe) { + struct file *fh; + int fd = trapframe->x[0]; + const char *buf = (char *)trapframe->x[1]; + unsigned long count = trapframe->x[2]; +#ifdef DEBUG_FS + kprintf("write(%d, %s, %d)\n", fd, buf, count); +#endif + if (fd < 0) { + trapframe->x[0] = -1; + return; + } + fh = fd_get(&(get_current()->files), fd); + if (fh == 0) { + trapframe->x[0] = -1; + return; + } + trapframe->x[0] = vfs_write(fh, buf, count); +} + +inline void sys_read(struct trapframe *trapframe) { + struct file *fh; + int fd = trapframe->x[0]; + char *buf = (char *)trapframe->x[1]; + unsigned long count = trapframe->x[2]; +#ifdef DEBUG_FS + kprintf("read(%d, %d)\n", fd, count); +#endif + if (fd < 0) { + trapframe->x[0] = -1; + return; + } + fh = fd_get(&(get_current()->files), fd); + if (fh == 0) { + trapframe->x[0] = -1; + return; + } + trapframe->x[0] = vfs_read(fh, buf, count); +} + +inline void sys_mkdir(struct trapframe *trapframe) { + const char *pathname = (char *)trapframe->x[0]; +#ifdef DEBUG_FS + kprintf("mkdir(%s)\n", pathname); +#endif + // unsigned mode = trapframe->x[1]; + trapframe->x[0] = vfs_mkdir(pathname); +} + +inline void sys_mount(struct trapframe *trapframe) { + const char *target = (char *)trapframe->x[1]; + const char *filesystem = (char *)trapframe->x[2]; +#ifdef DEBUG_FS + kprintf("mount(%s, %s)\n", target, filesystem); +#endif + trapframe->x[0] = vfs_mount(target, filesystem); +} + +inline void sys_chdir(struct trapframe *trapframe) { + const char *path = (char *)trapframe->x[0]; +#ifdef DEBUG_FS + kprintf("chdir(%s)\n", path); +#endif + trapframe->x[0] = vfs_chdir(path); +} + +inline void sys_lseek64(struct trapframe *trapframe) { + struct file *fh; + int fd = trapframe->x[0]; + long offset = trapframe->x[1]; + int whence = trapframe->x[2]; + + if (fd < 0) { + trapframe->x[0] = -1; + return; + } + fh = fd_get(&(get_current()->files), fd); + if (fh == 0) { + trapframe->x[0] = -1; + return; + } + trapframe->x[0] = vfs_lseek64(fh, offset, whence); +} + +inline void sys_sync(struct trapframe *trapframe) { + vfs_sync(); +} + +void syscall_main(struct trapframe *trapframe) { + int_enable(); + long syscall_num = trapframe->x[8]; + switch(syscall_num) { + case SYS_GET_PID: + sys_getpid(trapframe); + break; + case SYS_UART_READ: + sys_uart_read(trapframe); + break; + case SYS_UART_WRITE: + sys_uart_write(trapframe); + break; + case SYS_EXEC: + sys_exec(trapframe); + break; + case SYS_FORK: + sys_fork(trapframe); + break; + case SYS_EXIT: + sys_exit(trapframe); + break; + case SYS_MBOX_CALL: + sys_mbox_call(trapframe); + break; + case SYS_KILL: + sys_kill(trapframe); + break; + case SYS_SIGNAL: + sys_signal(trapframe); + break; + case SYS_SIGKILL: + sys_sigkill(trapframe); + break; + case SYS_OPEN: + sys_open(trapframe); + break; + case SYS_CLOSE: + sys_close(trapframe); + break; + case SYS_WRITE: + sys_write(trapframe); + break; + case SYS_READ: + sys_read(trapframe); + break; + case SYS_MKDIR: + sys_mkdir(trapframe); + break; + case SYS_MOUNT: + sys_mount(trapframe); + break; + case SYS_CHDIR: + sys_chdir(trapframe); + break; + case SYS_LSEEK64: + sys_lseek64(trapframe); + break; + case SYS_SYNC: + sys_sync(trapframe); + break; + case 30: + sys_sigreturn(trapframe); + break; + default: + uart_sync_puts("Undefined syscall number, about to reboot...\n"); + reset(1000); + while(1); + } + int_disable(); +} + +void svc_main(unsigned long spsr, unsigned long elr, unsigned long esr, struct trapframe *trapframe) { + unsigned int svc_num; + svc_num = esr & 0xFFFFFF; + + switch(svc_num) { + case 0: + syscall_main(trapframe); + break; + case 1: + kputs("svc 1\n"); + core_timer_enable(); + break; + case 2: + /* + bits [31:26] 0b010101 SVC instruction execution in AArch64 state. + */ + kprintf("\nspsr_el1: \t%x\n", spsr); + kprintf("elr_el1: \t%x\n", elr); + kprintf("esr_el1: \t%x\n", esr); + break; + default: + uart_sync_printNum(svc_num, 10); + uart_sync_puts(": Undefined svc number, about to reboot...\n"); + reset(1000); + while(1); + } +} + +void fault_parse(unsigned long sc) { + unsigned long far; + if (sc & 0b110000) { + kprintf("Others fault...\n"); + return; + } + + switch((sc & 0b1100) >> 2) { + case 0: + kprintf("Address size fault,"); + break; + case 1: + kprintf("Translation fault,"); + break; + case 2: + kprintf("Access flag fault,"); + break; + case 3: + kprintf("Permission fault,"); + break; + } + + kprintf(" level %d\n", sc & 0b11); + asm volatile("mrs %0, far_el1":"=r"(far)); + if (VIRT_CHECK(far)) + kprintf("Address: \t0x%x\n", VIRT_2_PHY(far)); + else + kprintf("Address: \t0x%x\n", far); +} + +void sync_main(unsigned long spsr, unsigned long elr, unsigned long esr, struct trapframe *trapframe) { + switch(EC_BITS(esr)) { + case EC_SVC_64: + svc_main(spsr, elr, esr, trapframe); + break; + case EC_IA_EL0: + kprintf("(EL0)"); + case EC_IA_EL1: + kprintf("Instruction Abort\n"); + fault_parse(IFSC(esr)); + kprintf("spsr_el0: \t0x%x\n", trapframe->sp_el0); + __exit(); + break; + case EC_DA_EL0: + kprintf("(EL0)"); + case EC_DA_EL1: + kprintf("Data Abort\n"); + fault_parse(DFSC(esr)); + kprintf("spsr_el0: \t0x%x\n", trapframe->sp_el0); + __exit(); + break; + default: + uart_sync_printNum(EC_BITS(esr), 10); + uart_sync_puts(": Unknown ec bit, about to reboot...\n"); + reset(1000); + while(1); + } +} \ No newline at end of file diff --git a/lab8/kern/syscall.S b/lab8/kern/syscall.S new file mode 100644 index 000000000..5072f32d3 --- /dev/null +++ b/lab8/kern/syscall.S @@ -0,0 +1,113 @@ + +.global getpid +getpid: + mov x8, #0 + svc #0 + ret + +.global uart_read +uart_read: + mov x8, #1 + svc #0 + ret + +.global uart_write +uart_write: + mov x8, #2 + svc #0 + ret + +.global exec +exec: + mov x8, #3 + svc #0 + ret + +.global fork +fork: + mov x8, #4 + svc #0 + ret + +.global exit +exit: + mov x8, #5 + svc #0 + +.global mbox_call +mbox_call: + mov x8, #6 + svc #0 + ret + +.global kill +kill: + mov x8, #7 + svc #0 + ret + +.global signal +signal: + mov x8, #8 + svc #0 + ret + +.global sigkill +sigkill: + mov x8, #9 + svc #0 + ret + +.global open +open: + mov x8, #11 + svc #0 + ret + +.global close +close: + mov x8, #12 + svc #0 + ret + +.global write +write: + mov x8, #13 + svc #0 + ret + +.global read +read: + mov x8, #14 + svc #0 + ret + +.global mkdir +mkdir: + mov x8, #15 + svc #0 + ret + +.global mount +mount: + mov x8, #16 + svc #0 + ret + +.global chdir +chdir: + mov x8, #17 + svc #0 + ret + +.global lseek64 +lseek64: + mov x8, #18 + svc #0 + ret + +.global sync +sync: + mov x8, #20 + svc #0 + ret \ No newline at end of file diff --git a/lab8/kern/timer.S b/lab8/kern/timer.S new file mode 100644 index 000000000..f8ad2a60e --- /dev/null +++ b/lab8/kern/timer.S @@ -0,0 +1,44 @@ +.section ".text" + +#include "peripheral/arm.h" + +.global core_timer_enable +core_timer_enable: + mov x0, 1 + msr cntp_ctl_el0, x0 // enable + mrs x0, cntfrq_el0 + msr cntp_tval_el0, x0 // set expired time + mov x0, 2 + ldr x1, =CORE0_TIMER_IRQ_CTRL + str w0, [x1] // unmask timer interrupt + ret + +.global core_timer_disable +core_timer_disable: + mov x0, 0 + msr cntp_ctl_el0, x0 // disable + mov x0, 0 + ldr x1, =CORE0_TIMER_IRQ_CTRL + str x0, [x1] // disable timer interrupt + ret + +.global timer_enable_int +timer_enable_int: + mov x0, 2 + ldr x1, =CORE0_TIMER_IRQ_CTRL + str w0, [x1] // unmask timer interrupt + ret + +.global timer_disable_int +timer_disable_int: + mov x0, 0 + ldr x1, =CORE0_TIMER_IRQ_CTRL + str x0, [x1] // disable timer interrupt + ret + +.global timer_sched_latency +timer_sched_latency: + mrs x0, cntfrq_el0 + asr x0, x0, 7 // 1/2 secs + msr cntp_tval_el0, x0 + ret \ No newline at end of file diff --git a/lab8/kern/timer.c b/lab8/kern/timer.c new file mode 100644 index 000000000..7f76e5b35 --- /dev/null +++ b/lab8/kern/timer.c @@ -0,0 +1,130 @@ +#include "kern/timer.h" +#include "kern/kio.h" +#include "startup_alloc.h" +#include "string.h" + +struct timer_queue *timer_head; +struct timer_queue *timer_tail; + +unsigned long get_current_time() { + unsigned long cntpct; + unsigned long cntfrq; + asm volatile("mrs %0, cntpct_el0" : "=r"(cntpct)); + asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq)); + return cntpct/cntfrq; +} + +void set_expired(unsigned int seconds) { + unsigned long cntfrq; + asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq)); + asm volatile("msr cntp_tval_el0, %0" : : "r"(cntfrq * seconds)); +} + +void timer_el0_handler() { + kprintf("Seconds after booting: %d\n", get_current_time()); + set_expired(2); + timer_enable_int(); +} + +void timer_el1_handler() { + struct timer_queue *next; + unsigned long timeout; + + timer_head->callback(timer_head->message, timer_head->register_time); + next = timer_head->next; + if (next) { + next->prev = 0; + timer_head = next; + timeout = next->register_time + next->duration - get_current_time(); + set_expired(timeout); + timer_enable_int(); + } else { + timer_head = 0; + timer_tail = 0; + } +} + +void timer_unknown_handler() { + kputs("Timer interrupt: unknown source EL, delay one seconds...\n"); + set_expired(1); + timer_enable_int(); +} + + +void timer_init() { + timer_head = 0; + timer_tail = 0; +} + +void add_timer(void (*callback)(char *, unsigned long), char *message, unsigned int duration) { + struct timer_queue *new_timer = (struct timer_queue *)sumalloc(sizeof(struct timer_queue)); + struct timer_queue *itr; + unsigned long timeout; + int i; + + new_timer->register_time = get_current_time(); + new_timer->duration = duration; + new_timer->callback = callback; + for(i=0 ; message[i]!='\0' ; i++) + new_timer->message[i] = message[i]; + new_timer->message[i] = '\0'; + new_timer->prev = 0; + new_timer->next = 0; + + if (!timer_head) { + timer_head = new_timer; + timer_tail = new_timer; + core_timer_enable(); + set_expired(duration); + } else { + timeout = new_timer->register_time + new_timer->duration; + for(itr=timer_head ; itr ; itr=itr->next) { + if(itr->register_time + itr->duration > timeout) + break; + } + + if (!itr) { // tail + new_timer->prev = timer_tail; + timer_tail->next = new_timer; + timer_tail = new_timer; + } else if (!itr->prev) { // head + new_timer->next = timer_head; + timer_head->prev = new_timer; + timer_head = new_timer; + set_expired(duration); + } else { // middle + new_timer->prev = itr->prev; + new_timer->next = itr; + itr->prev->next = new_timer; + itr->prev = new_timer; + } + } +} + +void timer_callback(char *msg, unsigned long register_time) { + kprintf("\nSeconds after booting: %d\n", get_current_time()); + kprintf("%s, register at: %d\n", msg, register_time); +} + +void set_timeout(char *args) { + int i; + int duration; + int message_end = -1; + + for(i=0 ; args[i]!='\0' ; i++) if (args[i] == ' ') { + message_end = i; + break; + } + if (message_end == -1) { + kputs("setTimeout: MESSAGE SECONDS\n"); + return; + } + args[message_end] = '\0'; + duration = atoi(args+message_end+1, 10, strlen(args+message_end+1)); + if (duration <= 0 || duration >= 35) { + kputs("setTimeout: time error\n"); + return; + } + kprintf("Timeout: %ds\n", duration); + add_timer(timer_callback, args, duration); +} \ No newline at end of file diff --git a/lab8/lib/dtb.c b/lab8/lib/dtb.c new file mode 100644 index 000000000..905348585 --- /dev/null +++ b/lab8/lib/dtb.c @@ -0,0 +1,60 @@ +#include "dtb.h" +#include "string.h" +#include "byteswap.h" +#include "kern/mm.h" + +#define align4(num) ((num + 3) & (-4)) + +char FDT_HEADER_MAGIC[4] = {0xd0, 0x0d, 0xfe, 0xed}; + +void *DTB_ADDRESS = 0; +void *DTB_END_ADR = 0; + +int fdt_init() { + asm volatile("MOV %0, x23" : "=r"(DTB_ADDRESS)); + DTB_ADDRESS = (void*)PHY_2_VIRT(DTB_ADDRESS); + if (strncmp((char*)DTB_ADDRESS, FDT_HEADER_MAGIC, 4)) + return -1; + return 0; +} + +int fdt_traverse(void (*cb)(char *, char *, void *)) { + unsigned int token; + void *ptr; + void *struct_block; + void *string_block; + char *node_name = 0; + char *prop_name = 0; + struct fdt_prop *prop; + struct fdt_header *header = DTB_ADDRESS; + + struct_block = DTB_ADDRESS + __bswap_32(header->off_dt_struct); + string_block = DTB_ADDRESS + __bswap_32(header->off_dt_strings); + + for (ptr=struct_block ; ; ptr+=4) { + token = __bswap_32(*((unsigned int*)ptr)); + if (token == FDT_BEGIN_NODE) { + node_name = ptr + 4; + ptr += align4(strlen(node_name) + 1); + } else if (token == FDT_END_NODE) { + } else if (token == FDT_PROP) { + prop = ptr + 4; + prop_name = string_block + __bswap_32(prop->nameoff); + cb(node_name, prop_name, ptr + 12); + ptr += align4(8 + __bswap_32(prop->len)); + } else if (token == FDT_NOP) { + } else if (token == FDT_END) { + break; + } else { + return -1; + } + } + DTB_END_ADR = ptr; + return 0; +} + +void fdt_reserve() { + if (!DTB_END_ADR) + return; + mm_reserve(DTB_ADDRESS, DTB_END_ADR); +} \ No newline at end of file diff --git a/lab8/lib/mailbox.c b/lab8/lib/mailbox.c new file mode 100644 index 000000000..bb7a13927 --- /dev/null +++ b/lab8/lib/mailbox.c @@ -0,0 +1,89 @@ +#include "peripheral/mailbox.h" +#include "string.h" +#include "kern/mm_types.h" + +unsigned int mailbox_call(unsigned char ch, unsigned int* mailbox) { + unsigned int message; + unsigned int data; + + // Combine the message address (upper 28 bits) with channel number (lower 4 bits) + message = ((unsigned long)VIRT_2_PHY(mailbox) & 0xfffffff0) | (ch & 0xf); + // Check if Mailbox 0 status register’s full flag is set + while((*MAILBOX_STATUS & MAILBOX_FULL)) asm volatile("nop"); + // write to Mailbox 1 Read/Write register + *MAILBOX_WRITE = message; + while(1) { + // Check if Mailbox 0 status register’s empty flag is set + while((*MAILBOX_STATUS & MAILBOX_EMPTY)) asm volatile("nop"); + // read from Mailbox 0 Read/Write register + data = (unsigned int)(*MAILBOX_READ); + // Check if the value is the same as you wrote + if (data == message) { + return mailbox[1] == REQUEST_SUCCEED; + } + } + return 0; +} + +/* +https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface +Get board revision + Tag: 0x00010002 + Request: + Length: 0 + Response: + Length: 4 + Value: + u32: board revision +*/ +void get_board_revision(unsigned int *result){ + unsigned int mailbox[7]; + + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = END_TAG; + + // message passing procedure call + if (mailbox_call(0x8, mailbox)) { + // it should be 0xa020d3 for rpi3 b+ + result[0] = mailbox[5]; + } +} + +/* +Get ARM memory + Tag: 0x00010005 + Request: + Length: 0 + Response: + Length: 8 + Value: + u32: base address in bytes + u32: size in bytes +*/ +void get_ARM_memory(unsigned int *result) { + unsigned int mailbox[8]; + + mailbox[0] = 8 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_ARM_MEMORY; // tag identifier + mailbox[3] = 8; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + mailbox[6] = 0; // value buffer + // tags end + mailbox[7] = END_TAG; + + // message passing procedure call + if (mailbox_call(0x8, mailbox)) { + result[0] = mailbox[5]; + result[1] = mailbox[6]; + } +} \ No newline at end of file diff --git a/lab8/lib/reset.c b/lab8/lib/reset.c new file mode 100644 index 000000000..933c7d00d --- /dev/null +++ b/lab8/lib/reset.c @@ -0,0 +1,16 @@ +#include "reset.h" + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +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 +} + +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} diff --git a/lab8/lib/startup_alloc.c b/lab8/lib/startup_alloc.c new file mode 100644 index 000000000..96e423fa2 --- /dev/null +++ b/lab8/lib/startup_alloc.c @@ -0,0 +1,22 @@ +#include "kern/mm.h" + +extern unsigned int __heap_start; + +void *heap_start = (void *)&__heap_start; +void *heap_cur = (void *)&__heap_start; + +int startup = 1; + +void* sumalloc(unsigned int size) { + void *ret = (void*)0; + if (!startup) + goto out; + ret = heap_cur; + heap_cur += size; +out: + return ret; +} + +void reserved_kern_startup() { + mm_reserve(heap_start, heap_cur + 8192); +} \ No newline at end of file diff --git a/lab8/lib/string.c b/lab8/lib/string.c new file mode 100644 index 000000000..f1b62666c --- /dev/null +++ b/lab8/lib/string.c @@ -0,0 +1,118 @@ + +unsigned int strlen(const char *str) { + const char *c; + for (c=str ; *c ; ++c); + return c - str; +} + +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 int n) { + unsigned char c1 = '\0'; + unsigned char c2 = '\0'; + + // if (n >= 4) { + // unsigned int 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; +} + +void strrev(char* str, unsigned int len) { + int i; + int j; + char a; + for (i = 0, j = len - 1; i < j; i++, j--) { + a = str[i]; + str[i] = str[j]; + str[j] = a; + } +} + +int itoa(long num, char* str, int base) { + long sum = num; + int i = 0; + int digit; + do { + digit = sum % base; + if (digit < 0xA) + str[i++] = '0' + digit; + else + str[i++] = 'A' + digit - 0xA; + sum /= base; + } while(sum); + if (sum) + return -1; + str[i] = '\0'; + strrev(str, i); + return 0; +} + +long atoi(char* str, int base, unsigned int len) { + long num = 0; + int i; + for (i=0 ; i= 'A') + num += str[i] - 'A' + 10; + else + num += str[i] - '0'; + } + return num; +} + +void* memcpy (void* dest, const void* src, unsigned int len) { + char *d = dest; + const char *s = src; + while (len--) + *d++ = *s++; + return dest; +} + +void* memset (void *dest, int val, unsigned int len) { + unsigned char *ptr = dest; + while (len-- > 0) + *ptr++ = val; + return dest; +} + +char *strcpy(char *dest, const char *src) { + return memcpy(dest, src, strlen(src)+1); +} \ No newline at end of file diff --git a/lab8/lib/test_func.c b/lab8/lib/test_func.c new file mode 100644 index 000000000..e5de355f5 --- /dev/null +++ b/lab8/lib/test_func.c @@ -0,0 +1,102 @@ + + +#include "syscall.h" +#include "string.h" +#include "user_lib.h" + +void delay(int times) { + while(times--) { + asm volatile("nop"); + } +} + +void fork_test() { + printf("\nFork Test, pid %d\n", getpid()); + int cnt = 1; + int ret = 0; + if ((ret = fork()) == 0) { // child + long long cur_sp; + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", getpid(), cnt, &cnt, cur_sp); + ++cnt; + + if ((ret = fork()) != 0){ + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", getpid(), cnt, &cnt, cur_sp); + } + else{ + while (cnt < 5) { + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("second child pid: %d, cnt: %d, ptr: %x, sp : %x\n", getpid(), cnt, &cnt, cur_sp); + delay(1000000); + ++cnt; + } + } + exit(); + } + else { + printf("parent here, pid %d, child %d\n", getpid(), ret); + } + exit(); +} + +void fs_test() { + char buf[100]; + mkdir("mnt", 0); + int fd = open("/mnt/a.txt", O_CREAT); + write(fd, "Hi", 2); + close(fd); + chdir("mnt"); + fd = open("./a.txt", 0); + if (fd < 0) { + printf("error1\n"); + return; + } + read(fd, buf, 2); + if (strncmp(buf, "Hi", 2) != 0) { + printf("error2\n"); + return; + } + close(fd); + + chdir(".."); + mount("", "mnt", "tmpfs", 0, 0); + mount("", "mnt", "tmpfs", 0, 0); + fd = open("mnt/a.txt", 0); + if (fd > 0) { + printf("error3\n"); + return; + } +} + +void fat_test() { + int fd = open("/boot/FAT_11.TXT", 0); + int size = 600; + char buf[size+1]; + for(int i=0 ; iNV7<3HcemDl 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 literal 0 HcmV?d00001 diff --git a/lab8/raspi3/config.txt b/lab8/raspi3/config.txt new file mode 100644 index 000000000..e82fa85fa --- /dev/null +++ b/lab8/raspi3/config.txt @@ -0,0 +1,3 @@ +kernel=bootloader.img +arm_64bit=1 +initramfs initramfs.cpio 0x8000000 \ No newline at end of file diff --git a/lab8/rootfs/Makefile b/lab8/rootfs/Makefile new file mode 100644 index 000000000..d864058e8 --- /dev/null +++ b/lab8/rootfs/Makefile @@ -0,0 +1,20 @@ +# OSC 2022 +CC = aarch64-linux-gnu-gcc +LD = aarch64-linux-gnu-ld +OBJCOPY = aarch64-linux-gnu-objcopy + +LINKER_FILE = linker.ld + +# -fno-stack-protector: to disable stack protection +# -fno-builtin is required to avoid refs to undefined functions in the kernel. +# Only optimize to -O1 to discourage inlining, which complicates backtraces. +CFLAGS := -O1 -fno-builtin -nostdinc +CFLAGS += -Wall -c -fno-stack-protector + +user_prog: user_prog.S $(LINKER_FILE) + $(CC) $(CFLAGS) $< -o $@.o + $(LD) -T $(LINKER_FILE) -o $@ $@.o + $(OBJCOPY) $@ -O binary $@ + +archv: + find . | cpio -o -H newc > ../initramfs.cpio \ No newline at end of file diff --git a/lab8/rootfs/dir1/file3.txt b/lab8/rootfs/dir1/file3.txt new file mode 100644 index 000000000..873fb8d66 --- /dev/null +++ b/lab8/rootfs/dir1/file3.txt @@ -0,0 +1 @@ +file3 \ No newline at end of file diff --git a/lab8/rootfs/dir1/file5.txt b/lab8/rootfs/dir1/file5.txt new file mode 100644 index 000000000..d92b9c318 --- /dev/null +++ b/lab8/rootfs/dir1/file5.txt @@ -0,0 +1 @@ +file5 \ No newline at end of file diff --git a/lab8/rootfs/file1 b/lab8/rootfs/file1 new file mode 100644 index 000000000..d88c464a9 --- /dev/null +++ b/lab8/rootfs/file1 @@ -0,0 +1 @@ +This is file1 \ No newline at end of file diff --git a/lab8/rootfs/file2.txt b/lab8/rootfs/file2.txt new file mode 100644 index 000000000..d9a0c4d55 --- /dev/null +++ b/lab8/rootfs/file2.txt @@ -0,0 +1 @@ +This is file2 \ No newline at end of file diff --git a/lab8/rootfs/linker.ld b/lab8/rootfs/linker.ld new file mode 100644 index 000000000..05132105e --- /dev/null +++ b/lab8/rootfs/linker.ld @@ -0,0 +1,31 @@ +SECTIONS +{ + . = 0x0; + .text : { + *(.text .text.* .gnu.linkonce.t.*) + } + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + . = ALIGN(0x1000); + + /* The data segment */ + .data : { + *(.data) + } + + .bss ALIGN(16) (NOLOAD) : { + PROVIDE(__bss_start = .); + *(.bss) + PROVIDE(__bss_end = .); + BYTE(0) + } + + . = ALIGN(0x1000); + + /DISCARD/ : { + *(.eh_frame .note.GNU-stack) + } +} \ No newline at end of file diff --git a/lab8/rootfs/user_prog.S b/lab8/rootfs/user_prog.S new file mode 100644 index 000000000..ad2655ba4 --- /dev/null +++ b/lab8/rootfs/user_prog.S @@ -0,0 +1,14 @@ +.section ".text" + +.global _start +_start: + mov x0, 0 + svc 1 +1: + add x0, x0, 1 + svc 0 + cmp x0, 5 + blt 1b + svc 4 +1: + b 1b \ No newline at end of file