From 53e226bc7a2a4339aeaa032cf6007bea335cf849 Mon Sep 17 00:00:00 2001 From: kent lee Date: Thu, 27 Jun 2024 03:01:11 +0800 Subject: [PATCH 1/3] Lab 5 done --- Lab 5/Makefile | 30 ++ Lab 5/docs/TODO.md | 43 +++ Lab 5/docs/frame.c | 451 +++++++++++++++++++++++++++++ Lab 5/kernel/Makefile | 57 ++++ Lab 5/kernel/include/arm/sysregs.h | 63 ++++ Lab 5/kernel/include/asm.h | 17 ++ Lab 5/kernel/include/aux.h | 41 +++ Lab 5/kernel/include/cpio.h | 52 ++++ Lab 5/kernel/include/gpio.h | 44 +++ Lab 5/kernel/include/irq.h | 16 + Lab 5/kernel/include/kernel.h | 11 + Lab 5/kernel/include/list.h | 146 ++++++++++ Lab 5/kernel/include/mmio.h | 9 + Lab 5/kernel/include/sprintf.h | 120 ++++++++ Lab 5/kernel/include/type.h | 33 +++ Lab 5/kernel/src/chunk.c | 209 +++++++++++++ Lab 5/kernel/src/chunk.h | 22 ++ Lab 5/kernel/src/core_timer.c | 192 ++++++++++++ Lab 5/kernel/src/core_timer.h | 20 ++ Lab 5/kernel/src/delay.c | 27 ++ Lab 5/kernel/src/delay.h | 9 + Lab 5/kernel/src/dtb.c | 218 ++++++++++++++ Lab 5/kernel/src/dtb.h | 28 ++ Lab 5/kernel/src/entry.S | 218 ++++++++++++++ Lab 5/kernel/src/entry.h | 11 + Lab 5/kernel/src/exception.S | 19 ++ Lab 5/kernel/src/exception.c | 206 +++++++++++++ Lab 5/kernel/src/exception.h | 10 + Lab 5/kernel/src/frame.c | 398 +++++++++++++++++++++++++ Lab 5/kernel/src/frame.h | 22 ++ Lab 5/kernel/src/info.c | 187 ++++++++++++ Lab 5/kernel/src/info.h | 10 + Lab 5/kernel/src/initrd.c | 174 +++++++++++ Lab 5/kernel/src/initrd.h | 20 ++ Lab 5/kernel/src/kernel_main.c | 84 ++++++ Lab 5/kernel/src/kernel_start.S | 99 +++++++ Lab 5/kernel/src/linker.ld | 23 ++ Lab 5/kernel/src/mailbox.c | 52 ++++ Lab 5/kernel/src/mailbox.h | 77 +++++ Lab 5/kernel/src/memory.S | 15 + Lab 5/kernel/src/memory.c | 152 ++++++++++ Lab 5/kernel/src/memory.h | 28 ++ Lab 5/kernel/src/mini_uart.c | 294 +++++++++++++++++++ Lab 5/kernel/src/mini_uart.h | 26 ++ Lab 5/kernel/src/power.c | 26 ++ Lab 5/kernel/src/power.h | 9 + Lab 5/kernel/src/sched.S | 32 ++ Lab 5/kernel/src/sched.c | 284 ++++++++++++++++++ Lab 5/kernel/src/sched.h | 27 ++ Lab 5/kernel/src/shell.c | 202 +++++++++++++ Lab 5/kernel/src/shell.h | 6 + Lab 5/kernel/src/string.c | 168 +++++++++++ Lab 5/kernel/src/string.h | 20 ++ Lab 5/kernel/src/sys.S | 72 +++++ Lab 5/kernel/src/syscall.c | 97 +++++++ Lab 5/kernel/src/syscall.h | 73 +++++ Lab 5/kernel/src/task.c | 190 ++++++++++++ Lab 5/kernel/src/task.h | 96 ++++++ Lab 5/kernel/src/thread.c | 146 ++++++++++ Lab 5/kernel/src/thread.h | 19 ++ Lab 5/kernel/src/uart.h | 19 ++ Lab 5/sd/bcm2710-rpi-3-b-plus.dtb | Bin 0 -> 34228 bytes Lab 5/sd/config.txt | 3 + Lab 5/sd/rootfs/3.txt | 25 ++ Lab 5/sd/rootfs/f1.txt | 19 ++ Lab 5/sd/rootfs/file2 | 21 ++ Lab 5/uploader/uploader.py | 59 ++++ Lab 5/user/Makefile | 22 ++ Lab 5/user/user1/Makefile | 40 +++ Lab 5/user/user1/src/linker.ld | 14 + Lab 5/user/user1/src/main.S | 11 + 71 files changed, 5683 insertions(+) create mode 100644 Lab 5/Makefile create mode 100644 Lab 5/docs/TODO.md create mode 100644 Lab 5/docs/frame.c create mode 100644 Lab 5/kernel/Makefile create mode 100644 Lab 5/kernel/include/arm/sysregs.h create mode 100644 Lab 5/kernel/include/asm.h create mode 100644 Lab 5/kernel/include/aux.h create mode 100644 Lab 5/kernel/include/cpio.h create mode 100644 Lab 5/kernel/include/gpio.h create mode 100644 Lab 5/kernel/include/irq.h create mode 100644 Lab 5/kernel/include/kernel.h create mode 100644 Lab 5/kernel/include/list.h create mode 100644 Lab 5/kernel/include/mmio.h create mode 100644 Lab 5/kernel/include/sprintf.h create mode 100644 Lab 5/kernel/include/type.h create mode 100644 Lab 5/kernel/src/chunk.c create mode 100644 Lab 5/kernel/src/chunk.h create mode 100644 Lab 5/kernel/src/core_timer.c create mode 100644 Lab 5/kernel/src/core_timer.h create mode 100644 Lab 5/kernel/src/delay.c create mode 100644 Lab 5/kernel/src/delay.h create mode 100644 Lab 5/kernel/src/dtb.c create mode 100644 Lab 5/kernel/src/dtb.h create mode 100644 Lab 5/kernel/src/entry.S create mode 100644 Lab 5/kernel/src/entry.h create mode 100644 Lab 5/kernel/src/exception.S create mode 100644 Lab 5/kernel/src/exception.c create mode 100644 Lab 5/kernel/src/exception.h create mode 100644 Lab 5/kernel/src/frame.c create mode 100644 Lab 5/kernel/src/frame.h create mode 100644 Lab 5/kernel/src/info.c create mode 100644 Lab 5/kernel/src/info.h create mode 100644 Lab 5/kernel/src/initrd.c create mode 100644 Lab 5/kernel/src/initrd.h create mode 100644 Lab 5/kernel/src/kernel_main.c create mode 100644 Lab 5/kernel/src/kernel_start.S create mode 100644 Lab 5/kernel/src/linker.ld create mode 100644 Lab 5/kernel/src/mailbox.c create mode 100644 Lab 5/kernel/src/mailbox.h create mode 100644 Lab 5/kernel/src/memory.S create mode 100644 Lab 5/kernel/src/memory.c create mode 100644 Lab 5/kernel/src/memory.h create mode 100644 Lab 5/kernel/src/mini_uart.c create mode 100644 Lab 5/kernel/src/mini_uart.h create mode 100644 Lab 5/kernel/src/power.c create mode 100644 Lab 5/kernel/src/power.h create mode 100644 Lab 5/kernel/src/sched.S create mode 100644 Lab 5/kernel/src/sched.c create mode 100644 Lab 5/kernel/src/sched.h create mode 100644 Lab 5/kernel/src/shell.c create mode 100644 Lab 5/kernel/src/shell.h create mode 100644 Lab 5/kernel/src/string.c create mode 100644 Lab 5/kernel/src/string.h create mode 100644 Lab 5/kernel/src/sys.S create mode 100644 Lab 5/kernel/src/syscall.c create mode 100644 Lab 5/kernel/src/syscall.h create mode 100644 Lab 5/kernel/src/task.c create mode 100644 Lab 5/kernel/src/task.h create mode 100644 Lab 5/kernel/src/thread.c create mode 100644 Lab 5/kernel/src/thread.h create mode 100644 Lab 5/kernel/src/uart.h create mode 100644 Lab 5/sd/bcm2710-rpi-3-b-plus.dtb create mode 100644 Lab 5/sd/config.txt create mode 100644 Lab 5/sd/rootfs/3.txt create mode 100644 Lab 5/sd/rootfs/f1.txt create mode 100644 Lab 5/sd/rootfs/file2 create mode 100644 Lab 5/uploader/uploader.py create mode 100644 Lab 5/user/Makefile create mode 100644 Lab 5/user/user1/Makefile create mode 100644 Lab 5/user/user1/src/linker.ld create mode 100644 Lab 5/user/user1/src/main.S diff --git a/Lab 5/Makefile b/Lab 5/Makefile new file mode 100644 index 000000000..78269afed --- /dev/null +++ b/Lab 5/Makefile @@ -0,0 +1,30 @@ +SUBDIR = kernel # bootloader + +BUILDSUBDIR = $(SUBDIR:%=build-%) +CLEANSUBDIR = $(SUBDIR:%=clean-%) + +SD_DIR = sd +FS_DIR = rootfs + +all: $(SD_DIR)/initrd.cpio $(BUILDSUBDIR) + +$(SD_DIR)/initrd.cpio: + cd $(SD_DIR)/$(FS_DIR) && ls -a | cpio -o -H newc > ../../$@ && cd .. + +$(BUILDSUBDIR): + @echo "===>" $@ + $(MAKE) -C $(@:build-%=%) + @echo "<===" $@ + +$(CLEANSUBDIR): + @echo "===>" $@ + $(MAKE) -C $(@:clean-%=%) clean + @echo "<===" $@ + +clean: $(CLEANSUBDIR) + rm -f $(SD_DIR)/*.cpio + + +# $(call make_subdir, clean) + +.PHONY: all clean $(SUBDIR) $(BUILDSUBDIR) $(CLEANSUBDIR) $(SD_DIR)/initrd.cpio \ No newline at end of file diff --git a/Lab 5/docs/TODO.md b/Lab 5/docs/TODO.md new file mode 100644 index 000000000..e91a967bb --- /dev/null +++ b/Lab 5/docs/TODO.md @@ -0,0 +1,43 @@ +### Basic Exercise 1 - Buddy System - 40% + +**Todo** +``` +Implement the buddy system fro contiguous page frames allocation and your max order should be larger than 5. + +(You don't need to handle the case of out-of-memory.) +``` + + +**The Frame Array** +``` +For each entry in The Frame Array with idx and value val +(Suppose the framesize to be 4kb) + +val + >= 0 : allocatable + = : belongs to a larger block + = : already allocated + +Frame Freelists + linkedlists + +``` + + + + +### Basic Exercise 2 - - + + + + + + + + + + + + + + diff --git a/Lab 5/docs/frame.c b/Lab 5/docs/frame.c new file mode 100644 index 000000000..cbae49e03 --- /dev/null +++ b/Lab 5/docs/frame.c @@ -0,0 +1,451 @@ +#include "frame.h" +#include "type.h" +#include "list.h" +#include "uart.h" +#include "memory.h" + + +static void +bucket_init(byteptr_t bucket) +{ + list_head_ptr_t list = (list_head_ptr_t) bucket; + INIT_LIST_HEAD(list); +} + + +static list_head_ptr_t +list_pop(const list_head_ptr_t list) +{ + if (list->next == list) return 0; + list_head_ptr_t head = list->next; + list_del_entry(head); + return head; +} + + +static void +list_push(const list_head_ptr_t list, list_head_ptr_t entry) +{ + INIT_LIST_HEAD(entry); + list_add_tail(entry, list); +} + + + +#define FRAME_SIZE_ORDER 12 +#define MIN_ALLOC_ORDER FRAME_SIZE_ORDER + +#define INDEX_LOG2(index) ({31 - __builtin_clz(index);}) + +/* + * This is the starting address of the address range for this allocator. Every + * returned allocation will be an offset of this pointer from 0 to MAX_ALLOC. + */ +static byteptr_t base_ptr; + + +/** + * frame size = 4kb = 2^12b + * The maximum allocation size is currently set to 1mb = 2^20b + * thus the max order is 20-12=8 (256 pages) + */ +static uint32_t max_alloc_order; +static uint32_t max_alloc_size; +static uint32_t total_frames; + + +/** + * Frame Array Structure: Binary Heap + * example: + * - 16 frames = 2^4 frames + * - 5 freelists + * - 31 nodes, 15 internals + * - array size : 15 + 1 + * root index: 1 + * indices of leaves: 2^4 ~ 2^5-1 +*/ +// static uint8_t frame_array[(1 << (BUCKET_COUNT - 1))]; +static byteptr_t frame_array; + +#define FRAME_SPLIT (1 << 7) +#define FRAME_USED_L (1 << 6) +#define FRAME_USED_R (1 << 5) + + +/** + * Freelists +*/ +static uint32_t bucket_count; +static list_head_ptr_t buckets; + + + +static uint32_t +parent_is_split(uint32_t index) +{ + return frame_array[index >> 1] & FRAME_SPLIT; +} + + +static void +set_parent_split(uint32_t index) +{ + frame_array[index >> 1] |= FRAME_SPLIT; +} + + +static void +clr_parent_split(uint32_t index) +{ + frame_array[index >> 1] &= ~(FRAME_SPLIT); +} + + +static uint32_t +node_is_split(uint32_t index) +{ + return (INDEX_LOG2(index) > (bucket_count - 2)) ? 0 : frame_array[index] & FRAME_SPLIT; +} + + +static uint32_t +node_is_used(uint32_t index) +{ + return frame_array[index >> 1] & (FRAME_USED_L >> (index & 1)); +} + + +static void +set_node_used(uint32_t index) +{ + frame_array[index >> 1] |= (FRAME_USED_L >> (index & 1)); +} + + +static void +clr_node_used(uint32_t index) +{ + frame_array[index >> 1] &= ~(FRAME_USED_L >> (index & 1)); +} + + +/** + * 1. (index - (1 << index)) : the index of the corresponding level + * 2. (the index of the level) << (MAX_ALLOC_ORDER - bucket) : the index of the bottom level + */ +static byteptr_t +index_to_ptr(uint32_t index, uint32_t bucket) +{ + return base_ptr + ((index - (1 << bucket)) << (max_alloc_order - bucket)); +} + + +static uint32_t +ptr_to_index(byteptr_t ptr, uint32_t bucket) +{ + return ((ptr - base_ptr) >> (max_alloc_order - bucket)) + (1 << bucket); +} + + +static uint32_t +order_for_request(uint32_t request) +{ + uint32_t order = 0, size = 1 << MIN_ALLOC_ORDER; + while (size < request) { + ++order; + size = size << 1; + } + return order; +} + + +static uint32_t +bucket_for_request(uint32_t request) +{ + return bucket_count - order_for_request(request) - 1; +} + + +static inline uint32_t +search_free_bucket(uint32_t bucket) +{ + while (bucket >= 0) { + if (!list_empty(&buckets[bucket])) + return bucket; + bucket--; + } + return -1; +} + + +static inline uint32_t +search_available_node(uint32_t index) +{ + while (index > 0) { + if (node_is_used(index)) + return 0; + if (parent_is_split(index)) + return index; + index = index >> 1; + } + return index; +} + + +static void +split_up(uint32_t target, uint32_t index) +{ + while (target < index) { + set_parent_split(index); + uint32_t bucket = INDEX_LOG2(index); + byteptr_t buddy = index_to_ptr(index ^ 1, bucket); + + uart_printf("[DEBUG] split_up - bucket: %d, buddy: %d, addr: 0x%x\n", bucket, index ^ 1, buddy); + + list_push(&buckets[bucket], (list_head_ptr_t) buddy); + index = (index >> 1); + } +} + + +byteptr_t +add_init_free_block(byteptr_t ptr, uint32_t n_frames) +{ + uint32_t order = INT32_LEFTMOST_ORDER(n_frames); + list_add((list_head_ptr_t) ptr, &buckets[(bucket_count - 1 - order)]); + return (uint32_t) ptr + n_frames; +} + + +byteptr_t +init_frame_array(byteptr_t ptr, uint32_t n_frames) +{ + *ptr = *ptr | FRAME_SPLIT; + return ptr + n_frames; +} + + +void +frame_system_init(byteptr_t base, byteptr_t limit) +{ + base_ptr = base; + max_alloc_order = INDEX_LOG2((uint32_t) (limit - base)); + bucket_count = (max_alloc_order - FRAME_SIZE_ORDER + 1); + buckets = smalloc(bucket_count * sizeof(list_head_t)); + uart_printf("[DEBUG] frame_system_init - max_alloc_order: %d, bucket count: %d\n", max_alloc_order, bucket_count); + uart_printf("[DEBUG] frame_system_init - buckets addr: 0x%x, size: %d*%d bytes\n", buckets, bucket_count, sizeof(list_head_t)); + + max_alloc_size = (uint32_t) memory_align(limit, FRAME_SIZE_ORDER) + - (uint32_t) memory_align(base, FRAME_SIZE_ORDER); + uart_printf("[DEBUG] frame_system_init - max_alloc_size: 0x%x\n", max_alloc_size); + + total_frames = max_alloc_size >> FRAME_SIZE_ORDER; + frame_array = smalloc(total_frames * sizeof(byte_t)); + for (int i = 0; i < total_frames; ++i) frame_array[i] = 0; + uart_printf("[DEBUG] frame_system_init - frame_array addr: 0x%x, size: %d*%d bytes\n", frame_array, (1 << (bucket_count - 1)), sizeof(byte_t)); + + for (int i = 0; i < bucket_count; ++i) + bucket_init((byteptr_t) &buckets[i]); + + memseg_process(add_init_free_block, buckets, total_frames); + memseg_process(init_frame_array, frame_array, total_frames); + + // byteptr_t ptr = base_ptr; + // uint32_t frames = total_frames; // 3C000 + + // while (frames != 0) { + // /** + // * if total pages is 0x3C000 + // * 0x20000(17), 0x10000(16), 0x8000(15), 0x4000(14) + // */ + + // uint32_t order = INT32_LEFTMOST_ORDER(frames); + // list_add((list_head_ptr_t) ptr, &buckets[(bucket_count - 1 - order)]); + // ptr = (uint32_t) ptr + (1 << order); + // frames = frames & ~(1 << order); + // } + + // frame_array[0] |= FRAME_SPLIT; +} + + +byteptr_t +frame_alloc(uint32_t request) +{ + /** + * calculate the ideal order level + */ + uint32_t target_bucket = bucket_for_request(request); + + /** + * find the available order level if there's a free block smallest larger than request + */ + uint32_t bucket = search_free_bucket(target_bucket); + if (bucket < 0) return 0; + + /** + * pop the free block + */ + byteptr_t ptr = (byteptr_t) list_pop(&buckets[bucket]); + uint32_t target_index = ptr_to_index(ptr, target_bucket); + + /** + * get the free index of the block + */ + uint32_t index = ptr_to_index(ptr, bucket); + + /** + * iteratively split the block into the ideal order level, and update the index + */ + set_node_used(target_index); + split_up(index, target_index); + + return ptr; +} + + +byteptr_t +frame_request(uint32_t count) +{ + uint32_t request = count << FRAME_SIZE_ORDER; + if (request > max_alloc_size) { return 0; } + return frame_alloc(request); +} + + +byteptr_t +frame_alloc_addr(uint32_t addr, uint32_t count) +{ + byteptr_t ptr = memory_align(addr, FRAME_SIZE_ORDER); + + uart_printf("[DEBUG] frame_alloc_addr - addr: %x\n", addr); + + /** + * calculate the ideal order level and index of the block + */ + uint32_t target_bucket = bucket_for_request(count << FRAME_SIZE_ORDER); + uint32_t target_index = ptr_to_index(ptr, target_bucket); + + uart_printf("[DEBUG] frame_alloc_addr - target index: %d, bucket: %d\n", target_index, target_bucket); + + /** + * find available free block + */ + uint32_t index = search_available_node(target_index); + if (index == 0 || node_is_used(index)) { return 0; } + uint32_t bucket = INDEX_LOG2(index); + + /** + * pop the free block + */ + ptr = index_to_ptr(index, bucket); + list_del_entry((list_head_ptr_t) ptr); + + /** + * split buddies + */ + set_node_used(target_index); + + uart_printf("[DEBUG] frame_alloc_addr - index: %d, target: %d, addr: 0x%x\n", index, target_index, addr); + split_up(index, target_index); + + return ptr; +} + + +#define identify_ptr(ptr, index, bucket) \ + bucket = bucket_count - 1; index = ptr_to_index(ptr, bucket);\ + while (bucket > 0 && !parent_is_split(index)) {index = index >> 1; --bucket;} + + +void +frame_release(byteptr_t ptr) +{ + if (!ptr) return; + + /** + * identify the index and order level + */ + uint32_t index, bucket; + identify_ptr(ptr, index, bucket); + clr_node_used(index); + + /** + * merge the buddy by bottom-up if it's unused + */ + uint32_t buddy = index ^ 1; + while (bucket > 0 && !node_is_used(buddy) && !node_is_split(buddy)) { + byteptr_t buddy_ptr = index_to_ptr(buddy, bucket); + list_del_entry((list_head_ptr_t) buddy_ptr); + clr_parent_split(index); + index = index >> 1; --bucket; buddy = index ^ 1; + } + + list_add((list_head_ptr_t) ptr, &buckets[bucket]); +} + + +uint32_t next_child(byteptr_t ptr, uint32_t index) +{ + while(!parent_is_split(index)) { + index = index >> 1; + } +} + +static byteptr_t +print_buddy_info(byteptr_t ptr, uint32_t n_frames) +{ + byteptr_t mem_base = (uint32_t) base_ptr + (((uint32_t)ptr - (uint32_t)frame_array) << FRAME_SIZE_ORDER); + + uint32_t i = n_frames; + while (i > 0) { + + } + +} + + +void +frame_print_info() +{ + #define block_type(index) ({(node_is_used(index)) ? "allocated" : "free"; }) + + uart_printf("\n==== FRAME SYSTEM INFO ====\n"); + uart_printf("base: 0x%8x\n", base_ptr); + uart_printf("limit: 0x%8x\n", base_ptr + max_alloc_size); + uart_printf("freelist: %d buckets\n", bucket_count); + + uart_printf("\n==== MEMORY FRAME LAYOUT ====\n"); + + // byteptr_t ptr = base_ptr; + // uint32_t index, bucket; + // while (ptr < base_ptr + max_alloc_size) { + // identify_ptr(ptr, index, bucket); + // uint32_t order = (bucket_count-1)-bucket; + // uart_printf("0x%8x |%6dkb | %s\n", ptr, (1 << order + 2), block_type(index)); + // ptr = index_to_ptr(index+1, bucket); + // } + + // uint32_t count = total_frames; + // byteptr_t ptr = frame_array; + // while (count != 0) { + // uint32_t order = INT32_LEFTMOST_ORDER(count); + + + + // ptr = (uint32_t) ptr + (1 << order); + // count = count & ~(1 << order); + // } + + + uart_printf("\n==== FREE FRAME LISTS ====\n"); + for (int i = 0; i < bucket_count; ++i) { + if (!list_empty(&buckets[i])) { + uart_printf("bucket: %d, size: %dkb\n", i, 1 << (bucket_count-1 - i + 2)); + list_head_ptr_t pos; + list_for_each(pos, (list_head_ptr_t) &buckets[i]) + uart_printf(" +- 0x%8x\n", pos); + } + } + uart_printf("\n====================\n\n"); +} diff --git a/Lab 5/kernel/Makefile b/Lab 5/kernel/Makefile new file mode 100644 index 000000000..bfdb389d4 --- /dev/null +++ b/Lab 5/kernel/Makefile @@ -0,0 +1,57 @@ +TARGET = kernel8 + +ARMGNU ?= aarch64-linux-gnu + +CFLAGS = -MMD -Wall -nostdlib -nostartfiles -ffreestanding -mgeneral-regs-only -Iinclude -Wno-pointer-to-int-cast -g +ASMOPS = -MMD -Iinclude + +OUT_DIR = out +BUILD_DIR = build +SRC_DIR = src + +# all: clean $(TARGET).img +all: clean ramdisk $(TARGET).img + +debug: CCFLAGS += -DDEBUG -g +# debug: clean $(TARGET).img +debug: clean ramdisk $(TARGET).img + + +clean: + rm -rf $(BUILD_DIR) $(OUT_DIR) *.img + +remake: clean all + + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + $(ARMGNU)-gcc $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +SD_DIR = ../sd + +ramdisk: + mkdir -p $(BUILD_DIR) +# $(ARMGNU)-ld -r -b binary -o $(BUILD_DIR)/rd.o $(SD_DIR)/initramfs.cpio + +# OBJ_FILES += $(BUILD_DIR)/rd.o + +$(TARGET).img: $(SRC_DIR)/linker.ld $(OBJ_FILES) + mkdir -p $(OUT_DIR) + $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -o $(BUILD_DIR)/$(TARGET).elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/$(TARGET).elf -O binary $(OUT_DIR)/$(TARGET).img + +run: $(OUT_DIR)/$(TARGET).img + qemu-system-aarch64 -M raspi3b -kernel $(OUT_DIR)/$(TARGET).img -serial null -serial stdio -initrd $(SD_DIR)/initramfs.cpio -dtb $(SD_DIR)/bcm2710-rpi-3-b-plus.dtb + +gdb: $(OUT_DIR)/$(TARGET).img + qemu-system-aarch64 -M raspi3b -kernel $(OUT_DIR)/$(TARGET).img -serial null -serial stdio -initrd $(SD_DIR)/initramfs.cpio -dtb $(SD_DIR)/bcm2710-rpi-3-b-plus.dtb -S -s \ No newline at end of file diff --git a/Lab 5/kernel/include/arm/sysregs.h b/Lab 5/kernel/include/arm/sysregs.h new file mode 100644 index 000000000..f33e024bb --- /dev/null +++ b/Lab 5/kernel/include/arm/sysregs.h @@ -0,0 +1,63 @@ +#ifndef _SYSREGS_H +#define _SYSREGS_H + +// *************************************** +// SCTLR_EL1, System Control Register (EL1), Page 2654 of AArch64-Reference-Manual. +// *************************************** + +#define SCTLR_RESERVED (3 << 28) | (3 << 22) | (1 << 20) | (1 << 11) +#define SCTLR_EE_LITTLE_ENDIAN (0 << 25) +#define SCTLR_EOE_LITTLE_ENDIAN (0 << 24) +#define SCTLR_I_CACHE_DISABLED (0 << 12) +#define SCTLR_D_CACHE_DISABLED (0 << 2) +#define SCTLR_MMU_DISABLED (0 << 0) +#define SCTLR_MMU_ENABLED (1 << 0) + +#define SCTLR_VALUE_MMU_DISABLED (SCTLR_RESERVED | SCTLR_EE_LITTLE_ENDIAN | SCTLR_I_CACHE_DISABLED | SCTLR_D_CACHE_DISABLED | SCTLR_MMU_DISABLED) + +// *************************************** +// HCR_EL2, Hypervisor Configuration Register (EL2), Page 2487 of AArch64-Reference-Manual. +// *************************************** + +#define HCR_RW (1 << 31) +#define HCR_VALUE HCR_RW + +// *************************************** +// SCR_EL3, Secure Configuration Register (EL3), Page 2648 of AArch64-Reference-Manual. +// *************************************** + +#define SCR_RESERVED (3 << 4) +#define SCR_RW (1 << 10) +#define SCR_NS (1 << 0) +#define SCR_VALUE (SCR_RESERVED | SCR_RW | SCR_NS) + +// *************************************** +// SPSR_EL3, Saved Program Status Register (EL3) Page 389 of AArch64-Reference-Manual. +// *************************************** + +#define SPSR_MASK_ALL (7 << 6) +#define SPSR_EL1h (5 << 0) +#define SPSR_VALUE (SPSR_MASK_ALL | SPSR_EL1h) + +// *************************************** +// ESR_EL1, Exception Syndrome Register (EL1). Page 2431 of AArch64-Reference-Manual. +// *************************************** + +#define ESR_ELx_EC_SHIFT 26 +#define ESR_ELx_EC_SVC64 0x15 + + +// *************************************** +// PSR bits +// *************************************** + +#define PSR_MODE_EL0t 0x00000000 +#define PSR_MODE_EL1t 0x00000004 +#define PSR_MODE_EL1h 0x00000005 +#define PSR_MODE_EL2t 0x00000008 +#define PSR_MODE_EL2h 0x00000009 +#define PSR_MODE_EL3t 0x0000000c +#define PSR_MODE_EL3h 0x0000000d + + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/include/asm.h b/Lab 5/kernel/include/asm.h new file mode 100644 index 000000000..bae411a68 --- /dev/null +++ b/Lab 5/kernel/include/asm.h @@ -0,0 +1,17 @@ +#ifndef __ASM_H__ +#define __ASM_H__ + + +#define asm_read_sysregister(r) ({ \ + uint64_t __val; \ + asm volatile("mrs %0, " #r : "=r" (__val)); \ + __val; \ +}) + +#define asm_write_sysregister(r, __val) ({ \ + asm volatile("msr " #r ", %0" :: "r" (__val)); \ +}) + + + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/include/aux.h b/Lab 5/kernel/include/aux.h new file mode 100644 index 000000000..98216c7c9 --- /dev/null +++ b/Lab 5/kernel/include/aux.h @@ -0,0 +1,41 @@ +#ifndef __AUX_H__ +#define __AUX_H__ + +#include "mmio.h" + +#define AUX_BASE (MMIO_BASE + 0x215000) + +/* Auxilary mini UART registers */ +#define AUX_IRQ ((volatile unsigned int*)(AUX_BASE + 0x00)) +#define AUX_ENABLES ((volatile unsigned int*)(AUX_BASE + 0x04)) // Auxiliary enables | 3 +#define AUX_MU_IO ((volatile unsigned int*)(AUX_BASE + 0x40)) // I/O Data | 8 +#define AUX_MU_IER ((volatile unsigned int*)(AUX_BASE + 0x44)) // Interrupt Enable Register | 8 +#define AUX_MU_IIR ((volatile unsigned int*)(AUX_BASE + 0x48)) // Interrupt Identify Register | 8 +#define AUX_MU_LCR ((volatile unsigned int*)(AUX_BASE + 0x4C)) // Line Control Register | 8 +#define AUX_MU_MCR ((volatile unsigned int*)(AUX_BASE + 0x50)) // Modem Control Register | 8 +#define AUX_MU_LSR ((volatile unsigned int*)(AUX_BASE + 0x54)) // Line Status Register | 8 +#define AUX_MU_MSR ((volatile unsigned int*)(AUX_BASE + 0x58)) // Modem Status Register | 8 +#define AUX_MU_SCRATCH ((volatile unsigned int*)(AUX_BASE + 0x5C)) // Scratch | 8 +#define AUX_MU_CNTL ((volatile unsigned int*)(AUX_BASE + 0x60)) // Extra Control | 8 +#define AUX_MU_STAT ((volatile unsigned int*)(AUX_BASE + 0x64)) // Extra Status | 32 +#define AUX_MU_BAUD ((volatile unsigned int*)(AUX_BASE + 0x68)) // Baudrate | 16 + +#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_set_rx_interrupts() { *AUX_MU_IER |= 0x1; } +#define aux_clr_rx_interrupts() { *AUX_MU_IER &= ~(0x1); } +#define aux_set_tx_interrupts() { *AUX_MU_IER |= 0x2; } +#define aux_clr_tx_interrupts() { *AUX_MU_IER &= ~(0x2); } + + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/include/cpio.h b/Lab 5/kernel/include/cpio.h new file mode 100644 index 000000000..f45d6a1bb --- /dev/null +++ b/Lab 5/kernel/include/cpio.h @@ -0,0 +1,52 @@ +#ifndef __CPIO_H__ +#define __CPIO_H__ + +/* + https://man.freebsd.org/cgi/man.cgi?query=cpio + https://man.freebsd.org/cgi/man.cgi?query=cpio&sektion=5 + + CPIO New ASCII Format + The "new" ASCII format uses 8-byte hexadecimal fields for all numbers + and separates device numbers into separate fields for major and minor + numbers. + + magic The string "070701". + check This field is always set to zero by writers and ignored by readers. + + The end of the archive is indicated by a special record with the pathname "TRAILER!!". + + + ### The cpio file will be read like: + + 000001110000111.....0000 -> 110 byte header + ABC.txt -> file name + This is ABC.txt -> content + + 000001110000111.....0000 -> 110 byte header + DEF.txt -> file name + This is DEF.txt -> content + + 000001110000111.....0000 -> 110 byte header + TRAILER!!! ---> END OF THE CPIO +*/ + +typedef struct { + char c_magic[6]; /* Magic header '070701' */ + char c_ino[8]; /* "i-node" number */ + char c_mode[8]; /* Permisions */ + char c_uid[8]; /* User ID */ + char c_gid[8]; /* Group ID */ + char c_nlink[8]; /* Number of hard links */ + char c_mtime[8]; /* Modification time */ + char c_filesize[8]; /* File size */ + char c_devmajor[8]; /* Device number major */ + char c_devminor[8]; /* Device number minor */ + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; /* length of the path name */ + char c_check[8]; /* always set to zero */ +} cpio_t; + +typedef cpio_t* cpio_ptr_t; + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/include/gpio.h b/Lab 5/kernel/include/gpio.h new file mode 100644 index 000000000..08a217f29 --- /dev/null +++ b/Lab 5/kernel/include/gpio.h @@ -0,0 +1,44 @@ +#ifndef __GPIO_H__ +#define __GPIO_H__ + +#include "mmio.h" + +#define GPIO_BASE (MMIO_BASE + 0x00200000) + +#define GPFSEL0 ((volatile unsigned int*)(GPIO_BASE + 0x00000000)) +#define GPFSEL1 ((volatile unsigned int*)(GPIO_BASE + 0x00000004)) +#define GPFSEL2 ((volatile unsigned int*)(GPIO_BASE + 0x00000008)) +#define GPFSEL3 ((volatile unsigned int*)(GPIO_BASE + 0x0000000C)) +#define GPFSEL4 ((volatile unsigned int*)(GPIO_BASE + 0x00000010)) +#define GPFSEL5 ((volatile unsigned int*)(GPIO_BASE + 0x00000014)) + +#define GPSET0 ((volatile unsigned int*)(GPIO_BASE + 0x0000001C)) +#define GPSET1 ((volatile unsigned int*)(GPIO_BASE + 0x00000020)) + +#define GPCLR0 ((volatile unsigned int*)(GPIO_BASE + 0x00000028)) +#define GPCLR1 ((volatile unsigned int*)(GPIO_BASE + 0x0000002C)) + +#define GPLEV0 ((volatile unsigned int*)(GPIO_BASE + 0x00000034)) +#define GPLEV1 ((volatile unsigned int*)(GPIO_BASE + 0x00000038)) + +#define GPEDS0 ((volatile unsigned int*)(GPIO_BASE + 0x00000040)) +#define GPEDS1 ((volatile unsigned int*)(GPIO_BASE + 0x00000044)) + +#define GPHEN0 ((volatile unsigned int*)(GPIO_BASE + 0x00000064)) +#define GPHEN1 ((volatile unsigned int*)(GPIO_BASE + 0x00000068)) + +#define GPLEN0 ((volatile unsigned int*)(GPIO_BASE + 0x00000070)) +#define GPLEN1 ((volatile unsigned int*)(GPIO_BASE + 0x00000074)) + +#define GPAREN0 ((volatile unsigned int*)(GPIO_BASE + 0x0000007C)) +#define GPAREN1 ((volatile unsigned int*)(GPIO_BASE + 0x00000080)) + +#define GPAFEN0 ((volatile unsigned int*)(GPIO_BASE + 0x00000088)) +#define GPAFEN1 ((volatile unsigned int*)(GPIO_BASE + 0x0000008C)) + +#define GPPUD ((volatile unsigned int*)(GPIO_BASE + 0x00000094)) + +#define GPPUDCLK0 ((volatile unsigned int*)(GPIO_BASE + 0x00000098)) +#define GPPUDCLK1 ((volatile unsigned int*)(GPIO_BASE + 0x0000009C)) + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/include/irq.h b/Lab 5/kernel/include/irq.h new file mode 100644 index 000000000..c9379a5bd --- /dev/null +++ b/Lab 5/kernel/include/irq.h @@ -0,0 +1,16 @@ +#ifndef __IRQ_H__ +#define __IRQ_H__ + +#include "mmio.h" + +#define IRQ_BASIC ((volatile uint32ptr_t) (MMIO_BASE + 0xb200)) // p.114 +#define IRQ_PENDING1 ((volatile uint32ptr_t) (MMIO_BASE + 0xb204)) // p.115 +#define IRQ_ENABLE1 ((volatile uint32ptr_t) (MMIO_BASE + 0xb210)) // p.116 +#define IRQ_DISABLE1 ((volatile uint32ptr_t) (MMIO_BASE + 0xb21c)) // p.117 + + +#define irq_enable_aux_interrupt() { *IRQ_ENABLE1 = (1 << 29); } +#define irq_disable_aux_interrupt() { *IRQ_DISABLE1 = (1 << 29); } + + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/include/kernel.h b/Lab 5/kernel/include/kernel.h new file mode 100644 index 000000000..a5b337865 --- /dev/null +++ b/Lab 5/kernel/include/kernel.h @@ -0,0 +1,11 @@ +#ifndef __KERNEL_H__ +#define __KERNEL_H__ + +#include "type.h" + +uint64_t current_exception_level(); +byteptr_t align(const byteptr_t p, uint32_t s); + +int32_t get_el(); + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/include/list.h b/Lab 5/kernel/include/list.h new file mode 100644 index 000000000..4508c47ff --- /dev/null +++ b/Lab 5/kernel/include/list.h @@ -0,0 +1,146 @@ +#ifndef _LIST_H_ +#define _LIST_H_ + +typedef struct list_head { + struct list_head *next, *prev; +} list_head_t; + +typedef list_head_t* list_head_ptr_t; +typedef list_head_ptr_t list_ptr; + + +/* + struct list_head mylist = {&mylist, &mylist} ; +*/ +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + + +/* + Usage: + struct list_head myhead; + INIT_LIST_HEAD(&myhead); +*/ +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. + */ +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_; +} + + + /* + Insert a new entry after the specified head. + */ +static inline void +list_add(struct list_head *new_, struct list_head *head) +{ + __list_add(new_, head, head->next); +} + + +/* + Insert a new entry before the specified head. + */ +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. + */ +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. +*/ +static inline void +list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = 0; + entry->prev = 0; +} + + +/* + check if it is pointing to the list head +*/ +static inline int +list_is_head(const struct list_head *list, const struct list_head *head) +{ + return list == head; +} + + +/* + check if is is the first entry of the list +*/ +static inline int +list_is_first(const struct list_head *list, const struct list_head *head) +{ + return list->prev == head; +} + + +/* + check if the list is empty +*/ +static inline int +list_empty(const struct list_head *head) +{ + return head->next == head; +} + + +/* + iterate over a list + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next) + + +#define offsetof(st, m) __builtin_offsetof(st, m) + + +#define container_of(ptr, type, member) \ + __extension__({ \ + const __typeof__(((type*)0)->member)* __pmember = (ptr); \ + (type*) ((char*) __pmember - offsetof(type, member)); \ + }) + + +#define list_entry(ptr, type, member) container_of(ptr, type, member) + + +#define list_for_each_entry(entry, head, member) \ + for (entry = list_entry((head)->next, __typeof__(*entry), member); \ + &entry->member != (head); \ + entry = list_entry(entry->member.next, __typeof__(*entry), member)) + + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/include/mmio.h b/Lab 5/kernel/include/mmio.h new file mode 100644 index 000000000..71590998f --- /dev/null +++ b/Lab 5/kernel/include/mmio.h @@ -0,0 +1,9 @@ +#ifndef __MMIO_H__ +#define __MMIO_H__ + +#include "type.h" + +#define MMIO_BASE 0x3F000000 + + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/include/sprintf.h b/Lab 5/kernel/include/sprintf.h new file mode 100644 index 000000000..1ed4e6af0 --- /dev/null +++ b/Lab 5/kernel/include/sprintf.h @@ -0,0 +1,120 @@ +#ifndef _SPRINTF_H_ +#define _SPRINTF_H_ + +/** + * minimal sprintf implementation + */ +static unsigned int vsprintf(char *dst, char* fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig = dst, tmpstr[19]; + + // failsafes + if (dst==(void*) 0 || fmt == (void*) 0) { + return 0; + } + + // main loop + arg = 0; + while (*fmt) { + // argument access + if (*fmt == '%') { + fmt++; + // literal % + if (*fmt == '%') { + goto put; + } + len = 0; + // size modifier + while (*fmt >= '0' && *fmt <= '9') { + len *= 10; + len += *fmt - '0'; + fmt++; + } + // skip long modifier + if (*fmt == 'l') { + fmt++; + } + // character + if (*fmt == 'c') { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } else + // decimal number + if (*fmt=='d') { + arg = __builtin_va_arg(args, int); + // check input + sign = 0; + if ((int) arg < 0) { + arg *= -1; + sign++; + } + if (arg > 99999999999999999L) { + arg = 99999999999999999L; + } + // convert to string + i = 18; + tmpstr[i] = 0; + do { + tmpstr[--i] = '0' + (arg % 10); + arg /= 10; + } while (arg != 0 && i > 0); + if (sign) { + tmpstr[--i] = '-'; + } + // padding, only space + if (len > 0 && len < 18) { + while (i > 18 - len ) { + tmpstr[--i] = ' '; + } + } + p = &tmpstr[i]; + goto copystring; + } else + // hex number + if (*fmt == 'x') { + arg = __builtin_va_arg(args, long int); + // convert to string + i = 16; + tmpstr[i] = 0; + do { + char n = arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i] = n + (n > 9 ? 0x37 : 0x30); + arg >>= 4; + } while (arg != 0 && i > 0); + // padding, only leading zeros + if (len > 0 && len <= 16) { + while (i > 16 - len) { + tmpstr[--i] = '0'; + } + } + p = &tmpstr[i]; + goto copystring; + } else + // string + if (*fmt=='s') { + p = __builtin_va_arg(args, char*); +copystring: if (p == (void*) 0) { + p = "(null)"; + } + while (*p) { + *dst++ = *p++; + } + } + } else { +put: *dst++ = *fmt; + } + fmt++; + } + *dst = 0; + // number of bytes written + return dst - orig; +} + + + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/include/type.h b/Lab 5/kernel/include/type.h new file mode 100644 index 000000000..b7e49cfeb --- /dev/null +++ b/Lab 5/kernel/include/type.h @@ -0,0 +1,33 @@ +#ifndef __TYPE_H__ +#define __TYPE_H__ + +#include + +#define nullptr 0l + +typedef void* voidptr_t; +typedef void* void_ptr; +typedef char* byteptr_t; +typedef char* byte_ptr; +typedef char* char_ptr; +typedef char byte_t; +typedef uint8_t* uint8ptr_t; +typedef uint8_t* uint8_ptr; +typedef uint32_t* uint32ptr_t; +typedef uint32_t* uint32_ptr; +typedef uint64_t* uint64ptr_t; +typedef uint64_t* uint64_ptr; + +#define INT32_LEFTMOST_ORDER(x) ({31 - __builtin_clz(x);}) +#define INT32_LEFTMOST(x) 1 << INT32_LEFTMOST_ORDER(x) +#define INT32_RIGHTMOST_ORDER(x) ({__builtin_ctz(x);}) +#define INT32_RIGHTMOST(x) 1 << INT32_RIGHTMOST_ORDER(x) + +#define UINT32_ALIGN(v, o) ({(v) & ~((1 << o) - 1);}) +#define UINT32_PADDING(v, o) ({(v + ((1 << o) - 1)) & ~((1 << o) - 1);}) + + +#define max(a, b) (a > b ? a : b) +#define min(a, b) (a < b ? a : b) + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/chunk.c b/Lab 5/kernel/src/chunk.c new file mode 100644 index 000000000..b2e2834b6 --- /dev/null +++ b/Lab 5/kernel/src/chunk.c @@ -0,0 +1,209 @@ +#include "chunk.h" +#include "frame.h" +#include "list.h" +#include "uart.h" + + +#define CHUNK_UNIT_ORDER 4 +#define CHUNK_MAX_COUNT 0xEF // 240 - 1 +#define CHUNK_MIN_SIZE (1 << CHUNK_UNIT_ORDER) +#define CHUNK_MAX_SIZE (CHUNK_MAX_COUNT * CHUNK_MIN_SIZE) + +#define CHUNK_LIST_OFFSET 0x10 // 16 +#define CHUNK_DATA_OFFSET 0x100 // 256 + +#define CHUNK_SIZE_INDEX 0xF0 // 240 +#define CHUNK_COUNT_INDEX 0xF1 // 241 + +#define ADDR_TO_PTR(addr) ({(byteptr_t)(addr | 0l);}) +#define PTR_TO_ADDR(ptr) ({(uint32_t) ptr;}) + +#define FRAME_ADDR(ptr) ({(uint32_t) ptr & ~((1 << FRAME_SIZE_ORDER) - 1);}) +#define CHUNK_LIST(ptr) ({(FRAME_ADDR(ptr) + CHUNK_LIST_OFFSET);}) +#define CHUNK_DATA(ptr) ({(FRAME_ADDR(ptr) + CHUNK_DATA_OFFSET);}) + +#define CHUNK_TO_INDEX(ptr) ({((uint32_t) ptr - CHUNK_DATA(ptr)) >> CHUNK_UNIT_ORDER;}) +#define CLAMP_CHUNK_SIZE(size) ({(size < CHUNK_MIN_SIZE) ? CHUNK_MIN_SIZE : (size > CHUNK_MAX_SIZE) ? CHUNK_MAX_SIZE : size;}) + + +/** + * chunk size: 1~15 (x16bytes) +*/ +static void +init_frame(byteptr_t frame, uint32_t chunk_size) +{ + INIT_LIST_HEAD((list_head_ptr_t) frame); + + byteptr_t list = ADDR_TO_PTR(CHUNK_LIST(frame)); + + list[0] = 1; + for (int32_t i = 1; i < CHUNK_SIZE_INDEX; ++i) { list[i] = 0; } + int32_t i = 1; + while (i < CHUNK_SIZE_INDEX) { list[i] = i + chunk_size; i += chunk_size; } + list[i - chunk_size] = 0; + list[CHUNK_COUNT_INDEX] = 0; + list[CHUNK_SIZE_INDEX] = (uint8_t) chunk_size; +} + + +static byteptr_t +frame_request_chunk(byteptr_t frame) +{ + byteptr_t list = ADDR_TO_PTR(CHUNK_LIST(frame)); + + // check top, it's full when top is zero + if (list[0] == 0) return 0; + + // pop free list + uint8_t top = list[0]; + uint8_t second = list[top]; + list[0] = second; + + // accumlate the counter (# of allocated 16-byte units) + uint8_t size = list[CHUNK_SIZE_INDEX]; + list[CHUNK_COUNT_INDEX] += size; + + // index to ptr + byteptr_t data = ADDR_TO_PTR(CHUNK_DATA(frame)); + + // uart_printf("[DEBUG] frame: 0x%x, data: 0x%x, top: %d\n", frame, data, top); + + return &data[top * (1 << CHUNK_UNIT_ORDER)]; +} + + +/** + * return value: + * 1 - this frame is empty after released + * 0 - otherwise +*/ +static uint32_t +frame_release_chunk(byteptr_t chunk) +{ + byteptr_t list = ADDR_TO_PTR(CHUNK_LIST(chunk)); + + // push free list + uint32_t index = CHUNK_TO_INDEX(chunk); + list[index] = list[0]; + list[0] = index; + + // decrease the counter + uint8_t size = list[CHUNK_SIZE_INDEX]; + list[CHUNK_COUNT_INDEX] -= size; + + // return 1 if empty + return (list[CHUNK_COUNT_INDEX] == 0) ? 1 : 0; +} + + +static uint32_t +frame_count_free_chunks(byteptr_t frame) +{ + byteptr_t list = ADDR_TO_PTR(CHUNK_LIST(frame)); + uint32_t i = 0, count = 0; + while (i < CHUNK_MAX_COUNT && list[i] != 0) { ++count; i = list[i]; } + return count; +} + + +static list_head_ptr_t chunk_table; + +#define CHUNK_TABLE(i) ({(list_head_ptr_t) &chunk_table[i];}) +#define FRAME_IS_FULL(ptr) ({ADDR_TO_PTR(CHUNK_LIST(ptr))[0] == 0;}) +#define FRAME_IS_EMPTY(ptr) ({ADDR_TO_PTR(CHUNK_LIST(ptr))[CHUNK_COUNT_INDEX] == 0;}) + + +void +init_chunk_table() +{ + chunk_table = (list_head_ptr_t) CHUNK_TABLE_ADDR; + for (uint32_t i = 0; i < CHUNK_MAX_COUNT; ++i) + INIT_LIST_HEAD(CHUNK_TABLE(i)); +} + + +void +chunk_release(byteptr_t ptr) +{ + frame_release_chunk(ptr); + if (FRAME_IS_EMPTY(ptr)) { + list_del_entry((list_head_ptr_t) ADDR_TO_PTR(FRAME_ADDR(ptr))); + frame_release(ptr); + } +} + +/** + * size: request momory size in bytes +*/ +byteptr_t +chunk_request(uint32_t size) +{ + size = CLAMP_CHUNK_SIZE(size); + size = UINT32_PADDING(size, CHUNK_UNIT_ORDER); + + uint32_t index = (size >> CHUNK_UNIT_ORDER) - 1; + + // uart_printf("[DEBUG] chunk_request - index: %d, size: %d\n", index, size); + + list_head_ptr_t head = CHUNK_TABLE(index); + + // uart_printf("[DEBUG] chunk_request - head: 0x%x\n", head); + + list_head_ptr_t ptr = head->next; + while (ptr != head && FRAME_IS_FULL(ptr)) { ptr = ptr->next; } + + // uart_printf("[DEBUG] chunk_request - ptr: 0x%x\n", ptr); + + if (ptr == head) { + byteptr_t frame = frame_alloc(1); + INIT_LIST_HEAD((list_head_ptr_t) frame); + init_frame(frame, (size >> CHUNK_UNIT_ORDER)); + list_add_tail((list_head_ptr_t) frame, head); + + // uart_printf("[DEBUG] chunk_request - create frame: 0x%x, first: 0x%x\n", frame, head->next); + + ptr = (list_head_ptr_t) frame; + } + + byteptr_t ret = frame_request_chunk((byteptr_t) ptr); + return ret; +} + + +void +chunk_info(byteptr_t chunk) +{ + uart_printf("+- chunk addr: 0x%x, frame addr: 0x%x,", chunk, FRAME_ADDR(chunk)); + byteptr_t list = ADDR_TO_PTR(CHUNK_LIST(chunk)); + uint8_t size = list[CHUNK_SIZE_INDEX]; + uint8_t count = list[CHUNK_COUNT_INDEX]; + uart_printf(" chunk size: %d bytes, allocated count: %d, top: %d, free chunks: %d\n", size * 16, count, list[0], frame_count_free_chunks(chunk)); +} + +void +chunk_system_infro() +{ + uart_printf("==== CHUNK ALLOCATED INFO ====\n"); + for (uint32_t i = 0; i < CHUNK_MAX_COUNT; ++i) { + list_head_ptr_t head = CHUNK_TABLE(i); + if (!list_empty(head)) { + uart_printf("chunk size: %d bytes:\n", (i+1) * 16); + for (list_head_ptr_t ptr = head->next; ptr != head; ptr = ptr->next) + chunk_info((byteptr_t) ptr); + } + } +} + + +uint32_t +chunk_max_size() +{ + return CHUNK_MAX_SIZE; +} + + +uint32_t +chunk_data_offset() +{ + return CHUNK_DATA_OFFSET; +} diff --git a/Lab 5/kernel/src/chunk.h b/Lab 5/kernel/src/chunk.h new file mode 100644 index 000000000..4a01a1e8d --- /dev/null +++ b/Lab 5/kernel/src/chunk.h @@ -0,0 +1,22 @@ +#ifndef __CHUNK_H__ +#define __CHUNK_H__ + +#include "type.h" + +#define CHUNK_TABLE_ADDR 0x1000 +#define CHUNK_TABLE_END 0x2000 + + +void init_chunk_table(); + +void chunk_release(byteptr_t ptr); +byteptr_t chunk_request(uint32_t size); + +void chunk_info(byteptr_t chunk); + +uint32_t chunk_max_size(); +uint32_t chunk_data_offset(); + +void chunk_system_infro(); + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/core_timer.c b/Lab 5/kernel/src/core_timer.c new file mode 100644 index 000000000..84103f894 --- /dev/null +++ b/Lab 5/kernel/src/core_timer.c @@ -0,0 +1,192 @@ +#include "core_timer.h" +#include "asm.h" +#include "mmio.h" +#include "uart.h" +#include "string.h" +#include "memory.h" +#include "exception.h" +#include "list.h" + + +/* + 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 +*/ + + +static void +core_timer_set_timeout(uint32_t duration) +{ + uint64_t freq = asm_read_sysregister(cntfrq_el0); + asm_write_sysregister(cntp_tval_el0, freq * duration); +} + + +static void +core_timer_set_tick(uint32_t duration) +{ + uint64_t freq = asm_read_sysregister(cntfrq_el0); + asm_write_sysregister(cntp_tval_el0, freq >> duration); +} + + + +void +core_timer_enable() +{ + asm_write_sysregister(cntp_ctl_el0, 1); + *CORE0_TIMER_IRQ_CTRL = (uint32_t) 2; // unmask timer interrupt +} + + +void +core_timer_disable() +{ + asm_write_sysregister(cntp_ctl_el0, 0); // disable + *CORE0_TIMER_IRQ_CTRL = (uint32_t) 0; // unmask timer interrupt +} + + +uint64_t +core_timer_current_time() +{ + uint64_t freq = asm_read_sysregister(cntfrq_el0); + uint64_t cur_cnt = asm_read_sysregister(cntpct_el0); + return cur_cnt / freq; +} + + +typedef struct timer_event { + struct list_head listhead; + uint64_t event_time; + uint64_t duration; + uint64_t expired_time; + timer_event_cb callback; + byte_t message[32]; // todo: pointer to a allocated space + uint32_t is_tick; +} timer_event_t; + +typedef timer_event_t* timer_event_ptr_t; + + +static timer_event_ptr_t +timer_event_create(timer_event_cb cb, byteptr_t msg, uint64_t duration) +{ + timer_event_ptr_t event = (timer_event_ptr_t) kmalloc(sizeof(timer_event_t)); + INIT_LIST_HEAD(&event->listhead); + event->event_time = core_timer_current_time(); + event->duration = duration; + event->expired_time = event->event_time + duration; + + event->callback = cb; + event->is_tick = 0; + str_ncpy(event->message, msg, 32); + return event; +} + + +static LIST_HEAD(timer_event_queue); + + +static void +timer_event_queue_add(timer_event_ptr_t event) +{ + list_head_ptr_t curr = (&timer_event_queue)->next; + + while (!list_is_head(curr, &timer_event_queue) && ((timer_event_ptr_t) curr)->expired_time <= (event->expired_time)) { + curr = curr->next; + } + list_add(&event->listhead, curr->prev); + + // if the new event is inserted at the front, update the timer + if (list_is_first((list_head_ptr_t) event, &timer_event_queue)) { + if (event->is_tick) + core_timer_set_tick(event->duration); + else + core_timer_set_timeout(event->expired_time - core_timer_current_time()); + core_timer_enable(); + } +} + + +static void +core_timer_callback_print_message(byteptr_t data) +{ + timer_event_ptr_t event = (timer_event_ptr_t) data; + + uart_printf("command time: %d\n", event->event_time); + uart_printf("current time: %d\n", core_timer_current_time()); + uart_str("timer event message: "); + uart_line(event->message); +} + + +static void +core_timer_add_event(timer_event_cb cb, byteptr_t msg, uint64_t duration) +{ + timer_event_ptr_t event = timer_event_create(cb, msg, duration); + timer_event_queue_add(event); +} + + +void +core_timer_add_timeout_event(byteptr_t data, uint64_t duration) +{ + core_timer_add_event(core_timer_callback_print_message, data, duration); +} + + +void +core_timer_add_tick(timer_event_cb cb, byteptr_t msg, uint64_t duration) +{ + timer_event_ptr_t event = timer_event_create(cb, msg, duration); + event->is_tick = 1; + timer_event_queue_add(event); +} + + +/* + interrupt service routine + 1. run the first event of the list + 2. remove the first event + 3. check the next event of the list + 4. set the timer registers or clear them +*/ + +void +core_timer_interrupt_handler() +{ + // uart_printf("core_timer_interrupt_handler\n"); + + exception_l1_disable(); + + timer_event_ptr_t event = (timer_event_ptr_t) (&timer_event_queue)->next; + + list_del_entry((list_head_ptr_t) event); + + if (event->is_tick) { + timer_event_queue_add(event); + } + + if (!list_empty(&timer_event_queue)) { + timer_event_ptr_t first = (timer_event_ptr_t) (&timer_event_queue)->next; + if (first->is_tick) + core_timer_set_tick(first->duration); + else + core_timer_set_timeout(first->expired_time - core_timer_current_time()); + core_timer_enable(); + } + + exception_l1_enable(); + + event->callback((byteptr_t) event); + if (!event->is_tick) { kfree((byteptr_t) event); } +} \ No newline at end of file diff --git a/Lab 5/kernel/src/core_timer.h b/Lab 5/kernel/src/core_timer.h new file mode 100644 index 000000000..4543fe8e9 --- /dev/null +++ b/Lab 5/kernel/src/core_timer.h @@ -0,0 +1,20 @@ +#ifndef __CORE_TIMER_H__ +#define __CORE_TIMER_H__ + +#include "type.h" + +#define CORE0_TIMER_IRQ_CTRL ((volatile uint32ptr_t) (0x40000040)) +#define CORE0_INTERRUPT_SOURCE ((volatile uint32ptr_t) (0x40000060)) + +uint64_t core_timer_current_time(); +void core_timer_enable(); +void core_timer_disable(); + +void core_timer_interrupt_handler(); +void core_timer_add_timeout_event(byteptr_t message, uint64_t duration); + +typedef void (*timer_event_cb) (byteptr_t); + +void core_timer_add_tick(timer_event_cb cb, byteptr_t msg, uint64_t duration); + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/delay.c b/Lab 5/kernel/src/delay.c new file mode 100644 index 000000000..87ef63dbc --- /dev/null +++ b/Lab 5/kernel/src/delay.c @@ -0,0 +1,27 @@ +#include "type.h" + +/* Wait N CPU cycles (ARM CPU only) */ + +void +delay_cycles(uint32_t n) +{ + if (n) while (n--) { asm volatile("nop"); } +} + +/** + * Wait N microseconds (ARM CPU only) + */ +void +delay_msec(uint32_t n) +{ + register uint64_t freq, start, cur; + + asm volatile ("mrs %0, cntfrq_el0" : "=r"(freq)); // get current counter frequency + asm volatile ("mrs %0, cntpct_el0" : "=r"(start)); // read the current counter + + uint64_t i = ((freq / 1000) * n) / 1000; // calculate required count increase + + do { + asm volatile ("mrs %0, cntpct_el0" : "=r"(cur)); + } while (cur - start < i); // loop while counter increase is less than i +} \ No newline at end of file diff --git a/Lab 5/kernel/src/delay.h b/Lab 5/kernel/src/delay.h new file mode 100644 index 000000000..f3aaf8486 --- /dev/null +++ b/Lab 5/kernel/src/delay.h @@ -0,0 +1,9 @@ +#ifndef __DELAY_H__ +#define __DELAY_H__ + +#include "type.h" + +void delay_cycles(uint32_t n); +void delay_msec(uint32_t n); + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/dtb.c b/Lab 5/kernel/src/dtb.c new file mode 100644 index 000000000..3022adc1f --- /dev/null +++ b/Lab 5/kernel/src/dtb.c @@ -0,0 +1,218 @@ +#include "dtb.h" +#include "memory.h" +#include "string.h" +#include "uart.h" +#include "initrd.h" + + +/* + Flatten Devicetree (DTB) Format + + .dtb (devicetree blob) structure + + +----------------------------+ + | struct fdt_header | + +----------------------------+ + | (free space) | + +----------------------------+ + | memory reservation block | + +----------------------------+ + | (free space) | + +----------------------------+ + | structure block | + +----------------------------+ + | (free space) | + +----------------------------+ + | strings block | + +----------------------------+ + | (free space) | + +----------------------------+ +*/ + + +typedef struct fdt_header +{ + uint32_t magic; // contain the value 0xd00dfeed (big-endian). + uint32_t totalsize; // in byte + uint32_t off_dt_struct; // the offset in bytes of the structure block + uint32_t off_dt_strings; // the offset in bytes of the string block + uint32_t off_mem_rsvmap; // the offset in bytes of the memory reservation block + uint32_t version; // the version of the devicetree data structure (The version is 17 in the document) + uint32_t last_comp_version; // the lowest version with which the version used is backwards compatible. (17 to 16) + uint32_t boot_cpuid_phys; // the physical ID of the system's boot CPU + uint32_t size_dt_strings; // the length in bytes of the strings block section + uint32_t size_dt_struct; // the length in bytes of the structure block section +} fdt_header_t; + +typedef fdt_header_t* fdt_header_ptr_t; + + +/* + convert from 32-bit big-endian to little-endian +*/ +static uint32_t +_dtb_get_uint32(const byteptr_t p) +{ + return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; +} + + +/* + Strcuture block + + a sequence of 32-bit aligned {token, data} + + 1. FDT_BEGIN_NODE 0x00000001 + (name) : string + + 2. FDT_END_NODE 0x00000002 + (no data) + + 3. FDT_PROP 0x00000003 + struct { + uint32_t len; // the length of the property's value + uint32_t nameoff; // the offset into strings block at which the property's name is stored + } + (value) + + 4. FDT_NOP 0x00000004 + (no data) + + 5. FDT_END 0x00000009 + (no data) + it should be the only one and be the last token in the structure block + +*/ + + +static uint32_t +_struct_iteration(fdt_callback cb, const byteptr_t struct_ptr, const byteptr_t string_ptr, uint32_t struct_size) +{ + byteptr_t cur_ptr = struct_ptr; + byteptr_t end_ptr = cur_ptr + struct_size; + + while (cur_ptr < end_ptr) { + uint32_t token = _dtb_get_uint32(cur_ptr); + switch (token) { + case FDT_BEGIN_NODE: + byteptr_t name_ptr = cur_ptr + 4; + cb(token, name_ptr, 0, 0); + cur_ptr = memory_padding(name_ptr + str_len(name_ptr) + 1, 2); // the string length should contain '\0' + break; + case FDT_PROP: + uint32_t data_len = _dtb_get_uint32(cur_ptr + 4); + uint32_t name_off = _dtb_get_uint32(cur_ptr + 8); + byteptr_t data_ptr = cur_ptr + 12; + cb(token, string_ptr + name_off, data_ptr, data_len); + cur_ptr = memory_padding(data_ptr + data_len, 2); + break; + case FDT_END_NODE: + case FDT_NOP: + cb(token, 0, 0, 0); + cur_ptr += 4; + break; + case FDT_END: + cb(token, 0, 0, 0); + return FDT_TRAVERSE_CORRECT; + break; + default: + return FDT_TRAVERSE_FORMAT_ERROR; + } + } + return FDT_TRAVERSE_CORRECT; +} + + +static byteptr_t _dtb_ptr = nullptr; +static byteptr_t _dtb_end = nullptr; +byteptr_t dtb_get_ptr() { return _dtb_ptr; } +byteptr_t dtb_get_end() { return _dtb_end; } + + +uint32_t +dtb_set_ptr(byteptr_t ptr) +{ + fdt_header_ptr_t header = (fdt_header_ptr_t) ptr; + if (_dtb_get_uint32((byteptr_t) &(header->magic)) != 0xd00dfeed) { + return FDT_TRAVERSE_HEADER_ERROR; + } + _dtb_ptr = ptr; + _dtb_end = (byteptr_t) ((uint64_t) dtb_get_ptr() + _dtb_get_uint32((byteptr_t) &(header->totalsize))); + return FDT_TRAVERSE_CORRECT; +} + + +uint32_t +fdt_traverse(fdt_callback cb) +{ + byteptr_t dtb_ptr = dtb_get_ptr(); + fdt_header_ptr_t header = (fdt_header_ptr_t) dtb_ptr; + + if (_dtb_get_uint32((byteptr_t) &(header->magic)) != 0xd00dfeed) { + return FDT_TRAVERSE_HEADER_ERROR; + } + + uint32_t struct_size = _dtb_get_uint32((byteptr_t) &(header->size_dt_struct)); + byteptr_t struct_ptr = dtb_ptr + _dtb_get_uint32((byteptr_t) &(header->off_dt_struct)); + byteptr_t string_ptr = dtb_ptr + _dtb_get_uint32((byteptr_t) &(header->off_dt_strings)); + + return _struct_iteration(cb, struct_ptr, string_ptr, struct_size); +} + + +void +fdt_find_initrd_addr(uint32_t token, const byteptr_t name_ptr, const byteptr_t data_ptr, uint32_t v) +{ + if (token == FDT_PROP && str_eql(name_ptr, "linux,initrd-start")) { + byteptr_t _addr = (byteptr_t) (0l | _dtb_get_uint32(data_ptr)); + initrd_set_ptr(_addr); + } + + else if (token == FDT_PROP && str_eql(name_ptr, "linux,initrd-end")) { + byteptr_t _addr = (byteptr_t) (0l | _dtb_get_uint32(data_ptr)); + initrd_set_end(_addr); + } +} + + +static void +_print_space(uint32_t n) +{ + for (uint32_t i = 0; i < n; ++i) uart_put(' '); +} + +void +fdt_print_node(uint32_t token, const byteptr_t name_ptr, const byteptr_t, uint32_t) +{ + static uint32_t _level = 0; + + switch (token) { + case FDT_BEGIN_NODE: + _print_space(_level); + uart_str("FDT_BEGIN_NODE "); + uart_line(name_ptr); + _level += 2; + break; + case FDT_PROP: + _print_space(_level); + uart_str("FDT_PROP "); + uart_line(name_ptr); + break; + case FDT_END_NODE: + _level -= 2; + _print_space(_level); + uart_line("FDT_END_NODE"); + break; + case FDT_NOP: + _print_space(_level); + uart_line("FDT_NOP"); + break; + case FDT_END: + _print_space(_level); + uart_line("FDT_END"); + _level = 0; + break; + default: + break; + } +} diff --git a/Lab 5/kernel/src/dtb.h b/Lab 5/kernel/src/dtb.h new file mode 100644 index 000000000..994f9732e --- /dev/null +++ b/Lab 5/kernel/src/dtb.h @@ -0,0 +1,28 @@ +#ifndef __DTB_H__ +#define __DTB_H__ + +#include "type.h" + +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + +#define FDT_TRAVERSE_CORRECT 0 +#define FDT_TRAVERSE_HEADER_ERROR 1 +#define FDT_TRAVERSE_FORMAT_ERROR 2 + + +typedef void (*fdt_callback)(uint32_t token, const byteptr_t name_ptr, const byteptr_t data_ptr, uint32_t v); + +uint32_t dtb_set_ptr(byteptr_t ptr); +byteptr_t dtb_get_ptr(); +byteptr_t dtb_get_end(); + +uint32_t fdt_traverse(fdt_callback cb); + +void fdt_find_initrd_addr(uint32_t token, const byteptr_t name_ptr, const byteptr_t data_ptr, uint32_t v); +void fdt_print_node(uint32_t token, const byteptr_t name_ptr, const byteptr_t, uint32_t); + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/entry.S b/Lab 5/kernel/src/entry.S new file mode 100644 index 000000000..5e3a742ab --- /dev/null +++ b/Lab 5/kernel/src/entry.S @@ -0,0 +1,218 @@ +#include "syscall.h" + +#define S_FRAME_SIZE 272 // size of all saved registers (16 * 17) // 8 bytes = 64 bits +#define S_X0 0 // offset of x0 register in saved stack frame + + +// save general registers to stack +.macro save_all, el + // move stack top + sub sp, sp, #S_FRAME_SIZE + + // store pair of registers + 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] + + .if \el == 0 + mrs x21, sp_el0 + .else + add x21, sp, #S_FRAME_SIZE + .endif + + stp x30, x21, [sp, 16 * 15] // push x30, stack pointer + + // push information for nested interrupt + mrs x22, elr_el1 + mrs x23, spsr_el1 + + stp x22, x23, [sp, 16 * 16] // push spsr_el1, elr_el1 + +.endm + + +// load general registers from stack +.macro load_all, el + + ldp x30, x21, [sp, 16 * 15] + + .if \el == 0 + msr sp_el0, x21 + .endif + + ldp x22, x23, [sp, 16 * 16] + + msr elr_el1, x22 + msr spsr_el1, x23 + + 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] + + // restore stack top + add sp, sp, #S_FRAME_SIZE +.endm + + +.globl err_hang +err_hang: + b err_hang + +.macro handle_invalid_entry el, type + save_all \el + // mov x0, #\type + // mrs x1, esr_el1 + // mrs x2, elr_el1 + // bl show_invalid_entry_message + b err_hang +.endm + + + + +.macro exception_entry label + .align 7 // entry size is 0x80, should be aligned to 2^7 + b \label +.endm + + + // vbar_el1[10:0] bits are reserved + .align 11 // vector table should be aligned to 2^11 (0x800) + .global exception_vector_table +exception_vector_table: + // Exception from the current EL while using SP_EL0 + exception_entry exception_invalid // Synchronous EL1t (invalid) + exception_entry exception_invalid // IRQ EL1t (invalid) + exception_entry exception_invalid // FIQ EL1t (invalid) + exception_entry exception_invalid // SError EL1t (invalid) + + // Exception from the current EL while using SP_ELx + exception_entry el1_sync // Synchronous EL1h + exception_entry el1_irq // IRQ EL1h + exception_entry exception_invalid // FIQ EL1h (invalid) + exception_entry exception_invalid // SError EL1h (invalid) + + // Exception from a lower EL and at least one lower EL is AArch64 + exception_entry el0_sync // Synchronous 64-bit EL0 + exception_entry el0_irq // IRQ 64-bit EL0 + exception_entry exception_invalid // FIQ 64-bit EL0 (invalid) + exception_entry exception_invalid // Error 64-bit EL0 (invalid) + + // Exception from a lower EL and all lower EL are AArch32 + exception_entry exception_invalid // Synchronous 32-bit EL0 (invalid) + exception_entry exception_invalid // IRQ 64-bit EL0 (invalid) + exception_entry exception_invalid // FIQ 64-bit EL0 (invalid) + exception_entry exception_invalid // Error 64-bit EL0 (invalid) + + +exception_invalid: // default exception router + save_all 0 + bl exception_invalid_handler // c code + load_all 0 + eret // EL1 -> EL0 + + +el1_sync: + save_all 1 + bl exception_el1_sync_handler + load_all 1 + eret + + +el1_irq: + save_all 1 + bl exception_el1_irq_handler + load_all 1 + eret + + +#define ESR_ELx_EC_SHIFT 26 +#define ESR_ELx_EC_SVC64 0x15 +#define NR_SYSCALLS 11 + +el0_sync: + save_all 0 + // bl exception_el0_sync_handler + + mrs x25, esr_el1 // read the syndrome register + lsr x24, x25, #ESR_ELx_EC_SHIFT // exception class + cmp x24, #ESR_ELx_EC_SVC64 // SVC in 64-bit state + b.eq el0_svc + handle_invalid_entry 0, SYNC_ERROR + +sc_nr .req x25 // number of system calls +scno .req x26 // syscall number +stbl .req x27 // syscall table pointer + +el0_svc: + adr stbl, syscall_table // load syscall table pointer + uxtw scno, w8 // syscall number in w8 + mov sc_nr, #NR_SYSCALLS + bl enable_irq + cmp scno, sc_nr // check upper syscall limit + b.hs ni_sys + + ldr x16, [stbl, scno, lsl #3] // address in the syscall table + blr x16 // call sys_* routine + b ret_from_syscall +ni_sys: + handle_invalid_entry 0, SYSCALL_ERROR +ret_from_syscall: + bl disable_irq + str x0, [sp, #S_X0] // returned x0 + load_all 0 + eret + + +el0_irq: + save_all 0 + bl exception_el0_irq_handler + load_all 0 + eret + + + .global set_exception_vector_table +set_exception_vector_table: + adr x0, exception_vector_table + msr vbar_el1, x0 + ret + // vbar_el1: Vector Base Address Register (EL1) + // Holds the exception base address for any + // exception that is taken to EL1. + + +.globl ret_from_fork +ret_from_fork: + bl schedule_tail + cbz x19, ret_to_user // not a kernel thread + mov x0, x20 + blr x19 + +ret_to_user: + bl disable_irq + load_all 0 + eret \ No newline at end of file diff --git a/Lab 5/kernel/src/entry.h b/Lab 5/kernel/src/entry.h new file mode 100644 index 000000000..a043ebc11 --- /dev/null +++ b/Lab 5/kernel/src/entry.h @@ -0,0 +1,11 @@ +#ifndef __ENTRY_H__ +#define __ENTRY_H__ + + +#define SYNC_ERROR 16 +#define SYSCALL_ERROR 17 + + +void ret_from_fork(); + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/exception.S b/Lab 5/kernel/src/exception.S new file mode 100644 index 000000000..db8b4c242 --- /dev/null +++ b/Lab 5/kernel/src/exception.S @@ -0,0 +1,19 @@ +// #include "sched.h" + +// .globl irq_vector_init +// irq_vector_init: +// adr x0, vectors // load VBAR_EL1 with virtual +// msr vbar_el1, x0 // vector table address +// ret + + +.globl enable_irq +enable_irq: + msr daifclr, #2 + ret + + +.globl disable_irq +disable_irq: + msr daifset, #2 + ret diff --git a/Lab 5/kernel/src/exception.c b/Lab 5/kernel/src/exception.c new file mode 100644 index 000000000..aac232392 --- /dev/null +++ b/Lab 5/kernel/src/exception.c @@ -0,0 +1,206 @@ +#include "type.h" +#include "uart.h" +#include "asm.h" +#include "core_timer.h" +#include "irq.h" +#include "aux.h" +#include "list.h" +#include "sched.h" +#include "memory.h" + + +void +exception_l1_enable() { + asm volatile("msr daifclr, 0xf"); // umask all DAIF, it's column D,A,I,F on the register PASATE +} + + +void +exception_l1_disable() +{ + asm volatile("msr daifset, 0xf"); // mask all DAIF, it's column D,A,I,F on the register PASATE +} + + +typedef void (*task_callback) (); + +typedef struct irqtask +{ + struct list_head listhead; + uint64_t running; + uint64_t priority; // store priority (smaller number is more preemptive) + task_callback handler; // task function pointer +} irqtask_t; + +typedef irqtask_t* irqtask_ptr_t; + + +static LIST_HEAD(irqtask_queue); + + +static irqtask_ptr_t +irqtask_create(task_callback handler, uint64_t priority) +{ + irqtask_ptr_t task = (irqtask_ptr_t) kmalloc(sizeof(irqtask_t)); + INIT_LIST_HEAD(&task->listhead); + task->handler = handler; + task->priority = priority; + task->running = 0; + return task; +} + + +static void +irqtask_queue_add(irqtask_ptr_t task) +{ + if (task == 0) return; + list_head_ptr_t curr = (&irqtask_queue)->next; + // small value has higher priority + while (!list_is_head(curr, &irqtask_queue) && + ((irqtask_ptr_t) curr)->priority <= (task->priority)) + { + curr = curr->next; + } + list_add(&task->listhead, curr->prev); +} + + +static uint32_t +irqtask_queue_not_running() +{ + if (list_empty(&irqtask_queue)) + return 0; + irqtask_ptr_t first = (irqtask_ptr_t) (&irqtask_queue)->next; + return !(first->running); +} + + +static void +irqtask_queue_run() +{ + while (irqtask_queue_not_running()) { + irqtask_ptr_t first = (irqtask_ptr_t) (&irqtask_queue)->next; + list_del_entry((list_head_ptr_t) first); + exception_l1_enable(); + first->running = 1; + first->handler(); + exception_l1_disable(); + kfree((byteptr_t) first); + } +} + + +static void +show_exception_infomation() +{ + uint64_t spsr = asm_read_sysregister(spsr_el1); + uint64_t elr = asm_read_sysregister(elr_el1); + uint64_t esr = asm_read_sysregister(esr_el1); + uart_str("spsr_el1: 0x"); uart_hexl(spsr); uart_endl(); + uart_str("elr_el1: 0x"); uart_hexl(elr); uart_endl(); + uart_str("esr_el1: 0x"); uart_hexl(esr); uart_endl(); +} + + +void +exception_invalid_handler() +{ + exception_l1_disable(); + uart_line("---- exception_invalid_handler ----"); + show_exception_infomation(); + exception_l1_enable(); +} + + +// EC,bits[31:26] +#define ESR_ELx_EC(esr) ((esr & 0xFC000000) >> 26) +// ISS,bits[24:0] +#define ESR_ELx_ISS(esr) (esr & 0x03FFFFFF) + +#define ESR_ELx_EC_SVC64 0b010101 +#define ESR_ELx_EC_DABT_LOW 0b100100 +#define ESR_ELx_EC_IABT_LOW 0b100000 + + +// void +// exception_el0_sync_handler() +// { +// exception_l1_disable(); +// uart_line("---- exception_el0_sync_handler ----"); +// show_exception_infomation(); + +// uint64_t esr = asm_read_sysregister(esr_el1); // cause of that exception +// uint32_t ec = ESR_ELx_EC(esr); + +// switch (ec) +// { +// case ESR_ELx_EC_SVC64: +// exception_l1_enable(); + +// // syscall_handler(_regs); + +// exception_l1_disable(); +// break; +// case ESR_ELx_EC_DABT_LOW: +// uart_printf("in Data Abort\n"); +// break; +// case ESR_ELx_EC_IABT_LOW: +// uart_printf("in Instruction Abort\n"); +// break; +// default: +// return; +// } + +// exception_l1_enable(); +// } + + +void +exception_el0_irq_handler() +{ + exception_l1_disable(); + // uart_line("---- exception_el0_irq_handler ----"); + // show_exception_infomation(); + exception_l1_enable(); +} + + +void +exception_el1_sync_handler() +{ + exception_l1_disable(); + // uart_line("---- exception_el1_sync_handler ----"); + // show_exception_infomation(); + exception_l1_enable(); +} + + +void +exception_el1_irq_handler() +{ + exception_l1_disable(); + + irqtask_ptr_t task = 0; + if (*IRQ_PENDING1 & (1 << 29)) { // UART IRQ + if (*AUX_MU_IIR & 0x4) { // Receiver holds valid bytes + aux_clr_rx_interrupts(); + task = irqtask_create(mini_uart_rx_handler, 3); + } + else if (*AUX_MU_IIR & 0x2) { // Transmit holding register empty + aux_clr_tx_interrupts(); + task = irqtask_create(mini_uart_tx_handler, 3); + } + } + else if (*CORE0_INTERRUPT_SOURCE & 0x2) { // Core timer IRQ + core_timer_disable(); + task = irqtask_create(core_timer_interrupt_handler, 1); + } + + irqtask_queue_add(task); + irqtask_queue_run(); + + exception_l1_enable(); +} + + + diff --git a/Lab 5/kernel/src/exception.h b/Lab 5/kernel/src/exception.h new file mode 100644 index 000000000..1ae9c3494 --- /dev/null +++ b/Lab 5/kernel/src/exception.h @@ -0,0 +1,10 @@ +#ifndef __EXCEPTION_H__ +#define __EXCEPTION_H__ + +void exception_l1_enable(); +void exception_l1_disable(); + +void enable_irq(); +void disable_irq(); + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/frame.c b/Lab 5/kernel/src/frame.c new file mode 100644 index 000000000..73751ed3b --- /dev/null +++ b/Lab 5/kernel/src/frame.c @@ -0,0 +1,398 @@ +#include "frame.h" +#include "type.h" +#include "list.h" +#include "uart.h" +#include "memory.h" + + +#define FRAME_SIZE_ORDER 12 + + +static byteptr_t base_ptr; +static uint32_t max_alloc_size; +static uint32_t max_alloc_order; + +static uint32_t total_frames; +static byteptr_t frame_array; + +#define BUCKET_COUNT max_alloc_order + 1 + +#define FRAME_ALLOCATED 0x40 +#define FRAME_PRESERVED 0x20 +#define FRAME_BUDDY 0x60 + +#define FRAME_IS_ALLOCATED(x) ({frame_array[x] == FRAME_ALLOCATED;}) +#define FRAME_IS_PRESERVED(x) ({frame_array[x] == FRAME_PRESERVED;}) +#define FRAME_IS_BUDDY(x) ({frame_array[x] == FRAME_BUDDY;}) + +#define FRAME_IS_FREE(x) ({(frame_array[x] & 0xE0) == 0x00;}) +#define FRAME_ORDER(x) ({frame_array[x];}) + +#define FRAME_SET_ORDER(x, order) frame_array[x] = 0x1F & order +#define FRAME_OWNER(index, order) ({index & ~((1 << (order + 1)) - 1);}) +#define BUDDY_INDEX(index, order) ({index ^ (1 << order);}) + +#define FRAME_TYPE(index) ({(FRAME_IS_PRESERVED(index)) ? "preserved" : (FRAME_IS_ALLOCATED(index)) ? "allocated" : "free";}) + + +static byteptr_t +index_to_ptr(uint32_t index) +{ + return (byteptr_t) (((uint64_t) base_ptr) + (index << FRAME_SIZE_ORDER)); +} + + +static uint32_t +ptr_to_index(byteptr_t ptr) +{ + return ((uint32_t) ptr) >> FRAME_SIZE_ORDER; +} + + +/** + * Freelists +*/ + +static list_head_ptr_t buckets; + + +/** + * pop a free block from the designate bucket +*/ +static byteptr_t +bucket_pop(const byteptr_t bucket) +{ + list_head_ptr_t head = (list_head_ptr_t) bucket; + if (head->next == head) return 0; + list_head_ptr_t first = head->next; + list_del_entry(first); + return (byteptr_t) first; +} + + +/** + * push a free block by a designate index + * should set the order value properly before call this function +*/ +static void +buckets_push(uint32_t index) +{ + byteptr_t block = index_to_ptr(index); + uint32_t order = FRAME_ORDER(index); + + INIT_LIST_HEAD((list_head_ptr_t) block); + list_add_tail((list_head_ptr_t) block, (list_head_ptr_t) &buckets[order]); +} + + +static void +buckets_remove(uint32_t index) +{ + list_del_entry((list_head_ptr_t) index_to_ptr(index)); +} + + +/** + * frame array system basic tools +*/ + + +// preserved (not in use) +uint32_t +frame_split(uint32_t index, uint32_t order) +{ + if (!FRAME_IS_FREE(index)) { return 0; } + if (order == 0) { return 0; } + uint32_t buddy = BUDDY_INDEX(index, (order - 1)); + if (index > (total_frames - 1) || buddy > (total_frames - 1)) return 0; + FRAME_SET_ORDER(buddy, (order - 1)); + FRAME_SET_ORDER(index, (order - 1)); + buckets_push(buddy); + return 1; +} + + +static uint32_t +frame_mergeable(uint32_t index, uint32_t buddy) +{ + if (index > (total_frames - 1) || buddy > (total_frames - 1)) return 0; + if (FRAME_IS_FREE(index) && FRAME_ORDER(index) == FRAME_ORDER(buddy)) return 1; + return 0; +} + + +static uint32_t +frame_merge(uint32_t index, uint32_t order) +{ + if (!FRAME_IS_FREE(index)) return 0; + uint32_t buddy = BUDDY_INDEX(index, order); + + if (!frame_mergeable(index, buddy)) return 0; + frame_array[buddy] = FRAME_BUDDY; + frame_array[index] = order + 1; + return 1; +} + + +static void +frame_merge_up(uint32_t start, uint32_t end, uint32_t max_order) +{ + /** + * merge all free blocks as high order as possible + */ + for (uint32_t order = 0; order < max_order; order++) + for (uint32_t index = start; index < end; index += (1 << (order + 1))) + frame_merge(index, order); + /** + * push all the free blocks into freelists + */ + for (uint32_t index = start; index < end; ++index) + if (FRAME_IS_FREE(index)) + buckets_push(index); +} + + +/** + * frame array system operatiors +*/ + + +#define SMALLEST_POW_OF_2(x) ({(INT32_LEFTMOST_ORDER(x) == INT32_RIGHTMOST_ORDER(x)) ? INT32_LEFTMOST_ORDER(x) : INT32_LEFTMOST_ORDER(x) + 1;}) +#define GREATEST_POW_OF_2(x) ({SMALLEST_POW_OF_2(x) >> 1;}) + + +byteptr_t +frame_alloc(uint32_t count) +{ + uint32_t request_order = SMALLEST_POW_OF_2(count); + + int32_t order = request_order; + while (order < BUCKET_COUNT && list_empty(&buckets[order])) { order++; } + + if (order == BUCKET_COUNT) return 0; + + byteptr_t block = bucket_pop((byteptr_t) &buckets[order]); + + // uart_printf("[DEBUG] frame alloc: 0x%x count: %d\n", block, count); + + uint32_t index = ptr_to_index(block); + uint32_t end = index + (1 << order); + + for (uint32_t i = 0; (index + i) < end; ++i) + frame_array[index + i] = (i < count) ? FRAME_ALLOCATED : 0; + + frame_merge_up(index, end, SMALLEST_POW_OF_2((1 << order) - count)); + return block; +} + + +void +frame_release(byteptr_t ptr) +{ + uint32_t index = ptr_to_index(ptr); + if (!FRAME_IS_ALLOCATED(index)) return; + + // uart_printf("[DEBUG] frame: 0x%x released\n", (index << FRAME_SIZE_ORDER)); + + frame_array[index] = 0; + + uint32_t order = 0; + uint32_t buddy = BUDDY_INDEX(index, order); + while (frame_mergeable(index, buddy)) { + buckets_remove(buddy); + index = FRAME_OWNER(index, order); + buddy = BUDDY_INDEX(index, order); + frame_array[buddy] = FRAME_BUDDY; + frame_array[index] = order + 1; + buddy = BUDDY_INDEX(index, order); + order++; + } + + buckets_push(index); +} + + +void +frame_release_block(byteptr_t ptr, uint32_t count) +{ + for (uint32_t i = 0; i < count; ++i) { + frame_release(ptr); + ptr = (byteptr_t) ((uint64_t) ptr + (1 << FRAME_SIZE_ORDER)); + } +} + + +byteptr_t +frame_allock_block(uint32_t size) +{ + uint32_t count = (uint32_t) memory_padding((byteptr_t) (size | 0l), FRAME_SIZE_ORDER) >> FRAME_SIZE_ORDER; + return frame_alloc(count); +} + + + +/** + * preserved (not in use) +*/ +byteptr_t +frame_request(uint32_t addr, uint8_t frame_state) +{ + byteptr_t ptr = (byteptr_t) (addr | 0l); + uint32_t index = ptr_to_index(ptr); + if (!FRAME_IS_FREE(index) && !FRAME_IS_BUDDY(index)) return 0; + + /** + * find the first frame of the free block + */ + uint32_t owner = index; + while (owner > 0 && FRAME_IS_BUDDY(owner)) owner--; + buckets_remove(owner); + + /** + * split up + */ + uint32_t original_order = FRAME_ORDER(owner); + frame_array[index] = frame_state; + uint32_t order = 0; + while (order < original_order) { + uint32_t buddy = BUDDY_INDEX(index, order); + frame_array[buddy] = order; + buckets_push(buddy); + index = FRAME_OWNER(index, order); + order++; + } + return ptr; +} + + +/** + * Frame System Startup Initialization + * frame_system_preserve() should be called before frame_system_init_free_blocks() +*/ + +void +frame_system_init_frame_array(uint32_t start_addr, uint32_t end_addr) +{ + start_addr = UINT32_ALIGN(start_addr, FRAME_SIZE_ORDER); + end_addr = UINT32_PADDING(end_addr, FRAME_SIZE_ORDER); + + max_alloc_size = (end_addr - start_addr); + total_frames = max_alloc_size >> FRAME_SIZE_ORDER; + base_ptr = (byteptr_t) (start_addr | 0l); + + frame_array = (byteptr_t) startup_memory_alloc(total_frames * sizeof(byte_t)); + for (int i = 0; i < total_frames; ++i) { frame_array[i] = 0; } +} + + +uint32_t +frame_system_preserve(uint32_t start, uint32_t end) +{ + uint32_t index_s = ptr_to_index((byteptr_t) (UINT32_ALIGN(start, FRAME_SIZE_ORDER) | 0l)); + uint32_t index_e = ptr_to_index((byteptr_t) (UINT32_PADDING(end, FRAME_SIZE_ORDER) | 0l)); + + if (index_s >= total_frames || index_e > total_frames) + return 0; + while (index_s < index_e) { + frame_array[index_s++] = FRAME_PRESERVED; + } + return 1; +} + + +void +frame_system_init_free_blocks() +{ + max_alloc_order = INT32_LEFTMOST_ORDER(total_frames); + buckets = (list_head_ptr_t) startup_memory_alloc((max_alloc_order + 1) * sizeof(list_head_t)); + + for (int i = 0; i < BUCKET_COUNT; ++i) + INIT_LIST_HEAD((list_head_ptr_t) &buckets[i]); + + frame_merge_up(0, total_frames, max_alloc_order); +} + + +/** + * visualization of frame system information +*/ + +void +print_memory_layout() +{ + uart_printf("\n==== MEMORY FRAME LAYOUT ====\n"); + uint32_t index = 0; + while (index < total_frames) { + uint32_t end = index + 1; + if (FRAME_IS_FREE(index)) { + while (FRAME_IS_FREE(end) || FRAME_IS_BUDDY(end)) end++; + } + else { + while (frame_array[index] == frame_array[end]) end++; + } + uart_printf("0x%8x | %dkb\t| %s\n", index_to_ptr(index), (end - index) << 2, FRAME_TYPE(index)); + index = end; + } +} + + +void +print_buddy_layout() +{ + uart_printf("\n==== MEMORY BUDDY LAYOUT ====\n"); + uint32_t index = 0; + while (index < total_frames) { + if (FRAME_IS_FREE(index)) { + uint32_t order = frame_array[index]; + uart_printf("0x%8x | %dkb\t| free\n", index_to_ptr(index), (1 << (order + 2))); + index += (1 << order); + } + else { + uint32_t end = index + 1; + while (frame_array[index] == frame_array[end]) end++; + uart_printf("0x%8x | %dkb\t| %s\n", index_to_ptr(index), (end - index) << 2, FRAME_TYPE(index)); + index = end; + } + } +} + + +void +print_free_lists() +{ + uart_printf("\n==== FREE FRAME LISTS ====\n"); + for (int i = 0; i < BUCKET_COUNT; ++i) { + if (!list_empty(&buckets[i])) { + uart_printf("bucket: %d, size: %dkb\n", i, 1 << (i + 2)); + list_head_ptr_t pos = ((list_head_ptr_t) &buckets[i])->next; + list_for_each(pos, (list_head_ptr_t) &buckets[i]) + uart_printf(" +- 0x%8x\n", pos); + } + } +} + + +void +frame_print_info() +{ + uart_printf("\n==== FRAME SYSTEM INFO ====\n"); + uart_printf("start: 0x%8x\n", base_ptr); + uart_printf("limit: 0x%8x\n", base_ptr + max_alloc_size); + uart_printf("frame_array: 0x%8x | 0x%x bytes\n", frame_array, total_frames); + uart_printf("free_list: 0x%8x | %d buckets\n", buckets, BUCKET_COUNT); + + // print_memory_layout(); + print_buddy_layout(); + print_free_lists(); + uart_printf("\n"); +} + + +uint32_t +frame_preserved_count() +{ + uint32_t count = 0; + for (uint32_t i = 0; i < total_frames; ++i) + if (FRAME_IS_PRESERVED(i)) count++; + return count; +} \ No newline at end of file diff --git a/Lab 5/kernel/src/frame.h b/Lab 5/kernel/src/frame.h new file mode 100644 index 000000000..abad5cc63 --- /dev/null +++ b/Lab 5/kernel/src/frame.h @@ -0,0 +1,22 @@ +#ifndef __FRAME_H__ +#define __FRAME_H__ + +#include "type.h" + +#define FRAME_SIZE_ORDER 12 + +void frame_print_info(); + +void frame_release(byteptr_t ptr); +void frame_release_block(byteptr_t ptr, uint32_t count); +byteptr_t frame_alloc(uint32_t count); +byteptr_t frame_allock_block(uint32_t size); + +void frame_system_init_frame_array(uint32_t start_addr, uint32_t end_addr); +uint32_t frame_system_preserve(uint32_t start_addr, uint32_t end_addr); +void frame_system_init_free_blocks(); + + +uint32_t frame_preserved_count(); + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/info.c b/Lab 5/kernel/src/info.c new file mode 100644 index 000000000..8d8ae4e81 --- /dev/null +++ b/Lab 5/kernel/src/info.c @@ -0,0 +1,187 @@ +#include "uart.h" +#include "mailbox.h" +#include "string.h" + + +void +info_board_revision() +{ + volatile unsigned int *mbox = mailbox; + + mbox[0] = 7 * 4; + mbox[1] = MBOX_REQUEST; + + mbox[2] = MBOX_TAG_GETREVISION; + mbox[3] = 4; + mbox[4] = MBOX_TAG_REQUEST; + mbox[5] = 0; + + mbox[6] = MBOX_TAG_END; + + mailbox_call(MBOX_CH_PROP, mbox); // message passing procedure call + + uart_str("Board revision: \t"); + uart_str("0x"); + uart_hex(mbox[5]); // it should be 0xa020d3 for rpi3 b+ + uart_endl(); +} + + +void +info_memory() +{ + volatile unsigned int *mbox = mailbox; + + mbox[0] = 8 * 4; + mbox[1] = MBOX_REQUEST; + + mbox[2] = MBOX_TAG_GETMEMORY; + mbox[3] = 8; + mbox[4] = MBOX_TAG_REQUEST; + mbox[5] = 0; // memory basee address + mbox[6] = 0; // memory size + + mbox[7] = MBOX_TAG_END; + + mailbox_call(MBOX_CH_PROP, mbox); + + uart_line("Arm memory info:"); + + uart_str(" > memory base: \t"); + uart_str("0x"); + uart_hex(mbox[5]); + uart_endl(); + + uart_str(" > memory size: \t"); + uart_str("0x"); + uart_hex(mbox[6]); + uart_endl(); +} + + +void +info_videocore() +{ + volatile unsigned int *mbox = mailbox; + char buffer[40]; + + /* size & request */ + mbox[0] = 35 * 4; + mbox[1] = MBOX_REQUEST; + + /* tags begin */ + mbox[2] = MBOX_TAG_GETVCMEM; + mbox[3] = 8; + mbox[4] = MBOX_TAG_REQUEST; + mbox[5] = 0; // VC memory base + mbox[6] = 0; // VC memory size + + mbox[7] = MBOX_TAG_ALLOCATEFB; // Allocate frame buffer command + mbox[8] = 8; + mbox[9] = MBOX_TAG_REQUEST; + mbox[10] = 4096; // alignment in bytes ==> frame buffer base address + mbox[11] = 0; // ==> frame buffer size + + mbox[12] = MBOX_TAG_GETPHYSICALWH; + mbox[13] = 8; + mbox[14] = MBOX_TAG_REQUEST; + mbox[15] = 0; // display width + mbox[16] = 0; // display height + + mbox[17] = MBOX_TAG_GETVIRTUALWH; + mbox[18] = 8; + mbox[19] = MBOX_TAG_REQUEST; + mbox[20] = 0; // virtual width + mbox[21] = 0; // virtual height + + mbox[22] = MBOX_TAG_GETVIRTUALOFFSET; + mbox[23] = 8; + mbox[24] = MBOX_TAG_REQUEST; + mbox[25] = 0; // offset X + mbox[26] = 0; // offset Y + + mbox[27] = MBOX_TAG_GETDEPTH; + mbox[28] = 4; + mbox[29] = MBOX_TAG_REQUEST; + mbox[30] = 0; // depth + + mbox[31] = MBOX_TAG_GETPIXELORDER; + mbox[32] = 4; + mbox[33] = MBOX_TAG_REQUEST; + mbox[34] = 0; // 0x0: BGR, 0x1: RGB + + mbox[35] = MBOX_TAG_GETPITCH; + mbox[36] = 4; + mbox[37] = MBOX_TAG_REQUEST; + mbox[38] = 0; // pitch + + /* tags end */ + mbox[39] = MBOX_TAG_END; + + mailbox_call(MBOX_CH_PROP, mbox); // message passing procedure call, you should implement it following the 6 steps provided above. + + uart_line("VideoCore info:"); + + uart_str(" > memory base: \t"); + uart_str("0x"); + uart_hex(mbox[5]); + uart_endl(); + + uart_str(" > memory size: \t"); + uart_str("0x"); + uart_hex(mbox[6]); + uart_endl(); + + uart_str(" > frame buffer base: \t"); + uart_str("0x"); + uart_hex(mbox[10] & 0x3fffffff); + uart_str("\r\n"); + + uart_str(" > frame buffer size: \t"); + uart_str("0x"); + uart_hex(mbox[11]); + uart_endl(); + + uart_str(" > physical width: \t"); + uint32_to_ascii(mbox[15], buffer); + uart_str(buffer); + uart_str("\r\n"); + + uart_str(" > physical height: \t"); + uint32_to_ascii(mbox[16], buffer); + uart_str(buffer); + uart_endl(); + + uart_str(" > virtual width: \t"); + uint32_to_ascii(mbox[20], buffer); + uart_str(buffer); + uart_endl(); + + uart_str(" > virtual height: \t"); + uint32_to_ascii(mbox[21], buffer); + uart_str(buffer); + uart_endl(); + + uart_str(" > buffer offset X: \t"); + uint32_to_ascii(mbox[25], buffer); + uart_str(buffer); + uart_endl(); + + uart_str(" > buffer offset Y: \t"); + uint32_to_ascii(mbox[26], buffer); + uart_str(buffer); + uart_endl(); + + uart_str(" > depth: \t\t"); + uint32_to_ascii(mbox[30], buffer); + uart_str(buffer); + uart_endl(); + + uart_str(" > pixel order: \t"); + if (mbox[34] == 0x0) uart_line("BGR"); else uart_line("RGB"); + + uart_str(" > pitch: \t\t"); + uint32_to_ascii(mbox[38], buffer); + uart_str(buffer); + uart_endl(); +} diff --git a/Lab 5/kernel/src/info.h b/Lab 5/kernel/src/info.h new file mode 100644 index 000000000..4d14c1809 --- /dev/null +++ b/Lab 5/kernel/src/info.h @@ -0,0 +1,10 @@ +#ifndef __INFO_H__ +#define __INFO_H__ + +#include "type.h" + +void info_board_revision(); +void info_memory(); +void info_videocore(); + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/initrd.c b/Lab 5/kernel/src/initrd.c new file mode 100644 index 000000000..dc610801b --- /dev/null +++ b/Lab 5/kernel/src/initrd.c @@ -0,0 +1,174 @@ +#include "type.h" +#include "uart.h" +#include "memory.h" +#include "string.h" +#include "cpio.h" +#include "sched.h" +#include "task.h" +#include "kernel.h" +#include "thread.h" + + +typedef struct { + + byteptr_t name; + byteptr_t content; + uint32_t size; + +} finfo_t; + +typedef finfo_t* finfoptr_t; + + +static byteptr_t +_initrd_next(const byteptr_t cpio_addr, finfoptr_t info) +{ + byteptr_t _addr = (byteptr_t) cpio_addr; + + if (!memory_cmp(_addr, "070701", 6) && memory_cmp(_addr + sizeof(cpio_t), "TRAILER!!!", 10)) { + + cpio_ptr_t header = (cpio_ptr_t) _addr; + + uint64_t name_size = ascii_to_uint64(header->c_namesize, (uint32_t) sizeof(header->c_namesize)); + uint64_t file_size = ascii_to_uint64(header->c_filesize, (uint32_t) sizeof(header->c_filesize)); + + uint64_t content_offset = (uint64_t) memory_padding((const byteptr_t) (sizeof(cpio_t) + name_size), 2); + uint64_t total_size = (uint64_t) memory_padding((const byteptr_t) (content_offset + file_size), 2); + + info->name = _addr + sizeof(cpio_t); + info->size = file_size; + info->content = _addr + content_offset; + + return _addr + total_size; + } + + return nullptr; +} + + +static byteptr_t +_initrd_find(const byteptr_t cpio_addr, const byteptr_t name, finfoptr_t info_ptr) +{ + byteptr_t curr = (byteptr_t) cpio_addr; + byteptr_t next = _initrd_next(cpio_addr, info_ptr); + + while (next) { + if (str_eql(info_ptr->name, name)) { + return curr; + } + curr = next; + next = _initrd_next(curr, info_ptr); + } + return nullptr; +} + + +static byteptr_t _cpio_ptr = nullptr; +static byteptr_t _cpio_end = nullptr; + +byteptr_t initrd_get_ptr() { return _cpio_ptr; } +void initrd_set_ptr(byteptr_t ptr) { _cpio_ptr = ptr; } +byteptr_t initrd_get_end() { return _cpio_end; } +void initrd_set_end(byteptr_t ptr) { _cpio_end = ptr; } + + +static byteptr_t +_initrd_find_file(const byteptr_t name, finfoptr_t info_ptr) +{ + byteptr_t cpio_addr = initrd_get_ptr(); + byteptr_t file = _initrd_find(cpio_addr, name, info_ptr); + if (!file) { uart_line("No such file or directory."); return 0; } + if (info_ptr->size == 0) { uart_line("It's a directory."); return 0; } + return file; +} + + +void +initrd_list() +{ + byteptr_t cpio_addr = initrd_get_ptr(); + finfo_t info; + byteptr_t next_addr = _initrd_next(cpio_addr, &info); + while (next_addr) { + mini_uart_putln(info.name); + next_addr = _initrd_next(next_addr, &info); + } +} + + +static void +_print_file(const byteptr_t content, uint32_t size) +{ + byteptr_t cur = (byteptr_t) content; + while (size--) { + if (*cur == '\n') { + uart_put('\r'); + } + uart_put(*cur); + cur++; + } + uart_endl(); +} + + +void +initrd_cat(const byteptr_t name) +{ + finfo_t info; + byteptr_t file = _initrd_find_file(name, &info); + if (file) { _print_file(info.content, info.size); } +} + + +static void +run_user_process(uint64_t program) // a kernel thread of +{ + uart_printf("[DEBUG] Kernel process (run_user_process) started. EL %d\r\n", get_el()); + int err = task_to_user_mode(current_task(), program); + if (err < 0) { + uart_printf("[DEBUG] Error while moving process to user mode\n"); + } +} + + +void +initrd_exec(const byteptr_t name) +{ + finfo_t info; + byteptr_t file = _initrd_find_file(name, &info); + if (file) { + uart_printf("[DEBUG] initrd_exec - info: %s, size: 0x%x\n", info.name, info.size); + thread_create_user((uint64_t) run_user_process, (uint64_t) info.content, info.size); + } +} + + + +// #define USTACK_SIZE 0x1000 + +// static void +// _execute_user_program(byteptr_t content, byteptr_t ustack_sp, byteptr_t sp) +// { +// asm volatile("mov x0, 0x340 \n"); // b'1101 00 0000 +// asm volatile("msr spsr_el1, x0 \n"); // unmask EL1 IRQ +// asm volatile("msr elr_el1, %0 \n" ::"r"(content)); +// asm volatile("msr sp_el0, %0 \n" ::"r"(ustack_sp + USTACK_SIZE)); +// if (sp) asm volatile("mov sp, %0 \n" ::"r"(sp)); +// asm volatile("eret \n"); +// } + + +void +initrd_exec_replace(const byteptr_t name) +{ + finfo_t info; + byteptr_t file = _initrd_find_file(name, &info); + if (file) { + // uart_printf("initrd_exec_replace - info: %s, size: 0x%x, ", info.name, info.size); + // int32_t pid = + thread_replace_user((uint64_t) 0, (uint64_t) info.content, info.size); + // uart_printf("pid = %d\n", pid); + run_user_process((uint64_t) current_task()->user_prog); + } +} + diff --git a/Lab 5/kernel/src/initrd.h b/Lab 5/kernel/src/initrd.h new file mode 100644 index 000000000..7726bacde --- /dev/null +++ b/Lab 5/kernel/src/initrd.h @@ -0,0 +1,20 @@ +#ifndef __INITRD_H__ +#define __INITRD_H__ + +#include "type.h" + + +byteptr_t initrd_get_ptr(); +void initrd_set_ptr(byteptr_t ptr); +byteptr_t initrd_get_end(); +void initrd_set_end(byteptr_t ptr); + +void initrd_list(); +void initrd_cat(const byteptr_t file); +void initrd_exec(const byteptr_t name); +void initrd_exec_replace(const byteptr_t name); + +// int initrd_call_exec(const char* name, char *const argv[]); + + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/kernel_main.c b/Lab 5/kernel/src/kernel_main.c new file mode 100644 index 000000000..5e1932ad5 --- /dev/null +++ b/Lab 5/kernel/src/kernel_main.c @@ -0,0 +1,84 @@ +#include "kernel.h" +#include "uart.h" +#include "irq.h" +#include "shell.h" +#include "dtb.h" +#include "initrd.h" +#include "string.h" +#include "exception.h" +#include "frame.h" +#include "memory.h" +#include "sched.h" +#include "thread.h" +#include "core_timer.h" +#include "delay.h" + +#include "chunk.h" + + +/** + * Note: + * 1. Spin tables for multicore boot (0x0000 - 0x1000) + * 2. Kernel image in the physical memory (0x80000 - ) + * 3. Initramfs (0x08000000 - 0x08002200) + * 4. Devicetree (Optional, if you have implement it) (0x08200000 - 0x08215988) + * 5. Your simple allocator (startup allocator) +*/ + +extern byte_t kernel_start; +extern byte_t kernel_end; + +static void +_kernel_init(uint64_t x0, void (*ptr)(uint64_t)) +{ + dtb_set_ptr((byteptr_t) x0); + fdt_traverse(fdt_find_initrd_addr); + memory_system_init(0x0, 0x3C000000); + + uart_init(); + + uart_printf("+------------------------------+\n"); + uart_printf("| Lab 5 - Kernel |\n"); + uart_printf("+------------------------------+\n"); + + uart_printf("| main() = 0x%8x |\n", ptr); + uart_printf("| kernel_start = 0x%8x |\n", &kernel_start); + uart_printf("| kernel_end = 0x%8x |\n", &kernel_end); + + uart_printf("| Initrd_start = 0x%8x |\n", initrd_get_ptr()); + uart_printf("| Initrd_end = 0x%8x |\n", initrd_get_end()); + + uart_printf("| DTB_start = 0x%8x |\n", dtb_get_ptr()); + uart_printf("| DTB_end = 0x%8x |\n", dtb_get_end()); + + uart_printf("| frame preserved = %d |\n", frame_preserved_count()); + + uart_line("+------------------------------+"); + + uint64_t tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); + + exception_l1_enable(); +} + + +void idle() +{ + while (1) { + kill_zombies(); + schedule(); + } +} + + +void +kernel_main(uint64_t x0) +{ + _kernel_init(x0, &kernel_main); + scheduler_init(); + thread_create_shell((uint64_t) shell); + // initrd_exec("syscall.img"); + idle(); +} diff --git a/Lab 5/kernel/src/kernel_start.S b/Lab 5/kernel/src/kernel_start.S new file mode 100644 index 000000000..8dd2c4ff2 --- /dev/null +++ b/Lab 5/kernel/src/kernel_start.S @@ -0,0 +1,99 @@ + .section ".text.boot" + .global _start +_start: + mov x10, x0 + + // read cpu id, hang slave cores + mrs x1, mpidr_el1 + and x1, x1, #0xFF // Check processor id in last 8 bits + cbnz x1, _hang + +_master: + // switch exception level from EL2 to EL1 + bl _el2_to_el1 + + // set vbar_el1 register + bl set_exception_vector_table + + // set top of stack just before our code (0x80000) + ldr x1, = kernel_start + mov sp, x1 + + // clear bss + bl _memzero + + // jump to c, should not return + mov x0, x10 + bl kernel_main + + // Hang for all non-primary CPU and this core when c code failed +_hang: + wfe + b _hang + +_memzero: + ldr x0, =_bss_begin + ldr x1, =_bss_size +_setzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt _setzero + ret + + +_el2_to_el1: + mov x1, (1 << 31) // hcr_el2: Execution state control for EL2 + msr hcr_el2, x1 // [31]: 1 = EL1 is AArch64, 0 = EL1/EL0 is AArch32 + + mov x1, 0x3c5 // spsr_el2: Holds the saved process state when an exception is taken to EL2. + msr spsr_el2, x1 // [1111]00[0101] -> (1) EL2-PSTATE.DAIF Disabled (2) Exception level = EL1h + + msr elr_el2, lr // elr_el2: When taking an exception to EL2, holds the address to return to. + eret // Perform an exception return. EL2 -> EL1 + + +/* + +SPSR_EL2: + +D,bit[9]: Process state Debug mask +A,bit[8]: SError (System Error) mask bit +I,bit[7]: IRQ mask bit +F,bit[6]: FIQ mask bit +M[4]: Execution state that the exception was taken from. A value of 0 indicates AArch64. +M[3:0]: AArch64 Exception level and selected Stack Pointer. + + +M[3:0] Meaning +------------------------------------ +0b0000 EL0. +0b0100 EL1 with SP_EL0 (ELt). +0b0101 EL1 with SP_EL1 (EL1h). +0b1000 EL2 with SP_EL0 (EL2t). +0b1001 EL2 with SP_EL2 (EL2h). + + */ + + + .global current_exception_level +current_exception_level: + mrs x0, CurrentEl + lsr x0, x0, #2 // remove reserved bits + and x0, x0, 0x3 + ret + + + .global align +align: + sub x1, x1, #1 + add x0, x0, x1 + mvn x1, x1 + and x0, x0, x1 + ret + + + .globl get_el +get_el: + mrs x0, CurrentEL + lsr x0, x0, #2 + ret \ No newline at end of file diff --git a/Lab 5/kernel/src/linker.ld b/Lab 5/kernel/src/linker.ld new file mode 100644 index 000000000..945ada002 --- /dev/null +++ b/Lab 5/kernel/src/linker.ld @@ -0,0 +1,23 @@ + +SECTIONS +{ + . = 0x80000; + kernel_start = .; + + .text.boot : { *(.text.boot) } + .text : { *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + + . = ALIGN(0x8); + + _bss_begin = .; + .bss : { *(.bss*) } + _bss_end = .; + + kernel_end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.en_frame*) } +} + +_bss_size = (_bss_end - _bss_begin) >> 3; diff --git a/Lab 5/kernel/src/mailbox.c b/Lab 5/kernel/src/mailbox.c new file mode 100644 index 000000000..dcf06b7f4 --- /dev/null +++ b/Lab 5/kernel/src/mailbox.c @@ -0,0 +1,52 @@ +#include "type.h" +#include "mmio.h" +#include "mailbox.h" + + +/* mailbox message buffer */ +volatile unsigned int __attribute__((aligned(16))) mailbox[36]; + +#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880) + +#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x00)) +#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x10)) +#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x14)) +#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x18)) +#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x1C)) +#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x20)) + + +/** + * Make a mailbox call. Returns 0 on failure, non-zero on success + */ +uint32_t +mailbox_call(unsigned char ch, volatile unsigned int *mbox) +{ + /* step 1. Combine the message address (upper 28 bits) with channel number (lower 4 bits) */ + unsigned int r = (((unsigned int)((unsigned long) mbox) & ~0xF) | (ch & 0xF)); + + /* step 2. Check if Mailbox 0 status register's full flag is set */ + /* wait until we can write to the mailbox */ + do { asm volatile("nop"); } while (*MBOX_STATUS & MBOX_FULL); + + /* step 3. If not full, then you can write to Mailbox 1 Read/Write register */ + /* write the address of our message to the mailbox with channel identifier */ + *MBOX_WRITE = r; + + /* now wait for the response */ + while(1) { + + /* 4. Check if Mailbox 0 status register's empty flag is set. */ + /* is there a response? */ + do { asm volatile("nop"); } while (*MBOX_STATUS & MBOX_EMPTY); + + /* 5. If not empty, then you can read from Mailbox 0 Read/Write register. */ + /* is it a response to our message? */ + if (r == *MBOX_READ) { + /* 6. Check if the value is the same as you wrote in step 1. */ + /* is it a valid successful response? */ + return mbox[1] == MBOX_RESPONSE; + } + } + return 0; +} diff --git a/Lab 5/kernel/src/mailbox.h b/Lab 5/kernel/src/mailbox.h new file mode 100644 index 000000000..7c9b88852 --- /dev/null +++ b/Lab 5/kernel/src/mailbox.h @@ -0,0 +1,77 @@ +/*** + Buffer contents: + + u32: size in bytes, (x+1) * 4, including the end tag + u32: Request code / response code + u8 ...: sequence of concatenated tags + u32: the end tag + u8 ...: padding + + + Tag format: + + u32: tag identifier + u32: value buffer size in bytes + u32: request code / response code + b31 = 0: request, b30-b0: reserved + b31 = 1: response, b30-b0: value length in bytes + u8 ...: value buffer + u8 ...: padding to align to 32 bits +***/ + + +#ifndef __MAILBOX_H__ +#define __MAILBOX_H__ + +#define MBOX_RESPONSE 0x80000000 + +#define MBOX_EMPTY 0x40000000 +#define MBOX_FULL 0x80000000 + +#define MBOX_REQUEST 0x00000000 +#define MBOX_RESPONSE_SUCCEED 0x80000000 +#define MBOX_RESPONSE_FAILED 0x80000001 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 // we only use channel 8 (CPU->GPU) + +/* tags */ + +#define MBOX_TAG_GETFWREVISION 0x00000001 // u32: firmware revision +#define MBOX_TAG_GETMODEL 0x00010001 // u32: board model +#define MBOX_TAG_GETREVISION 0x00010002 // u32: board revision +#define MBOX_TAG_GETMACADDR 0x00010003 // u8 * 6: MAC address in network byte order +#define MBOX_TAG_GETSERIAL 0x00010004 // u64: board serial +#define MBOX_TAG_GETMEMORY 0x00010005 // u32: base, u32: size +#define MBOX_TAG_GETVCMEM 0x00010006 // u32: base, u32: size +#define MBOX_TAG_GETCLOCKS 0x00010007 // u32: parent clock id, u32: clock id, (repeated) + +#define MBOX_TAG_ALLOCATEFB 0x00040001 // (u32: alignment in bytes) -> u32: base address, u32: size + +#define MBOX_TAG_GETPHYSICALWH 0x00040003 // u32: width in pixels, u32: height in pixels +#define MBOX_TAG_GETVIRTUALWH 0x00040004 // u32: width in pixels, u32: height in pixels +#define MBOX_TAG_GETDEPTH 0x00040005 // u32: bits per pixel +#define MBOX_TAG_GETPIXELORDER 0x00040006 // u32: 0x0=BGR, 0x1=RGB +#define MBOX_TAG_GETALPHAMODE 0x00040007 // u32: 0x0=enalbed, 0x1=reversed, 0x2=ignored +#define MBOX_TAG_GETPITCH 0x00040008 // u32: bytes per line +#define MBOX_TAG_GETVIRTUALOFFSET 0x00040009 // u32: X in pixels, u32: Y in pixels +#define MBOX_TAG_GETOVERSCAN 0x0004000a +#define MBOX_TAG_GETPALETTE 0x0004000b + +#define MBOX_TAG_REQUEST 0x00000000 +#define MBOX_TAG_END 0x00000000 + +/* a properly aligned buffer */ +extern volatile unsigned int mailbox[36]; + +uint32_t mailbox_call(unsigned char ch, volatile unsigned int *mbox); + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/memory.S b/Lab 5/kernel/src/memory.S new file mode 100644 index 000000000..df012b56e --- /dev/null +++ b/Lab 5/kernel/src/memory.S @@ -0,0 +1,15 @@ +.globl memcpy +memcpy: + ldr x3, [x1], #8 + str x3, [x0], #8 + subs x2, x2, #8 + b.gt memcpy + ret + + +.globl memzero +memzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero + ret \ No newline at end of file diff --git a/Lab 5/kernel/src/memory.c b/Lab 5/kernel/src/memory.c new file mode 100644 index 000000000..8bda29640 --- /dev/null +++ b/Lab 5/kernel/src/memory.c @@ -0,0 +1,152 @@ +#include "memory.h" +#include "chunk.h" +#include "frame.h" +#include "dtb.h" +#include "initrd.h" + + +byteptr_t +memory_align(const byteptr_t p, uint32_t s) { + uint64_t x = (uint64_t) p; + s = (1 << s); + return (byteptr_t) (x & ~(s - 1)); +} + + +byteptr_t +memory_padding(const byteptr_t p, uint32_t s) { + uint64_t x = (uint64_t) p; + s = (1 << s); + return (byteptr_t) ((x + s - 1) & (~(s - 1))); +} + + +int32_t +memory_cmp(byteptr_t s1, byteptr_t s2, int32_t n) +{ + byteptr_t a = s1, b = s2; + while (n-- > 0) { if (*a != *b) { return *a - *b; } a++; b++; } + return 0; +} + + +void +memory_copy(byteptr_t dest, byteptr_t source, int32_t size) +{ + while (size > 0) { *dest++ = *source++; --size; } +} + + +void +memory_zero(byteptr_t dest, int32_t size) +{ + while (size > 0) { *dest++ = 0; --size; } +} + + +#define STARTUP_HEAP_START 0x120000 +#define STARTUP_HEAP_END 0x180000 + +extern byte_t kernel_end; + +static byteptr_t _smalloc_cur = (byteptr_t) (STARTUP_HEAP_START | 0l); +static byteptr_t _smalloc_limit = (byteptr_t) (STARTUP_HEAP_END | 0l); + + + +byteptr_t +startup_memory_alloc(uint32_t size) +{ + size = (uint32_t) memory_padding((byteptr_t) (size | 0l), 3); + if ((uint32_t) (_smalloc_cur + size) > (uint32_t) _smalloc_limit) return 0; + byteptr_t ret_ptr = _smalloc_cur; + _smalloc_cur += size; + return ret_ptr; +} + + +byteptr_t +memory_alloc(uint32_t size) +{ + size = (uint32_t) memory_padding((byteptr_t) (size | 0l), 3); + if ((uint32_t) (_smalloc_cur + size) > (uint32_t) _smalloc_limit) return 0; + byteptr_t ret_ptr = _smalloc_cur; + _smalloc_cur += size; + return ret_ptr; +} + + +extern byte_t kernel_start, kernel_end; + +void +memory_system_init(uint32_t start, uint32_t end) +{ + frame_system_init_frame_array(start, end); + + frame_system_preserve(0, 0x1000); // spin table + frame_system_preserve(CHUNK_TABLE_ADDR, CHUNK_TABLE_END); + frame_system_preserve(0x60000, 0x80000); // call stack for kernel + frame_system_preserve((uint32_t) &kernel_start, (uint32_t) &kernel_end + 0x4000); // preserve some space for sprintf + frame_system_preserve(STARTUP_HEAP_START, STARTUP_HEAP_END); + frame_system_preserve((uint32_t) initrd_get_ptr(), (uint32_t) initrd_get_end()); + frame_system_preserve((uint32_t) dtb_get_ptr(), (uint32_t) dtb_get_end()); + + frame_system_init_free_blocks(); + init_chunk_table(); +} + +#define BLOCK_HEADER_SIZE 8 + +typedef struct block_header { + uint32_t count; + uint32_t size; +} block_header_t; + +typedef block_header_t * block_header_ptr; + +#include "uart.h" + +byteptr_t +kmemory_alloc(uint32_t size) +{ + if (size <= chunk_max_size()) + return chunk_request(size); + + uint32_t count = UINT32_PADDING((size + BLOCK_HEADER_SIZE), FRAME_SIZE_ORDER) >> FRAME_SIZE_ORDER; + + uart_printf("[DEBUG] kmemory_alloc - size: 0x%x, count: %d\n", size + BLOCK_HEADER_SIZE, count); + + byteptr_t block = frame_alloc(count); + + ((block_header_ptr) block)->count = count; + ((block_header_ptr) block)->size = size + BLOCK_HEADER_SIZE; + + // block[0] = (uint8_t) count; + // block[1] = (uint8_t) size + BLOCK_HEADER_SIZE; + return block + BLOCK_HEADER_SIZE; +} + + +void +kmemory_release(byteptr_t ptr) +{ + if ((uint32_t) ptr & chunk_data_offset()) { + chunk_release(ptr); + return; + } + + ptr = ptr - BLOCK_HEADER_SIZE; + uint32_t count = ((block_header_ptr) ptr)->count; + for (uint32_t i = 0; i < count; ++i) { + frame_release(ptr); + ptr = (byteptr_t) ((uint64_t) ptr + (1 << FRAME_SIZE_ORDER)); + } +} + + +void +memory_print_info() +{ + frame_print_info(); + chunk_system_infro(); +} \ No newline at end of file diff --git a/Lab 5/kernel/src/memory.h b/Lab 5/kernel/src/memory.h new file mode 100644 index 000000000..2b957c083 --- /dev/null +++ b/Lab 5/kernel/src/memory.h @@ -0,0 +1,28 @@ +#ifndef __MEMORY_H__ +#define __MEMORY_H__ + +#include "type.h" +#include "frame.h" + + +int32_t memory_cmp(byteptr_t s1, byteptr_t s2, int32_t n); +byteptr_t memory_align(const byteptr_t p, uint32_t s); +byteptr_t memory_padding(const byteptr_t p, uint32_t s); +void memory_copy(byteptr_t dest, byteptr_t source, int32_t size); +void memory_zero(byteptr_t dest, int32_t size); + +void memory_system_init(uint32_t start, uint32_t end); +void memory_print_info(); + +byteptr_t memory_alloc(uint32_t size); +byteptr_t startup_memory_alloc(uint32_t size); + +byteptr_t kmemory_alloc(uint32_t size); +void kmemory_release(byteptr_t ptr); + +#define malloc memory_alloc +#define smalloc startup_memory_alloc +#define kmalloc kmemory_alloc +#define kfree kmemory_release + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/mini_uart.c b/Lab 5/kernel/src/mini_uart.c new file mode 100644 index 000000000..7da365ed9 --- /dev/null +++ b/Lab 5/kernel/src/mini_uart.c @@ -0,0 +1,294 @@ +#include "type.h" +#include "gpio.h" +#include "aux.h" +#include "delay.h" +#include "irq.h" +#include "uart.h" +#include "sprintf.h" + + +#define BUFFER_SIZE 0x100 +#define BUFFER_END 0xFF + +static uint8_t _read_buffer[BUFFER_SIZE]; +static uint8_t _write_buffer[BUFFER_SIZE]; + +static uint32_t _read_start = 0, _read_end = 0; +static uint32_t _write_start = 0, _write_end = 0; + +static void +read_buffer_add(uint8_t c) +{ + _read_buffer[_read_end++] = c; + _read_end &= BUFFER_END; +} + +static uint8_t +read_buffer_get() +{ + uint8_t c = _read_buffer[_read_start++]; + _read_start &= BUFFER_END; + return c; +} + +static uint32_t +read_buffer_empty() +{ + return _read_start == _read_end; +} + + +static void +write_buffer_add(uint8_t c) +{ + _write_buffer[_write_end++] = c; + _write_end &= BUFFER_END; +} + +static uint8_t +write_buffer_get() +{ + uint8_t c = _write_buffer[_write_start++]; + _write_start &= BUFFER_END; + return c; +} + +static uint32_t +write_buffer_empty() +{ + return _write_start == _write_end; +} + + + + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void +mini_uart_init(void) +{ + /* + setup GPIO pins + */ + + uint32_t selector; + + selector = *GPFSEL1; + selector &= ~((7<<12)|(7<<15)); // clean gpio14 and gpio15 + selector |= (2<<12)|(2<<15); // set alt5 for gpio14 and gpio15 + *GPFSEL1 = selector; + + *GPPUD = 0; + + delay_cycles(150); + + *GPPUDCLK0 = (1<<14)|(1<<15); // enable pins 14 and 15 + + delay_cycles(150); + + *GPPUDCLK0 = 0; // flush GPIO setup + + /* + setup AUX mini UART + */ + + *AUX_ENABLES |= 1; // Enable UART1, AUX mini uart (this also enables access to its registers) + *AUX_MU_CNTL = 0; // Disable auto flow control and disable receiver and transmitter (for now) + + *AUX_MU_LCR = 3; // Enable 8 bit mode + *AUX_MU_MCR = 0; // Set RTS line to be always high + + *AUX_MU_IER = 0; // Disable receive and transmit interrupts + + *AUX_MU_IIR = 0xc6; // disable interrupts + *AUX_MU_BAUD = 270; // Set baud rate to 115200 + + *AUX_MU_CNTL = 3; // Finally, enable transmitter and receiver + + + /* + init asynchronous buffers + */ + + _read_start = _read_end = 0; + _write_start = _write_end = 0; +} + + +/** + * Receive a character + * ref : BCM2837-ARM-Peripherals p5 + * AUX_MU_LSR_REG bit_0 == 1 -> readable + */ +uint8_t +mini_uart_getc() +{ + /* wait until something is in the buffer */ + do { asm volatile("nop"); } while (!(*AUX_MU_LSR & 0x01)); + /* read it and return */ + uint8_t r = (uint8_t)(*AUX_MU_IO & 0xFF); + /* convert carriage return to newline */ + return r == '\r' ? '\n' : r; +} + +uint8_t +mini_uart_getb() +{ + /* wait until something is in the buffer */ + do { asm volatile("nop"); } while (!(*AUX_MU_LSR & 0x01)); + /* read it and return */ + return (uint8_t)(*AUX_MU_IO | 0xFF); +} + + +/** + * Send a character + * ref : BCM2837-ARM-Peripherals p5 + * AUX_MU_LSR_REG bit_5 == 1 -> writable + */ +void mini_uart_putc(uint8_t c) +{ + /* wait until we can send */ + do { asm volatile("nop"); } while (!(*AUX_MU_LSR & 0x20)); + /* write the character to the buffer */ + *AUX_MU_IO = c; +} + + +/** + * Display a string + */ +void +mini_uart_puts(byteptr_t s) +{ + while (*s) { + mini_uart_putc(*s++); + } +} + +/** + * Display a string with the newline + */ +void +mini_uart_putln(byteptr_t s) +{ + mini_uart_puts(s); + mini_uart_puts("\r\n"); +} + + +/** + * Display a 32-bit binary value in hexadecimal + */ +void +mini_uart_hex(uint32_t d) +{ + for (int32_t c = 28; c >= 0; c -= 4) { + // get highest tetrad + uint8_t n = (d >> c) & 0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n += n > 9 ? 0x37 : 0x30; + mini_uart_putc(n); + } +} + +/** + * Display a 64-bit binary value in hexadecimal + */ +void +mini_uart_hexl(uint64_t d) +{ + for (int32_t c = 60; c >= 0; c -= 4) { + // get highest tetrad + uint8_t n = (d >> c) & 0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n += n > 9 ? 0x37 : 0x30; + mini_uart_putc(n); + } +} + + +void +mini_uart_endl() +{ + mini_uart_puts("\r\n"); +} + +extern volatile byte_t kernel_end; + +void +mini_uart_printf(char* fmt, ...) +{ + __builtin_va_list args; + __builtin_va_start(args, fmt); + char *s = (char*) &kernel_end; + vsprintf(s, fmt, args); + while (*s) { + if (*s == '\n') mini_uart_putc('\r'); + mini_uart_putc(*s++); + } +} + + +byte_t +mini_uart_async_getc() +{ + aux_set_rx_interrupts(); + while (read_buffer_empty()) { + asm volatile("nop"); + } + irq_disable_aux_interrupt(); + uint8_t c = read_buffer_get(); + irq_enable_aux_interrupt(); + return c; +} + + +void +mini_uart_async_putc(uint8_t c) +{ + write_buffer_add(c); + aux_set_tx_interrupts(); +} + + +void +mini_uart_rx_handler() +{ + irq_disable_aux_interrupt(); + read_buffer_add(mini_uart_getc()); + irq_enable_aux_interrupt(); + aux_clr_rx_interrupts(); +} + + +void +mini_uart_tx_handler() +{ + irq_disable_aux_interrupt(); + aux_clr_tx_interrupts(); + + while (!write_buffer_empty()) { + delay_cycles(1 << 21); // (1 << 28) for qemu + uint8_t c = write_buffer_get(); + mini_uart_putc(c); + } + mini_uart_putc('\n'); + mini_uart_putc('\r'); +} + + +void +mini_uart_async_demo() +{ + irq_enable_aux_interrupt(); + uint8_t c = mini_uart_async_getc(); + while (c != '\n') + { + write_buffer_add(c); + c = mini_uart_async_getc(); + } + write_buffer_add(c); + aux_set_tx_interrupts(); +} \ No newline at end of file diff --git a/Lab 5/kernel/src/mini_uart.h b/Lab 5/kernel/src/mini_uart.h new file mode 100644 index 000000000..b76f394ce --- /dev/null +++ b/Lab 5/kernel/src/mini_uart.h @@ -0,0 +1,26 @@ +#ifndef __MINI_UART_H__ +#define __MINI_UART_H__ + +#include "type.h" + +void mini_uart_init(void); + +uint8_t mini_uart_getc(void); +uint8_t mini_uart_getb(void); + +void mini_uart_putc(uint8_t c); +void mini_uart_puts(byteptr_t s); +void mini_uart_putln(byteptr_t s); +void mini_uart_endl(); + +void mini_uart_hex(uint32_t d); +void mini_uart_hexl(uint64_t d); + +void mini_uart_printf(char* fmt, ...); + +void mini_uart_async_demo(); + +void mini_uart_tx_handler(); +void mini_uart_rx_handler(); + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/power.c b/Lab 5/kernel/src/power.c new file mode 100644 index 000000000..ae5a04732 --- /dev/null +++ b/Lab 5/kernel/src/power.c @@ -0,0 +1,26 @@ +#include "mmio.h" +#include "power.h" + + +#define PM_RSTC ((volatile unsigned int*)(MMIO_BASE+0x0010001c)) +#define PM_RSTS ((volatile unsigned int*)(MMIO_BASE+0x00100020)) +#define PM_WDOG ((volatile unsigned int*)(MMIO_BASE+0x00100024)) + +#define PM_MAGIC 0x5a000000 +#define PM_RSTC_FULLRST 0x00000020 + + +void +power_reset(uint32_t ticks) +{ + *PM_RSTC = (PM_MAGIC | PM_RSTC_FULLRST); // full reset + *PM_WDOG = (PM_MAGIC | ticks); // number of watchdog ticks +} + + +void +power_reset_cancel() +{ + *PM_RSTC = (PM_MAGIC | 0); // cancel reset + *PM_WDOG = (PM_MAGIC | 0); // number of watchdog ticks +} \ No newline at end of file diff --git a/Lab 5/kernel/src/power.h b/Lab 5/kernel/src/power.h new file mode 100644 index 000000000..1d6b179b1 --- /dev/null +++ b/Lab 5/kernel/src/power.h @@ -0,0 +1,9 @@ +#ifndef __POWER_H__ +#define __POWER_H__ + +#include "type.h" + +void power_reset(uint32_t ticks); +void power_reset_cancel(); + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/sched.S b/Lab 5/kernel/src/sched.S new file mode 100644 index 000000000..262b69b9d --- /dev/null +++ b/Lab 5/kernel/src/sched.S @@ -0,0 +1,32 @@ +#define THREAD_CPU_CONTEXT_OFFSET 0 + + +.globl cpu_switch_to +cpu_switch_to: + + mov x10, #THREAD_CPU_CONTEXT_OFFSET + + // store current thread callee-saved registers + add x8, x0, x10 + mov x9, sp + stp x19, x20, [x8], #0x10 + stp x21, x22, [x8], #0x10 + stp x23, x24, [x8], #0x10 + stp x25, x26, [x8], #0x10 + stp x27, x28, [x8], #0x10 + stp fp, x9, [x8], #0x10 + str lr, [x8] + + + // restore next thread callee-saved registers + add x8, x1, x10 + ldp x19, x20, [x8], #0x10 + ldp x21, x22, [x8], #0x10 + ldp x23, x24, [x8], #0x10 + ldp x25, x26, [x8], #0x10 + ldp x27, x28, [x8], #0x10 + ldp fp, x9, [x8], #0x10 + ldr lr, [x8] + mov sp, x9 + + ret \ No newline at end of file diff --git a/Lab 5/kernel/src/sched.c b/Lab 5/kernel/src/sched.c new file mode 100644 index 000000000..c0d93c6ed --- /dev/null +++ b/Lab 5/kernel/src/sched.c @@ -0,0 +1,284 @@ +#include "sched.h" +#include "type.h" +#include "uart.h" +#include "list.h" +#include "frame.h" +#include "memory.h" +#include "delay.h" +#include "entry.h" +#include "shell.h" +#include "core_timer.h" +#include "exception.h" + + +// -------------------------------- // + + +/** + * p -> +-----------------+ 0 + * | task_struct | + * +-----------------+ + * | | USER_STACK + * | STACK | + * | | USER_PROGRAM + * childregs -> +-----------------+ + * | pt_regs | + * +-----------------+ 4096 +*/ + + +// #define THREAD_SIZE 0x1000 +// #define STACK_SIZE 0x1000 + + +void cpu_switch_to(void *, void *); + + +static task_t init_task; + +static task_ptr current; +static task_ptr shell_task; + + +int32_t +get_pid() +{ + return current->pid; +} + + +task_ptr +current_task() +{ + return current; +} + + +task_ptr +get_shell_task() +{ + return shell_task; +} + + + +/* *************************** * + * Scheduler OPs + * *************************** */ + +static LIST_HEAD(running_queue); +static LIST_HEAD(waiting_queue); +static LIST_HEAD(stopped_queue); + + +static void +_preempt_disable() +{ + current->preempt_count++; +} + + +static void +_preempt_enable() +{ + current->preempt_count--; +} + + +static void +_switch(task_ptr next) +{ + if (current == next) return; + task_ptr prev = current; + current = next; + cpu_switch_to(&(prev->cpu_context), &(next->cpu_context)); +} + + +static void +_schedule() +{ + _preempt_disable(); + + int32_t c = 0; + task_ptr next = 0; + + while (1) { + c = -1; + list_head_ptr_t p; + + // find next task + list_for_each(p, &running_queue) { + task_ptr tsk = (task_ptr) p; + if (tsk->state == TASK_RUNNING && tsk->counter > c) { + c = tsk->counter; + next = tsk; + } + } + + if (c) { break; } // found the next + // else the list is empty, or no one is old enough + + // not found the next, do aging + list_for_each(p, &running_queue) { + task_ptr tsk = (task_ptr) p; + tsk->counter = (tsk->counter >> 1) + tsk->priority; + } + } + + _switch(next); + + _preempt_enable(); +} + + +void +schedule_tail() +{ + _preempt_enable(); +} + + +/* + * called by the current task + * e.g, idle() or process_exit(), ..etc. + * switch the context itself + */ +void +schedule() +{ + // reset the age of current task + current->counter = 0; + _schedule(); +} + + +/* + * called from irq handler + * + */ +void +scheduler_tick(byteptr_t _) +{ + // uart_printf("---- scheduler_tick ----\n"); + + --current->counter; + if (current->counter > 0 || current->preempt_count > 0) { + return; + } + current->counter=0; + enable_irq(); + _schedule(); + disable_irq(); +} + + +static void +_pause_shell() +{ + if (!shell_task || shell_task->state != TASK_RUNNING) return; + shell_task->state = TASK_WAITING; + list_del_entry((list_head_ptr_t) shell_task); + list_add_tail((list_head_ptr_t) shell_task, &waiting_queue); +} + + +static void +_wake_shell() +{ + if (!shell_task || shell_task->state == TASK_RUNNING) return; + shell_task->state = TASK_RUNNING; + list_del_entry((list_head_ptr_t) shell_task); + list_add_tail((list_head_ptr_t) shell_task, &running_queue); +} + + + +void +scheduler_kill(task_ptr tsk, int32_t status) +{ + tsk->state = TASK_STOPPED; + tsk->exitcode = status; + if (tsk->user_stack) + frame_release(tsk->user_stack); + if (tsk->frame_count) + frame_release_block(tsk->user_prog, tsk->frame_count); + + _preempt_disable(); + list_del_entry((list_head_ptr_t) tsk); + list_add_tail((list_head_ptr_t) tsk, &stopped_queue); + if (tsk->foreground) _wake_shell(); + _preempt_enable(); + + schedule(); +} + + +task_ptr +scheduler_find(int32_t pid) +{ + list_head_ptr_t p; + + list_for_each(p, &running_queue) { + task_ptr tsk = (task_ptr) p; + if (tsk->pid == pid) return tsk; + } + + list_for_each(p, &waiting_queue) { + task_ptr tsk = (task_ptr) p; + if (tsk->pid == pid) return tsk; + } + + return 0; +} + + +void +scheduler_add(task_ptr tsk) +{ + tsk->state = TASK_RUNNING; + _preempt_disable(); + list_add_tail((list_head_ptr_t) tsk, &running_queue); + if (tsk->foreground) _pause_shell(); + _preempt_enable(); +} + + +void +scheduler_init() +{ + task_count = 0; + task_init(&init_task); + scheduler_add(&init_task); + + current = &(init_task); + shell_task = 0; + + uart_printf("[DEBUG] sched_init - init_stask: 0x%x, pid=%d\n", &init_task, init_task.pid); + core_timer_add_tick(scheduler_tick, "", 5); +} + + +void +scheduler_add_shell(task_ptr tsk) +{ + tsk->state = TASK_RUNNING; + _preempt_disable(); + list_add_tail((list_head_ptr_t) tsk, &running_queue); + shell_task = tsk; + _preempt_enable(); +} + + +void +kill_zombies() +{ + _preempt_disable(); + while (!list_empty(&stopped_queue)) { + task_ptr victim = (task_ptr) (&stopped_queue)->next; + uart_printf("[DEBUG] killed victim: 0x%x, pid = %d\n", victim, victim->pid); + list_del_entry((list_head_ptr_t) victim); + frame_release((byteptr_t) victim); + } + _preempt_enable(); +} diff --git a/Lab 5/kernel/src/sched.h b/Lab 5/kernel/src/sched.h new file mode 100644 index 000000000..a3f534d5c --- /dev/null +++ b/Lab 5/kernel/src/sched.h @@ -0,0 +1,27 @@ +#ifndef _SCHED_H +#define _SCHED_H + +#include "type.h" +#include "list.h" +#include "signal.h" +#include "task.h" + + +task_ptr current_task(); + +void scheduler_init(); +void scheduler_add(task_ptr tsk); +void scheduler_add_shell(task_ptr tsk); +void scheduler_kill(task_ptr tsk, int32_t status); +task_ptr scheduler_find(int32_t pid); + +void schedule(); +void kill_zombies(); + +void schedule_tail(); +void scheduler_tick(byteptr_t); + +int32_t get_pid(); + + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/shell.c b/Lab 5/kernel/src/shell.c new file mode 100644 index 000000000..7e5def662 --- /dev/null +++ b/Lab 5/kernel/src/shell.c @@ -0,0 +1,202 @@ +#include "type.h" +#include "uart.h" +#include "string.h" +#include "initrd.h" +#include "power.h" +#include "info.h" +#include "memory.h" +#include "dtb.h" +#include "delay.h" +#include "sched.h" +#include "core_timer.h" +#include "thread.h" + + +#define BUFFER_MAX_SIZE 64 + + +static void +print_help() +{ + uart_line("--------------------------------"); + + uart_str("help\t| "); + uart_line("print this help menu"); + + uart_str("info\t| "); + uart_line("print VideoCore info"); + + uart_str("dtb\t| "); + uart_line("print the device tree"); + + uart_str("ls\t| "); + uart_line("list directory contents"); + + uart_str("cat\t| "); + uart_line("print the file content"); + + uart_str("exe\t| "); + uart_line("execute a user program"); + + uart_str("async\t| "); + uart_line("async uart demo"); + + uart_str("timer\t| "); + uart_line("set timeout message [timer msg duration]"); + + uart_str("malloc\t| "); + uart_line("memory allocation [data size in bytes]"); + + uart_str("free\t| "); + uart_line("memory release [block addr in hexdecimal]"); + + uart_str("memory\t| "); + uart_line("memory infomation"); + + uart_str("thread\t| "); + uart_line("thread test demo"); + + uart_str("reboot\t| "); + uart_line("reboot this device"); + + uart_line("--------------------------------"); +} + + +static byteptr_t +read_command(byteptr_t buffer) +{ + uint32_t index = 0; + byte_t r = 0; + do { + r = uart_getc(); + // uart_printf("\n0x%x\n", r); + if (r == '\n') { + uart_put('\n'); + uart_put('\r'); + } + else if (r == 0x7f && index > 0) { + index--; + uart_put(0x8); + uart_put(r); + } + else if (r < 0x7f && (r < 0x11 || r > 0x1f)) { + buffer[index++] = r; + uart_put(r); + } + } while (index < (BUFFER_MAX_SIZE - 1) && r != '\n'); + buffer[index] = '\0'; + return buffer; +} + + +static byteptr_t +next_tok(byteptr_t buffer, byteptr_t message) +{ + byteptr_t tok = str_tok(0); + if (tok == nullptr) { + uart_str(message); + while (tok == nullptr) { + read_command(buffer); + tok = str_tok(buffer); + } + } + return tok; +} + + +static void +parse_command(byteptr_t buffer) +{ + byteptr_t cmd = str_tok(buffer); + + if (str_eql(cmd, "help")) { + print_help(); + } + + else if (str_eql(cmd, "reboot")) { + uart_line("rebooting..."); + power_reset(100); + uart_get(); + delay_cycles(500); + } + + else if (str_eql(cmd, "ls")) { + initrd_list(); + } + + else if (str_eql(cmd, "cat")) { + byteptr_t tok = next_tok(buffer, "file: "); + initrd_cat(tok); + } + + else if (str_eql(cmd, "info")) { + info_board_revision(); + info_memory(); + // info_videocore(); + } + + else if (str_eql(cmd, "dtb")) { + fdt_traverse(fdt_print_node); + } + + else if (str_eql(cmd, "exe")) { + byteptr_t tok = next_tok(buffer, "file: "); + initrd_exec(tok); + } + + else if (str_eql(cmd, "async")) { + mini_uart_async_demo(); + } + + else if (str_eql(cmd, "timer")) { + byteptr_t tok = next_tok(buffer, "message: "); + byte_t msg[32]; str_ncpy(msg, tok, 32); + tok = next_tok(buffer, "duration: "); + uint32_t duration = ascii_dec_to_uint32(tok); + core_timer_add_timeout_event(msg, duration); + } + + else if (str_eql(cmd, "malloc")) { + byteptr_t tok = next_tok(buffer, "size: "); + uint32_t size = ascii_dec_to_uint32(tok); + byteptr_t ptr = kmemory_alloc(size); + uart_printf("malloc: %d bytes, addr: 0x%x\n", size, ptr); + } + + else if (str_eql(cmd, "free")) { + byteptr_t tok = next_tok(buffer, "addr: "); + uint64_t addr = ascii_to_uint64(tok, str_len(tok)); + uart_printf("free: %s, 0x%x\n", tok, addr); + kmemory_release((byteptr_t) addr); + } + + else if (str_eql(cmd, "memory")) { + memory_print_info(); + } + + else if (str_eql(cmd, "thread")) { + thread_demo(); + } + + else if (str_len(buffer) > 0) { + uart_str("not a command: "); + uart_line(buffer); + } +} + + +void +shell() +{ + while (1) + { + byte_t buffer[BUFFER_MAX_SIZE]; + uart_str("> "); + read_command(buffer); + parse_command(buffer); + } +} + + + diff --git a/Lab 5/kernel/src/shell.h b/Lab 5/kernel/src/shell.h new file mode 100644 index 000000000..cb1251c17 --- /dev/null +++ b/Lab 5/kernel/src/shell.h @@ -0,0 +1,6 @@ +#ifndef __SHELL_H__ +#define __SHELL_H__ + +void shell(); + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/string.c b/Lab 5/kernel/src/string.c new file mode 100644 index 000000000..cfee123fd --- /dev/null +++ b/Lab 5/kernel/src/string.c @@ -0,0 +1,168 @@ +#include "string.h" + + +static uint32_t +_is_delim(uint8_t c) +{ + return (c == ' ' || c == '\t' || c == '\n') ? 1 : 0; +} + +byteptr_t +str_tok(byteptr_t s) +{ + static byteptr_t old_s; + if (!s) s = old_s; + if (!s) return nullptr; + // find begin + while (_is_delim(*s)) { s++; } + // reached the end + if (*s == '\0') return nullptr; + byteptr_t ret = s; + // find end + while (1) { + if (*s == '\0') { + old_s = s; + return ret; + } + if (_is_delim(*s)) { + *s = '\0'; + old_s = s + 1; + return ret; + } + s++; + } + return nullptr; +} + + +int32_t +str_cmp(const byteptr_t s1, const byteptr_t s2) +{ + byteptr_t p1 = (byteptr_t) s1; + byteptr_t p2 = (byteptr_t) s2; + while (*p1 && *p1 == *p2) ++p1, ++p2; + return (*p1 > *p2) - (*p2 > *p1); +} + + +uint32_t +str_eql(const byteptr_t s1, const byteptr_t s2) +{ + return str_cmp(s1, s2) == 0; +} + + +uint32_t +str_len(const byteptr_t str) +{ + uint32_t len = 0; + byteptr_t p = (byteptr_t) str; + while (*p++ != '\0') ++len; + return len; +} + + +void +str_ncpy(byteptr_t dest, byteptr_t src, uint32_t n) +{ + while (n > 0 && *src != '\0') { + *dest++ = *src++; + n--; + } + *dest = '\0'; +} + + +static void +_reverse(byteptr_t str, uint32_t length) +{ + uint32_t start = 0; + uint32_t end = length - 1; + while (start < end) { + uint8_t temp = str[start]; + str[start] = str[end]; + str[end] = temp; + end--; + start++; + } +} + + +void +uint32_to_hex(uint32_t n, byteptr_t buffer) +{ + uint32_t length = 0; + while (n != 0) { + int rem = n % 16; + buffer[length++] = (rem < 10) ? rem + '0' : rem + 'A'; + n = n / 16; + } + if (length == 0) buffer[length++] = '0'; + buffer[length] = '\0'; + _reverse(buffer, length); +} + + +void +uint32_to_ascii(uint32_t n, byteptr_t buffer) +{ + uint32_t length = 0; + while (n != 0) { + int rem = n % 10; + buffer[length++] = rem + '0'; + n = n / 10; + } + if (length == 0) buffer[length++] = '0'; + buffer[length] = '\0'; + _reverse(buffer, length); +} + + +uint32_t +ascii_to_uint32(const byteptr_t str, uint32_t len) { + byteptr_t s = (byteptr_t) str; + uint32_t num = 0; + for (uint32_t i = 0; i < len; ++i) { + num = num << 4; + if (*s >= 'A' && *s <= 'F') { + num += (*s - 'A' + 10); + } else if (*s >= 'a' && *s <= 'f') { + num += (*s - 'a' + 10); + } else { + num += (*s - '0'); + } + s++; + } + return num; +} + + +uint64_t +ascii_to_uint64(const byteptr_t str, uint32_t len) { + byteptr_t s = (byteptr_t) str; + uint64_t num = 0; + for (uint32_t i = 0; i < len; ++i) { + num = num << 4; + if (*s >= 'A' && *s <= 'F') { + num += (*s - 'A' + 10); + } else if (*s >= 'a' && *s <= 'f') { + num += (*s - 'a' + 10); + } else { + num += (*s - '0'); + } + s++; + } + return num; +} + + +uint32_t +ascii_dec_to_uint32(const byteptr_t str) { + byteptr_t s = (byteptr_t) str; + uint32_t value = 0; + while (*s) { + value = value * 10 + (*s - '0'); + ++s; + } + return value; +} \ No newline at end of file diff --git a/Lab 5/kernel/src/string.h b/Lab 5/kernel/src/string.h new file mode 100644 index 000000000..978c81d82 --- /dev/null +++ b/Lab 5/kernel/src/string.h @@ -0,0 +1,20 @@ +#ifndef __STRING_H__ +#define __STRING_H__ + +#include "type.h" + +int32_t str_cmp(const byteptr_t s1, const byteptr_t s2); +uint32_t str_eql(const byteptr_t s1, const byteptr_t s2); +uint32_t str_len(const byteptr_t str); +byteptr_t str_tok(byteptr_t s); +void str_ncpy(byteptr_t dest, byteptr_t src, uint32_t n); + +void uint32_to_hex(uint32_t n, byteptr_t buffer); +void uint32_to_ascii(uint32_t n, byteptr_t buffer); + +uint32_t ascii_to_uint32(const byteptr_t s, uint32_t len); +uint64_t ascii_to_uint64(const byteptr_t s, uint32_t len); + +uint32_t ascii_dec_to_uint32(const byteptr_t str); + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/sys.S b/Lab 5/kernel/src/sys.S new file mode 100644 index 000000000..314e8202b --- /dev/null +++ b/Lab 5/kernel/src/sys.S @@ -0,0 +1,72 @@ +#include "syscall.h" + + +// .globl call_sys_write +// call_sys_write: +// mov w8, #SYS_WRITE_NUMBER +// svc #0 +// ret + + +// .globl call_sys_malloc +// call_sys_malloc: +// mov w8, #SYS_MALLOC_NUMBER +// svc #0 +// ret + + +// .globl call_sys_exit +// call_sys_exit: +// mov w8, #SYS_EXIT_NUMBER +// svc #0 +// ret + + +// .globl call_sys_clone +// call_sys_clone: +// /* Save args for the child. */ +// mov x10, x0 /*fn*/ +// mov x11, x1 /*arg*/ +// mov x12, x2 /*stack*/ + +// /* Do the system call. */ +// mov x0, x2 /* stack */ +// mov x8, #SYS_CLONE_NUMBER +// svc 0x0 + +// cmp x0, #0 +// beq thread_start +// ret + + +// thread_start: +// mov x29, 0 + +// /* Pick the function arg and execute. */ +// mov x0, x11 +// blr x10 + +// /* We are done, pass the return value through x0. */ +// mov x8, #SYS_EXIT_NUMBER +// svc 0x0 + + +.globl call_get_pid +call_get_pid: + mov w8, #SYS_CALL_GETPID + svc #0 + ret + +.globl call_fork +call_fork: + mov w8, #SYS_CALL_FORK + svc #0 + ret + + +.globl call_exit +call_exit: + mov w8, #SYS_CALL_EXIT + svc #0 + ret + \ No newline at end of file diff --git a/Lab 5/kernel/src/syscall.c b/Lab 5/kernel/src/syscall.c new file mode 100644 index 000000000..87dba5864 --- /dev/null +++ b/Lab 5/kernel/src/syscall.c @@ -0,0 +1,97 @@ +#include "syscall.h" +#include "uart.h" +#include "mailbox.h" +#include "initrd.h" +#include "sched.h" +#include "thread.h" +#include "signal.h" + + +int32_t +sys_getpid() +{ + return current_task()->pid; +} + + +uint32_t +sys_uart_read(byteptr_t buf, uint32_t size) +{ + for (int32_t i = 0; i < size; i++) { buf[i] = uart_getc(); } + return size; +} + + +uint32_t +sys_uart_write(const byteptr_t buf, uint32_t size) +{ + for (int32_t i = 0; i < size; i++) { uart_put(buf[i]); } + return size; +} + + +int32_t +sys_exec(const char *name, char *const argv[]) +{ + initrd_exec_replace((const byteptr_t) name); + return 0; +} + + +int32_t +sys_fork() +{ + return thread_fork(); +} + + +void +sys_exit(int status) +{ + thread_exit(status); +} + + +int32_t +sys_mbox_call(byte_t ch, uint32_t *mbox) +{ + return mailbox_call(ch, mbox); +} + + +void +sys_kill_pid(int32_t pid) +{ + task_ptr tsk = scheduler_find(pid); + if (tsk) scheduler_kill(tsk, 0); +} + + +void +sys_signal(int32_t sig_number, byteptr_t handler) +{ + uart_printf("syscall_signal (register) - signal number: %d, handler: 0x%x\n", sig_number, handler); + task_ptr current = current_task(); + task_add_signal(current, sig_number, handler); +} + + +void +sys_sigkill(int32_t pid, int32_t sig_number) +{ + uart_printf("syscall_sigkill (signal) - number: %d, pid: %d\n", pid, sig_number); + task_ptr tsk = scheduler_find(pid); + + if (tsk) task_to_signal_handler(tsk, sig_number); + else uart_printf("[DEBUG] signal(%d) default handler\n", sig_number); +} + + +void +sys_sigreturn() +{ + uart_printf("syscall_sigreturn\n"); + task_ptr tsk = current_task(); + task_ret_from_signal_handler(tsk); +} + diff --git a/Lab 5/kernel/src/syscall.h b/Lab 5/kernel/src/syscall.h new file mode 100644 index 000000000..3b633ffdf --- /dev/null +++ b/Lab 5/kernel/src/syscall.h @@ -0,0 +1,73 @@ +#ifndef __SYSCALL_H__ +#define __SYSCALL_H__ + +// #define __NR_syscalls 4 + +// #define SYS_WRITE_NUMBER 0 // syscal numbers +// #define SYS_MALLOC_NUMBER 1 +// #define SYS_CLONE_NUMBER 2 +// #define SYS_EXIT_NUMBER 3 + +#define SYS_CALL_GETPID 0 +#define SYS_CALL_FORK 4 +#define SYS_CALL_EXIT 5 + + +#ifndef __ASSEMBLER__ + +#include "type.h" + + +typedef void (*syscall) (); + + +enum { + SYS_GETPID, // 0 + SYS_UART_RECV, // 1 + SYS_UART_WRITE, // 2 + SYS_EXEC, // 3 + SYS_FORK, // 4 + SYS_EXIT, // 5 + SYS_MBOX, // 6 + SYS_KILL_PID, // 7 + SYS_SIGNAL, // 8 + SYS_SIGKILL, // 9 + SYS_SIGRETURN, // 10 + NR_SYSCALLS // 11 +}; + + +int32_t sys_getpid(); +uint32_t sys_uart_read(byteptr_t buf, uint32_t size); +uint32_t sys_uart_write(const byteptr_t buf, uint32_t size); +int32_t sys_exec(const char *name, char *const argv[]); +int32_t sys_fork(); +void sys_exit(int status); +int32_t sys_mbox_call(byte_t ch, uint32_t *mbox); +void sys_kill_pid(int32_t pid); + +void sys_signal(); +void sys_sigkill(); +void sys_sigreturn(); + +int32_t call_get_pid(void); +int32_t call_fork(void); + + +void * const syscall_table[NR_SYSCALLS] = { + [SYS_GETPID] = &sys_getpid, + [SYS_UART_RECV] = &sys_uart_read, + [SYS_UART_WRITE] = &sys_uart_write, + [SYS_EXEC] = &sys_exec, + [SYS_FORK] = &sys_fork, + [SYS_EXIT] = &sys_exit, + [SYS_MBOX] = &sys_mbox_call, + [SYS_KILL_PID] = &sys_kill_pid, + [SYS_SIGNAL] = &sys_signal, + [SYS_SIGKILL] = &sys_sigkill, + [SYS_SIGRETURN] = &sys_sigreturn, +}; + + +#endif +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/task.c b/Lab 5/kernel/src/task.c new file mode 100644 index 000000000..6d32a3eef --- /dev/null +++ b/Lab 5/kernel/src/task.c @@ -0,0 +1,190 @@ +#include "task.h" +#include "memory.h" +#include "exception.h" +#include "entry.h" +#include "uart.h" +#include "list.h" +#include "arm/sysregs.h" + +#define THREAD_SIZE 0x1000 + + +void +task_kill(task_ptr tsk, int32_t status) +{ + tsk->state = TASK_STOPPED; + tsk->exitcode = status; + + if (tsk->user_stack) + frame_release(tsk->user_stack); + if (tsk->frame_count) + frame_release_block(tsk->user_prog, tsk->frame_count); +} + + +int32_t task_count = 0; + + +ptregs_ptr +task_pt_regs(task_ptr tsk) +{ + uint64_t p = (uint64_t) tsk + THREAD_SIZE - sizeof(pt_regs_t); + return (ptregs_ptr) p; +} + + +void +task_init(task_ptr tsk) +{ + memory_zero((byteptr_t) tsk, sizeof(task_t)); + memory_zero((byteptr_t) &tsk->cpu_context, sizeof(cpu_context_t)); + ptregs_ptr childregs = task_pt_regs(tsk); + memory_zero((byteptr_t) childregs, sizeof(pt_regs_t)); + tsk->cpu_context.sp = (uint64_t) childregs; + tsk->cpu_context.lr = (uint64_t) ret_from_fork; + INIT_LIST_HEAD((list_head_ptr_t) tsk); + tsk->priority = 1; +} + + +void +task_reset(task_ptr tsk, uint64_t fn, uint64_t arg) +{ + int32_t pid = tsk->pid; + task_init(tsk); + tsk->cpu_context.x19 = fn; + tsk->cpu_context.x20 = arg; + tsk->state = TASK_RUNNING; + tsk->pid = pid; +} + + +task_ptr +task_create(uint64_t fn, uint64_t arg) +{ + task_ptr p = (task_ptr) frame_alloc(1); + if (!p) { return 0; } + task_reset(p, fn, arg); + p->pid = ++task_count; + + return p; +} + + +task_ptr +task_fork(task_ptr parent) +{ + // 1. build child task + task_ptr child = (task_ptr) frame_alloc(1); + if (!child) { return 0; } + // memory_copy((byteptr_t) child, (byteptr_t) parent, sizeof(task_t)); + memory_zero((byteptr_t) child, sizeof(task_t)); + child->foreground = 0; + child->sig9_handler = parent->sig9_handler; + + // 2. copy trapframe + ptregs_ptr currentregs = task_pt_regs(parent); + ptregs_ptr childregs = task_pt_regs(child); + memory_copy((byteptr_t) childregs, (byteptr_t) currentregs, sizeof(pt_regs_t)); + + // 3. set the kernel stack of the child + child->cpu_context.x19 = 0; + child->cpu_context.x20 = 0; + child->cpu_context.sp = (uint64_t) childregs; + child->cpu_context.lr = (uint64_t) ret_from_fork; + child->priority = 1; + + // 4. assign the child a new id + child->pid = ++task_count; + + // 5. copy user stack + if (parent->user_stack) { + child->user_stack = frame_alloc(1); + memory_copy((byteptr_t) child->user_stack, (byteptr_t) parent->user_stack, THREAD_SIZE); + } + + // 6. copy user program + if (parent->user_prog) { + child->user_prog_size = parent->user_prog_size; + child->frame_count = parent->frame_count; + child->user_prog = frame_alloc(parent->frame_count); + memory_copy((byteptr_t) child->user_prog, (byteptr_t) parent->user_prog, parent->user_prog_size); + } + + // 7. calculate the offsets of user mode + childregs->regs[30] = (uint64_t) child->user_prog + (currentregs->regs[30] - (uint64_t) parent->user_prog); // link return + childregs->sp = (uint64_t) child->user_stack + (currentregs->sp - (uint64_t) parent->user_stack); + childregs->pc = (uint64_t) child->user_prog + (currentregs->pc - (uint64_t) parent->user_prog); + childregs->pstate = 0; + + // 8. returned value + childregs->regs[0] = 0; + + return child; +} + + +int32_t +task_to_user_mode(task_ptr tsk, uint64_t pc) +{ + uart_printf("[DEBUG] task_to_user_mode - pc: 0x%x\n", pc); + + // 1. build a user stack + uint64_t stack = (uint64_t) frame_alloc(1); + if (!stack) { return -1; } + + tsk->user_stack = (byteptr_t) stack; + + // 2. prepare cpu state for user mode + ptregs_ptr regs = task_pt_regs(tsk); + memory_zero((byteptr_t) regs, sizeof(pt_regs_t)); + + regs->sp = stack + THREAD_SIZE; + regs->pc = pc; + regs->pstate = PSR_MODE_EL0t; // + return 0; +} + + +void +task_add_signal(task_ptr tsk, int32_t number, byteptr_t handler) +{ + // TODO: build a signal handler table + if (number == 9) tsk->sig9_handler = (signal_handler) handler; +} + +static void sigcall_return() +{ + asm volatile("mov x8, 10"); + asm volatile("svc 0"); +} + + +void +task_to_signal_handler(task_ptr tsk, int32_t number) +{ + if (number == 9 && tsk->sig9_handler) { + ptregs_ptr tsk_regs = task_pt_regs(tsk); + tsk->signal_stack = (byteptr_t) frame_alloc(1); + tsk->ptregs_backup = (ptregs_ptr) kmalloc(sizeof(pt_regs_t)); + memory_copy((byteptr_t) tsk->ptregs_backup, (byteptr_t) tsk_regs, sizeof(pt_regs_t)); + + tsk_regs->regs[30] = (uint64_t) &sigcall_return; + tsk_regs->sp = (uint64_t) tsk->signal_stack + THREAD_SIZE; + tsk_regs->pc = (uint64_t) tsk->sig9_handler; + } +} + + +void +task_ret_from_signal_handler(task_ptr tsk) +{ + ptregs_ptr tsk_regs = task_pt_regs(tsk); + memory_copy((byteptr_t) tsk_regs, (byteptr_t) tsk->ptregs_backup, sizeof(pt_regs_t)); + + frame_release((byteptr_t) tsk->signal_stack); + kfree((byteptr_t) tsk->ptregs_backup); + + tsk->signal_stack = 0; + tsk->ptregs_backup = 0; +} \ No newline at end of file diff --git a/Lab 5/kernel/src/task.h b/Lab 5/kernel/src/task.h new file mode 100644 index 000000000..e3b475765 --- /dev/null +++ b/Lab 5/kernel/src/task.h @@ -0,0 +1,96 @@ +#ifndef __TASK_H__ +#define __TASK_H__ + +#include "type.h" +#include "list.h" + + +typedef struct pt_regs { + uint64_t regs[31]; + uint64_t sp; + uint64_t pc; + uint64_t pstate; +} pt_regs_t; +typedef pt_regs_t * ptregs_ptr; + + +typedef void (*signal_handler)(int); + +typedef struct signal { + list_head_t list; + signal_handler handler; + uint32_t sig_num; +} signal_t; +typedef signal_t * signal_ptr; + + + +#define TASK_SIZE 0x1000 + +typedef struct cpu_context { + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + unsigned long fp; // x30 + unsigned long sp; // x31 + unsigned long lr; +} cpu_context_t; + + +typedef enum { + TASK_RUNNING, + TASK_WAITING, + TASK_STOPPED +} state_t; + + +typedef struct task { + list_head_t list; + cpu_context_t cpu_context; + int32_t pid; + uint32_t exitcode; + state_t state; + + byteptr_t user_stack; + byteptr_t user_prog; + uint32_t user_prog_size; + uint32_t frame_count; + uint32_t foreground; + + int32_t priority; + int32_t preempt_count; + int32_t counter; + + signal_handler sig9_handler; + ptregs_ptr ptregs_backup; + byteptr_t signal_stack; + +} task_t; + +typedef task_t * task_ptr; + + + + +extern int32_t task_count; + + +task_ptr task_create(uint64_t fn, uint64_t arg); +void task_init(task_ptr tsk); +void task_kill(task_ptr tsk, int32_t status); +void task_reset(task_ptr tsk, uint64_t fn, uint64_t arg); +task_ptr task_fork(task_ptr tsk); +int32_t task_to_user_mode(task_ptr tsk, uint64_t pc); +void task_add_signal(task_ptr tsk, int32_t number, byteptr_t handler); + +void task_to_signal_handler(task_ptr tsk, int32_t number); +void task_ret_from_signal_handler(task_ptr tsk); + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/thread.c b/Lab 5/kernel/src/thread.c new file mode 100644 index 000000000..bca97d563 --- /dev/null +++ b/Lab 5/kernel/src/thread.c @@ -0,0 +1,146 @@ +#include "thread.h" +#include "asm.h" +#include "frame.h" +#include "sched.h" +#include "uart.h" +#include "delay.h" +#include "memory.h" +#include "exception.h" + + +void +thread_exit(int32_t status) +{ + scheduler_kill(current_task(), status); +} + + +int32_t +thread_create_shell(uint64_t fn) +{ + task_ptr p = task_create(fn, 0); + if (!p) return -1; + uart_printf("[DEBUG] thread_create pid: %d (0x%x)\n", p->pid, p); + scheduler_add_shell(p); + return 0; +} + + +task_ptr +thread_create(uint64_t fn, uint64_t arg) +{ + task_ptr p = task_create(fn, arg); + if (!p) return 0; + uart_printf("[DEBUG] thread_create pid: %d (0x%x)\n", p->pid, p); + scheduler_add(p); + return p; +} + + +int32_t +thread_create_user(uint64_t fn, uint64_t program, uint32_t size) +{ + uart_printf("[DEBUG] thread_create_user - "); + + task_ptr p; + if (size) { + // code duplicate + uint32_t count = (uint32_t) memory_padding((byteptr_t) (size | 0l), FRAME_SIZE_ORDER) >> FRAME_SIZE_ORDER; + byteptr_t user_prog = frame_alloc(count); + uart_printf("frame_count: %d, user_prog: 0x%x", count, user_prog); + if (!user_prog) { return -1; } + memory_copy(user_prog, (byteptr_t) program, size); + uart_printf("(from program: 0x%x), size: %d, ", program, size); + + // build a new task + p = task_create(fn, (uint64_t) user_prog); // fn = run_user_process + p->user_prog = user_prog; + p->user_prog_size = size; + p->frame_count = count; + p->foreground = 1; + } + else { + // build a new task + p = task_create(fn, (uint64_t) program); + p->user_prog = 0; + p->user_prog_size = 0; + p->frame_count = 0; + p->foreground = 1; + } + + uart_printf("pid: %d (%x)\n", p->pid, p); + scheduler_add(p); + return p->pid; +} + + +int32_t +thread_replace_user(uint64_t fn, uint64_t program, uint32_t size) +{ + task_ptr p = current_task(); + uint32_t foreground = p->foreground; + + uart_printf("[DEBUG] thread_replace_user - "); + + if (size) { + // code duplicate + uint32_t count = (uint32_t) memory_padding((byteptr_t) (size | 0l), FRAME_SIZE_ORDER) >> FRAME_SIZE_ORDER; + byteptr_t user_prog = frame_alloc(count); + uart_printf("frame_count: %d, user_prog: 0x%x", count, user_prog); + if (!user_prog) { return -1; } + memory_copy(user_prog, (byteptr_t) program, size); + uart_printf("(from program: 0x%x), size: %d, ", program, size); + + // reset the current task + // task_reset(p, fn, (uint64_t) user_prog); // x19 = fn (e.g, run_user_process, it will call to_user(x20)) + p->user_prog = user_prog; + p->user_prog_size = size; + p->frame_count = count; + p->foreground = foreground; + } + + else { + p->user_prog = 0; + p->user_prog_size = 0; + p->frame_count = 0; + p->foreground = foreground; + } + + uart_printf("pid: %d (%x)\n", p->pid, p); + return p->pid; +} + + +int32_t +thread_fork() +{ + task_ptr child = (task_ptr) task_fork(current_task()); + scheduler_add(child); + + return child->pid; +} + + +#include "asm.h" + + +static void +foo() +{ + for (int i = 0; i < 5; ++i) { + uart_printf("> thread id: %d i=%d\n", current_task()->pid, i); + uint64_t freq = asm_read_sysregister(cntfrq_el0); + delay_cycles(freq >> 5); + } + thread_exit(0); +} + + +void +thread_demo() +{ + for (int i = 0; i < 4; ++i) { + uart_printf("Thread_test i: %d, ", i); + thread_create((uint64_t) &foo, 0); + } +} diff --git a/Lab 5/kernel/src/thread.h b/Lab 5/kernel/src/thread.h new file mode 100644 index 000000000..e136ad757 --- /dev/null +++ b/Lab 5/kernel/src/thread.h @@ -0,0 +1,19 @@ +#ifndef __THREAD_H__ +#define __THREAD_H__ + +#include "list.h" +#include "type.h" +#include "task.h" + + +void thread_exit(int32_t status); +task_ptr thread_create(uint64_t fn, uint64_t arg); +int32_t thread_create_user(uint64_t fn, uint64_t program, uint32_t size); +int32_t thread_replace_user(uint64_t fn, uint64_t program, uint32_t size); +int32_t thread_create_shell(uint64_t fn); +int32_t thread_fork(); + +void thread_demo(); + + +#endif \ No newline at end of file diff --git a/Lab 5/kernel/src/uart.h b/Lab 5/kernel/src/uart.h new file mode 100644 index 000000000..f17ab2d02 --- /dev/null +++ b/Lab 5/kernel/src/uart.h @@ -0,0 +1,19 @@ +#ifndef __UART_H__ +#define __UART_H__ + +#include "mini_uart.h" + +#define uart_init mini_uart_init +#define uart_getc mini_uart_getc +#define uart_get mini_uart_getb +#define uart_put mini_uart_putc +#define uart_str mini_uart_puts +#define uart_line mini_uart_putln +#define uart_endl mini_uart_endl + +#define uart_hex mini_uart_hex +#define uart_hexl mini_uart_hexl + +#define uart_printf mini_uart_printf + +#endif \ No newline at end of file diff --git a/Lab 5/sd/bcm2710-rpi-3-b-plus.dtb b/Lab 5/sd/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 0000000000000000000000000000000000000000..c83b0817e2eb5295a3dfe6aafe3aa55d93e9785d GIT binary patch literal 34228 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 ").lower() + "\n") + if 'exit' in key_in: + ser.close() + print('\nbye!') + sys.exit() + ser.write(key_in.encode()) + sleep(0.1) + + except KeyboardInterrupt: + ser.close() + print('\nbye!') + + +def main(): + port = sys.argv[1] if len(sys.argv) > 1 else "/dev/tty.usbserial-0001" + try: + ser = serial.Serial(port, 115200, timeout=50) + serial_shell(ser) + except serial.serialutil.SerialException as e: + print(e); + + + +if __name__ == "__main__": + main() diff --git a/Lab 5/user/Makefile b/Lab 5/user/Makefile new file mode 100644 index 000000000..cae3e0285 --- /dev/null +++ b/Lab 5/user/Makefile @@ -0,0 +1,22 @@ +SUBDIR = user1 + +BUILDSUBDIR = $(SUBDIR:%=build-%) +CLEANSUBDIR = $(SUBDIR:%=clean-%) + +all: $(BUILDSUBDIR) + +$(BUILDSUBDIR): + @echo "===>" $@ + $(MAKE) -C $(@:build-%=%) + @echo "<===" $@ + +$(CLEANSUBDIR): + @echo "===>" $@ + $(MAKE) -C $(@:clean-%=%) clean + @echo "<===" $@ + +clean: $(CLEANSUBDIR) + +# $(call make_subdir, clean) + +.PHONY: all clean $(SUBDIR) $(BUILDSUBDIR) $(CLEANSUBDIR) \ No newline at end of file diff --git a/Lab 5/user/user1/Makefile b/Lab 5/user/user1/Makefile new file mode 100644 index 000000000..c6cb04b05 --- /dev/null +++ b/Lab 5/user/user1/Makefile @@ -0,0 +1,40 @@ +TARGET = user1 + +ARMGNU ?= aarch64-linux-gnu + +CFLAGS = -MMD -Wall -nostdlib -nostartfiles -ffreestanding -mgeneral-regs-only -Iinclude -Wno-pointer-to-int-cast +ASMOPS = -MMD + +OUT_DIR = out +BUILD_DIR = build +SRC_DIR = src + +all: clean $(TARGET).img + +debug: CCFLAGS += -DDEBUG -g +debug: $(TARGET).img + +clean: + rm -rf $(BUILD_DIR) $(OUT_DIR) *.img + +remake: clean all + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + mkdir -p $(@D) + $(ARMGNU)-gcc $(ASMOPS) -c $< -o $@ + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + $(ARMGNU)-gcc $(CFLAGS) -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES += $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES = $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +$(TARGET).img: $(SRC_DIR)/linker.ld $(OBJ_FILES) + mkdir -p $(OUT_DIR) + $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -o $(BUILD_DIR)/$(TARGET).elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/$(TARGET).elf -O binary $(OUT_DIR)/$(TARGET).img \ No newline at end of file diff --git a/Lab 5/user/user1/src/linker.ld b/Lab 5/user/user1/src/linker.ld new file mode 100644 index 000000000..9dba0a4fd --- /dev/null +++ b/Lab 5/user/user1/src/linker.ld @@ -0,0 +1,14 @@ +SECTIONS +{ + . = 0x200000; + + .text : { *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + + . = ALIGN(0x8); + + _bss_begin = .; + .bss : { *(.bss*) } + _bss_end = .; +} \ No newline at end of file diff --git a/Lab 5/user/user1/src/main.S b/Lab 5/user/user1/src/main.S new file mode 100644 index 000000000..ee1416eb9 --- /dev/null +++ b/Lab 5/user/user1/src/main.S @@ -0,0 +1,11 @@ + .section ".text" + .global _start +_start: + mov x0, 0 +1: + add x0, x0, 1 + svc 0 // system call (el0 -> el1) + cmp x0, 5 // Run `svc 0` 5 times + blt 1b +1: + b 1b \ No newline at end of file From 7b0085ef5cd89d9fa4dc9f71fc088aa17a2a52de Mon Sep 17 00:00:00 2001 From: kent lee Date: Thu, 27 Jun 2024 05:07:44 +0800 Subject: [PATCH 2/3] fixed scheduler initialization bugs --- Lab 5/kernel/src/sched.c | 4 ++-- Lab 5/kernel/src/sys.S | 38 -------------------------------------- Lab 5/kernel/src/task.c | 1 + 3 files changed, 3 insertions(+), 40 deletions(-) diff --git a/Lab 5/kernel/src/sched.c b/Lab 5/kernel/src/sched.c index c0d93c6ed..c7bd055ec 100644 --- a/Lab 5/kernel/src/sched.c +++ b/Lab 5/kernel/src/sched.c @@ -247,12 +247,12 @@ scheduler_add(task_ptr tsk) void scheduler_init() { + shell_task = 0; task_count = 0; task_init(&init_task); - scheduler_add(&init_task); + list_add_tail((list_head_ptr_t) &init_task, &running_queue); current = &(init_task); - shell_task = 0; uart_printf("[DEBUG] sched_init - init_stask: 0x%x, pid=%d\n", &init_task, init_task.pid); core_timer_add_tick(scheduler_tick, "", 5); diff --git a/Lab 5/kernel/src/sys.S b/Lab 5/kernel/src/sys.S index 314e8202b..a22da0aa1 100644 --- a/Lab 5/kernel/src/sys.S +++ b/Lab 5/kernel/src/sys.S @@ -1,44 +1,6 @@ #include "syscall.h" -// .globl call_sys_write -// call_sys_write: -// mov w8, #SYS_WRITE_NUMBER -// svc #0 -// ret - - -// .globl call_sys_malloc -// call_sys_malloc: -// mov w8, #SYS_MALLOC_NUMBER -// svc #0 -// ret - - -// .globl call_sys_exit -// call_sys_exit: -// mov w8, #SYS_EXIT_NUMBER -// svc #0 -// ret - - -// .globl call_sys_clone -// call_sys_clone: -// /* Save args for the child. */ -// mov x10, x0 /*fn*/ -// mov x11, x1 /*arg*/ -// mov x12, x2 /*stack*/ - -// /* Do the system call. */ -// mov x0, x2 /* stack */ -// mov x8, #SYS_CLONE_NUMBER -// svc 0x0 - -// cmp x0, #0 -// beq thread_start -// ret - - // thread_start: // mov x29, 0 diff --git a/Lab 5/kernel/src/task.c b/Lab 5/kernel/src/task.c index 6d32a3eef..959668a8b 100644 --- a/Lab 5/kernel/src/task.c +++ b/Lab 5/kernel/src/task.c @@ -36,6 +36,7 @@ task_pt_regs(task_ptr tsk) void task_init(task_ptr tsk) { + uart_printf("[DEBUG] task_init\n"); memory_zero((byteptr_t) tsk, sizeof(task_t)); memory_zero((byteptr_t) &tsk->cpu_context, sizeof(cpu_context_t)); ptregs_ptr childregs = task_pt_regs(tsk); From 9d1aa485cb2c91aadacb75e84b9ab21947bdf894 Mon Sep 17 00:00:00 2001 From: kent lee Date: Thu, 27 Jun 2024 20:20:54 +0800 Subject: [PATCH 3/3] updated --- Lab 7/Makefile | 30 ++ Lab 7/docs/TODO.md | 43 +++ Lab 7/docs/frame.c | 451 +++++++++++++++++++++++++ Lab 7/kernel/Makefile | 57 ++++ Lab 7/kernel/include/arm/sysregs.h | 63 ++++ Lab 7/kernel/include/asm.h | 17 + Lab 7/kernel/include/aux.h | 41 +++ Lab 7/kernel/include/cpio.h | 52 +++ Lab 7/kernel/include/gpio.h | 44 +++ Lab 7/kernel/include/irq.h | 16 + Lab 7/kernel/include/kernel.h | 11 + Lab 7/kernel/include/list.h | 146 ++++++++ Lab 7/kernel/include/mmio.h | 9 + Lab 7/kernel/include/sprintf.h | 120 +++++++ Lab 7/kernel/include/stat.h | 40 +++ Lab 7/kernel/include/type.h | 33 ++ Lab 7/kernel/src/chunk.c | 209 ++++++++++++ Lab 7/kernel/src/chunk.h | 22 ++ Lab 7/kernel/src/core_timer.c | 192 +++++++++++ Lab 7/kernel/src/core_timer.h | 20 ++ Lab 7/kernel/src/delay.c | 27 ++ Lab 7/kernel/src/delay.h | 9 + Lab 7/kernel/src/dtb.c | 218 ++++++++++++ Lab 7/kernel/src/dtb.h | 28 ++ Lab 7/kernel/src/entry.S | 218 ++++++++++++ Lab 7/kernel/src/entry.h | 11 + Lab 7/kernel/src/exception.S | 19 ++ Lab 7/kernel/src/exception.c | 206 ++++++++++++ Lab 7/kernel/src/exception.h | 10 + Lab 7/kernel/src/frame.c | 398 ++++++++++++++++++++++ Lab 7/kernel/src/frame.h | 22 ++ Lab 7/kernel/src/info.c | 187 +++++++++++ Lab 7/kernel/src/info.h | 10 + Lab 7/kernel/src/initramfs.c | 165 ++++++++++ Lab 7/kernel/src/initramfs.h | 9 + Lab 7/kernel/src/initrd.c | 190 +++++++++++ Lab 7/kernel/src/initrd.h | 24 ++ Lab 7/kernel/src/kernel_main.c | 86 +++++ Lab 7/kernel/src/kernel_start.S | 99 ++++++ Lab 7/kernel/src/linker.ld | 23 ++ Lab 7/kernel/src/mailbox.c | 52 +++ Lab 7/kernel/src/mailbox.h | 77 +++++ Lab 7/kernel/src/memory.S | 15 + Lab 7/kernel/src/memory.c | 154 +++++++++ Lab 7/kernel/src/memory.h | 28 ++ Lab 7/kernel/src/mini_uart.c | 294 +++++++++++++++++ Lab 7/kernel/src/mini_uart.h | 26 ++ Lab 7/kernel/src/power.c | 26 ++ Lab 7/kernel/src/power.h | 9 + Lab 7/kernel/src/sched.S | 32 ++ Lab 7/kernel/src/sched.c | 284 ++++++++++++++++ Lab 7/kernel/src/sched.h | 27 ++ Lab 7/kernel/src/shell.c | 207 ++++++++++++ Lab 7/kernel/src/shell.h | 6 + Lab 7/kernel/src/string.c | 168 ++++++++++ Lab 7/kernel/src/string.h | 20 ++ Lab 7/kernel/src/sys.S | 72 ++++ Lab 7/kernel/src/syscall.c | 165 ++++++++++ Lab 7/kernel/src/syscall.h | 98 ++++++ Lab 7/kernel/src/task.c | 190 +++++++++++ Lab 7/kernel/src/task.h | 99 ++++++ Lab 7/kernel/src/thread.c | 146 ++++++++ Lab 7/kernel/src/thread.h | 19 ++ Lab 7/kernel/src/tmpfs.c | 191 +++++++++++ Lab 7/kernel/src/tmpfs.h | 14 + Lab 7/kernel/src/uart.h | 19 ++ Lab 7/kernel/src/vfs.c | 512 +++++++++++++++++++++++++++++ Lab 7/kernel/src/vfs.h | 92 ++++++ Lab 7/sd/bcm2710-rpi-3-b-plus.dtb | Bin 0 -> 34228 bytes Lab 7/sd/config.txt | 3 + Lab 7/sd/rootfs/3.txt | 25 ++ Lab 7/sd/rootfs/f1.txt | 19 ++ Lab 7/sd/rootfs/file2 | 21 ++ Lab 7/uploader/uploader.py | 59 ++++ Lab 7/user/Makefile | 22 ++ Lab 7/user/user1/Makefile | 40 +++ Lab 7/user/user1/src/linker.ld | 14 + Lab 7/user/user1/src/main.S | 11 + 78 files changed, 6831 insertions(+) create mode 100644 Lab 7/Makefile create mode 100644 Lab 7/docs/TODO.md create mode 100644 Lab 7/docs/frame.c create mode 100644 Lab 7/kernel/Makefile create mode 100644 Lab 7/kernel/include/arm/sysregs.h create mode 100644 Lab 7/kernel/include/asm.h create mode 100644 Lab 7/kernel/include/aux.h create mode 100644 Lab 7/kernel/include/cpio.h create mode 100644 Lab 7/kernel/include/gpio.h create mode 100644 Lab 7/kernel/include/irq.h create mode 100644 Lab 7/kernel/include/kernel.h create mode 100644 Lab 7/kernel/include/list.h create mode 100644 Lab 7/kernel/include/mmio.h create mode 100644 Lab 7/kernel/include/sprintf.h create mode 100644 Lab 7/kernel/include/stat.h create mode 100644 Lab 7/kernel/include/type.h create mode 100644 Lab 7/kernel/src/chunk.c create mode 100644 Lab 7/kernel/src/chunk.h create mode 100644 Lab 7/kernel/src/core_timer.c create mode 100644 Lab 7/kernel/src/core_timer.h create mode 100644 Lab 7/kernel/src/delay.c create mode 100644 Lab 7/kernel/src/delay.h create mode 100644 Lab 7/kernel/src/dtb.c create mode 100644 Lab 7/kernel/src/dtb.h create mode 100644 Lab 7/kernel/src/entry.S create mode 100644 Lab 7/kernel/src/entry.h create mode 100644 Lab 7/kernel/src/exception.S create mode 100644 Lab 7/kernel/src/exception.c create mode 100644 Lab 7/kernel/src/exception.h create mode 100644 Lab 7/kernel/src/frame.c create mode 100644 Lab 7/kernel/src/frame.h create mode 100644 Lab 7/kernel/src/info.c create mode 100644 Lab 7/kernel/src/info.h create mode 100644 Lab 7/kernel/src/initramfs.c create mode 100644 Lab 7/kernel/src/initramfs.h create mode 100644 Lab 7/kernel/src/initrd.c create mode 100644 Lab 7/kernel/src/initrd.h create mode 100644 Lab 7/kernel/src/kernel_main.c create mode 100644 Lab 7/kernel/src/kernel_start.S create mode 100644 Lab 7/kernel/src/linker.ld create mode 100644 Lab 7/kernel/src/mailbox.c create mode 100644 Lab 7/kernel/src/mailbox.h create mode 100644 Lab 7/kernel/src/memory.S create mode 100644 Lab 7/kernel/src/memory.c create mode 100644 Lab 7/kernel/src/memory.h create mode 100644 Lab 7/kernel/src/mini_uart.c create mode 100644 Lab 7/kernel/src/mini_uart.h create mode 100644 Lab 7/kernel/src/power.c create mode 100644 Lab 7/kernel/src/power.h create mode 100644 Lab 7/kernel/src/sched.S create mode 100644 Lab 7/kernel/src/sched.c create mode 100644 Lab 7/kernel/src/sched.h create mode 100644 Lab 7/kernel/src/shell.c create mode 100644 Lab 7/kernel/src/shell.h create mode 100644 Lab 7/kernel/src/string.c create mode 100644 Lab 7/kernel/src/string.h create mode 100644 Lab 7/kernel/src/sys.S create mode 100644 Lab 7/kernel/src/syscall.c create mode 100644 Lab 7/kernel/src/syscall.h create mode 100644 Lab 7/kernel/src/task.c create mode 100644 Lab 7/kernel/src/task.h create mode 100644 Lab 7/kernel/src/thread.c create mode 100644 Lab 7/kernel/src/thread.h create mode 100644 Lab 7/kernel/src/tmpfs.c create mode 100644 Lab 7/kernel/src/tmpfs.h create mode 100644 Lab 7/kernel/src/uart.h create mode 100644 Lab 7/kernel/src/vfs.c create mode 100644 Lab 7/kernel/src/vfs.h create mode 100644 Lab 7/sd/bcm2710-rpi-3-b-plus.dtb create mode 100644 Lab 7/sd/config.txt create mode 100644 Lab 7/sd/rootfs/3.txt create mode 100644 Lab 7/sd/rootfs/f1.txt create mode 100644 Lab 7/sd/rootfs/file2 create mode 100644 Lab 7/uploader/uploader.py create mode 100644 Lab 7/user/Makefile create mode 100644 Lab 7/user/user1/Makefile create mode 100644 Lab 7/user/user1/src/linker.ld create mode 100644 Lab 7/user/user1/src/main.S diff --git a/Lab 7/Makefile b/Lab 7/Makefile new file mode 100644 index 000000000..78269afed --- /dev/null +++ b/Lab 7/Makefile @@ -0,0 +1,30 @@ +SUBDIR = kernel # bootloader + +BUILDSUBDIR = $(SUBDIR:%=build-%) +CLEANSUBDIR = $(SUBDIR:%=clean-%) + +SD_DIR = sd +FS_DIR = rootfs + +all: $(SD_DIR)/initrd.cpio $(BUILDSUBDIR) + +$(SD_DIR)/initrd.cpio: + cd $(SD_DIR)/$(FS_DIR) && ls -a | cpio -o -H newc > ../../$@ && cd .. + +$(BUILDSUBDIR): + @echo "===>" $@ + $(MAKE) -C $(@:build-%=%) + @echo "<===" $@ + +$(CLEANSUBDIR): + @echo "===>" $@ + $(MAKE) -C $(@:clean-%=%) clean + @echo "<===" $@ + +clean: $(CLEANSUBDIR) + rm -f $(SD_DIR)/*.cpio + + +# $(call make_subdir, clean) + +.PHONY: all clean $(SUBDIR) $(BUILDSUBDIR) $(CLEANSUBDIR) $(SD_DIR)/initrd.cpio \ No newline at end of file diff --git a/Lab 7/docs/TODO.md b/Lab 7/docs/TODO.md new file mode 100644 index 000000000..e91a967bb --- /dev/null +++ b/Lab 7/docs/TODO.md @@ -0,0 +1,43 @@ +### Basic Exercise 1 - Buddy System - 40% + +**Todo** +``` +Implement the buddy system fro contiguous page frames allocation and your max order should be larger than 5. + +(You don't need to handle the case of out-of-memory.) +``` + + +**The Frame Array** +``` +For each entry in The Frame Array with idx and value val +(Suppose the framesize to be 4kb) + +val + >= 0 : allocatable + = : belongs to a larger block + = : already allocated + +Frame Freelists + linkedlists + +``` + + + + +### Basic Exercise 2 - - + + + + + + + + + + + + + + diff --git a/Lab 7/docs/frame.c b/Lab 7/docs/frame.c new file mode 100644 index 000000000..cbae49e03 --- /dev/null +++ b/Lab 7/docs/frame.c @@ -0,0 +1,451 @@ +#include "frame.h" +#include "type.h" +#include "list.h" +#include "uart.h" +#include "memory.h" + + +static void +bucket_init(byteptr_t bucket) +{ + list_head_ptr_t list = (list_head_ptr_t) bucket; + INIT_LIST_HEAD(list); +} + + +static list_head_ptr_t +list_pop(const list_head_ptr_t list) +{ + if (list->next == list) return 0; + list_head_ptr_t head = list->next; + list_del_entry(head); + return head; +} + + +static void +list_push(const list_head_ptr_t list, list_head_ptr_t entry) +{ + INIT_LIST_HEAD(entry); + list_add_tail(entry, list); +} + + + +#define FRAME_SIZE_ORDER 12 +#define MIN_ALLOC_ORDER FRAME_SIZE_ORDER + +#define INDEX_LOG2(index) ({31 - __builtin_clz(index);}) + +/* + * This is the starting address of the address range for this allocator. Every + * returned allocation will be an offset of this pointer from 0 to MAX_ALLOC. + */ +static byteptr_t base_ptr; + + +/** + * frame size = 4kb = 2^12b + * The maximum allocation size is currently set to 1mb = 2^20b + * thus the max order is 20-12=8 (256 pages) + */ +static uint32_t max_alloc_order; +static uint32_t max_alloc_size; +static uint32_t total_frames; + + +/** + * Frame Array Structure: Binary Heap + * example: + * - 16 frames = 2^4 frames + * - 5 freelists + * - 31 nodes, 15 internals + * - array size : 15 + 1 + * root index: 1 + * indices of leaves: 2^4 ~ 2^5-1 +*/ +// static uint8_t frame_array[(1 << (BUCKET_COUNT - 1))]; +static byteptr_t frame_array; + +#define FRAME_SPLIT (1 << 7) +#define FRAME_USED_L (1 << 6) +#define FRAME_USED_R (1 << 5) + + +/** + * Freelists +*/ +static uint32_t bucket_count; +static list_head_ptr_t buckets; + + + +static uint32_t +parent_is_split(uint32_t index) +{ + return frame_array[index >> 1] & FRAME_SPLIT; +} + + +static void +set_parent_split(uint32_t index) +{ + frame_array[index >> 1] |= FRAME_SPLIT; +} + + +static void +clr_parent_split(uint32_t index) +{ + frame_array[index >> 1] &= ~(FRAME_SPLIT); +} + + +static uint32_t +node_is_split(uint32_t index) +{ + return (INDEX_LOG2(index) > (bucket_count - 2)) ? 0 : frame_array[index] & FRAME_SPLIT; +} + + +static uint32_t +node_is_used(uint32_t index) +{ + return frame_array[index >> 1] & (FRAME_USED_L >> (index & 1)); +} + + +static void +set_node_used(uint32_t index) +{ + frame_array[index >> 1] |= (FRAME_USED_L >> (index & 1)); +} + + +static void +clr_node_used(uint32_t index) +{ + frame_array[index >> 1] &= ~(FRAME_USED_L >> (index & 1)); +} + + +/** + * 1. (index - (1 << index)) : the index of the corresponding level + * 2. (the index of the level) << (MAX_ALLOC_ORDER - bucket) : the index of the bottom level + */ +static byteptr_t +index_to_ptr(uint32_t index, uint32_t bucket) +{ + return base_ptr + ((index - (1 << bucket)) << (max_alloc_order - bucket)); +} + + +static uint32_t +ptr_to_index(byteptr_t ptr, uint32_t bucket) +{ + return ((ptr - base_ptr) >> (max_alloc_order - bucket)) + (1 << bucket); +} + + +static uint32_t +order_for_request(uint32_t request) +{ + uint32_t order = 0, size = 1 << MIN_ALLOC_ORDER; + while (size < request) { + ++order; + size = size << 1; + } + return order; +} + + +static uint32_t +bucket_for_request(uint32_t request) +{ + return bucket_count - order_for_request(request) - 1; +} + + +static inline uint32_t +search_free_bucket(uint32_t bucket) +{ + while (bucket >= 0) { + if (!list_empty(&buckets[bucket])) + return bucket; + bucket--; + } + return -1; +} + + +static inline uint32_t +search_available_node(uint32_t index) +{ + while (index > 0) { + if (node_is_used(index)) + return 0; + if (parent_is_split(index)) + return index; + index = index >> 1; + } + return index; +} + + +static void +split_up(uint32_t target, uint32_t index) +{ + while (target < index) { + set_parent_split(index); + uint32_t bucket = INDEX_LOG2(index); + byteptr_t buddy = index_to_ptr(index ^ 1, bucket); + + uart_printf("[DEBUG] split_up - bucket: %d, buddy: %d, addr: 0x%x\n", bucket, index ^ 1, buddy); + + list_push(&buckets[bucket], (list_head_ptr_t) buddy); + index = (index >> 1); + } +} + + +byteptr_t +add_init_free_block(byteptr_t ptr, uint32_t n_frames) +{ + uint32_t order = INT32_LEFTMOST_ORDER(n_frames); + list_add((list_head_ptr_t) ptr, &buckets[(bucket_count - 1 - order)]); + return (uint32_t) ptr + n_frames; +} + + +byteptr_t +init_frame_array(byteptr_t ptr, uint32_t n_frames) +{ + *ptr = *ptr | FRAME_SPLIT; + return ptr + n_frames; +} + + +void +frame_system_init(byteptr_t base, byteptr_t limit) +{ + base_ptr = base; + max_alloc_order = INDEX_LOG2((uint32_t) (limit - base)); + bucket_count = (max_alloc_order - FRAME_SIZE_ORDER + 1); + buckets = smalloc(bucket_count * sizeof(list_head_t)); + uart_printf("[DEBUG] frame_system_init - max_alloc_order: %d, bucket count: %d\n", max_alloc_order, bucket_count); + uart_printf("[DEBUG] frame_system_init - buckets addr: 0x%x, size: %d*%d bytes\n", buckets, bucket_count, sizeof(list_head_t)); + + max_alloc_size = (uint32_t) memory_align(limit, FRAME_SIZE_ORDER) + - (uint32_t) memory_align(base, FRAME_SIZE_ORDER); + uart_printf("[DEBUG] frame_system_init - max_alloc_size: 0x%x\n", max_alloc_size); + + total_frames = max_alloc_size >> FRAME_SIZE_ORDER; + frame_array = smalloc(total_frames * sizeof(byte_t)); + for (int i = 0; i < total_frames; ++i) frame_array[i] = 0; + uart_printf("[DEBUG] frame_system_init - frame_array addr: 0x%x, size: %d*%d bytes\n", frame_array, (1 << (bucket_count - 1)), sizeof(byte_t)); + + for (int i = 0; i < bucket_count; ++i) + bucket_init((byteptr_t) &buckets[i]); + + memseg_process(add_init_free_block, buckets, total_frames); + memseg_process(init_frame_array, frame_array, total_frames); + + // byteptr_t ptr = base_ptr; + // uint32_t frames = total_frames; // 3C000 + + // while (frames != 0) { + // /** + // * if total pages is 0x3C000 + // * 0x20000(17), 0x10000(16), 0x8000(15), 0x4000(14) + // */ + + // uint32_t order = INT32_LEFTMOST_ORDER(frames); + // list_add((list_head_ptr_t) ptr, &buckets[(bucket_count - 1 - order)]); + // ptr = (uint32_t) ptr + (1 << order); + // frames = frames & ~(1 << order); + // } + + // frame_array[0] |= FRAME_SPLIT; +} + + +byteptr_t +frame_alloc(uint32_t request) +{ + /** + * calculate the ideal order level + */ + uint32_t target_bucket = bucket_for_request(request); + + /** + * find the available order level if there's a free block smallest larger than request + */ + uint32_t bucket = search_free_bucket(target_bucket); + if (bucket < 0) return 0; + + /** + * pop the free block + */ + byteptr_t ptr = (byteptr_t) list_pop(&buckets[bucket]); + uint32_t target_index = ptr_to_index(ptr, target_bucket); + + /** + * get the free index of the block + */ + uint32_t index = ptr_to_index(ptr, bucket); + + /** + * iteratively split the block into the ideal order level, and update the index + */ + set_node_used(target_index); + split_up(index, target_index); + + return ptr; +} + + +byteptr_t +frame_request(uint32_t count) +{ + uint32_t request = count << FRAME_SIZE_ORDER; + if (request > max_alloc_size) { return 0; } + return frame_alloc(request); +} + + +byteptr_t +frame_alloc_addr(uint32_t addr, uint32_t count) +{ + byteptr_t ptr = memory_align(addr, FRAME_SIZE_ORDER); + + uart_printf("[DEBUG] frame_alloc_addr - addr: %x\n", addr); + + /** + * calculate the ideal order level and index of the block + */ + uint32_t target_bucket = bucket_for_request(count << FRAME_SIZE_ORDER); + uint32_t target_index = ptr_to_index(ptr, target_bucket); + + uart_printf("[DEBUG] frame_alloc_addr - target index: %d, bucket: %d\n", target_index, target_bucket); + + /** + * find available free block + */ + uint32_t index = search_available_node(target_index); + if (index == 0 || node_is_used(index)) { return 0; } + uint32_t bucket = INDEX_LOG2(index); + + /** + * pop the free block + */ + ptr = index_to_ptr(index, bucket); + list_del_entry((list_head_ptr_t) ptr); + + /** + * split buddies + */ + set_node_used(target_index); + + uart_printf("[DEBUG] frame_alloc_addr - index: %d, target: %d, addr: 0x%x\n", index, target_index, addr); + split_up(index, target_index); + + return ptr; +} + + +#define identify_ptr(ptr, index, bucket) \ + bucket = bucket_count - 1; index = ptr_to_index(ptr, bucket);\ + while (bucket > 0 && !parent_is_split(index)) {index = index >> 1; --bucket;} + + +void +frame_release(byteptr_t ptr) +{ + if (!ptr) return; + + /** + * identify the index and order level + */ + uint32_t index, bucket; + identify_ptr(ptr, index, bucket); + clr_node_used(index); + + /** + * merge the buddy by bottom-up if it's unused + */ + uint32_t buddy = index ^ 1; + while (bucket > 0 && !node_is_used(buddy) && !node_is_split(buddy)) { + byteptr_t buddy_ptr = index_to_ptr(buddy, bucket); + list_del_entry((list_head_ptr_t) buddy_ptr); + clr_parent_split(index); + index = index >> 1; --bucket; buddy = index ^ 1; + } + + list_add((list_head_ptr_t) ptr, &buckets[bucket]); +} + + +uint32_t next_child(byteptr_t ptr, uint32_t index) +{ + while(!parent_is_split(index)) { + index = index >> 1; + } +} + +static byteptr_t +print_buddy_info(byteptr_t ptr, uint32_t n_frames) +{ + byteptr_t mem_base = (uint32_t) base_ptr + (((uint32_t)ptr - (uint32_t)frame_array) << FRAME_SIZE_ORDER); + + uint32_t i = n_frames; + while (i > 0) { + + } + +} + + +void +frame_print_info() +{ + #define block_type(index) ({(node_is_used(index)) ? "allocated" : "free"; }) + + uart_printf("\n==== FRAME SYSTEM INFO ====\n"); + uart_printf("base: 0x%8x\n", base_ptr); + uart_printf("limit: 0x%8x\n", base_ptr + max_alloc_size); + uart_printf("freelist: %d buckets\n", bucket_count); + + uart_printf("\n==== MEMORY FRAME LAYOUT ====\n"); + + // byteptr_t ptr = base_ptr; + // uint32_t index, bucket; + // while (ptr < base_ptr + max_alloc_size) { + // identify_ptr(ptr, index, bucket); + // uint32_t order = (bucket_count-1)-bucket; + // uart_printf("0x%8x |%6dkb | %s\n", ptr, (1 << order + 2), block_type(index)); + // ptr = index_to_ptr(index+1, bucket); + // } + + // uint32_t count = total_frames; + // byteptr_t ptr = frame_array; + // while (count != 0) { + // uint32_t order = INT32_LEFTMOST_ORDER(count); + + + + // ptr = (uint32_t) ptr + (1 << order); + // count = count & ~(1 << order); + // } + + + uart_printf("\n==== FREE FRAME LISTS ====\n"); + for (int i = 0; i < bucket_count; ++i) { + if (!list_empty(&buckets[i])) { + uart_printf("bucket: %d, size: %dkb\n", i, 1 << (bucket_count-1 - i + 2)); + list_head_ptr_t pos; + list_for_each(pos, (list_head_ptr_t) &buckets[i]) + uart_printf(" +- 0x%8x\n", pos); + } + } + uart_printf("\n====================\n\n"); +} diff --git a/Lab 7/kernel/Makefile b/Lab 7/kernel/Makefile new file mode 100644 index 000000000..bfdb389d4 --- /dev/null +++ b/Lab 7/kernel/Makefile @@ -0,0 +1,57 @@ +TARGET = kernel8 + +ARMGNU ?= aarch64-linux-gnu + +CFLAGS = -MMD -Wall -nostdlib -nostartfiles -ffreestanding -mgeneral-regs-only -Iinclude -Wno-pointer-to-int-cast -g +ASMOPS = -MMD -Iinclude + +OUT_DIR = out +BUILD_DIR = build +SRC_DIR = src + +# all: clean $(TARGET).img +all: clean ramdisk $(TARGET).img + +debug: CCFLAGS += -DDEBUG -g +# debug: clean $(TARGET).img +debug: clean ramdisk $(TARGET).img + + +clean: + rm -rf $(BUILD_DIR) $(OUT_DIR) *.img + +remake: clean all + + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + $(ARMGNU)-gcc $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +SD_DIR = ../sd + +ramdisk: + mkdir -p $(BUILD_DIR) +# $(ARMGNU)-ld -r -b binary -o $(BUILD_DIR)/rd.o $(SD_DIR)/initramfs.cpio + +# OBJ_FILES += $(BUILD_DIR)/rd.o + +$(TARGET).img: $(SRC_DIR)/linker.ld $(OBJ_FILES) + mkdir -p $(OUT_DIR) + $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -o $(BUILD_DIR)/$(TARGET).elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/$(TARGET).elf -O binary $(OUT_DIR)/$(TARGET).img + +run: $(OUT_DIR)/$(TARGET).img + qemu-system-aarch64 -M raspi3b -kernel $(OUT_DIR)/$(TARGET).img -serial null -serial stdio -initrd $(SD_DIR)/initramfs.cpio -dtb $(SD_DIR)/bcm2710-rpi-3-b-plus.dtb + +gdb: $(OUT_DIR)/$(TARGET).img + qemu-system-aarch64 -M raspi3b -kernel $(OUT_DIR)/$(TARGET).img -serial null -serial stdio -initrd $(SD_DIR)/initramfs.cpio -dtb $(SD_DIR)/bcm2710-rpi-3-b-plus.dtb -S -s \ No newline at end of file diff --git a/Lab 7/kernel/include/arm/sysregs.h b/Lab 7/kernel/include/arm/sysregs.h new file mode 100644 index 000000000..f33e024bb --- /dev/null +++ b/Lab 7/kernel/include/arm/sysregs.h @@ -0,0 +1,63 @@ +#ifndef _SYSREGS_H +#define _SYSREGS_H + +// *************************************** +// SCTLR_EL1, System Control Register (EL1), Page 2654 of AArch64-Reference-Manual. +// *************************************** + +#define SCTLR_RESERVED (3 << 28) | (3 << 22) | (1 << 20) | (1 << 11) +#define SCTLR_EE_LITTLE_ENDIAN (0 << 25) +#define SCTLR_EOE_LITTLE_ENDIAN (0 << 24) +#define SCTLR_I_CACHE_DISABLED (0 << 12) +#define SCTLR_D_CACHE_DISABLED (0 << 2) +#define SCTLR_MMU_DISABLED (0 << 0) +#define SCTLR_MMU_ENABLED (1 << 0) + +#define SCTLR_VALUE_MMU_DISABLED (SCTLR_RESERVED | SCTLR_EE_LITTLE_ENDIAN | SCTLR_I_CACHE_DISABLED | SCTLR_D_CACHE_DISABLED | SCTLR_MMU_DISABLED) + +// *************************************** +// HCR_EL2, Hypervisor Configuration Register (EL2), Page 2487 of AArch64-Reference-Manual. +// *************************************** + +#define HCR_RW (1 << 31) +#define HCR_VALUE HCR_RW + +// *************************************** +// SCR_EL3, Secure Configuration Register (EL3), Page 2648 of AArch64-Reference-Manual. +// *************************************** + +#define SCR_RESERVED (3 << 4) +#define SCR_RW (1 << 10) +#define SCR_NS (1 << 0) +#define SCR_VALUE (SCR_RESERVED | SCR_RW | SCR_NS) + +// *************************************** +// SPSR_EL3, Saved Program Status Register (EL3) Page 389 of AArch64-Reference-Manual. +// *************************************** + +#define SPSR_MASK_ALL (7 << 6) +#define SPSR_EL1h (5 << 0) +#define SPSR_VALUE (SPSR_MASK_ALL | SPSR_EL1h) + +// *************************************** +// ESR_EL1, Exception Syndrome Register (EL1). Page 2431 of AArch64-Reference-Manual. +// *************************************** + +#define ESR_ELx_EC_SHIFT 26 +#define ESR_ELx_EC_SVC64 0x15 + + +// *************************************** +// PSR bits +// *************************************** + +#define PSR_MODE_EL0t 0x00000000 +#define PSR_MODE_EL1t 0x00000004 +#define PSR_MODE_EL1h 0x00000005 +#define PSR_MODE_EL2t 0x00000008 +#define PSR_MODE_EL2h 0x00000009 +#define PSR_MODE_EL3t 0x0000000c +#define PSR_MODE_EL3h 0x0000000d + + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/include/asm.h b/Lab 7/kernel/include/asm.h new file mode 100644 index 000000000..bae411a68 --- /dev/null +++ b/Lab 7/kernel/include/asm.h @@ -0,0 +1,17 @@ +#ifndef __ASM_H__ +#define __ASM_H__ + + +#define asm_read_sysregister(r) ({ \ + uint64_t __val; \ + asm volatile("mrs %0, " #r : "=r" (__val)); \ + __val; \ +}) + +#define asm_write_sysregister(r, __val) ({ \ + asm volatile("msr " #r ", %0" :: "r" (__val)); \ +}) + + + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/include/aux.h b/Lab 7/kernel/include/aux.h new file mode 100644 index 000000000..98216c7c9 --- /dev/null +++ b/Lab 7/kernel/include/aux.h @@ -0,0 +1,41 @@ +#ifndef __AUX_H__ +#define __AUX_H__ + +#include "mmio.h" + +#define AUX_BASE (MMIO_BASE + 0x215000) + +/* Auxilary mini UART registers */ +#define AUX_IRQ ((volatile unsigned int*)(AUX_BASE + 0x00)) +#define AUX_ENABLES ((volatile unsigned int*)(AUX_BASE + 0x04)) // Auxiliary enables | 3 +#define AUX_MU_IO ((volatile unsigned int*)(AUX_BASE + 0x40)) // I/O Data | 8 +#define AUX_MU_IER ((volatile unsigned int*)(AUX_BASE + 0x44)) // Interrupt Enable Register | 8 +#define AUX_MU_IIR ((volatile unsigned int*)(AUX_BASE + 0x48)) // Interrupt Identify Register | 8 +#define AUX_MU_LCR ((volatile unsigned int*)(AUX_BASE + 0x4C)) // Line Control Register | 8 +#define AUX_MU_MCR ((volatile unsigned int*)(AUX_BASE + 0x50)) // Modem Control Register | 8 +#define AUX_MU_LSR ((volatile unsigned int*)(AUX_BASE + 0x54)) // Line Status Register | 8 +#define AUX_MU_MSR ((volatile unsigned int*)(AUX_BASE + 0x58)) // Modem Status Register | 8 +#define AUX_MU_SCRATCH ((volatile unsigned int*)(AUX_BASE + 0x5C)) // Scratch | 8 +#define AUX_MU_CNTL ((volatile unsigned int*)(AUX_BASE + 0x60)) // Extra Control | 8 +#define AUX_MU_STAT ((volatile unsigned int*)(AUX_BASE + 0x64)) // Extra Status | 32 +#define AUX_MU_BAUD ((volatile unsigned int*)(AUX_BASE + 0x68)) // Baudrate | 16 + +#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_set_rx_interrupts() { *AUX_MU_IER |= 0x1; } +#define aux_clr_rx_interrupts() { *AUX_MU_IER &= ~(0x1); } +#define aux_set_tx_interrupts() { *AUX_MU_IER |= 0x2; } +#define aux_clr_tx_interrupts() { *AUX_MU_IER &= ~(0x2); } + + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/include/cpio.h b/Lab 7/kernel/include/cpio.h new file mode 100644 index 000000000..f45d6a1bb --- /dev/null +++ b/Lab 7/kernel/include/cpio.h @@ -0,0 +1,52 @@ +#ifndef __CPIO_H__ +#define __CPIO_H__ + +/* + https://man.freebsd.org/cgi/man.cgi?query=cpio + https://man.freebsd.org/cgi/man.cgi?query=cpio&sektion=5 + + CPIO New ASCII Format + The "new" ASCII format uses 8-byte hexadecimal fields for all numbers + and separates device numbers into separate fields for major and minor + numbers. + + magic The string "070701". + check This field is always set to zero by writers and ignored by readers. + + The end of the archive is indicated by a special record with the pathname "TRAILER!!". + + + ### The cpio file will be read like: + + 000001110000111.....0000 -> 110 byte header + ABC.txt -> file name + This is ABC.txt -> content + + 000001110000111.....0000 -> 110 byte header + DEF.txt -> file name + This is DEF.txt -> content + + 000001110000111.....0000 -> 110 byte header + TRAILER!!! ---> END OF THE CPIO +*/ + +typedef struct { + char c_magic[6]; /* Magic header '070701' */ + char c_ino[8]; /* "i-node" number */ + char c_mode[8]; /* Permisions */ + char c_uid[8]; /* User ID */ + char c_gid[8]; /* Group ID */ + char c_nlink[8]; /* Number of hard links */ + char c_mtime[8]; /* Modification time */ + char c_filesize[8]; /* File size */ + char c_devmajor[8]; /* Device number major */ + char c_devminor[8]; /* Device number minor */ + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; /* length of the path name */ + char c_check[8]; /* always set to zero */ +} cpio_t; + +typedef cpio_t* cpio_ptr_t; + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/include/gpio.h b/Lab 7/kernel/include/gpio.h new file mode 100644 index 000000000..08a217f29 --- /dev/null +++ b/Lab 7/kernel/include/gpio.h @@ -0,0 +1,44 @@ +#ifndef __GPIO_H__ +#define __GPIO_H__ + +#include "mmio.h" + +#define GPIO_BASE (MMIO_BASE + 0x00200000) + +#define GPFSEL0 ((volatile unsigned int*)(GPIO_BASE + 0x00000000)) +#define GPFSEL1 ((volatile unsigned int*)(GPIO_BASE + 0x00000004)) +#define GPFSEL2 ((volatile unsigned int*)(GPIO_BASE + 0x00000008)) +#define GPFSEL3 ((volatile unsigned int*)(GPIO_BASE + 0x0000000C)) +#define GPFSEL4 ((volatile unsigned int*)(GPIO_BASE + 0x00000010)) +#define GPFSEL5 ((volatile unsigned int*)(GPIO_BASE + 0x00000014)) + +#define GPSET0 ((volatile unsigned int*)(GPIO_BASE + 0x0000001C)) +#define GPSET1 ((volatile unsigned int*)(GPIO_BASE + 0x00000020)) + +#define GPCLR0 ((volatile unsigned int*)(GPIO_BASE + 0x00000028)) +#define GPCLR1 ((volatile unsigned int*)(GPIO_BASE + 0x0000002C)) + +#define GPLEV0 ((volatile unsigned int*)(GPIO_BASE + 0x00000034)) +#define GPLEV1 ((volatile unsigned int*)(GPIO_BASE + 0x00000038)) + +#define GPEDS0 ((volatile unsigned int*)(GPIO_BASE + 0x00000040)) +#define GPEDS1 ((volatile unsigned int*)(GPIO_BASE + 0x00000044)) + +#define GPHEN0 ((volatile unsigned int*)(GPIO_BASE + 0x00000064)) +#define GPHEN1 ((volatile unsigned int*)(GPIO_BASE + 0x00000068)) + +#define GPLEN0 ((volatile unsigned int*)(GPIO_BASE + 0x00000070)) +#define GPLEN1 ((volatile unsigned int*)(GPIO_BASE + 0x00000074)) + +#define GPAREN0 ((volatile unsigned int*)(GPIO_BASE + 0x0000007C)) +#define GPAREN1 ((volatile unsigned int*)(GPIO_BASE + 0x00000080)) + +#define GPAFEN0 ((volatile unsigned int*)(GPIO_BASE + 0x00000088)) +#define GPAFEN1 ((volatile unsigned int*)(GPIO_BASE + 0x0000008C)) + +#define GPPUD ((volatile unsigned int*)(GPIO_BASE + 0x00000094)) + +#define GPPUDCLK0 ((volatile unsigned int*)(GPIO_BASE + 0x00000098)) +#define GPPUDCLK1 ((volatile unsigned int*)(GPIO_BASE + 0x0000009C)) + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/include/irq.h b/Lab 7/kernel/include/irq.h new file mode 100644 index 000000000..c9379a5bd --- /dev/null +++ b/Lab 7/kernel/include/irq.h @@ -0,0 +1,16 @@ +#ifndef __IRQ_H__ +#define __IRQ_H__ + +#include "mmio.h" + +#define IRQ_BASIC ((volatile uint32ptr_t) (MMIO_BASE + 0xb200)) // p.114 +#define IRQ_PENDING1 ((volatile uint32ptr_t) (MMIO_BASE + 0xb204)) // p.115 +#define IRQ_ENABLE1 ((volatile uint32ptr_t) (MMIO_BASE + 0xb210)) // p.116 +#define IRQ_DISABLE1 ((volatile uint32ptr_t) (MMIO_BASE + 0xb21c)) // p.117 + + +#define irq_enable_aux_interrupt() { *IRQ_ENABLE1 = (1 << 29); } +#define irq_disable_aux_interrupt() { *IRQ_DISABLE1 = (1 << 29); } + + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/include/kernel.h b/Lab 7/kernel/include/kernel.h new file mode 100644 index 000000000..a5b337865 --- /dev/null +++ b/Lab 7/kernel/include/kernel.h @@ -0,0 +1,11 @@ +#ifndef __KERNEL_H__ +#define __KERNEL_H__ + +#include "type.h" + +uint64_t current_exception_level(); +byteptr_t align(const byteptr_t p, uint32_t s); + +int32_t get_el(); + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/include/list.h b/Lab 7/kernel/include/list.h new file mode 100644 index 000000000..4508c47ff --- /dev/null +++ b/Lab 7/kernel/include/list.h @@ -0,0 +1,146 @@ +#ifndef _LIST_H_ +#define _LIST_H_ + +typedef struct list_head { + struct list_head *next, *prev; +} list_head_t; + +typedef list_head_t* list_head_ptr_t; +typedef list_head_ptr_t list_ptr; + + +/* + struct list_head mylist = {&mylist, &mylist} ; +*/ +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + + +/* + Usage: + struct list_head myhead; + INIT_LIST_HEAD(&myhead); +*/ +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. + */ +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_; +} + + + /* + Insert a new entry after the specified head. + */ +static inline void +list_add(struct list_head *new_, struct list_head *head) +{ + __list_add(new_, head, head->next); +} + + +/* + Insert a new entry before the specified head. + */ +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. + */ +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. +*/ +static inline void +list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = 0; + entry->prev = 0; +} + + +/* + check if it is pointing to the list head +*/ +static inline int +list_is_head(const struct list_head *list, const struct list_head *head) +{ + return list == head; +} + + +/* + check if is is the first entry of the list +*/ +static inline int +list_is_first(const struct list_head *list, const struct list_head *head) +{ + return list->prev == head; +} + + +/* + check if the list is empty +*/ +static inline int +list_empty(const struct list_head *head) +{ + return head->next == head; +} + + +/* + iterate over a list + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next) + + +#define offsetof(st, m) __builtin_offsetof(st, m) + + +#define container_of(ptr, type, member) \ + __extension__({ \ + const __typeof__(((type*)0)->member)* __pmember = (ptr); \ + (type*) ((char*) __pmember - offsetof(type, member)); \ + }) + + +#define list_entry(ptr, type, member) container_of(ptr, type, member) + + +#define list_for_each_entry(entry, head, member) \ + for (entry = list_entry((head)->next, __typeof__(*entry), member); \ + &entry->member != (head); \ + entry = list_entry(entry->member.next, __typeof__(*entry), member)) + + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/include/mmio.h b/Lab 7/kernel/include/mmio.h new file mode 100644 index 000000000..71590998f --- /dev/null +++ b/Lab 7/kernel/include/mmio.h @@ -0,0 +1,9 @@ +#ifndef __MMIO_H__ +#define __MMIO_H__ + +#include "type.h" + +#define MMIO_BASE 0x3F000000 + + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/include/sprintf.h b/Lab 7/kernel/include/sprintf.h new file mode 100644 index 000000000..1ed4e6af0 --- /dev/null +++ b/Lab 7/kernel/include/sprintf.h @@ -0,0 +1,120 @@ +#ifndef _SPRINTF_H_ +#define _SPRINTF_H_ + +/** + * minimal sprintf implementation + */ +static unsigned int vsprintf(char *dst, char* fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig = dst, tmpstr[19]; + + // failsafes + if (dst==(void*) 0 || fmt == (void*) 0) { + return 0; + } + + // main loop + arg = 0; + while (*fmt) { + // argument access + if (*fmt == '%') { + fmt++; + // literal % + if (*fmt == '%') { + goto put; + } + len = 0; + // size modifier + while (*fmt >= '0' && *fmt <= '9') { + len *= 10; + len += *fmt - '0'; + fmt++; + } + // skip long modifier + if (*fmt == 'l') { + fmt++; + } + // character + if (*fmt == 'c') { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } else + // decimal number + if (*fmt=='d') { + arg = __builtin_va_arg(args, int); + // check input + sign = 0; + if ((int) arg < 0) { + arg *= -1; + sign++; + } + if (arg > 99999999999999999L) { + arg = 99999999999999999L; + } + // convert to string + i = 18; + tmpstr[i] = 0; + do { + tmpstr[--i] = '0' + (arg % 10); + arg /= 10; + } while (arg != 0 && i > 0); + if (sign) { + tmpstr[--i] = '-'; + } + // padding, only space + if (len > 0 && len < 18) { + while (i > 18 - len ) { + tmpstr[--i] = ' '; + } + } + p = &tmpstr[i]; + goto copystring; + } else + // hex number + if (*fmt == 'x') { + arg = __builtin_va_arg(args, long int); + // convert to string + i = 16; + tmpstr[i] = 0; + do { + char n = arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i] = n + (n > 9 ? 0x37 : 0x30); + arg >>= 4; + } while (arg != 0 && i > 0); + // padding, only leading zeros + if (len > 0 && len <= 16) { + while (i > 16 - len) { + tmpstr[--i] = '0'; + } + } + p = &tmpstr[i]; + goto copystring; + } else + // string + if (*fmt=='s') { + p = __builtin_va_arg(args, char*); +copystring: if (p == (void*) 0) { + p = "(null)"; + } + while (*p) { + *dst++ = *p++; + } + } + } else { +put: *dst++ = *fmt; + } + fmt++; + } + *dst = 0; + // number of bytes written + return dst - orig; +} + + + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/include/stat.h b/Lab 7/kernel/include/stat.h new file mode 100644 index 000000000..0402890be --- /dev/null +++ b/Lab 7/kernel/include/stat.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __STAT_H__ +#define __STAT_H__ + +#define S_IFMT 00170000 +#define S_IFSOCK 0140000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFBLK 0060000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFIFO 0010000 +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define S_ISVTX 0001000 + +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) + +#define S_IRWXU 00700 +#define S_IRUSR 00400 +#define S_IWUSR 00200 +#define S_IXUSR 00100 + +#define S_IRWXG 00070 +#define S_IRGRP 00040 +#define S_IWGRP 00020 +#define S_IXGRP 00010 + +#define S_IRWXO 00007 +#define S_IROTH 00004 +#define S_IWOTH 00002 +#define S_IXOTH 00001 + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/include/type.h b/Lab 7/kernel/include/type.h new file mode 100644 index 000000000..b7e49cfeb --- /dev/null +++ b/Lab 7/kernel/include/type.h @@ -0,0 +1,33 @@ +#ifndef __TYPE_H__ +#define __TYPE_H__ + +#include + +#define nullptr 0l + +typedef void* voidptr_t; +typedef void* void_ptr; +typedef char* byteptr_t; +typedef char* byte_ptr; +typedef char* char_ptr; +typedef char byte_t; +typedef uint8_t* uint8ptr_t; +typedef uint8_t* uint8_ptr; +typedef uint32_t* uint32ptr_t; +typedef uint32_t* uint32_ptr; +typedef uint64_t* uint64ptr_t; +typedef uint64_t* uint64_ptr; + +#define INT32_LEFTMOST_ORDER(x) ({31 - __builtin_clz(x);}) +#define INT32_LEFTMOST(x) 1 << INT32_LEFTMOST_ORDER(x) +#define INT32_RIGHTMOST_ORDER(x) ({__builtin_ctz(x);}) +#define INT32_RIGHTMOST(x) 1 << INT32_RIGHTMOST_ORDER(x) + +#define UINT32_ALIGN(v, o) ({(v) & ~((1 << o) - 1);}) +#define UINT32_PADDING(v, o) ({(v + ((1 << o) - 1)) & ~((1 << o) - 1);}) + + +#define max(a, b) (a > b ? a : b) +#define min(a, b) (a < b ? a : b) + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/chunk.c b/Lab 7/kernel/src/chunk.c new file mode 100644 index 000000000..b2e2834b6 --- /dev/null +++ b/Lab 7/kernel/src/chunk.c @@ -0,0 +1,209 @@ +#include "chunk.h" +#include "frame.h" +#include "list.h" +#include "uart.h" + + +#define CHUNK_UNIT_ORDER 4 +#define CHUNK_MAX_COUNT 0xEF // 240 - 1 +#define CHUNK_MIN_SIZE (1 << CHUNK_UNIT_ORDER) +#define CHUNK_MAX_SIZE (CHUNK_MAX_COUNT * CHUNK_MIN_SIZE) + +#define CHUNK_LIST_OFFSET 0x10 // 16 +#define CHUNK_DATA_OFFSET 0x100 // 256 + +#define CHUNK_SIZE_INDEX 0xF0 // 240 +#define CHUNK_COUNT_INDEX 0xF1 // 241 + +#define ADDR_TO_PTR(addr) ({(byteptr_t)(addr | 0l);}) +#define PTR_TO_ADDR(ptr) ({(uint32_t) ptr;}) + +#define FRAME_ADDR(ptr) ({(uint32_t) ptr & ~((1 << FRAME_SIZE_ORDER) - 1);}) +#define CHUNK_LIST(ptr) ({(FRAME_ADDR(ptr) + CHUNK_LIST_OFFSET);}) +#define CHUNK_DATA(ptr) ({(FRAME_ADDR(ptr) + CHUNK_DATA_OFFSET);}) + +#define CHUNK_TO_INDEX(ptr) ({((uint32_t) ptr - CHUNK_DATA(ptr)) >> CHUNK_UNIT_ORDER;}) +#define CLAMP_CHUNK_SIZE(size) ({(size < CHUNK_MIN_SIZE) ? CHUNK_MIN_SIZE : (size > CHUNK_MAX_SIZE) ? CHUNK_MAX_SIZE : size;}) + + +/** + * chunk size: 1~15 (x16bytes) +*/ +static void +init_frame(byteptr_t frame, uint32_t chunk_size) +{ + INIT_LIST_HEAD((list_head_ptr_t) frame); + + byteptr_t list = ADDR_TO_PTR(CHUNK_LIST(frame)); + + list[0] = 1; + for (int32_t i = 1; i < CHUNK_SIZE_INDEX; ++i) { list[i] = 0; } + int32_t i = 1; + while (i < CHUNK_SIZE_INDEX) { list[i] = i + chunk_size; i += chunk_size; } + list[i - chunk_size] = 0; + list[CHUNK_COUNT_INDEX] = 0; + list[CHUNK_SIZE_INDEX] = (uint8_t) chunk_size; +} + + +static byteptr_t +frame_request_chunk(byteptr_t frame) +{ + byteptr_t list = ADDR_TO_PTR(CHUNK_LIST(frame)); + + // check top, it's full when top is zero + if (list[0] == 0) return 0; + + // pop free list + uint8_t top = list[0]; + uint8_t second = list[top]; + list[0] = second; + + // accumlate the counter (# of allocated 16-byte units) + uint8_t size = list[CHUNK_SIZE_INDEX]; + list[CHUNK_COUNT_INDEX] += size; + + // index to ptr + byteptr_t data = ADDR_TO_PTR(CHUNK_DATA(frame)); + + // uart_printf("[DEBUG] frame: 0x%x, data: 0x%x, top: %d\n", frame, data, top); + + return &data[top * (1 << CHUNK_UNIT_ORDER)]; +} + + +/** + * return value: + * 1 - this frame is empty after released + * 0 - otherwise +*/ +static uint32_t +frame_release_chunk(byteptr_t chunk) +{ + byteptr_t list = ADDR_TO_PTR(CHUNK_LIST(chunk)); + + // push free list + uint32_t index = CHUNK_TO_INDEX(chunk); + list[index] = list[0]; + list[0] = index; + + // decrease the counter + uint8_t size = list[CHUNK_SIZE_INDEX]; + list[CHUNK_COUNT_INDEX] -= size; + + // return 1 if empty + return (list[CHUNK_COUNT_INDEX] == 0) ? 1 : 0; +} + + +static uint32_t +frame_count_free_chunks(byteptr_t frame) +{ + byteptr_t list = ADDR_TO_PTR(CHUNK_LIST(frame)); + uint32_t i = 0, count = 0; + while (i < CHUNK_MAX_COUNT && list[i] != 0) { ++count; i = list[i]; } + return count; +} + + +static list_head_ptr_t chunk_table; + +#define CHUNK_TABLE(i) ({(list_head_ptr_t) &chunk_table[i];}) +#define FRAME_IS_FULL(ptr) ({ADDR_TO_PTR(CHUNK_LIST(ptr))[0] == 0;}) +#define FRAME_IS_EMPTY(ptr) ({ADDR_TO_PTR(CHUNK_LIST(ptr))[CHUNK_COUNT_INDEX] == 0;}) + + +void +init_chunk_table() +{ + chunk_table = (list_head_ptr_t) CHUNK_TABLE_ADDR; + for (uint32_t i = 0; i < CHUNK_MAX_COUNT; ++i) + INIT_LIST_HEAD(CHUNK_TABLE(i)); +} + + +void +chunk_release(byteptr_t ptr) +{ + frame_release_chunk(ptr); + if (FRAME_IS_EMPTY(ptr)) { + list_del_entry((list_head_ptr_t) ADDR_TO_PTR(FRAME_ADDR(ptr))); + frame_release(ptr); + } +} + +/** + * size: request momory size in bytes +*/ +byteptr_t +chunk_request(uint32_t size) +{ + size = CLAMP_CHUNK_SIZE(size); + size = UINT32_PADDING(size, CHUNK_UNIT_ORDER); + + uint32_t index = (size >> CHUNK_UNIT_ORDER) - 1; + + // uart_printf("[DEBUG] chunk_request - index: %d, size: %d\n", index, size); + + list_head_ptr_t head = CHUNK_TABLE(index); + + // uart_printf("[DEBUG] chunk_request - head: 0x%x\n", head); + + list_head_ptr_t ptr = head->next; + while (ptr != head && FRAME_IS_FULL(ptr)) { ptr = ptr->next; } + + // uart_printf("[DEBUG] chunk_request - ptr: 0x%x\n", ptr); + + if (ptr == head) { + byteptr_t frame = frame_alloc(1); + INIT_LIST_HEAD((list_head_ptr_t) frame); + init_frame(frame, (size >> CHUNK_UNIT_ORDER)); + list_add_tail((list_head_ptr_t) frame, head); + + // uart_printf("[DEBUG] chunk_request - create frame: 0x%x, first: 0x%x\n", frame, head->next); + + ptr = (list_head_ptr_t) frame; + } + + byteptr_t ret = frame_request_chunk((byteptr_t) ptr); + return ret; +} + + +void +chunk_info(byteptr_t chunk) +{ + uart_printf("+- chunk addr: 0x%x, frame addr: 0x%x,", chunk, FRAME_ADDR(chunk)); + byteptr_t list = ADDR_TO_PTR(CHUNK_LIST(chunk)); + uint8_t size = list[CHUNK_SIZE_INDEX]; + uint8_t count = list[CHUNK_COUNT_INDEX]; + uart_printf(" chunk size: %d bytes, allocated count: %d, top: %d, free chunks: %d\n", size * 16, count, list[0], frame_count_free_chunks(chunk)); +} + +void +chunk_system_infro() +{ + uart_printf("==== CHUNK ALLOCATED INFO ====\n"); + for (uint32_t i = 0; i < CHUNK_MAX_COUNT; ++i) { + list_head_ptr_t head = CHUNK_TABLE(i); + if (!list_empty(head)) { + uart_printf("chunk size: %d bytes:\n", (i+1) * 16); + for (list_head_ptr_t ptr = head->next; ptr != head; ptr = ptr->next) + chunk_info((byteptr_t) ptr); + } + } +} + + +uint32_t +chunk_max_size() +{ + return CHUNK_MAX_SIZE; +} + + +uint32_t +chunk_data_offset() +{ + return CHUNK_DATA_OFFSET; +} diff --git a/Lab 7/kernel/src/chunk.h b/Lab 7/kernel/src/chunk.h new file mode 100644 index 000000000..4a01a1e8d --- /dev/null +++ b/Lab 7/kernel/src/chunk.h @@ -0,0 +1,22 @@ +#ifndef __CHUNK_H__ +#define __CHUNK_H__ + +#include "type.h" + +#define CHUNK_TABLE_ADDR 0x1000 +#define CHUNK_TABLE_END 0x2000 + + +void init_chunk_table(); + +void chunk_release(byteptr_t ptr); +byteptr_t chunk_request(uint32_t size); + +void chunk_info(byteptr_t chunk); + +uint32_t chunk_max_size(); +uint32_t chunk_data_offset(); + +void chunk_system_infro(); + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/core_timer.c b/Lab 7/kernel/src/core_timer.c new file mode 100644 index 000000000..84103f894 --- /dev/null +++ b/Lab 7/kernel/src/core_timer.c @@ -0,0 +1,192 @@ +#include "core_timer.h" +#include "asm.h" +#include "mmio.h" +#include "uart.h" +#include "string.h" +#include "memory.h" +#include "exception.h" +#include "list.h" + + +/* + 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 +*/ + + +static void +core_timer_set_timeout(uint32_t duration) +{ + uint64_t freq = asm_read_sysregister(cntfrq_el0); + asm_write_sysregister(cntp_tval_el0, freq * duration); +} + + +static void +core_timer_set_tick(uint32_t duration) +{ + uint64_t freq = asm_read_sysregister(cntfrq_el0); + asm_write_sysregister(cntp_tval_el0, freq >> duration); +} + + + +void +core_timer_enable() +{ + asm_write_sysregister(cntp_ctl_el0, 1); + *CORE0_TIMER_IRQ_CTRL = (uint32_t) 2; // unmask timer interrupt +} + + +void +core_timer_disable() +{ + asm_write_sysregister(cntp_ctl_el0, 0); // disable + *CORE0_TIMER_IRQ_CTRL = (uint32_t) 0; // unmask timer interrupt +} + + +uint64_t +core_timer_current_time() +{ + uint64_t freq = asm_read_sysregister(cntfrq_el0); + uint64_t cur_cnt = asm_read_sysregister(cntpct_el0); + return cur_cnt / freq; +} + + +typedef struct timer_event { + struct list_head listhead; + uint64_t event_time; + uint64_t duration; + uint64_t expired_time; + timer_event_cb callback; + byte_t message[32]; // todo: pointer to a allocated space + uint32_t is_tick; +} timer_event_t; + +typedef timer_event_t* timer_event_ptr_t; + + +static timer_event_ptr_t +timer_event_create(timer_event_cb cb, byteptr_t msg, uint64_t duration) +{ + timer_event_ptr_t event = (timer_event_ptr_t) kmalloc(sizeof(timer_event_t)); + INIT_LIST_HEAD(&event->listhead); + event->event_time = core_timer_current_time(); + event->duration = duration; + event->expired_time = event->event_time + duration; + + event->callback = cb; + event->is_tick = 0; + str_ncpy(event->message, msg, 32); + return event; +} + + +static LIST_HEAD(timer_event_queue); + + +static void +timer_event_queue_add(timer_event_ptr_t event) +{ + list_head_ptr_t curr = (&timer_event_queue)->next; + + while (!list_is_head(curr, &timer_event_queue) && ((timer_event_ptr_t) curr)->expired_time <= (event->expired_time)) { + curr = curr->next; + } + list_add(&event->listhead, curr->prev); + + // if the new event is inserted at the front, update the timer + if (list_is_first((list_head_ptr_t) event, &timer_event_queue)) { + if (event->is_tick) + core_timer_set_tick(event->duration); + else + core_timer_set_timeout(event->expired_time - core_timer_current_time()); + core_timer_enable(); + } +} + + +static void +core_timer_callback_print_message(byteptr_t data) +{ + timer_event_ptr_t event = (timer_event_ptr_t) data; + + uart_printf("command time: %d\n", event->event_time); + uart_printf("current time: %d\n", core_timer_current_time()); + uart_str("timer event message: "); + uart_line(event->message); +} + + +static void +core_timer_add_event(timer_event_cb cb, byteptr_t msg, uint64_t duration) +{ + timer_event_ptr_t event = timer_event_create(cb, msg, duration); + timer_event_queue_add(event); +} + + +void +core_timer_add_timeout_event(byteptr_t data, uint64_t duration) +{ + core_timer_add_event(core_timer_callback_print_message, data, duration); +} + + +void +core_timer_add_tick(timer_event_cb cb, byteptr_t msg, uint64_t duration) +{ + timer_event_ptr_t event = timer_event_create(cb, msg, duration); + event->is_tick = 1; + timer_event_queue_add(event); +} + + +/* + interrupt service routine + 1. run the first event of the list + 2. remove the first event + 3. check the next event of the list + 4. set the timer registers or clear them +*/ + +void +core_timer_interrupt_handler() +{ + // uart_printf("core_timer_interrupt_handler\n"); + + exception_l1_disable(); + + timer_event_ptr_t event = (timer_event_ptr_t) (&timer_event_queue)->next; + + list_del_entry((list_head_ptr_t) event); + + if (event->is_tick) { + timer_event_queue_add(event); + } + + if (!list_empty(&timer_event_queue)) { + timer_event_ptr_t first = (timer_event_ptr_t) (&timer_event_queue)->next; + if (first->is_tick) + core_timer_set_tick(first->duration); + else + core_timer_set_timeout(first->expired_time - core_timer_current_time()); + core_timer_enable(); + } + + exception_l1_enable(); + + event->callback((byteptr_t) event); + if (!event->is_tick) { kfree((byteptr_t) event); } +} \ No newline at end of file diff --git a/Lab 7/kernel/src/core_timer.h b/Lab 7/kernel/src/core_timer.h new file mode 100644 index 000000000..4543fe8e9 --- /dev/null +++ b/Lab 7/kernel/src/core_timer.h @@ -0,0 +1,20 @@ +#ifndef __CORE_TIMER_H__ +#define __CORE_TIMER_H__ + +#include "type.h" + +#define CORE0_TIMER_IRQ_CTRL ((volatile uint32ptr_t) (0x40000040)) +#define CORE0_INTERRUPT_SOURCE ((volatile uint32ptr_t) (0x40000060)) + +uint64_t core_timer_current_time(); +void core_timer_enable(); +void core_timer_disable(); + +void core_timer_interrupt_handler(); +void core_timer_add_timeout_event(byteptr_t message, uint64_t duration); + +typedef void (*timer_event_cb) (byteptr_t); + +void core_timer_add_tick(timer_event_cb cb, byteptr_t msg, uint64_t duration); + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/delay.c b/Lab 7/kernel/src/delay.c new file mode 100644 index 000000000..87ef63dbc --- /dev/null +++ b/Lab 7/kernel/src/delay.c @@ -0,0 +1,27 @@ +#include "type.h" + +/* Wait N CPU cycles (ARM CPU only) */ + +void +delay_cycles(uint32_t n) +{ + if (n) while (n--) { asm volatile("nop"); } +} + +/** + * Wait N microseconds (ARM CPU only) + */ +void +delay_msec(uint32_t n) +{ + register uint64_t freq, start, cur; + + asm volatile ("mrs %0, cntfrq_el0" : "=r"(freq)); // get current counter frequency + asm volatile ("mrs %0, cntpct_el0" : "=r"(start)); // read the current counter + + uint64_t i = ((freq / 1000) * n) / 1000; // calculate required count increase + + do { + asm volatile ("mrs %0, cntpct_el0" : "=r"(cur)); + } while (cur - start < i); // loop while counter increase is less than i +} \ No newline at end of file diff --git a/Lab 7/kernel/src/delay.h b/Lab 7/kernel/src/delay.h new file mode 100644 index 000000000..f3aaf8486 --- /dev/null +++ b/Lab 7/kernel/src/delay.h @@ -0,0 +1,9 @@ +#ifndef __DELAY_H__ +#define __DELAY_H__ + +#include "type.h" + +void delay_cycles(uint32_t n); +void delay_msec(uint32_t n); + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/dtb.c b/Lab 7/kernel/src/dtb.c new file mode 100644 index 000000000..3022adc1f --- /dev/null +++ b/Lab 7/kernel/src/dtb.c @@ -0,0 +1,218 @@ +#include "dtb.h" +#include "memory.h" +#include "string.h" +#include "uart.h" +#include "initrd.h" + + +/* + Flatten Devicetree (DTB) Format + + .dtb (devicetree blob) structure + + +----------------------------+ + | struct fdt_header | + +----------------------------+ + | (free space) | + +----------------------------+ + | memory reservation block | + +----------------------------+ + | (free space) | + +----------------------------+ + | structure block | + +----------------------------+ + | (free space) | + +----------------------------+ + | strings block | + +----------------------------+ + | (free space) | + +----------------------------+ +*/ + + +typedef struct fdt_header +{ + uint32_t magic; // contain the value 0xd00dfeed (big-endian). + uint32_t totalsize; // in byte + uint32_t off_dt_struct; // the offset in bytes of the structure block + uint32_t off_dt_strings; // the offset in bytes of the string block + uint32_t off_mem_rsvmap; // the offset in bytes of the memory reservation block + uint32_t version; // the version of the devicetree data structure (The version is 17 in the document) + uint32_t last_comp_version; // the lowest version with which the version used is backwards compatible. (17 to 16) + uint32_t boot_cpuid_phys; // the physical ID of the system's boot CPU + uint32_t size_dt_strings; // the length in bytes of the strings block section + uint32_t size_dt_struct; // the length in bytes of the structure block section +} fdt_header_t; + +typedef fdt_header_t* fdt_header_ptr_t; + + +/* + convert from 32-bit big-endian to little-endian +*/ +static uint32_t +_dtb_get_uint32(const byteptr_t p) +{ + return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; +} + + +/* + Strcuture block + + a sequence of 32-bit aligned {token, data} + + 1. FDT_BEGIN_NODE 0x00000001 + (name) : string + + 2. FDT_END_NODE 0x00000002 + (no data) + + 3. FDT_PROP 0x00000003 + struct { + uint32_t len; // the length of the property's value + uint32_t nameoff; // the offset into strings block at which the property's name is stored + } + (value) + + 4. FDT_NOP 0x00000004 + (no data) + + 5. FDT_END 0x00000009 + (no data) + it should be the only one and be the last token in the structure block + +*/ + + +static uint32_t +_struct_iteration(fdt_callback cb, const byteptr_t struct_ptr, const byteptr_t string_ptr, uint32_t struct_size) +{ + byteptr_t cur_ptr = struct_ptr; + byteptr_t end_ptr = cur_ptr + struct_size; + + while (cur_ptr < end_ptr) { + uint32_t token = _dtb_get_uint32(cur_ptr); + switch (token) { + case FDT_BEGIN_NODE: + byteptr_t name_ptr = cur_ptr + 4; + cb(token, name_ptr, 0, 0); + cur_ptr = memory_padding(name_ptr + str_len(name_ptr) + 1, 2); // the string length should contain '\0' + break; + case FDT_PROP: + uint32_t data_len = _dtb_get_uint32(cur_ptr + 4); + uint32_t name_off = _dtb_get_uint32(cur_ptr + 8); + byteptr_t data_ptr = cur_ptr + 12; + cb(token, string_ptr + name_off, data_ptr, data_len); + cur_ptr = memory_padding(data_ptr + data_len, 2); + break; + case FDT_END_NODE: + case FDT_NOP: + cb(token, 0, 0, 0); + cur_ptr += 4; + break; + case FDT_END: + cb(token, 0, 0, 0); + return FDT_TRAVERSE_CORRECT; + break; + default: + return FDT_TRAVERSE_FORMAT_ERROR; + } + } + return FDT_TRAVERSE_CORRECT; +} + + +static byteptr_t _dtb_ptr = nullptr; +static byteptr_t _dtb_end = nullptr; +byteptr_t dtb_get_ptr() { return _dtb_ptr; } +byteptr_t dtb_get_end() { return _dtb_end; } + + +uint32_t +dtb_set_ptr(byteptr_t ptr) +{ + fdt_header_ptr_t header = (fdt_header_ptr_t) ptr; + if (_dtb_get_uint32((byteptr_t) &(header->magic)) != 0xd00dfeed) { + return FDT_TRAVERSE_HEADER_ERROR; + } + _dtb_ptr = ptr; + _dtb_end = (byteptr_t) ((uint64_t) dtb_get_ptr() + _dtb_get_uint32((byteptr_t) &(header->totalsize))); + return FDT_TRAVERSE_CORRECT; +} + + +uint32_t +fdt_traverse(fdt_callback cb) +{ + byteptr_t dtb_ptr = dtb_get_ptr(); + fdt_header_ptr_t header = (fdt_header_ptr_t) dtb_ptr; + + if (_dtb_get_uint32((byteptr_t) &(header->magic)) != 0xd00dfeed) { + return FDT_TRAVERSE_HEADER_ERROR; + } + + uint32_t struct_size = _dtb_get_uint32((byteptr_t) &(header->size_dt_struct)); + byteptr_t struct_ptr = dtb_ptr + _dtb_get_uint32((byteptr_t) &(header->off_dt_struct)); + byteptr_t string_ptr = dtb_ptr + _dtb_get_uint32((byteptr_t) &(header->off_dt_strings)); + + return _struct_iteration(cb, struct_ptr, string_ptr, struct_size); +} + + +void +fdt_find_initrd_addr(uint32_t token, const byteptr_t name_ptr, const byteptr_t data_ptr, uint32_t v) +{ + if (token == FDT_PROP && str_eql(name_ptr, "linux,initrd-start")) { + byteptr_t _addr = (byteptr_t) (0l | _dtb_get_uint32(data_ptr)); + initrd_set_ptr(_addr); + } + + else if (token == FDT_PROP && str_eql(name_ptr, "linux,initrd-end")) { + byteptr_t _addr = (byteptr_t) (0l | _dtb_get_uint32(data_ptr)); + initrd_set_end(_addr); + } +} + + +static void +_print_space(uint32_t n) +{ + for (uint32_t i = 0; i < n; ++i) uart_put(' '); +} + +void +fdt_print_node(uint32_t token, const byteptr_t name_ptr, const byteptr_t, uint32_t) +{ + static uint32_t _level = 0; + + switch (token) { + case FDT_BEGIN_NODE: + _print_space(_level); + uart_str("FDT_BEGIN_NODE "); + uart_line(name_ptr); + _level += 2; + break; + case FDT_PROP: + _print_space(_level); + uart_str("FDT_PROP "); + uart_line(name_ptr); + break; + case FDT_END_NODE: + _level -= 2; + _print_space(_level); + uart_line("FDT_END_NODE"); + break; + case FDT_NOP: + _print_space(_level); + uart_line("FDT_NOP"); + break; + case FDT_END: + _print_space(_level); + uart_line("FDT_END"); + _level = 0; + break; + default: + break; + } +} diff --git a/Lab 7/kernel/src/dtb.h b/Lab 7/kernel/src/dtb.h new file mode 100644 index 000000000..994f9732e --- /dev/null +++ b/Lab 7/kernel/src/dtb.h @@ -0,0 +1,28 @@ +#ifndef __DTB_H__ +#define __DTB_H__ + +#include "type.h" + +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + +#define FDT_TRAVERSE_CORRECT 0 +#define FDT_TRAVERSE_HEADER_ERROR 1 +#define FDT_TRAVERSE_FORMAT_ERROR 2 + + +typedef void (*fdt_callback)(uint32_t token, const byteptr_t name_ptr, const byteptr_t data_ptr, uint32_t v); + +uint32_t dtb_set_ptr(byteptr_t ptr); +byteptr_t dtb_get_ptr(); +byteptr_t dtb_get_end(); + +uint32_t fdt_traverse(fdt_callback cb); + +void fdt_find_initrd_addr(uint32_t token, const byteptr_t name_ptr, const byteptr_t data_ptr, uint32_t v); +void fdt_print_node(uint32_t token, const byteptr_t name_ptr, const byteptr_t, uint32_t); + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/entry.S b/Lab 7/kernel/src/entry.S new file mode 100644 index 000000000..5e3a742ab --- /dev/null +++ b/Lab 7/kernel/src/entry.S @@ -0,0 +1,218 @@ +#include "syscall.h" + +#define S_FRAME_SIZE 272 // size of all saved registers (16 * 17) // 8 bytes = 64 bits +#define S_X0 0 // offset of x0 register in saved stack frame + + +// save general registers to stack +.macro save_all, el + // move stack top + sub sp, sp, #S_FRAME_SIZE + + // store pair of registers + 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] + + .if \el == 0 + mrs x21, sp_el0 + .else + add x21, sp, #S_FRAME_SIZE + .endif + + stp x30, x21, [sp, 16 * 15] // push x30, stack pointer + + // push information for nested interrupt + mrs x22, elr_el1 + mrs x23, spsr_el1 + + stp x22, x23, [sp, 16 * 16] // push spsr_el1, elr_el1 + +.endm + + +// load general registers from stack +.macro load_all, el + + ldp x30, x21, [sp, 16 * 15] + + .if \el == 0 + msr sp_el0, x21 + .endif + + ldp x22, x23, [sp, 16 * 16] + + msr elr_el1, x22 + msr spsr_el1, x23 + + 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] + + // restore stack top + add sp, sp, #S_FRAME_SIZE +.endm + + +.globl err_hang +err_hang: + b err_hang + +.macro handle_invalid_entry el, type + save_all \el + // mov x0, #\type + // mrs x1, esr_el1 + // mrs x2, elr_el1 + // bl show_invalid_entry_message + b err_hang +.endm + + + + +.macro exception_entry label + .align 7 // entry size is 0x80, should be aligned to 2^7 + b \label +.endm + + + // vbar_el1[10:0] bits are reserved + .align 11 // vector table should be aligned to 2^11 (0x800) + .global exception_vector_table +exception_vector_table: + // Exception from the current EL while using SP_EL0 + exception_entry exception_invalid // Synchronous EL1t (invalid) + exception_entry exception_invalid // IRQ EL1t (invalid) + exception_entry exception_invalid // FIQ EL1t (invalid) + exception_entry exception_invalid // SError EL1t (invalid) + + // Exception from the current EL while using SP_ELx + exception_entry el1_sync // Synchronous EL1h + exception_entry el1_irq // IRQ EL1h + exception_entry exception_invalid // FIQ EL1h (invalid) + exception_entry exception_invalid // SError EL1h (invalid) + + // Exception from a lower EL and at least one lower EL is AArch64 + exception_entry el0_sync // Synchronous 64-bit EL0 + exception_entry el0_irq // IRQ 64-bit EL0 + exception_entry exception_invalid // FIQ 64-bit EL0 (invalid) + exception_entry exception_invalid // Error 64-bit EL0 (invalid) + + // Exception from a lower EL and all lower EL are AArch32 + exception_entry exception_invalid // Synchronous 32-bit EL0 (invalid) + exception_entry exception_invalid // IRQ 64-bit EL0 (invalid) + exception_entry exception_invalid // FIQ 64-bit EL0 (invalid) + exception_entry exception_invalid // Error 64-bit EL0 (invalid) + + +exception_invalid: // default exception router + save_all 0 + bl exception_invalid_handler // c code + load_all 0 + eret // EL1 -> EL0 + + +el1_sync: + save_all 1 + bl exception_el1_sync_handler + load_all 1 + eret + + +el1_irq: + save_all 1 + bl exception_el1_irq_handler + load_all 1 + eret + + +#define ESR_ELx_EC_SHIFT 26 +#define ESR_ELx_EC_SVC64 0x15 +#define NR_SYSCALLS 11 + +el0_sync: + save_all 0 + // bl exception_el0_sync_handler + + mrs x25, esr_el1 // read the syndrome register + lsr x24, x25, #ESR_ELx_EC_SHIFT // exception class + cmp x24, #ESR_ELx_EC_SVC64 // SVC in 64-bit state + b.eq el0_svc + handle_invalid_entry 0, SYNC_ERROR + +sc_nr .req x25 // number of system calls +scno .req x26 // syscall number +stbl .req x27 // syscall table pointer + +el0_svc: + adr stbl, syscall_table // load syscall table pointer + uxtw scno, w8 // syscall number in w8 + mov sc_nr, #NR_SYSCALLS + bl enable_irq + cmp scno, sc_nr // check upper syscall limit + b.hs ni_sys + + ldr x16, [stbl, scno, lsl #3] // address in the syscall table + blr x16 // call sys_* routine + b ret_from_syscall +ni_sys: + handle_invalid_entry 0, SYSCALL_ERROR +ret_from_syscall: + bl disable_irq + str x0, [sp, #S_X0] // returned x0 + load_all 0 + eret + + +el0_irq: + save_all 0 + bl exception_el0_irq_handler + load_all 0 + eret + + + .global set_exception_vector_table +set_exception_vector_table: + adr x0, exception_vector_table + msr vbar_el1, x0 + ret + // vbar_el1: Vector Base Address Register (EL1) + // Holds the exception base address for any + // exception that is taken to EL1. + + +.globl ret_from_fork +ret_from_fork: + bl schedule_tail + cbz x19, ret_to_user // not a kernel thread + mov x0, x20 + blr x19 + +ret_to_user: + bl disable_irq + load_all 0 + eret \ No newline at end of file diff --git a/Lab 7/kernel/src/entry.h b/Lab 7/kernel/src/entry.h new file mode 100644 index 000000000..a043ebc11 --- /dev/null +++ b/Lab 7/kernel/src/entry.h @@ -0,0 +1,11 @@ +#ifndef __ENTRY_H__ +#define __ENTRY_H__ + + +#define SYNC_ERROR 16 +#define SYSCALL_ERROR 17 + + +void ret_from_fork(); + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/exception.S b/Lab 7/kernel/src/exception.S new file mode 100644 index 000000000..db8b4c242 --- /dev/null +++ b/Lab 7/kernel/src/exception.S @@ -0,0 +1,19 @@ +// #include "sched.h" + +// .globl irq_vector_init +// irq_vector_init: +// adr x0, vectors // load VBAR_EL1 with virtual +// msr vbar_el1, x0 // vector table address +// ret + + +.globl enable_irq +enable_irq: + msr daifclr, #2 + ret + + +.globl disable_irq +disable_irq: + msr daifset, #2 + ret diff --git a/Lab 7/kernel/src/exception.c b/Lab 7/kernel/src/exception.c new file mode 100644 index 000000000..aac232392 --- /dev/null +++ b/Lab 7/kernel/src/exception.c @@ -0,0 +1,206 @@ +#include "type.h" +#include "uart.h" +#include "asm.h" +#include "core_timer.h" +#include "irq.h" +#include "aux.h" +#include "list.h" +#include "sched.h" +#include "memory.h" + + +void +exception_l1_enable() { + asm volatile("msr daifclr, 0xf"); // umask all DAIF, it's column D,A,I,F on the register PASATE +} + + +void +exception_l1_disable() +{ + asm volatile("msr daifset, 0xf"); // mask all DAIF, it's column D,A,I,F on the register PASATE +} + + +typedef void (*task_callback) (); + +typedef struct irqtask +{ + struct list_head listhead; + uint64_t running; + uint64_t priority; // store priority (smaller number is more preemptive) + task_callback handler; // task function pointer +} irqtask_t; + +typedef irqtask_t* irqtask_ptr_t; + + +static LIST_HEAD(irqtask_queue); + + +static irqtask_ptr_t +irqtask_create(task_callback handler, uint64_t priority) +{ + irqtask_ptr_t task = (irqtask_ptr_t) kmalloc(sizeof(irqtask_t)); + INIT_LIST_HEAD(&task->listhead); + task->handler = handler; + task->priority = priority; + task->running = 0; + return task; +} + + +static void +irqtask_queue_add(irqtask_ptr_t task) +{ + if (task == 0) return; + list_head_ptr_t curr = (&irqtask_queue)->next; + // small value has higher priority + while (!list_is_head(curr, &irqtask_queue) && + ((irqtask_ptr_t) curr)->priority <= (task->priority)) + { + curr = curr->next; + } + list_add(&task->listhead, curr->prev); +} + + +static uint32_t +irqtask_queue_not_running() +{ + if (list_empty(&irqtask_queue)) + return 0; + irqtask_ptr_t first = (irqtask_ptr_t) (&irqtask_queue)->next; + return !(first->running); +} + + +static void +irqtask_queue_run() +{ + while (irqtask_queue_not_running()) { + irqtask_ptr_t first = (irqtask_ptr_t) (&irqtask_queue)->next; + list_del_entry((list_head_ptr_t) first); + exception_l1_enable(); + first->running = 1; + first->handler(); + exception_l1_disable(); + kfree((byteptr_t) first); + } +} + + +static void +show_exception_infomation() +{ + uint64_t spsr = asm_read_sysregister(spsr_el1); + uint64_t elr = asm_read_sysregister(elr_el1); + uint64_t esr = asm_read_sysregister(esr_el1); + uart_str("spsr_el1: 0x"); uart_hexl(spsr); uart_endl(); + uart_str("elr_el1: 0x"); uart_hexl(elr); uart_endl(); + uart_str("esr_el1: 0x"); uart_hexl(esr); uart_endl(); +} + + +void +exception_invalid_handler() +{ + exception_l1_disable(); + uart_line("---- exception_invalid_handler ----"); + show_exception_infomation(); + exception_l1_enable(); +} + + +// EC,bits[31:26] +#define ESR_ELx_EC(esr) ((esr & 0xFC000000) >> 26) +// ISS,bits[24:0] +#define ESR_ELx_ISS(esr) (esr & 0x03FFFFFF) + +#define ESR_ELx_EC_SVC64 0b010101 +#define ESR_ELx_EC_DABT_LOW 0b100100 +#define ESR_ELx_EC_IABT_LOW 0b100000 + + +// void +// exception_el0_sync_handler() +// { +// exception_l1_disable(); +// uart_line("---- exception_el0_sync_handler ----"); +// show_exception_infomation(); + +// uint64_t esr = asm_read_sysregister(esr_el1); // cause of that exception +// uint32_t ec = ESR_ELx_EC(esr); + +// switch (ec) +// { +// case ESR_ELx_EC_SVC64: +// exception_l1_enable(); + +// // syscall_handler(_regs); + +// exception_l1_disable(); +// break; +// case ESR_ELx_EC_DABT_LOW: +// uart_printf("in Data Abort\n"); +// break; +// case ESR_ELx_EC_IABT_LOW: +// uart_printf("in Instruction Abort\n"); +// break; +// default: +// return; +// } + +// exception_l1_enable(); +// } + + +void +exception_el0_irq_handler() +{ + exception_l1_disable(); + // uart_line("---- exception_el0_irq_handler ----"); + // show_exception_infomation(); + exception_l1_enable(); +} + + +void +exception_el1_sync_handler() +{ + exception_l1_disable(); + // uart_line("---- exception_el1_sync_handler ----"); + // show_exception_infomation(); + exception_l1_enable(); +} + + +void +exception_el1_irq_handler() +{ + exception_l1_disable(); + + irqtask_ptr_t task = 0; + if (*IRQ_PENDING1 & (1 << 29)) { // UART IRQ + if (*AUX_MU_IIR & 0x4) { // Receiver holds valid bytes + aux_clr_rx_interrupts(); + task = irqtask_create(mini_uart_rx_handler, 3); + } + else if (*AUX_MU_IIR & 0x2) { // Transmit holding register empty + aux_clr_tx_interrupts(); + task = irqtask_create(mini_uart_tx_handler, 3); + } + } + else if (*CORE0_INTERRUPT_SOURCE & 0x2) { // Core timer IRQ + core_timer_disable(); + task = irqtask_create(core_timer_interrupt_handler, 1); + } + + irqtask_queue_add(task); + irqtask_queue_run(); + + exception_l1_enable(); +} + + + diff --git a/Lab 7/kernel/src/exception.h b/Lab 7/kernel/src/exception.h new file mode 100644 index 000000000..1ae9c3494 --- /dev/null +++ b/Lab 7/kernel/src/exception.h @@ -0,0 +1,10 @@ +#ifndef __EXCEPTION_H__ +#define __EXCEPTION_H__ + +void exception_l1_enable(); +void exception_l1_disable(); + +void enable_irq(); +void disable_irq(); + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/frame.c b/Lab 7/kernel/src/frame.c new file mode 100644 index 000000000..73751ed3b --- /dev/null +++ b/Lab 7/kernel/src/frame.c @@ -0,0 +1,398 @@ +#include "frame.h" +#include "type.h" +#include "list.h" +#include "uart.h" +#include "memory.h" + + +#define FRAME_SIZE_ORDER 12 + + +static byteptr_t base_ptr; +static uint32_t max_alloc_size; +static uint32_t max_alloc_order; + +static uint32_t total_frames; +static byteptr_t frame_array; + +#define BUCKET_COUNT max_alloc_order + 1 + +#define FRAME_ALLOCATED 0x40 +#define FRAME_PRESERVED 0x20 +#define FRAME_BUDDY 0x60 + +#define FRAME_IS_ALLOCATED(x) ({frame_array[x] == FRAME_ALLOCATED;}) +#define FRAME_IS_PRESERVED(x) ({frame_array[x] == FRAME_PRESERVED;}) +#define FRAME_IS_BUDDY(x) ({frame_array[x] == FRAME_BUDDY;}) + +#define FRAME_IS_FREE(x) ({(frame_array[x] & 0xE0) == 0x00;}) +#define FRAME_ORDER(x) ({frame_array[x];}) + +#define FRAME_SET_ORDER(x, order) frame_array[x] = 0x1F & order +#define FRAME_OWNER(index, order) ({index & ~((1 << (order + 1)) - 1);}) +#define BUDDY_INDEX(index, order) ({index ^ (1 << order);}) + +#define FRAME_TYPE(index) ({(FRAME_IS_PRESERVED(index)) ? "preserved" : (FRAME_IS_ALLOCATED(index)) ? "allocated" : "free";}) + + +static byteptr_t +index_to_ptr(uint32_t index) +{ + return (byteptr_t) (((uint64_t) base_ptr) + (index << FRAME_SIZE_ORDER)); +} + + +static uint32_t +ptr_to_index(byteptr_t ptr) +{ + return ((uint32_t) ptr) >> FRAME_SIZE_ORDER; +} + + +/** + * Freelists +*/ + +static list_head_ptr_t buckets; + + +/** + * pop a free block from the designate bucket +*/ +static byteptr_t +bucket_pop(const byteptr_t bucket) +{ + list_head_ptr_t head = (list_head_ptr_t) bucket; + if (head->next == head) return 0; + list_head_ptr_t first = head->next; + list_del_entry(first); + return (byteptr_t) first; +} + + +/** + * push a free block by a designate index + * should set the order value properly before call this function +*/ +static void +buckets_push(uint32_t index) +{ + byteptr_t block = index_to_ptr(index); + uint32_t order = FRAME_ORDER(index); + + INIT_LIST_HEAD((list_head_ptr_t) block); + list_add_tail((list_head_ptr_t) block, (list_head_ptr_t) &buckets[order]); +} + + +static void +buckets_remove(uint32_t index) +{ + list_del_entry((list_head_ptr_t) index_to_ptr(index)); +} + + +/** + * frame array system basic tools +*/ + + +// preserved (not in use) +uint32_t +frame_split(uint32_t index, uint32_t order) +{ + if (!FRAME_IS_FREE(index)) { return 0; } + if (order == 0) { return 0; } + uint32_t buddy = BUDDY_INDEX(index, (order - 1)); + if (index > (total_frames - 1) || buddy > (total_frames - 1)) return 0; + FRAME_SET_ORDER(buddy, (order - 1)); + FRAME_SET_ORDER(index, (order - 1)); + buckets_push(buddy); + return 1; +} + + +static uint32_t +frame_mergeable(uint32_t index, uint32_t buddy) +{ + if (index > (total_frames - 1) || buddy > (total_frames - 1)) return 0; + if (FRAME_IS_FREE(index) && FRAME_ORDER(index) == FRAME_ORDER(buddy)) return 1; + return 0; +} + + +static uint32_t +frame_merge(uint32_t index, uint32_t order) +{ + if (!FRAME_IS_FREE(index)) return 0; + uint32_t buddy = BUDDY_INDEX(index, order); + + if (!frame_mergeable(index, buddy)) return 0; + frame_array[buddy] = FRAME_BUDDY; + frame_array[index] = order + 1; + return 1; +} + + +static void +frame_merge_up(uint32_t start, uint32_t end, uint32_t max_order) +{ + /** + * merge all free blocks as high order as possible + */ + for (uint32_t order = 0; order < max_order; order++) + for (uint32_t index = start; index < end; index += (1 << (order + 1))) + frame_merge(index, order); + /** + * push all the free blocks into freelists + */ + for (uint32_t index = start; index < end; ++index) + if (FRAME_IS_FREE(index)) + buckets_push(index); +} + + +/** + * frame array system operatiors +*/ + + +#define SMALLEST_POW_OF_2(x) ({(INT32_LEFTMOST_ORDER(x) == INT32_RIGHTMOST_ORDER(x)) ? INT32_LEFTMOST_ORDER(x) : INT32_LEFTMOST_ORDER(x) + 1;}) +#define GREATEST_POW_OF_2(x) ({SMALLEST_POW_OF_2(x) >> 1;}) + + +byteptr_t +frame_alloc(uint32_t count) +{ + uint32_t request_order = SMALLEST_POW_OF_2(count); + + int32_t order = request_order; + while (order < BUCKET_COUNT && list_empty(&buckets[order])) { order++; } + + if (order == BUCKET_COUNT) return 0; + + byteptr_t block = bucket_pop((byteptr_t) &buckets[order]); + + // uart_printf("[DEBUG] frame alloc: 0x%x count: %d\n", block, count); + + uint32_t index = ptr_to_index(block); + uint32_t end = index + (1 << order); + + for (uint32_t i = 0; (index + i) < end; ++i) + frame_array[index + i] = (i < count) ? FRAME_ALLOCATED : 0; + + frame_merge_up(index, end, SMALLEST_POW_OF_2((1 << order) - count)); + return block; +} + + +void +frame_release(byteptr_t ptr) +{ + uint32_t index = ptr_to_index(ptr); + if (!FRAME_IS_ALLOCATED(index)) return; + + // uart_printf("[DEBUG] frame: 0x%x released\n", (index << FRAME_SIZE_ORDER)); + + frame_array[index] = 0; + + uint32_t order = 0; + uint32_t buddy = BUDDY_INDEX(index, order); + while (frame_mergeable(index, buddy)) { + buckets_remove(buddy); + index = FRAME_OWNER(index, order); + buddy = BUDDY_INDEX(index, order); + frame_array[buddy] = FRAME_BUDDY; + frame_array[index] = order + 1; + buddy = BUDDY_INDEX(index, order); + order++; + } + + buckets_push(index); +} + + +void +frame_release_block(byteptr_t ptr, uint32_t count) +{ + for (uint32_t i = 0; i < count; ++i) { + frame_release(ptr); + ptr = (byteptr_t) ((uint64_t) ptr + (1 << FRAME_SIZE_ORDER)); + } +} + + +byteptr_t +frame_allock_block(uint32_t size) +{ + uint32_t count = (uint32_t) memory_padding((byteptr_t) (size | 0l), FRAME_SIZE_ORDER) >> FRAME_SIZE_ORDER; + return frame_alloc(count); +} + + + +/** + * preserved (not in use) +*/ +byteptr_t +frame_request(uint32_t addr, uint8_t frame_state) +{ + byteptr_t ptr = (byteptr_t) (addr | 0l); + uint32_t index = ptr_to_index(ptr); + if (!FRAME_IS_FREE(index) && !FRAME_IS_BUDDY(index)) return 0; + + /** + * find the first frame of the free block + */ + uint32_t owner = index; + while (owner > 0 && FRAME_IS_BUDDY(owner)) owner--; + buckets_remove(owner); + + /** + * split up + */ + uint32_t original_order = FRAME_ORDER(owner); + frame_array[index] = frame_state; + uint32_t order = 0; + while (order < original_order) { + uint32_t buddy = BUDDY_INDEX(index, order); + frame_array[buddy] = order; + buckets_push(buddy); + index = FRAME_OWNER(index, order); + order++; + } + return ptr; +} + + +/** + * Frame System Startup Initialization + * frame_system_preserve() should be called before frame_system_init_free_blocks() +*/ + +void +frame_system_init_frame_array(uint32_t start_addr, uint32_t end_addr) +{ + start_addr = UINT32_ALIGN(start_addr, FRAME_SIZE_ORDER); + end_addr = UINT32_PADDING(end_addr, FRAME_SIZE_ORDER); + + max_alloc_size = (end_addr - start_addr); + total_frames = max_alloc_size >> FRAME_SIZE_ORDER; + base_ptr = (byteptr_t) (start_addr | 0l); + + frame_array = (byteptr_t) startup_memory_alloc(total_frames * sizeof(byte_t)); + for (int i = 0; i < total_frames; ++i) { frame_array[i] = 0; } +} + + +uint32_t +frame_system_preserve(uint32_t start, uint32_t end) +{ + uint32_t index_s = ptr_to_index((byteptr_t) (UINT32_ALIGN(start, FRAME_SIZE_ORDER) | 0l)); + uint32_t index_e = ptr_to_index((byteptr_t) (UINT32_PADDING(end, FRAME_SIZE_ORDER) | 0l)); + + if (index_s >= total_frames || index_e > total_frames) + return 0; + while (index_s < index_e) { + frame_array[index_s++] = FRAME_PRESERVED; + } + return 1; +} + + +void +frame_system_init_free_blocks() +{ + max_alloc_order = INT32_LEFTMOST_ORDER(total_frames); + buckets = (list_head_ptr_t) startup_memory_alloc((max_alloc_order + 1) * sizeof(list_head_t)); + + for (int i = 0; i < BUCKET_COUNT; ++i) + INIT_LIST_HEAD((list_head_ptr_t) &buckets[i]); + + frame_merge_up(0, total_frames, max_alloc_order); +} + + +/** + * visualization of frame system information +*/ + +void +print_memory_layout() +{ + uart_printf("\n==== MEMORY FRAME LAYOUT ====\n"); + uint32_t index = 0; + while (index < total_frames) { + uint32_t end = index + 1; + if (FRAME_IS_FREE(index)) { + while (FRAME_IS_FREE(end) || FRAME_IS_BUDDY(end)) end++; + } + else { + while (frame_array[index] == frame_array[end]) end++; + } + uart_printf("0x%8x | %dkb\t| %s\n", index_to_ptr(index), (end - index) << 2, FRAME_TYPE(index)); + index = end; + } +} + + +void +print_buddy_layout() +{ + uart_printf("\n==== MEMORY BUDDY LAYOUT ====\n"); + uint32_t index = 0; + while (index < total_frames) { + if (FRAME_IS_FREE(index)) { + uint32_t order = frame_array[index]; + uart_printf("0x%8x | %dkb\t| free\n", index_to_ptr(index), (1 << (order + 2))); + index += (1 << order); + } + else { + uint32_t end = index + 1; + while (frame_array[index] == frame_array[end]) end++; + uart_printf("0x%8x | %dkb\t| %s\n", index_to_ptr(index), (end - index) << 2, FRAME_TYPE(index)); + index = end; + } + } +} + + +void +print_free_lists() +{ + uart_printf("\n==== FREE FRAME LISTS ====\n"); + for (int i = 0; i < BUCKET_COUNT; ++i) { + if (!list_empty(&buckets[i])) { + uart_printf("bucket: %d, size: %dkb\n", i, 1 << (i + 2)); + list_head_ptr_t pos = ((list_head_ptr_t) &buckets[i])->next; + list_for_each(pos, (list_head_ptr_t) &buckets[i]) + uart_printf(" +- 0x%8x\n", pos); + } + } +} + + +void +frame_print_info() +{ + uart_printf("\n==== FRAME SYSTEM INFO ====\n"); + uart_printf("start: 0x%8x\n", base_ptr); + uart_printf("limit: 0x%8x\n", base_ptr + max_alloc_size); + uart_printf("frame_array: 0x%8x | 0x%x bytes\n", frame_array, total_frames); + uart_printf("free_list: 0x%8x | %d buckets\n", buckets, BUCKET_COUNT); + + // print_memory_layout(); + print_buddy_layout(); + print_free_lists(); + uart_printf("\n"); +} + + +uint32_t +frame_preserved_count() +{ + uint32_t count = 0; + for (uint32_t i = 0; i < total_frames; ++i) + if (FRAME_IS_PRESERVED(i)) count++; + return count; +} \ No newline at end of file diff --git a/Lab 7/kernel/src/frame.h b/Lab 7/kernel/src/frame.h new file mode 100644 index 000000000..abad5cc63 --- /dev/null +++ b/Lab 7/kernel/src/frame.h @@ -0,0 +1,22 @@ +#ifndef __FRAME_H__ +#define __FRAME_H__ + +#include "type.h" + +#define FRAME_SIZE_ORDER 12 + +void frame_print_info(); + +void frame_release(byteptr_t ptr); +void frame_release_block(byteptr_t ptr, uint32_t count); +byteptr_t frame_alloc(uint32_t count); +byteptr_t frame_allock_block(uint32_t size); + +void frame_system_init_frame_array(uint32_t start_addr, uint32_t end_addr); +uint32_t frame_system_preserve(uint32_t start_addr, uint32_t end_addr); +void frame_system_init_free_blocks(); + + +uint32_t frame_preserved_count(); + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/info.c b/Lab 7/kernel/src/info.c new file mode 100644 index 000000000..8d8ae4e81 --- /dev/null +++ b/Lab 7/kernel/src/info.c @@ -0,0 +1,187 @@ +#include "uart.h" +#include "mailbox.h" +#include "string.h" + + +void +info_board_revision() +{ + volatile unsigned int *mbox = mailbox; + + mbox[0] = 7 * 4; + mbox[1] = MBOX_REQUEST; + + mbox[2] = MBOX_TAG_GETREVISION; + mbox[3] = 4; + mbox[4] = MBOX_TAG_REQUEST; + mbox[5] = 0; + + mbox[6] = MBOX_TAG_END; + + mailbox_call(MBOX_CH_PROP, mbox); // message passing procedure call + + uart_str("Board revision: \t"); + uart_str("0x"); + uart_hex(mbox[5]); // it should be 0xa020d3 for rpi3 b+ + uart_endl(); +} + + +void +info_memory() +{ + volatile unsigned int *mbox = mailbox; + + mbox[0] = 8 * 4; + mbox[1] = MBOX_REQUEST; + + mbox[2] = MBOX_TAG_GETMEMORY; + mbox[3] = 8; + mbox[4] = MBOX_TAG_REQUEST; + mbox[5] = 0; // memory basee address + mbox[6] = 0; // memory size + + mbox[7] = MBOX_TAG_END; + + mailbox_call(MBOX_CH_PROP, mbox); + + uart_line("Arm memory info:"); + + uart_str(" > memory base: \t"); + uart_str("0x"); + uart_hex(mbox[5]); + uart_endl(); + + uart_str(" > memory size: \t"); + uart_str("0x"); + uart_hex(mbox[6]); + uart_endl(); +} + + +void +info_videocore() +{ + volatile unsigned int *mbox = mailbox; + char buffer[40]; + + /* size & request */ + mbox[0] = 35 * 4; + mbox[1] = MBOX_REQUEST; + + /* tags begin */ + mbox[2] = MBOX_TAG_GETVCMEM; + mbox[3] = 8; + mbox[4] = MBOX_TAG_REQUEST; + mbox[5] = 0; // VC memory base + mbox[6] = 0; // VC memory size + + mbox[7] = MBOX_TAG_ALLOCATEFB; // Allocate frame buffer command + mbox[8] = 8; + mbox[9] = MBOX_TAG_REQUEST; + mbox[10] = 4096; // alignment in bytes ==> frame buffer base address + mbox[11] = 0; // ==> frame buffer size + + mbox[12] = MBOX_TAG_GETPHYSICALWH; + mbox[13] = 8; + mbox[14] = MBOX_TAG_REQUEST; + mbox[15] = 0; // display width + mbox[16] = 0; // display height + + mbox[17] = MBOX_TAG_GETVIRTUALWH; + mbox[18] = 8; + mbox[19] = MBOX_TAG_REQUEST; + mbox[20] = 0; // virtual width + mbox[21] = 0; // virtual height + + mbox[22] = MBOX_TAG_GETVIRTUALOFFSET; + mbox[23] = 8; + mbox[24] = MBOX_TAG_REQUEST; + mbox[25] = 0; // offset X + mbox[26] = 0; // offset Y + + mbox[27] = MBOX_TAG_GETDEPTH; + mbox[28] = 4; + mbox[29] = MBOX_TAG_REQUEST; + mbox[30] = 0; // depth + + mbox[31] = MBOX_TAG_GETPIXELORDER; + mbox[32] = 4; + mbox[33] = MBOX_TAG_REQUEST; + mbox[34] = 0; // 0x0: BGR, 0x1: RGB + + mbox[35] = MBOX_TAG_GETPITCH; + mbox[36] = 4; + mbox[37] = MBOX_TAG_REQUEST; + mbox[38] = 0; // pitch + + /* tags end */ + mbox[39] = MBOX_TAG_END; + + mailbox_call(MBOX_CH_PROP, mbox); // message passing procedure call, you should implement it following the 6 steps provided above. + + uart_line("VideoCore info:"); + + uart_str(" > memory base: \t"); + uart_str("0x"); + uart_hex(mbox[5]); + uart_endl(); + + uart_str(" > memory size: \t"); + uart_str("0x"); + uart_hex(mbox[6]); + uart_endl(); + + uart_str(" > frame buffer base: \t"); + uart_str("0x"); + uart_hex(mbox[10] & 0x3fffffff); + uart_str("\r\n"); + + uart_str(" > frame buffer size: \t"); + uart_str("0x"); + uart_hex(mbox[11]); + uart_endl(); + + uart_str(" > physical width: \t"); + uint32_to_ascii(mbox[15], buffer); + uart_str(buffer); + uart_str("\r\n"); + + uart_str(" > physical height: \t"); + uint32_to_ascii(mbox[16], buffer); + uart_str(buffer); + uart_endl(); + + uart_str(" > virtual width: \t"); + uint32_to_ascii(mbox[20], buffer); + uart_str(buffer); + uart_endl(); + + uart_str(" > virtual height: \t"); + uint32_to_ascii(mbox[21], buffer); + uart_str(buffer); + uart_endl(); + + uart_str(" > buffer offset X: \t"); + uint32_to_ascii(mbox[25], buffer); + uart_str(buffer); + uart_endl(); + + uart_str(" > buffer offset Y: \t"); + uint32_to_ascii(mbox[26], buffer); + uart_str(buffer); + uart_endl(); + + uart_str(" > depth: \t\t"); + uint32_to_ascii(mbox[30], buffer); + uart_str(buffer); + uart_endl(); + + uart_str(" > pixel order: \t"); + if (mbox[34] == 0x0) uart_line("BGR"); else uart_line("RGB"); + + uart_str(" > pitch: \t\t"); + uint32_to_ascii(mbox[38], buffer); + uart_str(buffer); + uart_endl(); +} diff --git a/Lab 7/kernel/src/info.h b/Lab 7/kernel/src/info.h new file mode 100644 index 000000000..4d14c1809 --- /dev/null +++ b/Lab 7/kernel/src/info.h @@ -0,0 +1,10 @@ +#ifndef __INFO_H__ +#define __INFO_H__ + +#include "type.h" + +void info_board_revision(); +void info_memory(); +void info_videocore(); + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/initramfs.c b/Lab 7/kernel/src/initramfs.c new file mode 100644 index 000000000..e17e5d292 --- /dev/null +++ b/Lab 7/kernel/src/initramfs.c @@ -0,0 +1,165 @@ +#include "initramfs.h" +#include "list.h" +#include "vfs.h" +#include "string.h" +#include "stat.h" +#include "initrd.h" +#include "uart.h" +#include "memory.h" + + +static int +lookup(struct vnode *dir_node, struct vnode **target, const char *component_name) +{ + vnode_ptr vnode = 0; + list_for_each_entry(vnode, &dir_node->children, self) { + if (!(str_cmp((byteptr_t) vnode->name, (byteptr_t) component_name))) { + *target = vnode; + return 0; + } + } + return -1; +} + + +static int +create(struct vnode *dir_node, struct vnode **target, const char *component_name) +{ + return -1; +} + + +static int +mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name) +{ + return -1; +} + + +struct vnode_operations initramfs_v_ops = { + lookup, + create, + mkdir, +}; + + + +static int +write(struct file *file, const void *buf, int32_t len) +{ + uart_printf("[DEBUG] initramfs_write - len: %d\n", len); + return 0; +} + + +static int +read(struct file *file, void *buf, int32_t len) +{ + struct vnode *vnode = file->vnode; + if (!S_ISREG(vnode->f_mode)) { + uart_printf("[INFO] initramfs_read - not a regular file\n"); + return -1; + } + + int min = (len > (vnode->content_size - file->f_pos - 1)) ? (vnode->content_size - file->f_pos - 1) : len; // -1 for EOF; + if (min <= 0) { return -1; } // f_pos at EOF or len==0; + file->f_pos += min; + memory_copy((byteptr_t) buf, (byteptr_t) ((uint64_t) vnode->content + file->f_pos), min); + + return min; +} + + +static int +open(struct vnode *file_node, struct file **target) +{ + return 0; +} + + +static int +close(struct file *file) +{ + kfree((byteptr_t) file); + return 0; +} + + +static long +lseek64(struct file *file, long offset, int whence) +{ + return 0; +} + + +struct file_operations initramfs_f_ops = { + write, + read, + open, + close, + lseek64, +}; + + +static vnode_ptr dir_node; + + +static void +_create_node(byteptr_t name, byteptr_t content, uint32_t size) +{ + vnode_ptr target = 0; + + if (!lookup(dir_node, &target, name)) { + uart_printf("[INFO] create_init - the %s file is already exist\n", name); return; + } + + vnode_ptr new_vnode = vnode_create(name, S_IFREG); + new_vnode->mount = dir_node->mount; + new_vnode->v_ops = dir_node->v_ops; + new_vnode->f_ops = dir_node->f_ops; + new_vnode->parent = dir_node; + + new_vnode->content = content; + new_vnode->content_size = size; + + list_add_tail(&new_vnode->self, &dir_node->children); + dir_node->child_num += 1; +} + + +static void +init_cpio_files() +{ + if (vfs_lookup("/initramfs", &dir_node)) { uart_printf("[INFO] init_cpio_files - fail to lookup dir\n"); } + initrd_traverse(&_create_node); +} + + +static int +setup_mount(struct filesystem *fs, struct mount *mount) +{ + // should set mount->root as a obj before call setup_mount + mount->root->mount = mount; + mount->root->f_ops = &initramfs_f_ops; + mount->root->v_ops = &initramfs_v_ops; + mount->fs = fs; + + // clear the internal content + INIT_LIST_HEAD(&mount->root->children); + mount->root->child_num = 0; + mount->root->content = 0; + mount->root->content_size = 0; + init_cpio_files(); + return 0; +} + + +struct filesystem * +initramfs_create() +{ + fs_ptr fs = (fs_ptr) kmalloc(sizeof(struct filesystem)); + fs->name = "initramfs"; + fs->setup_mount = &setup_mount; + INIT_LIST_HEAD(&fs->list); + return fs; +} \ No newline at end of file diff --git a/Lab 7/kernel/src/initramfs.h b/Lab 7/kernel/src/initramfs.h new file mode 100644 index 000000000..000a8a679 --- /dev/null +++ b/Lab 7/kernel/src/initramfs.h @@ -0,0 +1,9 @@ +#ifndef __INITRAM_FS_H__ +#define __INITRAM_FS_H__ + +struct filesystem * initramfs_create(); + +extern struct file_operations initramfs_f_ops; +extern struct vnode_operations initramfs_v_ops; + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/initrd.c b/Lab 7/kernel/src/initrd.c new file mode 100644 index 000000000..c3e99ebaf --- /dev/null +++ b/Lab 7/kernel/src/initrd.c @@ -0,0 +1,190 @@ +#include "initrd.h" +#include "type.h" +#include "uart.h" +#include "memory.h" +#include "string.h" +#include "cpio.h" +#include "sched.h" +#include "task.h" +#include "kernel.h" +#include "thread.h" + + +typedef struct { + + byteptr_t name; + byteptr_t content; + uint32_t size; + +} finfo_t; + +typedef finfo_t* finfoptr_t; + + +static byteptr_t +_initrd_next(const byteptr_t cpio_addr, finfoptr_t info) +{ + byteptr_t _addr = (byteptr_t) cpio_addr; + + if (!memory_cmp(_addr, "070701", 6) && memory_cmp(_addr + sizeof(cpio_t), "TRAILER!!!", 10)) { + + cpio_ptr_t header = (cpio_ptr_t) _addr; + + uint64_t name_size = ascii_to_uint64(header->c_namesize, (uint32_t) sizeof(header->c_namesize)); + uint64_t file_size = ascii_to_uint64(header->c_filesize, (uint32_t) sizeof(header->c_filesize)); + + uint64_t content_offset = (uint64_t) memory_padding((const byteptr_t) (sizeof(cpio_t) + name_size), 2); + uint64_t total_size = (uint64_t) memory_padding((const byteptr_t) (content_offset + file_size), 2); + + info->name = _addr + sizeof(cpio_t); + info->size = file_size; + info->content = _addr + content_offset; + + return _addr + total_size; + } + + return nullptr; +} + + +static byteptr_t +_initrd_find(const byteptr_t cpio_addr, const byteptr_t name, finfoptr_t info_ptr) +{ + byteptr_t curr = (byteptr_t) cpio_addr; + byteptr_t next = _initrd_next(cpio_addr, info_ptr); + + while (next) { + if (str_eql(info_ptr->name, name)) { + return curr; + } + curr = next; + next = _initrd_next(curr, info_ptr); + } + return nullptr; +} + + +static byteptr_t _cpio_ptr = nullptr; +static byteptr_t _cpio_end = nullptr; + +byteptr_t initrd_get_ptr() { return _cpio_ptr; } +void initrd_set_ptr(byteptr_t ptr) { _cpio_ptr = ptr; } +byteptr_t initrd_get_end() { return _cpio_end; } +void initrd_set_end(byteptr_t ptr) { _cpio_end = ptr; } + + +static byteptr_t +_initrd_find_file(const byteptr_t name, finfoptr_t info_ptr) +{ + byteptr_t cpio_addr = initrd_get_ptr(); + byteptr_t file = _initrd_find(cpio_addr, name, info_ptr); + if (!file) { uart_line("No such file or directory."); return 0; } + if (info_ptr->size == 0) { uart_line("It's a directory."); return 0; } + return file; +} + + +void +initrd_list() +{ + byteptr_t cpio_addr = initrd_get_ptr(); + finfo_t info; + byteptr_t next_addr = _initrd_next(cpio_addr, &info); + while (next_addr) { + mini_uart_putln(info.name); + next_addr = _initrd_next(next_addr, &info); + } +} + + +static void +_print_file(const byteptr_t content, uint32_t size) +{ + byteptr_t cur = (byteptr_t) content; + while (size--) { + if (*cur == '\n') { + uart_put('\r'); + } + uart_put(*cur); + cur++; + } + uart_endl(); +} + + +void +initrd_cat(const byteptr_t name) +{ + finfo_t info; + byteptr_t file = _initrd_find_file(name, &info); + if (file) { _print_file(info.content, info.size); } +} + + +static void +run_user_process(uint64_t program) // a kernel thread of +{ + uart_printf("[DEBUG] Kernel process (run_user_process) started. EL %d\r\n", get_el()); + int err = task_to_user_mode(current_task(), program); + if (err < 0) { + uart_printf("[DEBUG] Error while moving process to user mode\n"); + } +} + + +void +initrd_exec(const byteptr_t name) +{ + finfo_t info; + byteptr_t file = _initrd_find_file(name, &info); + if (file) { + uart_printf("[DEBUG] initrd_exec - info: %s, size: 0x%x\n", info.name, info.size); + thread_create_user((uint64_t) run_user_process, (uint64_t) info.content, info.size); + } +} + + + +// #define USTACK_SIZE 0x1000 + +// static void +// _execute_user_program(byteptr_t content, byteptr_t ustack_sp, byteptr_t sp) +// { +// asm volatile("mov x0, 0x340 \n"); // b'1101 00 0000 +// asm volatile("msr spsr_el1, x0 \n"); // unmask EL1 IRQ +// asm volatile("msr elr_el1, %0 \n" ::"r"(content)); +// asm volatile("msr sp_el0, %0 \n" ::"r"(ustack_sp + USTACK_SIZE)); +// if (sp) asm volatile("mov sp, %0 \n" ::"r"(sp)); +// asm volatile("eret \n"); +// } + + +void +initrd_exec_replace(const byteptr_t name) +{ + finfo_t info; + byteptr_t file = _initrd_find_file(name, &info); + if (file) { + // uart_printf("initrd_exec_replace - info: %s, size: 0x%x, ", info.name, info.size); + // int32_t pid = + thread_replace_user((uint64_t) 0, (uint64_t) info.content, info.size); + // uart_printf("pid = %d\n", pid); + run_user_process((uint64_t) current_task()->user_prog); + } +} + + +void +initrd_traverse(cpio_cb * cb) +{ + finfo_t info; + byteptr_t cpio_addr = initrd_get_ptr(); + byteptr_t curr = (byteptr_t) cpio_addr; + byteptr_t next = _initrd_next(cpio_addr, &info); + + while (next) { + (*cb)(info.name, info.content, info.size); + curr = next; + next = _initrd_next(curr, &info); + } +} \ No newline at end of file diff --git a/Lab 7/kernel/src/initrd.h b/Lab 7/kernel/src/initrd.h new file mode 100644 index 000000000..c6385c7e8 --- /dev/null +++ b/Lab 7/kernel/src/initrd.h @@ -0,0 +1,24 @@ +#ifndef __INITRD_H__ +#define __INITRD_H__ + +#include "type.h" + + +byteptr_t initrd_get_ptr(); +void initrd_set_ptr(byteptr_t ptr); +byteptr_t initrd_get_end(); +void initrd_set_end(byteptr_t ptr); + +void initrd_list(); +void initrd_cat(const byteptr_t file); +void initrd_exec(const byteptr_t name); +void initrd_exec_replace(const byteptr_t name); + +// int initrd_call_exec(const char* name, char *const argv[]); + + +typedef void (cpio_cb) (byteptr_t name, byteptr_t content, uint32_t size); + +void initrd_traverse(cpio_cb * cb); + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/kernel_main.c b/Lab 7/kernel/src/kernel_main.c new file mode 100644 index 000000000..1c41994c2 --- /dev/null +++ b/Lab 7/kernel/src/kernel_main.c @@ -0,0 +1,86 @@ +#include "kernel.h" +#include "uart.h" +#include "irq.h" +#include "shell.h" +#include "dtb.h" +#include "initrd.h" +#include "string.h" +#include "exception.h" +#include "frame.h" +#include "memory.h" +#include "sched.h" +#include "thread.h" +#include "core_timer.h" +#include "delay.h" +#include "chunk.h" +#include "vfs.h" + + +/** + * Note: + * 1. Spin tables for multicore boot (0x0000 - 0x1000) + * 2. Kernel image in the physical memory (0x80000 - ) + * 3. Initramfs (0x08000000 - 0x08002200) + * 4. Devicetree (Optional, if you have implement it) (0x08200000 - 0x08215988) + * 5. Your simple allocator (startup allocator) +*/ + +extern byte_t kernel_start; +extern byte_t kernel_end; + +static void +_kernel_init(uint64_t x0, void (*ptr)(uint64_t)) +{ + dtb_set_ptr((byteptr_t) x0); + fdt_traverse(fdt_find_initrd_addr); + memory_system_init(0x0, 0x3C000000); + + uart_init(); + + uart_printf("+------------------------------+\n"); + uart_printf("| Lab 7 - Kernel |\n"); + uart_printf("+------------------------------+\n"); + + uart_printf("| main() = 0x%8x |\n", ptr); + uart_printf("| kernel_start = 0x%8x |\n", &kernel_start); + uart_printf("| kernel_end = 0x%8x |\n", &kernel_end); + + uart_printf("| Initrd_start = 0x%8x |\n", initrd_get_ptr()); + uart_printf("| Initrd_end = 0x%8x |\n", initrd_get_end()); + + uart_printf("| DTB_start = 0x%8x |\n", dtb_get_ptr()); + uart_printf("| DTB_end = 0x%8x |\n", dtb_get_end()); + + uart_printf("| frame preserved = %d |\n", frame_preserved_count()); + + uart_line("+------------------------------+"); + + uint64_t tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); + + vfs_init(); + + exception_l1_enable(); +} + + +void idle() +{ + while (1) { + kill_zombies(); + schedule(); + } +} + + +void +kernel_main(uint64_t x0) +{ + _kernel_init(x0, &kernel_main); + scheduler_init(); + thread_create_shell((uint64_t) shell); + // initrd_exec("syscall.img"); + idle(); +} diff --git a/Lab 7/kernel/src/kernel_start.S b/Lab 7/kernel/src/kernel_start.S new file mode 100644 index 000000000..8dd2c4ff2 --- /dev/null +++ b/Lab 7/kernel/src/kernel_start.S @@ -0,0 +1,99 @@ + .section ".text.boot" + .global _start +_start: + mov x10, x0 + + // read cpu id, hang slave cores + mrs x1, mpidr_el1 + and x1, x1, #0xFF // Check processor id in last 8 bits + cbnz x1, _hang + +_master: + // switch exception level from EL2 to EL1 + bl _el2_to_el1 + + // set vbar_el1 register + bl set_exception_vector_table + + // set top of stack just before our code (0x80000) + ldr x1, = kernel_start + mov sp, x1 + + // clear bss + bl _memzero + + // jump to c, should not return + mov x0, x10 + bl kernel_main + + // Hang for all non-primary CPU and this core when c code failed +_hang: + wfe + b _hang + +_memzero: + ldr x0, =_bss_begin + ldr x1, =_bss_size +_setzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt _setzero + ret + + +_el2_to_el1: + mov x1, (1 << 31) // hcr_el2: Execution state control for EL2 + msr hcr_el2, x1 // [31]: 1 = EL1 is AArch64, 0 = EL1/EL0 is AArch32 + + mov x1, 0x3c5 // spsr_el2: Holds the saved process state when an exception is taken to EL2. + msr spsr_el2, x1 // [1111]00[0101] -> (1) EL2-PSTATE.DAIF Disabled (2) Exception level = EL1h + + msr elr_el2, lr // elr_el2: When taking an exception to EL2, holds the address to return to. + eret // Perform an exception return. EL2 -> EL1 + + +/* + +SPSR_EL2: + +D,bit[9]: Process state Debug mask +A,bit[8]: SError (System Error) mask bit +I,bit[7]: IRQ mask bit +F,bit[6]: FIQ mask bit +M[4]: Execution state that the exception was taken from. A value of 0 indicates AArch64. +M[3:0]: AArch64 Exception level and selected Stack Pointer. + + +M[3:0] Meaning +------------------------------------ +0b0000 EL0. +0b0100 EL1 with SP_EL0 (ELt). +0b0101 EL1 with SP_EL1 (EL1h). +0b1000 EL2 with SP_EL0 (EL2t). +0b1001 EL2 with SP_EL2 (EL2h). + + */ + + + .global current_exception_level +current_exception_level: + mrs x0, CurrentEl + lsr x0, x0, #2 // remove reserved bits + and x0, x0, 0x3 + ret + + + .global align +align: + sub x1, x1, #1 + add x0, x0, x1 + mvn x1, x1 + and x0, x0, x1 + ret + + + .globl get_el +get_el: + mrs x0, CurrentEL + lsr x0, x0, #2 + ret \ No newline at end of file diff --git a/Lab 7/kernel/src/linker.ld b/Lab 7/kernel/src/linker.ld new file mode 100644 index 000000000..945ada002 --- /dev/null +++ b/Lab 7/kernel/src/linker.ld @@ -0,0 +1,23 @@ + +SECTIONS +{ + . = 0x80000; + kernel_start = .; + + .text.boot : { *(.text.boot) } + .text : { *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + + . = ALIGN(0x8); + + _bss_begin = .; + .bss : { *(.bss*) } + _bss_end = .; + + kernel_end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.en_frame*) } +} + +_bss_size = (_bss_end - _bss_begin) >> 3; diff --git a/Lab 7/kernel/src/mailbox.c b/Lab 7/kernel/src/mailbox.c new file mode 100644 index 000000000..dcf06b7f4 --- /dev/null +++ b/Lab 7/kernel/src/mailbox.c @@ -0,0 +1,52 @@ +#include "type.h" +#include "mmio.h" +#include "mailbox.h" + + +/* mailbox message buffer */ +volatile unsigned int __attribute__((aligned(16))) mailbox[36]; + +#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880) + +#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x00)) +#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x10)) +#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x14)) +#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x18)) +#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x1C)) +#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x20)) + + +/** + * Make a mailbox call. Returns 0 on failure, non-zero on success + */ +uint32_t +mailbox_call(unsigned char ch, volatile unsigned int *mbox) +{ + /* step 1. Combine the message address (upper 28 bits) with channel number (lower 4 bits) */ + unsigned int r = (((unsigned int)((unsigned long) mbox) & ~0xF) | (ch & 0xF)); + + /* step 2. Check if Mailbox 0 status register's full flag is set */ + /* wait until we can write to the mailbox */ + do { asm volatile("nop"); } while (*MBOX_STATUS & MBOX_FULL); + + /* step 3. If not full, then you can write to Mailbox 1 Read/Write register */ + /* write the address of our message to the mailbox with channel identifier */ + *MBOX_WRITE = r; + + /* now wait for the response */ + while(1) { + + /* 4. Check if Mailbox 0 status register's empty flag is set. */ + /* is there a response? */ + do { asm volatile("nop"); } while (*MBOX_STATUS & MBOX_EMPTY); + + /* 5. If not empty, then you can read from Mailbox 0 Read/Write register. */ + /* is it a response to our message? */ + if (r == *MBOX_READ) { + /* 6. Check if the value is the same as you wrote in step 1. */ + /* is it a valid successful response? */ + return mbox[1] == MBOX_RESPONSE; + } + } + return 0; +} diff --git a/Lab 7/kernel/src/mailbox.h b/Lab 7/kernel/src/mailbox.h new file mode 100644 index 000000000..7c9b88852 --- /dev/null +++ b/Lab 7/kernel/src/mailbox.h @@ -0,0 +1,77 @@ +/*** + Buffer contents: + + u32: size in bytes, (x+1) * 4, including the end tag + u32: Request code / response code + u8 ...: sequence of concatenated tags + u32: the end tag + u8 ...: padding + + + Tag format: + + u32: tag identifier + u32: value buffer size in bytes + u32: request code / response code + b31 = 0: request, b30-b0: reserved + b31 = 1: response, b30-b0: value length in bytes + u8 ...: value buffer + u8 ...: padding to align to 32 bits +***/ + + +#ifndef __MAILBOX_H__ +#define __MAILBOX_H__ + +#define MBOX_RESPONSE 0x80000000 + +#define MBOX_EMPTY 0x40000000 +#define MBOX_FULL 0x80000000 + +#define MBOX_REQUEST 0x00000000 +#define MBOX_RESPONSE_SUCCEED 0x80000000 +#define MBOX_RESPONSE_FAILED 0x80000001 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 // we only use channel 8 (CPU->GPU) + +/* tags */ + +#define MBOX_TAG_GETFWREVISION 0x00000001 // u32: firmware revision +#define MBOX_TAG_GETMODEL 0x00010001 // u32: board model +#define MBOX_TAG_GETREVISION 0x00010002 // u32: board revision +#define MBOX_TAG_GETMACADDR 0x00010003 // u8 * 6: MAC address in network byte order +#define MBOX_TAG_GETSERIAL 0x00010004 // u64: board serial +#define MBOX_TAG_GETMEMORY 0x00010005 // u32: base, u32: size +#define MBOX_TAG_GETVCMEM 0x00010006 // u32: base, u32: size +#define MBOX_TAG_GETCLOCKS 0x00010007 // u32: parent clock id, u32: clock id, (repeated) + +#define MBOX_TAG_ALLOCATEFB 0x00040001 // (u32: alignment in bytes) -> u32: base address, u32: size + +#define MBOX_TAG_GETPHYSICALWH 0x00040003 // u32: width in pixels, u32: height in pixels +#define MBOX_TAG_GETVIRTUALWH 0x00040004 // u32: width in pixels, u32: height in pixels +#define MBOX_TAG_GETDEPTH 0x00040005 // u32: bits per pixel +#define MBOX_TAG_GETPIXELORDER 0x00040006 // u32: 0x0=BGR, 0x1=RGB +#define MBOX_TAG_GETALPHAMODE 0x00040007 // u32: 0x0=enalbed, 0x1=reversed, 0x2=ignored +#define MBOX_TAG_GETPITCH 0x00040008 // u32: bytes per line +#define MBOX_TAG_GETVIRTUALOFFSET 0x00040009 // u32: X in pixels, u32: Y in pixels +#define MBOX_TAG_GETOVERSCAN 0x0004000a +#define MBOX_TAG_GETPALETTE 0x0004000b + +#define MBOX_TAG_REQUEST 0x00000000 +#define MBOX_TAG_END 0x00000000 + +/* a properly aligned buffer */ +extern volatile unsigned int mailbox[36]; + +uint32_t mailbox_call(unsigned char ch, volatile unsigned int *mbox); + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/memory.S b/Lab 7/kernel/src/memory.S new file mode 100644 index 000000000..df012b56e --- /dev/null +++ b/Lab 7/kernel/src/memory.S @@ -0,0 +1,15 @@ +.globl memcpy +memcpy: + ldr x3, [x1], #8 + str x3, [x0], #8 + subs x2, x2, #8 + b.gt memcpy + ret + + +.globl memzero +memzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero + ret \ No newline at end of file diff --git a/Lab 7/kernel/src/memory.c b/Lab 7/kernel/src/memory.c new file mode 100644 index 000000000..9eeaf186a --- /dev/null +++ b/Lab 7/kernel/src/memory.c @@ -0,0 +1,154 @@ +#include "memory.h" +#include "chunk.h" +#include "frame.h" +#include "dtb.h" +#include "initrd.h" + + +byteptr_t +memory_align(const byteptr_t p, uint32_t s) { + uint64_t x = (uint64_t) p; + s = (1 << s); + return (byteptr_t) (x & ~(s - 1)); +} + + +byteptr_t +memory_padding(const byteptr_t p, uint32_t s) { + uint64_t x = (uint64_t) p; + s = (1 << s); + return (byteptr_t) ((x + s - 1) & (~(s - 1))); +} + + +int32_t +memory_cmp(byteptr_t s1, byteptr_t s2, int32_t n) +{ + byteptr_t a = s1, b = s2; + while (n-- > 0) { if (*a != *b) { return *a - *b; } a++; b++; } + return 0; +} + + +void +memory_copy(byteptr_t dest, byteptr_t source, int32_t size) +{ + while (size > 0) { *dest++ = *source++; --size; } +} + + +void +memory_zero(byteptr_t dest, int32_t size) +{ + while (size > 0) { *dest++ = 0; --size; } +} + + +#define STARTUP_HEAP_START 0x120000 +#define STARTUP_HEAP_END 0x180000 + +extern byte_t kernel_end; + +static byteptr_t _smalloc_cur = (byteptr_t) (STARTUP_HEAP_START | 0l); +static byteptr_t _smalloc_limit = (byteptr_t) (STARTUP_HEAP_END | 0l); + + + +byteptr_t +startup_memory_alloc(uint32_t size) +{ + size = (uint32_t) memory_padding((byteptr_t) (size | 0l), 3); + if ((uint32_t) (_smalloc_cur + size) > (uint32_t) _smalloc_limit) return 0; + byteptr_t ret_ptr = _smalloc_cur; + _smalloc_cur += size; + return ret_ptr; +} + + +byteptr_t +memory_alloc(uint32_t size) +{ + size = (uint32_t) memory_padding((byteptr_t) (size | 0l), 3); + if ((uint32_t) (_smalloc_cur + size) > (uint32_t) _smalloc_limit) return 0; + byteptr_t ret_ptr = _smalloc_cur; + _smalloc_cur += size; + return ret_ptr; +} + + +extern byte_t kernel_start, kernel_end; + +void +memory_system_init(uint32_t start, uint32_t end) +{ + frame_system_init_frame_array(start, end); + + frame_system_preserve(0, 0x1000); // spin table + frame_system_preserve(CHUNK_TABLE_ADDR, CHUNK_TABLE_END); + frame_system_preserve(0x60000, 0x80000); // call stack for kernel + frame_system_preserve((uint32_t) &kernel_start, (uint32_t) &kernel_end + 0x4000); // preserve some space for sprintf + frame_system_preserve(STARTUP_HEAP_START, STARTUP_HEAP_END); + frame_system_preserve((uint32_t) initrd_get_ptr(), (uint32_t) initrd_get_end()); + frame_system_preserve((uint32_t) dtb_get_ptr(), (uint32_t) dtb_get_end()); + + frame_system_init_free_blocks(); + init_chunk_table(); +} + +#define BLOCK_HEADER_SIZE 8 + +typedef struct block_header { + uint32_t count; + uint32_t size; +} block_header_t; + +typedef block_header_t * block_header_ptr; + +#include "uart.h" + +byteptr_t +kmemory_alloc(uint32_t size) +{ + // uart_printf("[DEBUG] kmemory_alloc - size: %d, %d\n", size, size + BLOCK_HEADER_SIZE); + + if (size <= chunk_max_size()) + return chunk_request(size); + + int32_t count = UINT32_PADDING((size + BLOCK_HEADER_SIZE), FRAME_SIZE_ORDER) >> FRAME_SIZE_ORDER; + + uart_printf("[DEBUG] kmemory_alloc - size: 0x%x, count: %d\n", size + BLOCK_HEADER_SIZE, count); + + byteptr_t block = frame_alloc(count); + + ((block_header_ptr) block)->count = count; + ((block_header_ptr) block)->size = size + BLOCK_HEADER_SIZE; + + return block + BLOCK_HEADER_SIZE; +} + + +void +kmemory_release(byteptr_t ptr) +{ + // uart_printf("[DEBUG] kmemory_release - ptr: 0x%x\n", ptr); + + if ((uint32_t) ptr & chunk_data_offset()) { + chunk_release(ptr); + return; + } + + ptr = ptr - BLOCK_HEADER_SIZE; + uint32_t count = ((block_header_ptr) ptr)->count; + for (uint32_t i = 0; i < count; ++i) { + frame_release(ptr); + ptr = (byteptr_t) ((uint64_t) ptr + (1 << FRAME_SIZE_ORDER)); + } +} + + +void +memory_print_info() +{ + frame_print_info(); + chunk_system_infro(); +} \ No newline at end of file diff --git a/Lab 7/kernel/src/memory.h b/Lab 7/kernel/src/memory.h new file mode 100644 index 000000000..2b957c083 --- /dev/null +++ b/Lab 7/kernel/src/memory.h @@ -0,0 +1,28 @@ +#ifndef __MEMORY_H__ +#define __MEMORY_H__ + +#include "type.h" +#include "frame.h" + + +int32_t memory_cmp(byteptr_t s1, byteptr_t s2, int32_t n); +byteptr_t memory_align(const byteptr_t p, uint32_t s); +byteptr_t memory_padding(const byteptr_t p, uint32_t s); +void memory_copy(byteptr_t dest, byteptr_t source, int32_t size); +void memory_zero(byteptr_t dest, int32_t size); + +void memory_system_init(uint32_t start, uint32_t end); +void memory_print_info(); + +byteptr_t memory_alloc(uint32_t size); +byteptr_t startup_memory_alloc(uint32_t size); + +byteptr_t kmemory_alloc(uint32_t size); +void kmemory_release(byteptr_t ptr); + +#define malloc memory_alloc +#define smalloc startup_memory_alloc +#define kmalloc kmemory_alloc +#define kfree kmemory_release + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/mini_uart.c b/Lab 7/kernel/src/mini_uart.c new file mode 100644 index 000000000..7da365ed9 --- /dev/null +++ b/Lab 7/kernel/src/mini_uart.c @@ -0,0 +1,294 @@ +#include "type.h" +#include "gpio.h" +#include "aux.h" +#include "delay.h" +#include "irq.h" +#include "uart.h" +#include "sprintf.h" + + +#define BUFFER_SIZE 0x100 +#define BUFFER_END 0xFF + +static uint8_t _read_buffer[BUFFER_SIZE]; +static uint8_t _write_buffer[BUFFER_SIZE]; + +static uint32_t _read_start = 0, _read_end = 0; +static uint32_t _write_start = 0, _write_end = 0; + +static void +read_buffer_add(uint8_t c) +{ + _read_buffer[_read_end++] = c; + _read_end &= BUFFER_END; +} + +static uint8_t +read_buffer_get() +{ + uint8_t c = _read_buffer[_read_start++]; + _read_start &= BUFFER_END; + return c; +} + +static uint32_t +read_buffer_empty() +{ + return _read_start == _read_end; +} + + +static void +write_buffer_add(uint8_t c) +{ + _write_buffer[_write_end++] = c; + _write_end &= BUFFER_END; +} + +static uint8_t +write_buffer_get() +{ + uint8_t c = _write_buffer[_write_start++]; + _write_start &= BUFFER_END; + return c; +} + +static uint32_t +write_buffer_empty() +{ + return _write_start == _write_end; +} + + + + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void +mini_uart_init(void) +{ + /* + setup GPIO pins + */ + + uint32_t selector; + + selector = *GPFSEL1; + selector &= ~((7<<12)|(7<<15)); // clean gpio14 and gpio15 + selector |= (2<<12)|(2<<15); // set alt5 for gpio14 and gpio15 + *GPFSEL1 = selector; + + *GPPUD = 0; + + delay_cycles(150); + + *GPPUDCLK0 = (1<<14)|(1<<15); // enable pins 14 and 15 + + delay_cycles(150); + + *GPPUDCLK0 = 0; // flush GPIO setup + + /* + setup AUX mini UART + */ + + *AUX_ENABLES |= 1; // Enable UART1, AUX mini uart (this also enables access to its registers) + *AUX_MU_CNTL = 0; // Disable auto flow control and disable receiver and transmitter (for now) + + *AUX_MU_LCR = 3; // Enable 8 bit mode + *AUX_MU_MCR = 0; // Set RTS line to be always high + + *AUX_MU_IER = 0; // Disable receive and transmit interrupts + + *AUX_MU_IIR = 0xc6; // disable interrupts + *AUX_MU_BAUD = 270; // Set baud rate to 115200 + + *AUX_MU_CNTL = 3; // Finally, enable transmitter and receiver + + + /* + init asynchronous buffers + */ + + _read_start = _read_end = 0; + _write_start = _write_end = 0; +} + + +/** + * Receive a character + * ref : BCM2837-ARM-Peripherals p5 + * AUX_MU_LSR_REG bit_0 == 1 -> readable + */ +uint8_t +mini_uart_getc() +{ + /* wait until something is in the buffer */ + do { asm volatile("nop"); } while (!(*AUX_MU_LSR & 0x01)); + /* read it and return */ + uint8_t r = (uint8_t)(*AUX_MU_IO & 0xFF); + /* convert carriage return to newline */ + return r == '\r' ? '\n' : r; +} + +uint8_t +mini_uart_getb() +{ + /* wait until something is in the buffer */ + do { asm volatile("nop"); } while (!(*AUX_MU_LSR & 0x01)); + /* read it and return */ + return (uint8_t)(*AUX_MU_IO | 0xFF); +} + + +/** + * Send a character + * ref : BCM2837-ARM-Peripherals p5 + * AUX_MU_LSR_REG bit_5 == 1 -> writable + */ +void mini_uart_putc(uint8_t c) +{ + /* wait until we can send */ + do { asm volatile("nop"); } while (!(*AUX_MU_LSR & 0x20)); + /* write the character to the buffer */ + *AUX_MU_IO = c; +} + + +/** + * Display a string + */ +void +mini_uart_puts(byteptr_t s) +{ + while (*s) { + mini_uart_putc(*s++); + } +} + +/** + * Display a string with the newline + */ +void +mini_uart_putln(byteptr_t s) +{ + mini_uart_puts(s); + mini_uart_puts("\r\n"); +} + + +/** + * Display a 32-bit binary value in hexadecimal + */ +void +mini_uart_hex(uint32_t d) +{ + for (int32_t c = 28; c >= 0; c -= 4) { + // get highest tetrad + uint8_t n = (d >> c) & 0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n += n > 9 ? 0x37 : 0x30; + mini_uart_putc(n); + } +} + +/** + * Display a 64-bit binary value in hexadecimal + */ +void +mini_uart_hexl(uint64_t d) +{ + for (int32_t c = 60; c >= 0; c -= 4) { + // get highest tetrad + uint8_t n = (d >> c) & 0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n += n > 9 ? 0x37 : 0x30; + mini_uart_putc(n); + } +} + + +void +mini_uart_endl() +{ + mini_uart_puts("\r\n"); +} + +extern volatile byte_t kernel_end; + +void +mini_uart_printf(char* fmt, ...) +{ + __builtin_va_list args; + __builtin_va_start(args, fmt); + char *s = (char*) &kernel_end; + vsprintf(s, fmt, args); + while (*s) { + if (*s == '\n') mini_uart_putc('\r'); + mini_uart_putc(*s++); + } +} + + +byte_t +mini_uart_async_getc() +{ + aux_set_rx_interrupts(); + while (read_buffer_empty()) { + asm volatile("nop"); + } + irq_disable_aux_interrupt(); + uint8_t c = read_buffer_get(); + irq_enable_aux_interrupt(); + return c; +} + + +void +mini_uart_async_putc(uint8_t c) +{ + write_buffer_add(c); + aux_set_tx_interrupts(); +} + + +void +mini_uart_rx_handler() +{ + irq_disable_aux_interrupt(); + read_buffer_add(mini_uart_getc()); + irq_enable_aux_interrupt(); + aux_clr_rx_interrupts(); +} + + +void +mini_uart_tx_handler() +{ + irq_disable_aux_interrupt(); + aux_clr_tx_interrupts(); + + while (!write_buffer_empty()) { + delay_cycles(1 << 21); // (1 << 28) for qemu + uint8_t c = write_buffer_get(); + mini_uart_putc(c); + } + mini_uart_putc('\n'); + mini_uart_putc('\r'); +} + + +void +mini_uart_async_demo() +{ + irq_enable_aux_interrupt(); + uint8_t c = mini_uart_async_getc(); + while (c != '\n') + { + write_buffer_add(c); + c = mini_uart_async_getc(); + } + write_buffer_add(c); + aux_set_tx_interrupts(); +} \ No newline at end of file diff --git a/Lab 7/kernel/src/mini_uart.h b/Lab 7/kernel/src/mini_uart.h new file mode 100644 index 000000000..b76f394ce --- /dev/null +++ b/Lab 7/kernel/src/mini_uart.h @@ -0,0 +1,26 @@ +#ifndef __MINI_UART_H__ +#define __MINI_UART_H__ + +#include "type.h" + +void mini_uart_init(void); + +uint8_t mini_uart_getc(void); +uint8_t mini_uart_getb(void); + +void mini_uart_putc(uint8_t c); +void mini_uart_puts(byteptr_t s); +void mini_uart_putln(byteptr_t s); +void mini_uart_endl(); + +void mini_uart_hex(uint32_t d); +void mini_uart_hexl(uint64_t d); + +void mini_uart_printf(char* fmt, ...); + +void mini_uart_async_demo(); + +void mini_uart_tx_handler(); +void mini_uart_rx_handler(); + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/power.c b/Lab 7/kernel/src/power.c new file mode 100644 index 000000000..ae5a04732 --- /dev/null +++ b/Lab 7/kernel/src/power.c @@ -0,0 +1,26 @@ +#include "mmio.h" +#include "power.h" + + +#define PM_RSTC ((volatile unsigned int*)(MMIO_BASE+0x0010001c)) +#define PM_RSTS ((volatile unsigned int*)(MMIO_BASE+0x00100020)) +#define PM_WDOG ((volatile unsigned int*)(MMIO_BASE+0x00100024)) + +#define PM_MAGIC 0x5a000000 +#define PM_RSTC_FULLRST 0x00000020 + + +void +power_reset(uint32_t ticks) +{ + *PM_RSTC = (PM_MAGIC | PM_RSTC_FULLRST); // full reset + *PM_WDOG = (PM_MAGIC | ticks); // number of watchdog ticks +} + + +void +power_reset_cancel() +{ + *PM_RSTC = (PM_MAGIC | 0); // cancel reset + *PM_WDOG = (PM_MAGIC | 0); // number of watchdog ticks +} \ No newline at end of file diff --git a/Lab 7/kernel/src/power.h b/Lab 7/kernel/src/power.h new file mode 100644 index 000000000..1d6b179b1 --- /dev/null +++ b/Lab 7/kernel/src/power.h @@ -0,0 +1,9 @@ +#ifndef __POWER_H__ +#define __POWER_H__ + +#include "type.h" + +void power_reset(uint32_t ticks); +void power_reset_cancel(); + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/sched.S b/Lab 7/kernel/src/sched.S new file mode 100644 index 000000000..262b69b9d --- /dev/null +++ b/Lab 7/kernel/src/sched.S @@ -0,0 +1,32 @@ +#define THREAD_CPU_CONTEXT_OFFSET 0 + + +.globl cpu_switch_to +cpu_switch_to: + + mov x10, #THREAD_CPU_CONTEXT_OFFSET + + // store current thread callee-saved registers + add x8, x0, x10 + mov x9, sp + stp x19, x20, [x8], #0x10 + stp x21, x22, [x8], #0x10 + stp x23, x24, [x8], #0x10 + stp x25, x26, [x8], #0x10 + stp x27, x28, [x8], #0x10 + stp fp, x9, [x8], #0x10 + str lr, [x8] + + + // restore next thread callee-saved registers + add x8, x1, x10 + ldp x19, x20, [x8], #0x10 + ldp x21, x22, [x8], #0x10 + ldp x23, x24, [x8], #0x10 + ldp x25, x26, [x8], #0x10 + ldp x27, x28, [x8], #0x10 + ldp fp, x9, [x8], #0x10 + ldr lr, [x8] + mov sp, x9 + + ret \ No newline at end of file diff --git a/Lab 7/kernel/src/sched.c b/Lab 7/kernel/src/sched.c new file mode 100644 index 000000000..c0d93c6ed --- /dev/null +++ b/Lab 7/kernel/src/sched.c @@ -0,0 +1,284 @@ +#include "sched.h" +#include "type.h" +#include "uart.h" +#include "list.h" +#include "frame.h" +#include "memory.h" +#include "delay.h" +#include "entry.h" +#include "shell.h" +#include "core_timer.h" +#include "exception.h" + + +// -------------------------------- // + + +/** + * p -> +-----------------+ 0 + * | task_struct | + * +-----------------+ + * | | USER_STACK + * | STACK | + * | | USER_PROGRAM + * childregs -> +-----------------+ + * | pt_regs | + * +-----------------+ 4096 +*/ + + +// #define THREAD_SIZE 0x1000 +// #define STACK_SIZE 0x1000 + + +void cpu_switch_to(void *, void *); + + +static task_t init_task; + +static task_ptr current; +static task_ptr shell_task; + + +int32_t +get_pid() +{ + return current->pid; +} + + +task_ptr +current_task() +{ + return current; +} + + +task_ptr +get_shell_task() +{ + return shell_task; +} + + + +/* *************************** * + * Scheduler OPs + * *************************** */ + +static LIST_HEAD(running_queue); +static LIST_HEAD(waiting_queue); +static LIST_HEAD(stopped_queue); + + +static void +_preempt_disable() +{ + current->preempt_count++; +} + + +static void +_preempt_enable() +{ + current->preempt_count--; +} + + +static void +_switch(task_ptr next) +{ + if (current == next) return; + task_ptr prev = current; + current = next; + cpu_switch_to(&(prev->cpu_context), &(next->cpu_context)); +} + + +static void +_schedule() +{ + _preempt_disable(); + + int32_t c = 0; + task_ptr next = 0; + + while (1) { + c = -1; + list_head_ptr_t p; + + // find next task + list_for_each(p, &running_queue) { + task_ptr tsk = (task_ptr) p; + if (tsk->state == TASK_RUNNING && tsk->counter > c) { + c = tsk->counter; + next = tsk; + } + } + + if (c) { break; } // found the next + // else the list is empty, or no one is old enough + + // not found the next, do aging + list_for_each(p, &running_queue) { + task_ptr tsk = (task_ptr) p; + tsk->counter = (tsk->counter >> 1) + tsk->priority; + } + } + + _switch(next); + + _preempt_enable(); +} + + +void +schedule_tail() +{ + _preempt_enable(); +} + + +/* + * called by the current task + * e.g, idle() or process_exit(), ..etc. + * switch the context itself + */ +void +schedule() +{ + // reset the age of current task + current->counter = 0; + _schedule(); +} + + +/* + * called from irq handler + * + */ +void +scheduler_tick(byteptr_t _) +{ + // uart_printf("---- scheduler_tick ----\n"); + + --current->counter; + if (current->counter > 0 || current->preempt_count > 0) { + return; + } + current->counter=0; + enable_irq(); + _schedule(); + disable_irq(); +} + + +static void +_pause_shell() +{ + if (!shell_task || shell_task->state != TASK_RUNNING) return; + shell_task->state = TASK_WAITING; + list_del_entry((list_head_ptr_t) shell_task); + list_add_tail((list_head_ptr_t) shell_task, &waiting_queue); +} + + +static void +_wake_shell() +{ + if (!shell_task || shell_task->state == TASK_RUNNING) return; + shell_task->state = TASK_RUNNING; + list_del_entry((list_head_ptr_t) shell_task); + list_add_tail((list_head_ptr_t) shell_task, &running_queue); +} + + + +void +scheduler_kill(task_ptr tsk, int32_t status) +{ + tsk->state = TASK_STOPPED; + tsk->exitcode = status; + if (tsk->user_stack) + frame_release(tsk->user_stack); + if (tsk->frame_count) + frame_release_block(tsk->user_prog, tsk->frame_count); + + _preempt_disable(); + list_del_entry((list_head_ptr_t) tsk); + list_add_tail((list_head_ptr_t) tsk, &stopped_queue); + if (tsk->foreground) _wake_shell(); + _preempt_enable(); + + schedule(); +} + + +task_ptr +scheduler_find(int32_t pid) +{ + list_head_ptr_t p; + + list_for_each(p, &running_queue) { + task_ptr tsk = (task_ptr) p; + if (tsk->pid == pid) return tsk; + } + + list_for_each(p, &waiting_queue) { + task_ptr tsk = (task_ptr) p; + if (tsk->pid == pid) return tsk; + } + + return 0; +} + + +void +scheduler_add(task_ptr tsk) +{ + tsk->state = TASK_RUNNING; + _preempt_disable(); + list_add_tail((list_head_ptr_t) tsk, &running_queue); + if (tsk->foreground) _pause_shell(); + _preempt_enable(); +} + + +void +scheduler_init() +{ + task_count = 0; + task_init(&init_task); + scheduler_add(&init_task); + + current = &(init_task); + shell_task = 0; + + uart_printf("[DEBUG] sched_init - init_stask: 0x%x, pid=%d\n", &init_task, init_task.pid); + core_timer_add_tick(scheduler_tick, "", 5); +} + + +void +scheduler_add_shell(task_ptr tsk) +{ + tsk->state = TASK_RUNNING; + _preempt_disable(); + list_add_tail((list_head_ptr_t) tsk, &running_queue); + shell_task = tsk; + _preempt_enable(); +} + + +void +kill_zombies() +{ + _preempt_disable(); + while (!list_empty(&stopped_queue)) { + task_ptr victim = (task_ptr) (&stopped_queue)->next; + uart_printf("[DEBUG] killed victim: 0x%x, pid = %d\n", victim, victim->pid); + list_del_entry((list_head_ptr_t) victim); + frame_release((byteptr_t) victim); + } + _preempt_enable(); +} diff --git a/Lab 7/kernel/src/sched.h b/Lab 7/kernel/src/sched.h new file mode 100644 index 000000000..a3f534d5c --- /dev/null +++ b/Lab 7/kernel/src/sched.h @@ -0,0 +1,27 @@ +#ifndef _SCHED_H +#define _SCHED_H + +#include "type.h" +#include "list.h" +#include "signal.h" +#include "task.h" + + +task_ptr current_task(); + +void scheduler_init(); +void scheduler_add(task_ptr tsk); +void scheduler_add_shell(task_ptr tsk); +void scheduler_kill(task_ptr tsk, int32_t status); +task_ptr scheduler_find(int32_t pid); + +void schedule(); +void kill_zombies(); + +void schedule_tail(); +void scheduler_tick(byteptr_t); + +int32_t get_pid(); + + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/shell.c b/Lab 7/kernel/src/shell.c new file mode 100644 index 000000000..63a8f0506 --- /dev/null +++ b/Lab 7/kernel/src/shell.c @@ -0,0 +1,207 @@ +#include "type.h" +#include "uart.h" +#include "string.h" +#include "initrd.h" +#include "power.h" +#include "info.h" +#include "memory.h" +#include "dtb.h" +#include "delay.h" +#include "sched.h" +#include "core_timer.h" +#include "thread.h" +#include "vfs.h" + + +#define BUFFER_MAX_SIZE 64 + + +static void +print_help() +{ + uart_line("--------------------------------"); + + uart_str("help\t| "); + uart_line("print this help menu"); + + uart_str("info\t| "); + uart_line("print VideoCore info"); + + uart_str("dtb\t| "); + uart_line("print the device tree"); + + uart_str("ls\t| "); + uart_line("list directory contents"); + + uart_str("cat\t| "); + uart_line("print the file content"); + + uart_str("exe\t| "); + uart_line("execute a user program"); + + uart_str("async\t| "); + uart_line("async uart demo"); + + uart_str("timer\t| "); + uart_line("set timeout message [timer msg duration]"); + + uart_str("malloc\t| "); + uart_line("memory allocation [data size in bytes]"); + + uart_str("free\t| "); + uart_line("memory release [block addr in hexdecimal]"); + + uart_str("memory\t| "); + uart_line("memory infomation"); + + uart_str("thread\t| "); + uart_line("thread test demo"); + + uart_str("reboot\t| "); + uart_line("reboot this device"); + + uart_line("--------------------------------"); +} + + +static byteptr_t +read_command(byteptr_t buffer) +{ + uint32_t index = 0; + byte_t r = 0; + do { + r = uart_getc(); + // uart_printf("\n0x%x\n", r); + if (r == '\n') { + uart_put('\n'); + uart_put('\r'); + } + else if (r == 0x7f && index > 0) { + index--; + uart_put(0x8); + uart_put(r); + } + else if (r < 0x7f && (r < 0x11 || r > 0x1f)) { + buffer[index++] = r; + uart_put(r); + } + } while (index < (BUFFER_MAX_SIZE - 1) && r != '\n'); + buffer[index] = '\0'; + return buffer; +} + + +static byteptr_t +next_tok(byteptr_t buffer, byteptr_t message) +{ + byteptr_t tok = str_tok(0); + if (tok == nullptr) { + uart_str(message); + while (tok == nullptr) { + read_command(buffer); + tok = str_tok(buffer); + } + } + return tok; +} + + +static void +parse_command(byteptr_t buffer) +{ + byteptr_t cmd = str_tok(buffer); + + if (str_eql(cmd, "help")) { + print_help(); + } + + else if (str_eql(cmd, "reboot")) { + uart_line("rebooting..."); + power_reset(100); + uart_get(); + delay_cycles(500); + } + + else if (str_eql(cmd, "ls")) { + initrd_list(); + } + + else if (str_eql(cmd, "cat")) { + byteptr_t tok = next_tok(buffer, "file: "); + initrd_cat(tok); + } + + else if (str_eql(cmd, "info")) { + info_board_revision(); + info_memory(); + // info_videocore(); + } + + else if (str_eql(cmd, "dtb")) { + fdt_traverse(fdt_print_node); + } + + else if (str_eql(cmd, "exe")) { + byteptr_t tok = next_tok(buffer, "file: "); + initrd_exec(tok); + } + + else if (str_eql(cmd, "async")) { + mini_uart_async_demo(); + } + + else if (str_eql(cmd, "timer")) { + byteptr_t tok = next_tok(buffer, "message: "); + byte_t msg[32]; str_ncpy(msg, tok, 32); + tok = next_tok(buffer, "duration: "); + uint32_t duration = ascii_dec_to_uint32(tok); + core_timer_add_timeout_event(msg, duration); + } + + else if (str_eql(cmd, "malloc")) { + byteptr_t tok = next_tok(buffer, "size: "); + uint32_t size = ascii_dec_to_uint32(tok); + byteptr_t ptr = kmalloc(size); + uart_printf("malloc: %d bytes, addr: 0x%x\n", size, ptr); + } + + else if (str_eql(cmd, "free")) { + byteptr_t tok = next_tok(buffer, "addr: "); + uint64_t addr = ascii_to_uint64(tok, str_len(tok)); + uart_printf("free: %s, 0x%x\n", tok, addr); + kmemory_release((byteptr_t) addr); + } + + else if (str_eql(cmd, "memory")) { + memory_print_info(); + } + + else if (str_eql(cmd, "thread")) { + thread_demo(); + } + + else if (str_eql(cmd, "vfs")) { + vfs_demo(); + } + + else if (str_len(buffer) > 0) { + uart_str("not a command: "); + uart_line(buffer); + } +} + + +void +shell() +{ + while (1) + { + byte_t buffer[BUFFER_MAX_SIZE]; + uart_str("> "); + read_command(buffer); + parse_command(buffer); + } +} + + + diff --git a/Lab 7/kernel/src/shell.h b/Lab 7/kernel/src/shell.h new file mode 100644 index 000000000..cb1251c17 --- /dev/null +++ b/Lab 7/kernel/src/shell.h @@ -0,0 +1,6 @@ +#ifndef __SHELL_H__ +#define __SHELL_H__ + +void shell(); + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/string.c b/Lab 7/kernel/src/string.c new file mode 100644 index 000000000..cfee123fd --- /dev/null +++ b/Lab 7/kernel/src/string.c @@ -0,0 +1,168 @@ +#include "string.h" + + +static uint32_t +_is_delim(uint8_t c) +{ + return (c == ' ' || c == '\t' || c == '\n') ? 1 : 0; +} + +byteptr_t +str_tok(byteptr_t s) +{ + static byteptr_t old_s; + if (!s) s = old_s; + if (!s) return nullptr; + // find begin + while (_is_delim(*s)) { s++; } + // reached the end + if (*s == '\0') return nullptr; + byteptr_t ret = s; + // find end + while (1) { + if (*s == '\0') { + old_s = s; + return ret; + } + if (_is_delim(*s)) { + *s = '\0'; + old_s = s + 1; + return ret; + } + s++; + } + return nullptr; +} + + +int32_t +str_cmp(const byteptr_t s1, const byteptr_t s2) +{ + byteptr_t p1 = (byteptr_t) s1; + byteptr_t p2 = (byteptr_t) s2; + while (*p1 && *p1 == *p2) ++p1, ++p2; + return (*p1 > *p2) - (*p2 > *p1); +} + + +uint32_t +str_eql(const byteptr_t s1, const byteptr_t s2) +{ + return str_cmp(s1, s2) == 0; +} + + +uint32_t +str_len(const byteptr_t str) +{ + uint32_t len = 0; + byteptr_t p = (byteptr_t) str; + while (*p++ != '\0') ++len; + return len; +} + + +void +str_ncpy(byteptr_t dest, byteptr_t src, uint32_t n) +{ + while (n > 0 && *src != '\0') { + *dest++ = *src++; + n--; + } + *dest = '\0'; +} + + +static void +_reverse(byteptr_t str, uint32_t length) +{ + uint32_t start = 0; + uint32_t end = length - 1; + while (start < end) { + uint8_t temp = str[start]; + str[start] = str[end]; + str[end] = temp; + end--; + start++; + } +} + + +void +uint32_to_hex(uint32_t n, byteptr_t buffer) +{ + uint32_t length = 0; + while (n != 0) { + int rem = n % 16; + buffer[length++] = (rem < 10) ? rem + '0' : rem + 'A'; + n = n / 16; + } + if (length == 0) buffer[length++] = '0'; + buffer[length] = '\0'; + _reverse(buffer, length); +} + + +void +uint32_to_ascii(uint32_t n, byteptr_t buffer) +{ + uint32_t length = 0; + while (n != 0) { + int rem = n % 10; + buffer[length++] = rem + '0'; + n = n / 10; + } + if (length == 0) buffer[length++] = '0'; + buffer[length] = '\0'; + _reverse(buffer, length); +} + + +uint32_t +ascii_to_uint32(const byteptr_t str, uint32_t len) { + byteptr_t s = (byteptr_t) str; + uint32_t num = 0; + for (uint32_t i = 0; i < len; ++i) { + num = num << 4; + if (*s >= 'A' && *s <= 'F') { + num += (*s - 'A' + 10); + } else if (*s >= 'a' && *s <= 'f') { + num += (*s - 'a' + 10); + } else { + num += (*s - '0'); + } + s++; + } + return num; +} + + +uint64_t +ascii_to_uint64(const byteptr_t str, uint32_t len) { + byteptr_t s = (byteptr_t) str; + uint64_t num = 0; + for (uint32_t i = 0; i < len; ++i) { + num = num << 4; + if (*s >= 'A' && *s <= 'F') { + num += (*s - 'A' + 10); + } else if (*s >= 'a' && *s <= 'f') { + num += (*s - 'a' + 10); + } else { + num += (*s - '0'); + } + s++; + } + return num; +} + + +uint32_t +ascii_dec_to_uint32(const byteptr_t str) { + byteptr_t s = (byteptr_t) str; + uint32_t value = 0; + while (*s) { + value = value * 10 + (*s - '0'); + ++s; + } + return value; +} \ No newline at end of file diff --git a/Lab 7/kernel/src/string.h b/Lab 7/kernel/src/string.h new file mode 100644 index 000000000..978c81d82 --- /dev/null +++ b/Lab 7/kernel/src/string.h @@ -0,0 +1,20 @@ +#ifndef __STRING_H__ +#define __STRING_H__ + +#include "type.h" + +int32_t str_cmp(const byteptr_t s1, const byteptr_t s2); +uint32_t str_eql(const byteptr_t s1, const byteptr_t s2); +uint32_t str_len(const byteptr_t str); +byteptr_t str_tok(byteptr_t s); +void str_ncpy(byteptr_t dest, byteptr_t src, uint32_t n); + +void uint32_to_hex(uint32_t n, byteptr_t buffer); +void uint32_to_ascii(uint32_t n, byteptr_t buffer); + +uint32_t ascii_to_uint32(const byteptr_t s, uint32_t len); +uint64_t ascii_to_uint64(const byteptr_t s, uint32_t len); + +uint32_t ascii_dec_to_uint32(const byteptr_t str); + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/sys.S b/Lab 7/kernel/src/sys.S new file mode 100644 index 000000000..314e8202b --- /dev/null +++ b/Lab 7/kernel/src/sys.S @@ -0,0 +1,72 @@ +#include "syscall.h" + + +// .globl call_sys_write +// call_sys_write: +// mov w8, #SYS_WRITE_NUMBER +// svc #0 +// ret + + +// .globl call_sys_malloc +// call_sys_malloc: +// mov w8, #SYS_MALLOC_NUMBER +// svc #0 +// ret + + +// .globl call_sys_exit +// call_sys_exit: +// mov w8, #SYS_EXIT_NUMBER +// svc #0 +// ret + + +// .globl call_sys_clone +// call_sys_clone: +// /* Save args for the child. */ +// mov x10, x0 /*fn*/ +// mov x11, x1 /*arg*/ +// mov x12, x2 /*stack*/ + +// /* Do the system call. */ +// mov x0, x2 /* stack */ +// mov x8, #SYS_CLONE_NUMBER +// svc 0x0 + +// cmp x0, #0 +// beq thread_start +// ret + + +// thread_start: +// mov x29, 0 + +// /* Pick the function arg and execute. */ +// mov x0, x11 +// blr x10 + +// /* We are done, pass the return value through x0. */ +// mov x8, #SYS_EXIT_NUMBER +// svc 0x0 + + +.globl call_get_pid +call_get_pid: + mov w8, #SYS_CALL_GETPID + svc #0 + ret + +.globl call_fork +call_fork: + mov w8, #SYS_CALL_FORK + svc #0 + ret + + +.globl call_exit +call_exit: + mov w8, #SYS_CALL_EXIT + svc #0 + ret + \ No newline at end of file diff --git a/Lab 7/kernel/src/syscall.c b/Lab 7/kernel/src/syscall.c new file mode 100644 index 000000000..9b490abed --- /dev/null +++ b/Lab 7/kernel/src/syscall.c @@ -0,0 +1,165 @@ +#include "syscall.h" +#include "uart.h" +#include "mailbox.h" +#include "initrd.h" +#include "sched.h" +#include "thread.h" +#include "signal.h" +#include "vfs.h" + + +int32_t +sys_getpid() +{ + return current_task()->pid; +} + + +uint32_t +sys_uart_read(byteptr_t buf, uint32_t size) +{ + for (int32_t i = 0; i < size; i++) { buf[i] = uart_getc(); } + return size; +} + + +uint32_t +sys_uart_write(const byteptr_t buf, uint32_t size) +{ + for (int32_t i = 0; i < size; i++) { uart_put(buf[i]); } + return size; +} + + +int32_t +sys_exec(const char *name, char *const argv[]) +{ + initrd_exec_replace((const byteptr_t) name); + return 0; +} + + +int32_t +sys_fork() +{ + return thread_fork(); +} + + +void +sys_exit(int status) +{ + thread_exit(status); +} + + +int32_t +sys_mbox_call(byte_t ch, uint32_t *mbox) +{ + return mailbox_call(ch, mbox); +} + + +void +sys_kill_pid(int32_t pid) +{ + task_ptr tsk = scheduler_find(pid); + if (tsk) scheduler_kill(tsk, 0); +} + + +void +sys_signal(int32_t sig_number, byteptr_t handler) +{ + uart_printf("syscall_signal (register) - signal number: %d, handler: 0x%x\n", sig_number, handler); + task_ptr current = current_task(); + task_add_signal(current, sig_number, handler); +} + + +void +sys_sigkill(int32_t pid, int32_t sig_number) +{ + uart_printf("syscall_sigkill (signal) - number: %d, pid: %d\n", pid, sig_number); + task_ptr tsk = scheduler_find(pid); + + if (tsk) task_to_signal_handler(tsk, sig_number); + else uart_printf("[DEBUG] signal(%d) default handler\n", sig_number); +} + + +void +sys_sigreturn() +{ + uart_printf("syscall_sigreturn\n"); + task_ptr tsk = current_task(); + task_ret_from_signal_handler(tsk); +} + + + +int32_t +syscall_open(const char *pathname, int flags) +{ + task_ptr current = current_task(); + for (int i = 0; i < FD_TABLE_SIZE; i++) { + if (!current->fd_table[i] && !vfs_open(pathname, flags, &(current->fd_table[i]))) { + return i; + } + } + return -1; +} + + +int32_t +syscall_close(int fd) +{ + if (fd < 0 || fd >= FD_TABLE_SIZE) { return -1; } + task_ptr current = current_task(); + if (current->fd_table[fd] && !vfs_close(current->fd_table[fd])) { + current->fd_table[fd] = 0; + return 0; + } + return -1; +} + + +int64_t +syscall_write(int fd, const void *buf, unsigned long count) +{ + if (fd < 0 || fd >= FD_TABLE_SIZE) { return -1; } + task_ptr current = current_task(); + if (current->fd_table[fd]) { return vfs_write(current->fd_table[fd], buf, count); } + return 0; +} + + +int64_t +syscall_read(int fd, void *buf, unsigned long count) +{ + if (fd < 0 || fd >= FD_TABLE_SIZE) { return -1; } + task_ptr current = current_task(); + if (current->fd_table[fd]) { return vfs_read(current->fd_table[fd], buf, count); } + return 0; +} + + +int32_t +syscall_mkdir(const char *pathname, unsigned mode) +{ + return vfs_mkdir(pathname); +} + + +int32_t +syscall_mount(const char *src, const char *target, const char *filesystem, uint64_t flags, const void *data) +{ + return vfs_mount(target, filesystem); +} + + +int32_t +syscall_chdir(const char *path) +{ + return vfs_chdir(path); +} diff --git a/Lab 7/kernel/src/syscall.h b/Lab 7/kernel/src/syscall.h new file mode 100644 index 000000000..db4805866 --- /dev/null +++ b/Lab 7/kernel/src/syscall.h @@ -0,0 +1,98 @@ +#ifndef __SYSCALL_H__ +#define __SYSCALL_H__ + +// #define __NR_syscalls 4 + +// #define SYS_WRITE_NUMBER 0 // syscal numbers +// #define SYS_MALLOC_NUMBER 1 +// #define SYS_CLONE_NUMBER 2 +// #define SYS_EXIT_NUMBER 3 + +#define SYS_CALL_GETPID 0 +#define SYS_CALL_FORK 4 +#define SYS_CALL_EXIT 5 + + +#ifndef __ASSEMBLER__ + +#include "type.h" + + +typedef void (*syscall) (); + + +enum { + SYS_GETPID, // 0 + SYS_UART_RECV, // 1 + SYS_UART_WRITE, // 2 + SYS_EXEC, // 3 + SYS_FORK, // 4 + SYS_EXIT, // 5 + SYS_MBOX, // 6 + SYS_KILL_PID, // 7 + SYS_SIGNAL, // 8 + SYS_SIGKILL, // 9 + SYS_SIGRETURN, // 10 + SYS_OPEN, // 11 + SYS_CLOSE, + SYS_WRITE, + SYS_READ, + SYS_MKDIR, + SYS_MOUNT, + SYS_CHDIR, + NR_SYSCALLS // 18 +}; + + +int32_t sys_getpid(); +uint32_t sys_uart_read(byteptr_t buf, uint32_t size); +uint32_t sys_uart_write(const byteptr_t buf, uint32_t size); +int32_t sys_exec(const char *name, char *const argv[]); +int32_t sys_fork(); +void sys_exit(int status); +int32_t sys_mbox_call(byte_t ch, uint32_t *mbox); +void sys_kill_pid(int32_t pid); + +void sys_signal(); +void sys_sigkill(); +void sys_sigreturn(); + + +int32_t syscall_open(const char *pathname, int flags); +int32_t syscall_close(int fd); +int64_t syscall_write(int fd, const void *buf, unsigned long count); +int64_t syscall_read(int fd, void *buf, unsigned long count); +int32_t syscall_mkdir(const char *pathname, unsigned mode); +int32_t syscall_mount(const char *src, const char *target, const char *filesystem, uint64_t flags, const void *data); +int32_t syscall_chdir(const char *path); + + + +int32_t call_get_pid(void); +int32_t call_fork(void); + + +void * const syscall_table[NR_SYSCALLS] = { + [SYS_GETPID] = &sys_getpid, + [SYS_UART_RECV] = &sys_uart_read, + [SYS_UART_WRITE] = &sys_uart_write, + [SYS_EXEC] = &sys_exec, + [SYS_FORK] = &sys_fork, + [SYS_EXIT] = &sys_exit, + [SYS_MBOX] = &sys_mbox_call, + [SYS_KILL_PID] = &sys_kill_pid, + [SYS_SIGNAL] = &sys_signal, + [SYS_SIGKILL] = &sys_sigkill, + [SYS_SIGRETURN] = &sys_sigreturn, + [SYS_OPEN] = &syscall_open, + [SYS_CLOSE] = &syscall_close, + [SYS_WRITE] = &syscall_write, + [SYS_READ] = &syscall_read, + [SYS_MKDIR] = &syscall_mkdir, + [SYS_MOUNT] = &syscall_mount, + [SYS_CHDIR] = &syscall_chdir, +}; + + +#endif +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/task.c b/Lab 7/kernel/src/task.c new file mode 100644 index 000000000..3ad1d2f08 --- /dev/null +++ b/Lab 7/kernel/src/task.c @@ -0,0 +1,190 @@ +#include "task.h" +#include "memory.h" +#include "exception.h" +#include "entry.h" +#include "uart.h" +#include "list.h" +#include "arm/sysregs.h" + +#define THREAD_SIZE 0x1000 + + +void +task_kill(task_ptr tsk, int32_t status) +{ + tsk->state = TASK_STOPPED; + tsk->exitcode = status; + + if (tsk->user_stack) + frame_release(tsk->user_stack); + if (tsk->frame_count) + frame_release_block(tsk->user_prog, tsk->frame_count); +} + + +int32_t task_count = 0; + + +ptregs_ptr +task_pt_regs(task_ptr tsk) +{ + uint64_t p = (uint64_t) tsk + THREAD_SIZE - sizeof(pt_regs_t); + return (ptregs_ptr) p; +} + + +void +task_init(task_ptr tsk) +{ + memory_zero((byteptr_t) tsk, sizeof(task_t)); + memory_zero((byteptr_t) &tsk->cpu_context, sizeof(cpu_context_t)); + ptregs_ptr childregs = task_pt_regs(tsk); + memory_zero((byteptr_t) childregs, sizeof(pt_regs_t)); + tsk->cpu_context.sp = (uint64_t) childregs; + tsk->cpu_context.lr = (uint64_t) ret_from_fork; + INIT_LIST_HEAD((list_head_ptr_t) tsk); + tsk->priority = 1; +} + + +void +task_reset(task_ptr tsk, uint64_t fn, uint64_t arg) +{ + int32_t pid = tsk->pid; + task_init(tsk); + tsk->cpu_context.x19 = fn; + tsk->cpu_context.x20 = arg; + tsk->state = TASK_RUNNING; + tsk->pid = pid; +} + + +task_ptr +task_create(uint64_t fn, uint64_t arg) +{ + task_ptr p = (task_ptr) frame_alloc(1); + if (!p) { return 0; } + task_reset(p, fn, arg); + p->pid = ++task_count; + + return p; +} + + +task_ptr +task_fork(task_ptr parent) +{ + // 1. build child task + task_ptr child = (task_ptr) frame_alloc(1); + if (!child) { return 0; } + // memory_copy((byteptr_t) child, (byteptr_t) parent, sizeof(task_t)); + memory_zero((byteptr_t) child, sizeof(task_t)); + child->foreground = 0; + child->sig9_handler = parent->sig9_handler; + + // 2. copy trapframe + ptregs_ptr currentregs = task_pt_regs(parent); + ptregs_ptr childregs = task_pt_regs(child); + memory_copy((byteptr_t) childregs, (byteptr_t) currentregs, sizeof(pt_regs_t)); + + // 3. set the kernel stack of the child + child->cpu_context.x19 = 0; + child->cpu_context.x20 = 0; + child->cpu_context.sp = (uint64_t) childregs; + child->cpu_context.lr = (uint64_t) ret_from_fork; + child->priority = 1; + + // 4. assign the child a new id + child->pid = ++task_count; + + // 5. copy user stack + if (parent->user_stack) { + child->user_stack = frame_alloc(1); + memory_copy((byteptr_t) child->user_stack, (byteptr_t) parent->user_stack, THREAD_SIZE); + } + + // 6. copy user program + if (parent->user_prog) { + child->user_prog_size = parent->user_prog_size; + child->frame_count = parent->frame_count; + child->user_prog = frame_alloc(parent->frame_count); + memory_copy((byteptr_t) child->user_prog, (byteptr_t) parent->user_prog, parent->user_prog_size); + } + + // 7. calculate the offsets of user mode + childregs->regs[30] = (uint64_t) child->user_prog + (currentregs->regs[30] - (uint64_t) parent->user_prog); // link return + childregs->sp = (uint64_t) child->user_stack + (currentregs->sp - (uint64_t) parent->user_stack); + childregs->pc = (uint64_t) child->user_prog + (currentregs->pc - (uint64_t) parent->user_prog); + // childregs->pstate = 0; + + // 8. returned value + childregs->regs[0] = 0; + + return child; +} + + +int32_t +task_to_user_mode(task_ptr tsk, uint64_t pc) +{ + uart_printf("[DEBUG] task_to_user_mode - pc: 0x%x\n", pc); + + // 1. build a user stack + uint64_t stack = (uint64_t) frame_alloc(1); + if (!stack) { return -1; } + + tsk->user_stack = (byteptr_t) stack; + + // 2. prepare cpu state for user mode + ptregs_ptr regs = task_pt_regs(tsk); + memory_zero((byteptr_t) regs, sizeof(pt_regs_t)); + + regs->sp = stack + THREAD_SIZE; + regs->pc = pc; + regs->pstate = PSR_MODE_EL0t; // + return 0; +} + + +void +task_add_signal(task_ptr tsk, int32_t number, byteptr_t handler) +{ + // TODO: build a signal handler table + if (number == 9) tsk->sig9_handler = (signal_handler) handler; +} + +static void sigcall_return() +{ + asm volatile("mov x8, 10"); + asm volatile("svc 0"); +} + + +void +task_to_signal_handler(task_ptr tsk, int32_t number) +{ + if (number == 9 && tsk->sig9_handler) { + ptregs_ptr tsk_regs = task_pt_regs(tsk); + tsk->signal_stack = (byteptr_t) frame_alloc(1); + tsk->ptregs_backup = (ptregs_ptr) kmalloc(sizeof(pt_regs_t)); + memory_copy((byteptr_t) tsk->ptregs_backup, (byteptr_t) tsk_regs, sizeof(pt_regs_t)); + + tsk_regs->regs[30] = (uint64_t) &sigcall_return; + tsk_regs->sp = (uint64_t) tsk->signal_stack + THREAD_SIZE; + tsk_regs->pc = (uint64_t) tsk->sig9_handler; + } +} + + +void +task_ret_from_signal_handler(task_ptr tsk) +{ + ptregs_ptr tsk_regs = task_pt_regs(tsk); + memory_copy((byteptr_t) tsk_regs, (byteptr_t) tsk->ptregs_backup, sizeof(pt_regs_t)); + + frame_release((byteptr_t) tsk->signal_stack); + kfree((byteptr_t) tsk->ptregs_backup); + + tsk->signal_stack = 0; + tsk->ptregs_backup = 0; +} \ No newline at end of file diff --git a/Lab 7/kernel/src/task.h b/Lab 7/kernel/src/task.h new file mode 100644 index 000000000..8cc4a69d2 --- /dev/null +++ b/Lab 7/kernel/src/task.h @@ -0,0 +1,99 @@ +#ifndef __TASK_H__ +#define __TASK_H__ + +#include "type.h" +#include "list.h" +#include "vfs.h" + + +typedef struct pt_regs { + uint64_t regs[31]; + uint64_t sp; + uint64_t pc; + uint64_t pstate; +} pt_regs_t; +typedef pt_regs_t * ptregs_ptr; + + +typedef void (*signal_handler)(int); + +typedef struct signal { + list_head_t list; + signal_handler handler; + uint32_t sig_num; +} signal_t; +typedef signal_t * signal_ptr; + + + +#define TASK_SIZE 0x1000 + +typedef struct cpu_context { + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + unsigned long fp; // x30 + unsigned long sp; // x31 + unsigned long lr; +} cpu_context_t; + + +typedef enum { + TASK_RUNNING, + TASK_WAITING, + TASK_STOPPED +} state_t; + + +typedef struct task { + list_head_t list; + cpu_context_t cpu_context; + int32_t pid; + uint32_t exitcode; + state_t state; + + byteptr_t user_stack; + byteptr_t user_prog; + uint32_t user_prog_size; + uint32_t frame_count; + uint32_t foreground; + + int32_t priority; + int32_t preempt_count; + int32_t counter; + + signal_handler sig9_handler; + ptregs_ptr ptregs_backup; + byteptr_t signal_stack; + + vnode_ptr pwd; + file_ptr fd_table[FD_TABLE_SIZE]; +} task_t; + +typedef task_t * task_ptr; + + + + +extern int32_t task_count; + + +task_ptr task_create(uint64_t fn, uint64_t arg); +void task_init(task_ptr tsk); +void task_kill(task_ptr tsk, int32_t status); +void task_reset(task_ptr tsk, uint64_t fn, uint64_t arg); +task_ptr task_fork(task_ptr tsk); +int32_t task_to_user_mode(task_ptr tsk, uint64_t pc); +void task_add_signal(task_ptr tsk, int32_t number, byteptr_t handler); + +void task_to_signal_handler(task_ptr tsk, int32_t number); +void task_ret_from_signal_handler(task_ptr tsk); + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/thread.c b/Lab 7/kernel/src/thread.c new file mode 100644 index 000000000..4b6417e69 --- /dev/null +++ b/Lab 7/kernel/src/thread.c @@ -0,0 +1,146 @@ +#include "thread.h" +#include "asm.h" +#include "frame.h" +#include "sched.h" +#include "uart.h" +#include "delay.h" +#include "memory.h" +#include "exception.h" + + +void +thread_exit(int32_t status) +{ + scheduler_kill(current_task(), status); +} + + +int32_t +thread_create_shell(uint64_t fn) +{ + task_ptr p = task_create(fn, 0); + if (!p) return -1; + uart_printf("[DEBUG] thread_create pid: %d (0x%x)\n", p->pid, p); + scheduler_add_shell(p); + return 0; +} + + +task_ptr +thread_create(uint64_t fn, uint64_t arg) +{ + task_ptr p = task_create(fn, arg); + if (!p) return 0; + uart_printf("[DEBUG] thread_create pid: %d (0x%x)\n", p->pid, p); + scheduler_add(p); + return p; +} + + +int32_t +thread_create_user(uint64_t fn, uint64_t program, uint32_t size) +{ + uart_printf("[DEBUG] thread_create_user - "); + + task_ptr p; + if (size) { + // code duplicate + uint32_t count = (uint32_t) memory_padding((byteptr_t) (size | 0l), FRAME_SIZE_ORDER) >> FRAME_SIZE_ORDER; + byteptr_t user_prog = frame_alloc(count); + uart_printf("frame_count: %d, user_prog: 0x%x", count, user_prog); + if (!user_prog) { return -1; } + memory_copy(user_prog, (byteptr_t) program, size); + uart_printf("(from program: 0x%x), size: %d, ", program, size); + + // build a new task + p = task_create(fn, (uint64_t) user_prog); // fn = run_user_process + p->user_prog = user_prog; + p->user_prog_size = size; + p->frame_count = count; + p->foreground = 1; + } + else { + // build a new task + p = task_create(fn, (uint64_t) program); + p->user_prog = 0; + p->user_prog_size = 0; + p->frame_count = 0; + p->foreground = 1; + } + + uart_printf("pid: %d (%x)\n", p->pid, p); + scheduler_add(p); + return p->pid; +} + + +int32_t +thread_replace_user(uint64_t fn, uint64_t program, uint32_t size) +{ + task_ptr p = current_task(); + uint32_t foreground = p->foreground; + + uart_printf("[DEBUG] thread_replace_user - "); + + if (size) { + // code duplicate + uint32_t count = (uint32_t) memory_padding((byteptr_t) (size | 0l), FRAME_SIZE_ORDER) >> FRAME_SIZE_ORDER; + byteptr_t user_prog = frame_alloc(count); + uart_printf("frame_count: %d, user_prog: 0x%x", count, user_prog); + if (!user_prog) { return -1; } + memory_copy(user_prog, (byteptr_t) program, size); + uart_printf("(from program: 0x%x), size: %d, ", program, size); + + // reset the current task + // task_reset(p, fn, (uint64_t) user_prog); // x19 = fn (e.g, run_user_process, it will call to_user(x20)) + p->user_prog = user_prog; + p->user_prog_size = size; + p->frame_count = count; + p->foreground = foreground; + } + + else { + p->user_prog = 0; + p->user_prog_size = 0; + p->frame_count = 0; + p->foreground = foreground; + } + + uart_printf("pid: %d (%x)\n", p->pid, p); + return p->pid; +} + + +int32_t +thread_fork() +{ + task_ptr child = (task_ptr) task_fork(current_task()); + scheduler_add(child); + + return child->pid; +} + + +#include "asm.h" + + +static void +foo() +{ + for (int i = 0; i < 5; ++i) { + uart_printf("> thread id: %d i=%d\n", current_task()->pid, i); + uint64_t freq = asm_read_sysregister(cntfrq_el0); + delay_cycles(freq >> 5); + } + thread_exit(0); +} + + +void +thread_demo() +{ + for (int i = 0; i < 4; ++i) { + uart_printf("Thread_test i: %d, ", i); + thread_create((uint64_t) &foo, 0); + } +} diff --git a/Lab 7/kernel/src/thread.h b/Lab 7/kernel/src/thread.h new file mode 100644 index 000000000..e136ad757 --- /dev/null +++ b/Lab 7/kernel/src/thread.h @@ -0,0 +1,19 @@ +#ifndef __THREAD_H__ +#define __THREAD_H__ + +#include "list.h" +#include "type.h" +#include "task.h" + + +void thread_exit(int32_t status); +task_ptr thread_create(uint64_t fn, uint64_t arg); +int32_t thread_create_user(uint64_t fn, uint64_t program, uint32_t size); +int32_t thread_replace_user(uint64_t fn, uint64_t program, uint32_t size); +int32_t thread_create_shell(uint64_t fn); +int32_t thread_fork(); + +void thread_demo(); + + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/tmpfs.c b/Lab 7/kernel/src/tmpfs.c new file mode 100644 index 000000000..26028a847 --- /dev/null +++ b/Lab 7/kernel/src/tmpfs.c @@ -0,0 +1,191 @@ +#include "tmpfs.h" +#include "stat.h" +#include "list.h" +#include "uart.h" +#include "memory.h" +#include "string.h" + + +static int +lookup(struct vnode *dir_node, struct vnode **target, const char *component_name) +{ + vnode_ptr vnode = 0; + list_for_each_entry(vnode, &dir_node->children, self) { + if (!(str_cmp(vnode->name, (byteptr_t) component_name))) { + *target = vnode; // the output is here + return 0; + } + } + *target = 0; + return -1; +} + + +static int +create(struct vnode *dir_node, struct vnode **target, const char *component_name) +{ + if (!lookup(dir_node, target, component_name)) { + uart_printf("[INFO] tmpfs_create - the %s file is already exist\n", component_name); + return -1; + } + + vnode_ptr new_vnode = vnode_create((byteptr_t) component_name, S_IFREG); + new_vnode->mount = dir_node->mount; + new_vnode->v_ops = dir_node->v_ops; + new_vnode->f_ops = dir_node->f_ops; + new_vnode->parent = dir_node; + + list_add_tail(&new_vnode->self, &dir_node->children); + dir_node->child_num += 1; + + *target = new_vnode; // the output is here + return 0; +} + + +static int +mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name) +{ + uart_printf("[DEBUG] tmpfs_mkdir - %s, dir: 0x%x, dir->name: %s\n", component_name, dir_node, dir_node->name); + if (!lookup(dir_node, target, component_name)) { + uart_printf("[INFO] tmpfs_mkdir - the %s directory is already exist\n", component_name); + return -1; + } + + vnode_ptr new_vnode = vnode_create((byteptr_t) component_name, S_IFDIR); + new_vnode->mount = dir_node->mount; + new_vnode->v_ops = dir_node->v_ops; + new_vnode->f_ops = dir_node->f_ops; + new_vnode->parent = dir_node; + + list_add_tail(&new_vnode->self, &dir_node->children); + dir_node->child_num += 1; + + *target = new_vnode; // the output is here + return 0; +} + + +vnode_ops_t tmpfs_v_ops = { + lookup, + create, + mkdir, +}; + + +static int +write(struct file *file, const void *buf, int32_t len) +{ + uart_printf("[DEBUG] tmpfs_write - len: %d\n", len); + + struct vnode *vnode = file->vnode; + if (!S_ISREG(vnode->f_mode)) { + uart_printf("[INFO] tmpfs_write - not a regular file\n"); + return 0; + } + + if ((file->f_pos + len) >= vnode->content_size ) { + // enlarge content, +1 for EOF + byteptr_t new_content = (byteptr_t) kmalloc((uint32_t) (file->f_pos) + len + 1); + + memory_copy(new_content, vnode->content, vnode->content_size); // copy origin data; + if (vnode->content) { kfree(vnode->content); } + + vnode->content = new_content; + vnode->content_size = file->f_pos + len + 1; + } + + memory_copy((byteptr_t) ((uint64_t) vnode->content + file->f_pos), (byteptr_t) buf, len); + file->f_pos += len; + + return len; +} + + +static int +read(struct file *file, void *buf, int32_t len) +{ + struct vnode *vnode = file->vnode; + if (!S_ISREG(vnode->f_mode)) { + uart_printf("[INFO] tmpfs_read - not a regular file\n"); + return -1; + } + + int min = (len > (vnode->content_size - file->f_pos - 1)) ? (vnode->content_size - file->f_pos - 1) : len; // -1 for EOF; + if (min <= 0) { return -1; } // f_pos at EOF or len==0; + + uart_printf("[INFO] tmpfs_read - len: %d, f_pos: %d\n", min, file->f_pos); + + memory_copy((byteptr_t) buf, (byteptr_t) ((uint64_t) vnode->content + file->f_pos), min); + file->f_pos += min; + + return min; +} + + +static int +open(struct vnode *file_node, struct file **target) // TODO +{ + return 0; +} + + +static int +close(struct file *file) +{ + kfree((byteptr_t) file); + return 0; +} + + +static long +lseek64(struct file *file, long offset, int whence) // TODO +{ + return 0; +} + + +file_ops_t tmpfs_f_ops = { + write, + read, + open, + close, + lseek64, +}; + + + +static int32_t +setup_mount(fs_ptr fs, mount_ptr mount) +{ + uart_line("setup_mount"); + + mount->fs = fs; + + // should set mount->root as a obj before call setup_mount + vnode_ptr root = mount->root; + + root->mount = mount; + root->f_ops = &tmpfs_f_ops; + root->v_ops = &tmpfs_v_ops; + + // clear the internal content + INIT_LIST_HEAD(&root->children); + root->child_num = 0; + root->content = 0; + root->content_size = 0; + + return 0; +} + + +fs_ptr +tmpfs_create() +{ + fs_ptr fs = (fs_ptr) kmalloc(sizeof(filesystem_t)); + fs->name = "tmpfs"; + fs->setup_mount = &setup_mount; + INIT_LIST_HEAD(&fs->list); + + return fs; +} \ No newline at end of file diff --git a/Lab 7/kernel/src/tmpfs.h b/Lab 7/kernel/src/tmpfs.h new file mode 100644 index 000000000..884991921 --- /dev/null +++ b/Lab 7/kernel/src/tmpfs.h @@ -0,0 +1,14 @@ +#ifndef __TMPFS_H_ +#define __TMPFS_H_ + +#include "vfs.h" + +#define COMPONENT_SIZE 16 + + +fs_ptr tmpfs_create(); + +extern struct file_operations tmpfs_f_ops; +extern struct vnode_operations tmpfs_v_ops; + +#endif diff --git a/Lab 7/kernel/src/uart.h b/Lab 7/kernel/src/uart.h new file mode 100644 index 000000000..f17ab2d02 --- /dev/null +++ b/Lab 7/kernel/src/uart.h @@ -0,0 +1,19 @@ +#ifndef __UART_H__ +#define __UART_H__ + +#include "mini_uart.h" + +#define uart_init mini_uart_init +#define uart_getc mini_uart_getc +#define uart_get mini_uart_getb +#define uart_put mini_uart_putc +#define uart_str mini_uart_puts +#define uart_line mini_uart_putln +#define uart_endl mini_uart_endl + +#define uart_hex mini_uart_hex +#define uart_hexl mini_uart_hexl + +#define uart_printf mini_uart_printf + +#endif \ No newline at end of file diff --git a/Lab 7/kernel/src/vfs.c b/Lab 7/kernel/src/vfs.c new file mode 100644 index 000000000..ccfdb39bc --- /dev/null +++ b/Lab 7/kernel/src/vfs.c @@ -0,0 +1,512 @@ +#include "vfs.h" +#include "tmpfs.h" +#include "initramfs.h" +#include "string.h" +#include "memory.h" +#include "stat.h" +#include "sched.h" +#include "uart.h" + + +#define O_CREAT 00000100 + + +mount_ptr rootfs, initramfs; +LIST_HEAD(vfs_list); + + +static const char * +_next_lvl_path(const char *src, char *dst, int size) +{ + for (int i = 0; i < size; ++i) { + if (src[i] == 0) { dst[i] = 0; return 0; } + else if (src[i] == '/') { dst[i] = 0; return ((char *) (uint64_t) src + i + 1); } + else { dst[i] = src[i]; } + } + return 0; +} + + +static int +_find_iter(const char *pathname, struct vnode **vnode) +{ + if (pathname[0] == '/') { + *vnode = rootfs->root; + return 1; + } + if (pathname[0] == '.') { + if (pathname[1] == '.') { + *vnode = current_task()->pwd->parent; + return 3; + } + *vnode = current_task()->pwd; + return 2; + } + *vnode = current_task()->pwd; + return 0; +} + + +/* if the pathname='/dir1/dir2/text' -> parent=dir2 child=text */ +static int +_find_nodes(struct vnode **parent, struct vnode **child, const char *pathname, char *prefix) +{ + vnode_ptr target_node = 0; + vnode_ptr itr = 0; + + int index = _find_iter(pathname, &itr); + const char * _pathname = &pathname[index]; // pathname=../dir2/file _pathname=dir2/file; + + /* if pathname='/' -> _pathname='' */ + if (!_pathname[0]) { + *parent = rootfs->root; + *child = rootfs->root; + _next_lvl_path(_pathname, prefix, COMPONENT_SIZE); // update prefix + return 0; + } + + /* The itr will be a directory (root is the toppest) */ + while (1) { + _pathname = _next_lvl_path(_pathname, prefix, COMPONENT_SIZE); + if (itr->v_ops->lookup(itr, &target_node, prefix) == -1) { + *parent = itr; + *child = 0; + return -1; + } + else { + if (S_ISDIR(target_node->f_mode)) { + if (!_pathname) { + /* encounter the last component */ + *child = target_node; + *parent = target_node->parent; + return 0; + } + itr = target_node; + } + else if (S_ISREG(target_node->f_mode)) { + *child = target_node; + *parent = target_node->parent; + return 0; + } + } + } + return 0; +} + + +static byteptr_t +dir_tok(byteptr_t s) +{ + static byteptr_t old_s = 0; + if (!s) s = old_s; + if (!s) return nullptr; + + // find begin + while (*s == '/') { s++; } + // reached the end + if (*s == '\0') return nullptr; + byteptr_t ret = s; + // find end + while (1) { + if (*s == '\0') { old_s = s; return ret; } + if (*s == '/') { *s = '\0'; old_s = s + 1; return ret; } + s++; + } + return nullptr; +} + + + +static int +_find_child_node(vnode_ptr *parent, char *path, vnode_ptr *child, char **name) +{ + // uart_printf("_find_child_node - parent->name: %s, path: %s\n", (*parent)->name, path); + + if (*parent == 0) + *parent = (path[0] == '/') ? rootfs->root : current_task()->pwd; + + *name = dir_tok(path); + + if ((*name)[0] == '.') { + if ((*name)[1] == '.') *child = current_task()->pwd->parent; + else *child = current_task()->pwd; + return 0; + } + + if ((*name) == 0) + return 1; // end + + if ((*parent)->v_ops->lookup(*parent, child, *name) == 0) { + return 0; // found + } + return -1; // not found +} + + + +fs_ptr vfs_get(const char *name) +{ + struct filesystem *fs; + list_for_each_entry(fs, &vfs_list, list) { + if (!str_cmp((byteptr_t) fs->name, (byteptr_t) name)) return fs; + } + return 0; +} + + +int32_t +vfs_register(fs_ptr fs) +{ + if (!vfs_get(fs->name)) { + list_add_tail(&fs->list, &vfs_list); + return 0; + } + return -1; +} + + +int +vfs_mkdir(const char *pathname) +{ + uart_printf("[DEBUG] vfs_mkdir: %s, ", pathname); + + vnode_ptr node, parent = 0; + char buf[128]; + char * tok; + + int code = _find_child_node(&parent, pathname, &node, &tok); + // uart_printf("node: 0x%x, name: %s, code: %d, buf: %s\n", node, node->name, code, tok); + + while (code < 1) { + if (code == -1) { parent->v_ops->mkdir(parent, &node, tok); } + + parent = node; + code = _find_child_node(&parent, 0, &node, &tok); + // uart_printf("node: 0x%x, name: %s, code: %d, buf: %s\n", node, node->name, code, tok); + } + return 0; +} + + +int +vfs_lookup(const char *pathname, struct vnode **target) +{ + char child_name[COMPONENT_SIZE]; + vnode_ptr parent = 0, child = 0; + _find_nodes(&parent, &child, pathname, child_name); + + if (child) { + *target = child; + return 0; + } + return -1; +} + + +static +vnode_ptr _find(vnode_ptr parent, char *name) {} + + +static int +_lookup(const char *pathname, vnode_ptr* target) +{ + vnode_ptr node, parent = 0; + char buf[128]; + char * tok; + + if (parent == 0) { + if (pathname[0] == '/') { + pathname += 1; + parent = rootfs->root; + } + else + parent = current_task()->pwd; + } + + tok = dir_tok(pathname); + int code = parent->v_ops->lookup(parent, &node, tok); + + uart_printf("node: 0x%x, name: %s, code: %d, tok: %s\n", node, node->name, code, tok); + + while (code == 0) { + parent = node; + tok = dir_tok(0); + code = parent->v_ops->lookup(parent, &node, tok); + uart_printf("node: 0x%x, name: %s, code: %d, tok: %s\n", node, node->name, code, tok); + } + + + // int code = _find_child_node(&parent, pathname, &node, &tok); + // *target = node; + // uart_printf("node: 0x%x, name: %s, code: %d, buf: %s\n", node, node->name, code, tok); + + // while (code == 0) { + // current_task()->pwd = node; + // parent = node; + // code = _find_child_node(&parent, 0, &node, &tok); + // uart_printf("node: 0x%x, name: %s, code: %d, buf: %s\n", node, node->name, code, tok); + // } + // if (code == 1) { + // *target = parent; + // uart_printf("--- %s ---\n", parent->name); + // } + return code; +} + + +int +vfs_chdir(const char *pathname) +{ + vnode_ptr node, parent = 0; + char buf[128]; + char * tok; + + int code = _find_child_node(&parent, pathname, &node, &tok); + // uart_printf("node: 0x%x, name: %s, code: %d, buf: %s\n", node, node->name, code, tok); + + while (code == 0) { + uart_printf("[DEBUG] vfs_chdir: %s\n", node->name); + current_task()->pwd = node; + parent = node; + code = _find_child_node(&parent, 0, &node, &tok); + // uart_printf("node: 0x%x, name: %s, code: %d, buf: %s\n", node, node->name, code, tok); + } + + return 0; + + // vnode_ptr node = 0; + // if (vfs_lookup(pathname, &node) == -1) { + // uart_printf("[INFO] vfs_chdir - fail to loopup the dir:%s\n", pathname); + // return -1; + // } + // current_task()->pwd = node; + // uart_printf("[DEBUG] vfs_chdir - current->pwd: 0x%x, %s\n", node, node->name); + // return 0; +} + + +int +vfs_mount(const char *target, const char *filesystem) +{ + struct filesystem *fs = vfs_get(filesystem); + if (!fs) { uart_printf("[INFO] vfs_mount - Error! fail to get fs\n"); return -1; } + + // find the vnode + struct vnode *vnode; + if (vfs_lookup(target, &vnode) == -1) { uart_printf("[INFO] vfs_mount - Error! fail to lookup\n"); return -2; } + + // check whether it's a dir + if (!S_ISDIR(vnode->f_mode)) { uart_printf("[INFO] vfs_mount - Error! the target is not a directory\n"); return -1; } + + // link the root of the mount + mount_ptr new_mount = (mount_ptr) kmalloc(sizeof(mount_t)); + new_mount->root = vnode; + new_mount->fs = vnode->mount->fs; + vnode->mount = new_mount; + + // run the setup + new_mount->fs->setup_mount(fs, new_mount); + + return 0; +} + + +int +vfs_open(const char *pathname, int flags, struct file **target) +{ + uart_printf("[DEBUG] vfs_open: %s, %d\n", pathname, sizeof(file_t)); + + int res = 0; + vnode_ptr target_node = 0; + res = vfs_lookup(pathname, &target_node); + + if (res == -1 && !(flags & O_CREAT)) { + /* can't lookup and without O_CREAT flag */ + uart_printf("[INFO] [vfs_open] fail to open the %s\n", pathname); + return -1; + } + + *target = (struct file *) kmalloc(sizeof(file_t)); + (*target)->flags = flags; + (*target)->f_ops = target_node->f_ops; + (*target)->f_pos = 0; + + if (!res) { + (*target)->vnode = target_node; + return 0; + } + + char child_name[COMPONENT_SIZE]; + vnode_ptr parent = 0, child = 0; + _find_nodes(&parent, &child, pathname, child_name); + if (!child) { + parent->v_ops->create(parent, &child, child_name); + (*target)->vnode = child; + return 0; + } + + return -1; +} + + +int +vfs_close(struct file *file) +{ + return file->vnode->f_ops->close(file); +} + + +int +vfs_write(struct file *file, const void *buf, int32_t len) +{ + return file->vnode->f_ops->write(file, buf, len); +} + + +int vfs_read(struct file *file, void *buf, int32_t len) +{ + return file->vnode->f_ops->read(file, buf, len); +} + + +static void +_init_rootfs() +{ + if (vfs_register(tmpfs_create())) { + uart_printf("[INFO] init_rootfs - Error! fail to register tmpfs\n"); + } + + rootfs = (mount_ptr) kmalloc(sizeof(mount_t)); + + fs_ptr fs = vfs_get("tmpfs"); + if (!fs) { + uart_printf("[INFO] init_rootfs - Error! fail to get tmpfs\n"); + return; + } + + rootfs->fs = fs; + rootfs->root = vnode_create("", S_IFDIR); + rootfs->fs->setup_mount(rootfs->fs, rootfs); +} + + +static void +_init_initramfs() +{ + vnode_ptr initramfs_root = 0; + if (vfs_lookup("/initramfs", &initramfs_root)) { uart_printf("[INFO] init_initramfs - fail to lookup /initramfs\n"); } + if (vfs_register(initramfs_create())) { uart_printf("[INFO] init_initramfs - Error! fail to register initramfs\n"); } + fs_ptr fs = vfs_get("initramfs"); + if (!fs) { uart_printf("[INFO] init_initramfs - Error! fail to get initramfs\n"); return; } + + initramfs = (mount_ptr) kmalloc(sizeof(mount_t)); + initramfs->fs = fs; + initramfs->root = initramfs_root; + initramfs->fs->setup_mount(initramfs->fs, initramfs); +} + + +void +vfs_init() +{ + _init_rootfs(); + vfs_mkdir("/initramfs"); + _init_initramfs(); +} + + + +vnode_ptr +vnode_create(const byteptr_t name, uint32_t flags) +{ + // uart_printf("[DEBUG] vnode_create: %s\n", name); + + vnode_ptr vnode = (vnode_ptr) kmalloc(sizeof(vnode_t)); + + INIT_LIST_HEAD(&vnode->children); + INIT_LIST_HEAD(&vnode->self); + + vnode->child_num = 0; + vnode->parent = 0; + + int32_t name_len = (int32_t) str_len(name); + vnode->name = (byteptr_t) kmalloc(name_len); + memory_copy((byteptr_t) vnode->name, (byteptr_t) name, name_len); + + vnode->f_mode = flags; + vnode->content = 0; + vnode->content_size = 0; + + return vnode; +} + + + +static int +vnode_path(vnode_ptr node, char *buf) +{ + if (node->parent == 0) { + buf[0] = 0; + return 0; + } + + int index = vnode_path(node->parent, buf); + buf[index++] = '/'; + int len = str_len(node->name); + memory_copy(&(buf[index]), node->name, len); + buf[index + len] = 0; + + return index + len; +} + + +static +vfs_pwd() +{ + char buf[128]; + vnode_path(current_task()->pwd, buf); + uart_printf("[DEBUG] vfs_pwd - %s\n", buf); +} + + +void +vfs_demo() +{ + vfs_mkdir("/doc/abc"); + vfs_chdir("/doc"); + vfs_chdir("abc"); + vfs_pwd(); + + vfs_mkdir("def"); + vfs_pwd(); + + vfs_chdir("/doc"); + vfs_pwd(); + + vfs_chdir("abc"); + vfs_pwd(); + + vfs_chdir(".."); + vfs_pwd(); + + if (vfs_mkdir("../home") == -1) { uart_printf("[INFO] fail to mkdir /home\n"); } + if (vfs_mkdir("./os") == -1) { uart_printf("[INFO] fail to mkdir /doc/os\n"); } + + file_ptr f1; + vfs_open("../home/f1", O_CREAT, &f1); + char buf1[10] = "345678abc"; + vfs_write(f1, buf1, 10); + vfs_close(f1); + + vfs_chdir(".."); + vfs_chdir("/home"); + vfs_pwd(); + + char buf2[10] = {0}; + vfs_open("./f1", 0, &f1); + vfs_read(f1, buf2, 8); + uart_printf("[INFO] read file /home/f1: %s\n", buf2); + vfs_close(f1); + + if (!vfs_mount("/doc/abc/def", "tmpfs")) { uart_printf("[INFO] vfs_mount /doc/abc/def success\n"); } +} \ No newline at end of file diff --git a/Lab 7/kernel/src/vfs.h b/Lab 7/kernel/src/vfs.h new file mode 100644 index 000000000..b3d0e01f5 --- /dev/null +++ b/Lab 7/kernel/src/vfs.h @@ -0,0 +1,92 @@ +#ifndef __VFS_H__ +#define __VFS_H__ + +#include "type.h" +#include "list.h" + +#define FD_TABLE_SIZE 16 +#define COMPONENT_SIZE 32 + +typedef struct vnode { + struct mount * mount; + struct vnode_operations * v_ops; + struct file_operations * f_ops; + + // internal + struct vnode* parent; + list_head_t children; + list_head_t self; + uint32_t child_num; + byteptr_t name; + + uint32_t f_mode; + + byteptr_t content; + uint32_t content_size; +} vnode_t; +typedef vnode_t * vnode_ptr; + + +typedef struct file { + struct vnode * vnode; + struct file_operations * f_ops; + int32_t f_pos; // RW position of this file handle + int32_t flags; +} file_t; +typedef file_t * file_ptr; + + +typedef struct mount { + struct vnode * root; + struct filesystem * fs; +} mount_t; +typedef mount_t * mount_ptr; + + +typedef struct filesystem { + const char * name; + int32_t (*setup_mount) (struct filesystem *fs, struct mount *mount); + list_head_t list; +} filesystem_t; +typedef filesystem_t * fs_ptr; + + +typedef struct file_operations { + int32_t (*write) (struct file *file, const void *buf, int32_t len); + int32_t (*read) (struct file *file, void *buf, int32_t len); + int32_t (*open) (struct vnode *file_node, struct file **target); + int32_t (*close) (struct file *file); + int64_t (*lseek64) (struct file *file, int64_t offset, int32_t whence); +} file_ops_t; +typedef file_ops_t * file_ops_ptr; + + +typedef struct vnode_operations { + int32_t (*lookup)(struct vnode *dir_node, struct vnode **target, const char *component_name); + int32_t (*create)(struct vnode *dir_node, struct vnode **target, const char *component_name); + int32_t (*mkdir) (struct vnode *dir_node, struct vnode **target, const char *component_name); +} vnode_ops_t; +typedef vnode_ops_t * vnode_ops_ptr; + + +vnode_ptr vnode_create(const byteptr_t name, uint32_t flags); + + +void vfs_init(); + +int vfs_register(struct filesystem *fs); +struct filesystem * vfs_get(const char *name); + +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, int32_t len); +int vfs_read(struct file *file, void *buf, int32_t len); +int vfs_mkdir(const char *pathname); +int vfs_mount(const char *target, const char *filesystem); +int vfs_lookup(const char *pathname, struct vnode **target); +int vfs_chdir(const char *pathname); + +void vfs_demo(); + + +#endif \ No newline at end of file diff --git a/Lab 7/sd/bcm2710-rpi-3-b-plus.dtb b/Lab 7/sd/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 0000000000000000000000000000000000000000..c83b0817e2eb5295a3dfe6aafe3aa55d93e9785d GIT binary patch literal 34228 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 ").lower() + "\n") + if 'exit' in key_in: + ser.close() + print('\nbye!') + sys.exit() + ser.write(key_in.encode()) + sleep(0.1) + + except KeyboardInterrupt: + ser.close() + print('\nbye!') + + +def main(): + port = sys.argv[1] if len(sys.argv) > 1 else "/dev/tty.usbserial-0001" + try: + ser = serial.Serial(port, 115200, timeout=50) + serial_shell(ser) + except serial.serialutil.SerialException as e: + print(e); + + + +if __name__ == "__main__": + main() diff --git a/Lab 7/user/Makefile b/Lab 7/user/Makefile new file mode 100644 index 000000000..cae3e0285 --- /dev/null +++ b/Lab 7/user/Makefile @@ -0,0 +1,22 @@ +SUBDIR = user1 + +BUILDSUBDIR = $(SUBDIR:%=build-%) +CLEANSUBDIR = $(SUBDIR:%=clean-%) + +all: $(BUILDSUBDIR) + +$(BUILDSUBDIR): + @echo "===>" $@ + $(MAKE) -C $(@:build-%=%) + @echo "<===" $@ + +$(CLEANSUBDIR): + @echo "===>" $@ + $(MAKE) -C $(@:clean-%=%) clean + @echo "<===" $@ + +clean: $(CLEANSUBDIR) + +# $(call make_subdir, clean) + +.PHONY: all clean $(SUBDIR) $(BUILDSUBDIR) $(CLEANSUBDIR) \ No newline at end of file diff --git a/Lab 7/user/user1/Makefile b/Lab 7/user/user1/Makefile new file mode 100644 index 000000000..c6cb04b05 --- /dev/null +++ b/Lab 7/user/user1/Makefile @@ -0,0 +1,40 @@ +TARGET = user1 + +ARMGNU ?= aarch64-linux-gnu + +CFLAGS = -MMD -Wall -nostdlib -nostartfiles -ffreestanding -mgeneral-regs-only -Iinclude -Wno-pointer-to-int-cast +ASMOPS = -MMD + +OUT_DIR = out +BUILD_DIR = build +SRC_DIR = src + +all: clean $(TARGET).img + +debug: CCFLAGS += -DDEBUG -g +debug: $(TARGET).img + +clean: + rm -rf $(BUILD_DIR) $(OUT_DIR) *.img + +remake: clean all + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + mkdir -p $(@D) + $(ARMGNU)-gcc $(ASMOPS) -c $< -o $@ + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + $(ARMGNU)-gcc $(CFLAGS) -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES += $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES = $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +$(TARGET).img: $(SRC_DIR)/linker.ld $(OBJ_FILES) + mkdir -p $(OUT_DIR) + $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -o $(BUILD_DIR)/$(TARGET).elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/$(TARGET).elf -O binary $(OUT_DIR)/$(TARGET).img \ No newline at end of file diff --git a/Lab 7/user/user1/src/linker.ld b/Lab 7/user/user1/src/linker.ld new file mode 100644 index 000000000..9dba0a4fd --- /dev/null +++ b/Lab 7/user/user1/src/linker.ld @@ -0,0 +1,14 @@ +SECTIONS +{ + . = 0x200000; + + .text : { *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + + . = ALIGN(0x8); + + _bss_begin = .; + .bss : { *(.bss*) } + _bss_end = .; +} \ No newline at end of file diff --git a/Lab 7/user/user1/src/main.S b/Lab 7/user/user1/src/main.S new file mode 100644 index 000000000..ee1416eb9 --- /dev/null +++ b/Lab 7/user/user1/src/main.S @@ -0,0 +1,11 @@ + .section ".text" + .global _start +_start: + mov x0, 0 +1: + add x0, x0, 1 + svc 0 // system call (el0 -> el1) + cmp x0, 5 // Run `svc 0` 5 times + blt 1b +1: + b 1b \ No newline at end of file