diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index f57f38ca2..4dfea6bba 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -3,7 +3,7 @@ { "name": "Linux", "includePath": [ - "${workspaceFolder}/include", + "${workspaceFolder}/include" ], "defines": [], "compilerPath": "/usr/bin/aarch64-linux-gnu-g++", diff --git a/Makefile b/Makefile index 71c98421a..02149a243 100644 --- a/Makefile +++ b/Makefile @@ -5,8 +5,10 @@ OBJCOPY := aarch64-linux-gnu-objcopy CCFLAGS := -std=gnu17 CXXFLAGS := -ffreestanding -nostdinc -nostdlib -nostdinc++ -nostartfiles -g -std=c++17 -MMD -I$(CURDIR)/include export -PROGS := $(patsubst %,initramfs/%,$(filter-out include lib,$(patsubst program/%,%,$(shell find program -maxdepth 1 -mindepth 1 -type d)))) -ELFS := $(patsubst initramfs/%,program/%.elf,$(PROGS)) +PROGS := $(patsubst %,initramfs/%,$(filter-out include lib,$(patsubst program/%,%,$(shell find program -maxdepth 1 -mindepth 1 -type d)))) +ELFS := $(patsubst initramfs/%,program/%.elf,$(PROGS)) +QEMU := qemu-system-aarch64 +QEMU_ARG := -M raspi3 -kernel kernel8.img -initrd initramfs.cpio -display none -serial null -serial stdio -semihosting -drive if=sd,file=nctuos.img,format=raw .PHONY: all inter_kernel @@ -42,7 +44,7 @@ clean: rm -rf initramfs initramfs.cpio kernel8.img run: all - qemu-system-aarch64 -M raspi3 -kernel kernel8.img -initrd initramfs.cpio -display none -serial null -serial stdio -semihosting + $(QEMU) $(QEMU_ARG) qemu-debug: all - qemu-system-aarch64 -M raspi3 -kernel kernel8.img -initrd initramfs.cpio -display none -serial null -serial stdio -semihosting -S -s + $(QEMU) $(QEMU_ARG) -S -s diff --git a/include/kernel/fat32.h b/include/kernel/fat32.h new file mode 100644 index 000000000..f3363cc0e --- /dev/null +++ b/include/kernel/fat32.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +struct mbr_table_entry +{ + uint32_t first_sector_addr; + uint32_t total_sectors; +}; + +struct mbr +{ + struct mbr_table_entry entry[4]; +}; + +struct fat32 { + uint16_t bytes_pre_logical_sector; + uint8_t logical_sector_per_cluster; + uint16_t reserved_logical_sector_size; + uint8_t fat_count; + uint32_t fat_size; // 0x24 + uint32_t root_dir_start; // 0x2c + uint16_t fs_info_size; // 0x30 + + uint32_t fat_start_block; + uint32_t data_start_block; +}; + +void get_fat(struct fat32 *fat, char *sector_buffer); diff --git a/include/kernel/fs.h b/include/kernel/fs.h index 0120550ba..ee8630032 100644 --- a/include/kernel/fs.h +++ b/include/kernel/fs.h @@ -9,6 +9,9 @@ struct file_entry { char filename[24]; uint32_t next_free_entry; }; + + uint32_t fat32_entry; + uint32_t fat32_block; uint32_t block; uint32_t file_size; @@ -23,6 +26,7 @@ struct fd_entry { uint32_t mode; }; +void fs_init(); int open(char *filename, int mode); size_t read(int fd, char *buf, size_t count); size_t write(int fd, char *buf, size_t count); diff --git a/include/kernel/memory_addr.h b/include/kernel/memory_addr.h index ee92e29f1..2f3ca375a 100644 --- a/include/kernel/memory_addr.h +++ b/include/kernel/memory_addr.h @@ -1,12 +1,13 @@ #pragma once -#define INITRAMFS_BASE 0x08000000 -#define BUDDY_INFO_BASE 0x10000000 -#define TASK_STRUCT_BASE 0x11000000 -#define MEM_ALLOC_PTR_BASE 0x12000000 -#define MOMORY_ALLOC_BASE 0x13000000 -#define MMIO_BASE 0x3F000000 -#define CPU_MMIO_BASE 0x40000000 -#define FILE_ENTRY_BASE 0x14000000 -#define FILE_BLOCK_ENTRY 0x15000000 -#define FILE_CONTENT_BASE 0x16000000 +#define INITRAMFS_BASE 0xFFFF000008000000 +#define BUDDY_INFO_BASE 0xFFFF000010000000 +#define TASK_STRUCT_BASE 0xFFFF000011000000 +#define MEM_ALLOC_PTR_BASE 0xFFFF000012000000 +#define MOMORY_ALLOC_BASE 0xFFFF000013000000 +#define MMIO_BASE 0xFFFF00003F000000 +#define CPU_MMIO_BASE 0xFFFF000040000000 +#define FILE_ENTRY_BASE 0xFFFF000014000000 +#define FILE_BLOCK_ENTRY 0xFFFF000015000000 +#define FILE_CONTENT_BASE 0xFFFF000016000000 +#define PAGE_TABLE_ADDR 0xFFFF000000004400 diff --git a/include/kernel/memory_func.h b/include/kernel/memory_func.h index dad481b0c..79a4ec546 100644 --- a/include/kernel/memory_func.h +++ b/include/kernel/memory_func.h @@ -4,4 +4,5 @@ extern "C" { void *memset(void *s, int c, size_t n); void *memcpy(void *dest, const void *src, size_t n); + int memcmp(const void *s1, const void *s2, size_t n); } diff --git a/include/kernel/mmio.h b/include/kernel/mmio.h index fe538b064..f7a950ba1 100644 --- a/include/kernel/mmio.h +++ b/include/kernel/mmio.h @@ -27,7 +27,7 @@ enum class MMIOREG : uint64_t { class MMIO { public: - static const uint32_t PM_PASSWORD = 0x5A000000; + static constexpr uint32_t PM_PASSWORD = 0x5A000000; static inline void set(MMIOREG addr, uint32_t val) { *reinterpret_cast(addr) = val; } diff --git a/include/kernel/sdhost.h b/include/kernel/sdhost.h new file mode 100644 index 000000000..a620bc270 --- /dev/null +++ b/include/kernel/sdhost.h @@ -0,0 +1,5 @@ +#pragma once + +void readblock(int block_idx, void* buf); +void writeblock(int block_idx, void* buf); +void sd_init(); diff --git a/include/kernel/thread.h b/include/kernel/thread.h index f84c59509..1c3bf1c1c 100644 --- a/include/kernel/thread.h +++ b/include/kernel/thread.h @@ -20,6 +20,10 @@ struct task_reg_struct { void *sp; }; +struct page_table_struct { + uint64_t stack_alloc; + uint64_t program_alloc; +}; struct alignas(16) task_struct { task_reg_struct regs; @@ -27,6 +31,7 @@ struct alignas(16) task_struct { void *kernel_stack_alloc; void *program_alloc; void *fd_entries; + page_table_struct *page_table; uint64_t pid; uint64_t sleep_until; uint64_t program_size; @@ -35,13 +40,20 @@ struct alignas(16) task_struct { int64_t first_untouched_fd; }; +#define NON_EXECUTE_FLAG 0x40000000000000 +#define USER_FLAG 0x447 + extern task_struct* tasks; +inline void* kernel_to_physical(void *addr) { + return (void*)(uint64_t(addr) & 0xffffffffffff); +} +void task_init(); extern "C" { void do_exit(); - void switch_to(task_struct *from, task_struct *to, uint64_t to_tpidr, ...); + void switch_to(task_reg_struct *from, task_reg_struct *to, page_table_struct *page, uint64_t to_tpidr, ...); uint64_t get_tpidr_el1(); void loop(); void set_eret_addr(void *addr); diff --git a/kernel/fat32.cpp b/kernel/fat32.cpp new file mode 100644 index 000000000..201cd231d --- /dev/null +++ b/kernel/fat32.cpp @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include + +void get_mbr(struct mbr *mbr, char *buffer) { + readblock(0, buffer); + char buffer2[20]; + for (int i = 0 ;i < 4; i++) { + memcpy(&mbr->entry[i].first_sector_addr, &buffer[446 + i * 16 + 8], 4); + memcpy(&mbr->entry[i].total_sectors, &buffer[446 + i * 16 + 12], 4); + io() << i << " first_sector_addr: " << u64tohex(mbr->entry[i].first_sector_addr, buffer2, sizeof(buffer2)) << "\r\n"; + io() << i << " total_sectors: " << u64tohex(mbr->entry[i].total_sectors, buffer2, sizeof(buffer2)) << "\r\n"; + } +} + +void get_fat(struct fat32 *fat, char *sector_buffer) { + struct mbr mbr; + char buffer2[20]; + io() << "Checkpoint 1\r\n"; + get_mbr(&mbr, sector_buffer); + io() << "Checkpoint 2\r\n"; + int fat32_start_sector = mbr.entry[0].first_sector_addr; + io() << "Checkpoint 3\r\n"; + readblock(fat32_start_sector, sector_buffer); + io() << "Checkpoint 4\r\n"; + memcpy(&fat->bytes_pre_logical_sector, §or_buffer[0xb], 2); + memcpy(&fat->logical_sector_per_cluster, §or_buffer[0xd], 1); + memcpy(&fat->reserved_logical_sector_size, §or_buffer[0xe], 2); + memcpy(&fat->fat_count, §or_buffer[0x10], 1); + memcpy(&fat->fat_size, §or_buffer[0x24], 4); + memcpy(&fat->root_dir_start, §or_buffer[0x2c], 4); + memcpy(&fat->fs_info_size, §or_buffer[0x30], 2); + + fat->fat_start_block = fat32_start_sector + fat->reserved_logical_sector_size; + fat->data_start_block = fat->fat_start_block + fat->fat_count * fat->fat_size; + io() << "bytes_pre_logical_sector: " << u64tohex(fat->bytes_pre_logical_sector, buffer2, sizeof(buffer2)) << "\r\n"; + io() << "logical_sector_per_cluster: " << u64tohex(fat->logical_sector_per_cluster, buffer2, sizeof(buffer2)) << "\r\n"; + io() << "reserved_logical_sector_size: " << u64tohex(fat->reserved_logical_sector_size, buffer2, sizeof(buffer2)) << "\r\n"; + io() << "fat_count: " << u64tohex(fat->fat_count, buffer2, sizeof(buffer2)) << "\r\n"; + io() << "fat_size: " << u64tohex(fat->fat_size, buffer2, sizeof(buffer2)) << "\r\n"; + io() << "root_dir_start: " << u64tohex(fat->root_dir_start, buffer2, sizeof(buffer2)) << "\r\n"; + io() << "fs_info_size: " << u64tohex(fat->fs_info_size, buffer2, sizeof(buffer2)) << "\r\n"; + io() << "fat_start_block: " << u64tohex(fat->fat_start_block, buffer2, sizeof(buffer2)) << "\r\n"; + io() << "data_start_block: " << u64tohex(fat->data_start_block, buffer2, sizeof(buffer2)) << "\r\n"; + io() << "Checkpoint 5\r\n"; + readblock(fat->fat_start_block, sector_buffer); + io() << "Checkpoint 6\r\n"; + readblock(fat->data_start_block, sector_buffer); + io() << "Checkpoint 7\r\n"; +} diff --git a/kernel/fs.cpp b/kernel/fs.cpp index 45e985d55..18da4bf62 100644 --- a/kernel/fs.cpp +++ b/kernel/fs.cpp @@ -2,17 +2,80 @@ #include #include #include +#include +#include - int total_file_counts = 0; -int first_free_block = -1; -int first_untouched_block = 0; -int first_free_entry = -1; -int first_untouched_entry = 0; +static int total_file_counts = 0; +static int first_free_block = -1; +static int first_untouched_block = 0; +static int first_free_entry = -1; +static int first_untouched_entry = 0; struct file_block { char content[512]; }; +static char fat32_buffer[512]; +static struct fat32 fat32; + +void fs_init() { + get_fat(&fat32, fat32_buffer); +} + +static bool valid_fat_name(char c) { + if (c >= 'A' && c <= 'Z') return true; + if (c >= '0' && c <= '9') return true; + if (c >= '#' && c <= ')') return true; + if (c >= 128 && c <= 228) return true; + if (c >= 230 && c <= 255) return true; + if (c == ' ') return true; + if (c == '!') return true; + if (c == '-') return true; + if (c == '@') return true; + if (c == '^') return true; + if (c == '_') return true; + return false; +} + +static char* to_fat_filename(char *dst, const char *filename) { + int filename_ptr = 0; + // main filename + for (int i = 0; i < 8; i++, filename_ptr++) { + char c = filename[filename_ptr]; + if (c >= 'a' && c <= 'z') c -= ('a' - 'A'); + else if (c == '.') { memset(&dst[i], ' ', 8 - i); break; } + else if (c == 0) { memset(&dst[i], ' ', 11 - i); return dst; } + else if (!valid_fat_name(c)) return nullptr; + dst[i] = c; + } + // check main filename length + char c = filename[filename_ptr]; + if (c == '.') filename_ptr++; + else if (c == 0) { memset(&dst[8], ' ', 3); return dst; } + else { return nullptr; } + + // sub filename + for (int i = 8; i < 11; i++, filename_ptr++) { + char c = filename[filename_ptr]; + if (c >= 'a' && c <= 'z') c -= ('a' - 'A'); + else if (c == 0) { memset(&dst[i], ' ', 11 - i); return dst; } + else if (!valid_fat_name(c)) return nullptr; + dst[i] = c; + } + + // check ending + if (filename[filename_ptr] != 0) { + return nullptr; + } + return dst; +} + +static bool fat32_filename_cmp(char *fat32_filename, char *filename) { + char filename_buffer[11]; + char *dst = to_fat_filename(filename_buffer, filename); + if (dst == nullptr) return false; + return memcmp(filename_buffer, fat32_filename, 11) == 0; +} static int get_free_block() { if (first_free_block != -1) { @@ -26,24 +89,75 @@ static int get_free_block() { } } -static file_entry * creat(char *filename) { +static void write_fat(int fat_block_index, char * buffer) { + for (int i = 0; i < fat32.fat_count; i++) { + writeblock(fat32.fat_start_block + i * fat32.fat_size + fat_block_index , buffer); + } +} + +static void creat(file_entry *filename) { + // for (int i = 0; i < fat32.root_dir_size; i++) { + // readblock(fat32.data_start_block + i, fat32_buffer); + // for (int j = 0; j < 16; j++) { + // if (fat32_buffer[j * 16 + 11] == 0x20) { + // file_entry->fat32_entry = i * 16 + j; + // return file_entry; + // } + // } + // } +} + +static file_entry * load(char *filename) { file_entry *file_entries = (file_entry*) FILE_ENTRY_BASE; int tpidr = get_tpidr_el1(); - file_entry *new_file_entry = nullptr; + file_entry *file_entry = nullptr; int32_t *block_entries = (int32_t*) FILE_BLOCK_ENTRY; if (first_free_entry != -1) { - new_file_entry = &file_entries[first_free_entry]; - first_free_entry = new_file_entry->next_free_entry; + file_entry = &file_entries[first_free_entry]; + first_free_entry = file_entry->next_free_entry; } else { - new_file_entry = &file_entries[first_untouched_entry++]; + file_entry = &file_entries[first_untouched_entry++]; } total_file_counts++; - new_file_entry->block = get_free_block(); - block_entries[new_file_entry->block] = -1; - strcpy_size(new_file_entry->filename, filename); - new_file_entry->file_size = 0; - return new_file_entry; + file_entry->block = get_free_block(); + block_entries[file_entry->block] = -1; + strcpy_size(file_entry->filename, filename); + file_entry->file_size = 0; + file_entry->fat32_entry = -1; + + file_block * file_block_root = (file_block*) FILE_CONTENT_BASE; + + readblock(fat32.data_start_block, fat32_buffer); + for (int j = 0; j < 16; j++) { + if (fat32_buffer[j * 32 + 11] == 0x20 && fat32_filename_cmp(&fat32_buffer[j * 32], file_entry->filename)) { + file_entry->fat32_entry = j; + memcpy(&file_entry->file_size, &fat32_buffer[j * 32 + 28], 4); + int data_block_index; + memcpy(&data_block_index, &fat32_buffer[j * 32 + 26], 2); + memcpy(((char*)&data_block_index) + 2, &fat32_buffer[j * 32 + 20], 2); + file_entry->fat32_block = data_block_index; + uint32_t block_index = file_entry->block; + + while (true) { + readblock(fat32.data_start_block + data_block_index - fat32.root_dir_start, &file_block_root[block_index]); + int fat_block_index = data_block_index / 128; + readblock(fat_block_index + fat32.fat_start_block, fat32_buffer); + data_block_index = ((int*)fat32_buffer)[data_block_index % 128]; + if ((data_block_index & 0xffffff8) != 0xffffff8) { + int new_block_index = get_free_block(); + block_entries[block_index] = new_block_index; + block_index = new_block_index; + } + else { + break; + } + } + + return file_entry; + } + } + return file_entry; } int open(char *filename, int mode) { @@ -57,12 +171,16 @@ int open(char *filename, int mode) { } } if (target_file_entry == nullptr) { - if (mode & O_CREAT != 0) { - target_file_entry = creat(filename); - } - else { - return -1; - } + target_file_entry = load(filename); + } + if (target_file_entry->fat32_entry == -1) { + // if (mode & O_CREAT != 0) { + // creat(target_file_entry); + // } + // else { + // return -1; + // } + return -1; } fd_entry * fd_entry_root = (fd_entry*)tasks[tpidr].fd_entries; fd_entry * new_fd_entry = nullptr; @@ -85,6 +203,20 @@ int open(char *filename, int mode) { } else { target_file_entry->file_size = 0; + readblock(fat32.data_start_block + target_file_entry->fat32_entry / 16, fat32_buffer); + memset(fat32_buffer + target_file_entry->fat32_entry * 32 + 0x1c, 0, 4); + writeblock(fat32.data_start_block + target_file_entry->fat32_entry / 16, fat32_buffer); + readblock(fat32.fat_start_block + target_file_entry->fat32_block / 128, fat32_buffer); + int block_index = ((int*)fat32_buffer)[target_file_entry->fat32_block % 128]; + ((int*)fat32_buffer)[target_file_entry->fat32_block % 128] = 0xffffffff; + write_fat(target_file_entry->fat32_block / 128, fat32_buffer); + while (block_index & 0xffffff8 != 0xffffff8) { + readblock(fat32.fat_start_block + block_index / 128, fat32_buffer); + int next_block_index = ((int*)fat32_buffer)[block_index % 128]; + ((int*)fat32_buffer)[block_index % 128] = 0; + write_fat(block_index / 128, fat32_buffer); + block_index = next_block_index; + } } } return new_fd; @@ -101,7 +233,6 @@ size_t read(int fd, char *buf, size_t count) { block_index = block_entry_root[block_index]; block_offset -= sizeof(file_block); } - file_block * target_file_block = file_block_root + block_index; uint32_t read_count = target_fd_entry->entry->file_size - target_fd_entry->pos > count ? count : target_fd_entry->entry->file_size - target_fd_entry->pos; uint32_t read_bytes_left = read_count; @@ -129,15 +260,18 @@ size_t write(int fd, char *buf, size_t count) { int32_t * block_entry_root = (int32_t*) FILE_BLOCK_ENTRY; uint32_t block_index = target_fd_entry->entry->block; uint32_t block_offset = target_fd_entry->pos; + uint32_t fs_block_index = target_fd_entry->entry->fat32_block; while (block_offset > sizeof(file_block)) { block_index = block_entry_root[block_index]; + readblock(fat32.fat_start_block + fs_block_index / 128, fat32_buffer); + fs_block_index = ((int*)fat32_buffer)[fs_block_index % 128]; block_offset -= sizeof(file_block); } - file_block * target_file_block = file_block_root + block_index; uint32_t write_bytes_left = count; while (write_bytes_left > 0) { uint32_t current_write = (write_bytes_left + block_offset > sizeof(file_block)) ? (sizeof(file_block) - block_offset) : write_bytes_left; memcpy(file_block_root[block_index].content + block_offset, buf, current_write); + writeblock(fat32.data_start_block + fs_block_index - fat32.root_dir_start, file_block_root[block_index].content); buf += current_write; write_bytes_left -= current_write; if (write_bytes_left > 0) { @@ -146,6 +280,31 @@ size_t write(int fd, char *buf, size_t count) { block_entry_root[new_block_index] = -1; block_entry_root[block_index] = new_block_index; } + readblock(fat32.fat_start_block + fs_block_index / 128, fat32_buffer); + uint32_t new_fs_block_index = ((int*)fat32_buffer)[fs_block_index % 128]; + if ((new_fs_block_index & 0xffffff8) == 0xffffff8) { + for (int i = 0; i < fat32.fat_size; i++) { + readblock(fat32.fat_start_block + i, fat32_buffer); + for (int j = 0; j < 128; j++) { + if (((int*)fat32_buffer)[j] == 0) { + uint32_t end_block_marker = new_fs_block_index; + new_fs_block_index = i * 128 + j; + ((int*)fat32_buffer)[j] = end_block_marker; + write_fat(i, fat32_buffer); + readblock(fat32.fat_start_block + fs_block_index / 128, fat32_buffer); + ((int*)fat32_buffer)[fs_block_index % 128] = new_fs_block_index; + write_fat(fs_block_index / 128, fat32_buffer); + fs_block_index = new_fs_block_index; + goto finish_alloc_new_block; + } + } + } + return -1; + } + else { + fs_block_index = new_fs_block_index; + } +finish_alloc_new_block: block_index = block_entry_root[block_index]; block_offset = 0; } @@ -153,6 +312,9 @@ size_t write(int fd, char *buf, size_t count) { target_fd_entry->pos += count; if (target_fd_entry->entry->file_size < target_fd_entry->pos) { target_fd_entry->entry->file_size = target_fd_entry->pos; + readblock(fat32.data_start_block + target_fd_entry->entry->fat32_entry / 16, fat32_buffer); + *(int*)(fat32_buffer + target_fd_entry->entry->fat32_entry * 32 + 0x1c) = target_fd_entry->entry->file_size; + writeblock(fat32.data_start_block + target_fd_entry->entry->fat32_entry / 16, fat32_buffer); } return count; } diff --git a/kernel/kernel.cpp b/kernel/kernel.cpp index 8fdb9f13a..640376f62 100644 --- a/kernel/kernel.cpp +++ b/kernel/kernel.cpp @@ -2,10 +2,11 @@ #include extern "C" void reset(); +void sys_exit(); extern"C" void kernel_exception(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6, uint64_t x7) { - uint64_t esr_el1, spsr_el1, elr_el1, sctlr_el1, el, spsel; + uint64_t esr_el1, spsr_el1, elr_el1, sctlr_el1, el, spsel, far_el1; char buffer[30]; asm(R"( mrs %x0, esr_el1 @@ -14,7 +15,12 @@ void kernel_exception(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint64 mrs %x3, SCTLR_EL1 mrs %x4, CurrentEL mrs %x5, SPSel - )":"=r"(esr_el1), "=r"(spsr_el1), "=r"(elr_el1), "=r"(sctlr_el1), "=r"(el), "=r"(spsel)); + mrs %x6, FAR_EL1 + )":"=r"(esr_el1), "=r"(spsr_el1), "=r"(elr_el1), "=r"(sctlr_el1), "=r"(el), "=r"(spsel), "=r"(far_el1)); + if (((esr_el1 >> 26) & 0b111111) == 0b100100) { + io() << "fault address, FAR_EL1 = " << u64tohex(far_el1, buffer, sizeof(buffer)) << "\r\n"; + sys_exit(); + } io() << "ESR_EL1 = " << u64tohex(esr_el1, buffer, sizeof(buffer)) << "\r\n"; io() << "SPSR_EL1 = " << u64tohex(spsr_el1, buffer, sizeof(buffer)) << "\r\n"; @@ -22,6 +28,7 @@ void kernel_exception(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint64 io() << "SCTLR_EL1 = " << u64tohex(sctlr_el1, buffer, sizeof(buffer)) << "\r\n"; io() << "CurrentEL = " << u64tohex(el >> 2, buffer, sizeof(buffer)) << "\r\n"; io() << "SPSel = " << u64tohex(spsel, buffer, sizeof(buffer)) << "\r\n"; + io() << "FAR_EL1 = " << u64tohex(far_el1, buffer, sizeof(buffer)) << "\r\n"; io() << "x0 = " << u64tohex(x0, buffer, sizeof(buffer)) << "\r\n"; io() << "x1 = " << u64tohex(x1, buffer, sizeof(buffer)) << "\r\n"; io() << "x2 = " << u64tohex(x2, buffer, sizeof(buffer)) << "\r\n"; @@ -31,6 +38,7 @@ void kernel_exception(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint64 io() << "x6 = " << u64tohex(x6, buffer, sizeof(buffer)) << "\r\n"; io() << "x7 = " << u64tohex(x7, buffer, sizeof(buffer)) << "\r\n"; io() << "Unknown exception\r\n"; + while (true); reset(); } diff --git a/kernel/kernel8.ld b/kernel/kernel8.ld index 6b18c06ed..63062806a 100644 --- a/kernel/kernel8.ld +++ b/kernel/kernel8.ld @@ -1,5 +1,6 @@ SECTIONS { - . = 0x80000; + . = 0xffff000000000000; + . += 0x80000; .text.boot : { *(.text.boot) } .bss : { __bss_start__ = .; diff --git a/kernel/kmain.cpp b/kernel/kmain.cpp index bebe07ee9..1963e30bc 100644 --- a/kernel/kmain.cpp +++ b/kernel/kmain.cpp @@ -4,12 +4,13 @@ #include #include #include +#include +#include void sys_exec(char* name, char** argv); -extern uint64_t total_threads; -extern uint64_t pid_counter; extern MemAlloc allocator; -task_struct *tasks; + +char buffer[512]; extern"C" void kmain() { @@ -19,23 +20,9 @@ void kmain() { tasks = (task_struct*)TASK_STRUCT_BASE; MiniUART::Init(); allocator.Init(); - memset(tasks, 0xcc, sizeof(tasks[0])); - tasks[0].program_alloc = malloc(4096); - tasks[0].stack_alloc = malloc(4096); - tasks[0].kernel_stack_alloc = malloc(4096); - tasks[0].fd_entries = malloc(4096); - tasks[0].pid = ++pid_counter; - tasks[0].first_free_fd = -1; - tasks[0].first_untouched_fd = 0; - total_threads++; + sd_init(); + fs_init(); + task_init(); - cpio_newc_header* header = (cpio_newc_header*) INITRAMFS_BASE; - CPIO cpio(header); - while (strcmp(cpio.filename, "TRAILER!!!") != 0) { - int fd = open(cpio.filename, O_WRONLY | O_CREAT); - write(fd, cpio.filecontent, cpio.filesize); - close(fd); - cpio = CPIO(cpio.next); - } sys_exec("terminal", tmp); } diff --git a/kernel/memcpy.S_ b/kernel/memcpy.S_ deleted file mode 100644 index d05bb484b..000000000 --- a/kernel/memcpy.S_ +++ /dev/null @@ -1,216 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2013 ARM Ltd. - * Copyright (C) 2013 Linaro. - * - * This code is based on glibc cortex strings work originally authored by Linaro - * be found @ - * - * http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/ - * files/head:/src/aarch64/ - */ - - -/* - * Copy a buffer from src to dest (alignment handled by the hardware) - * - * Parameters: - * x0 - dest - * x1 - src - * x2 - n - * Returns: - * x0 - dest - */ - .macro ldrb1 reg, ptr, val - ldrb \reg, [\ptr], \val - .endm - - .macro strb1 reg, ptr, val - strb \reg, [\ptr], \val - .endm - - .macro ldrh1 reg, ptr, val - ldrh \reg, [\ptr], \val - .endm - - .macro strh1 reg, ptr, val - strh \reg, [\ptr], \val - .endm - - .macro ldr1 reg, ptr, val - ldr \reg, [\ptr], \val - .endm - - .macro str1 reg, ptr, val - str \reg, [\ptr], \val - .endm - - .macro ldp1 reg1, reg2, ptr, val - ldp \reg1, \reg2, [\ptr], \val - .endm - - .macro stp1 reg1, reg2, ptr, val - stp \reg1, \reg2, [\ptr], \val - .endm - - dstin .req x0 - src .req x1 - count .req x2 - tmp1 .req x3 - tmp1w .req w3 - tmp2 .req x4 - tmp2w .req w4 - dst .req x6 - - A_l .req x7 - A_h .req x8 - B_l .req x9 - B_h .req x10 - C_l .req x11 - C_h .req x12 - D_l .req x13 - D_h .req x14 - - .global memcpy - memcpy: - mov dst, dstin - cmp count, #16 - /*When memory length is less than 16, the accessed are not aligned.*/ - b.lo .Ltiny15 - - neg tmp2, src - ands tmp2, tmp2, #15/* Bytes to reach alignment. */ - b.eq .LSrcAligned - sub count, count, tmp2 - /* - * Copy the leading memory data from src to dst in an increasing - * address order.By this way,the risk of overwriting the source - * memory data is eliminated when the distance between src and - * dst is less than 16. The memory accesses here are alignment. - */ - tbz tmp2, #0, 1f - ldrb1 tmp1w, src, #1 - strb1 tmp1w, dst, #1 -1: - tbz tmp2, #1, 2f - ldrh1 tmp1w, src, #2 - strh1 tmp1w, dst, #2 -2: - tbz tmp2, #2, 3f - ldr1 tmp1w, src, #4 - str1 tmp1w, dst, #4 -3: - tbz tmp2, #3, .LSrcAligned - ldr1 tmp1, src, #8 - str1 tmp1, dst, #8 - -.LSrcAligned: - cmp count, #64 - b.ge .Lcpy_over64 - /* - * Deal with small copies quickly by dropping straight into the - * exit block. - */ -.Ltail63: - /* - * Copy up to 48 bytes of data. At this point we only need the - * bottom 6 bits of count to be accurate. - */ - ands tmp1, count, #0x30 - b.eq .Ltiny15 - cmp tmp1w, #0x20 - b.eq 1f - b.lt 2f - ldp1 A_l, A_h, src, #16 - stp1 A_l, A_h, dst, #16 -1: - ldp1 A_l, A_h, src, #16 - stp1 A_l, A_h, dst, #16 -2: - ldp1 A_l, A_h, src, #16 - stp1 A_l, A_h, dst, #16 -.Ltiny15: - /* - * Prefer to break one ldp/stp into several load/store to access - * memory in an increasing address order,rather than to load/store 16 - * bytes from (src-16) to (dst-16) and to backward the src to aligned - * address,which way is used in original cortex memcpy. If keeping - * the original memcpy process here, memmove need to satisfy the - * precondition that src address is at least 16 bytes bigger than dst - * address,otherwise some source data will be overwritten when memove - * call memcpy directly. To make memmove simpler and decouple the - * memcpy's dependency on memmove, withdrew the original process. - */ - tbz count, #3, 1f - ldr1 tmp1, src, #8 - str1 tmp1, dst, #8 -1: - tbz count, #2, 2f - ldr1 tmp1w, src, #4 - str1 tmp1w, dst, #4 -2: - tbz count, #1, 3f - ldrh1 tmp1w, src, #2 - strh1 tmp1w, dst, #2 -3: - tbz count, #0, .Lexitfunc - ldrb1 tmp1w, src, #1 - strb1 tmp1w, dst, #1 - - b .Lexitfunc - -.Lcpy_over64: - subs count, count, #128 - b.ge .Lcpy_body_large - /* - * Less than 128 bytes to copy, so handle 64 here and then jump - * to the tail. - */ - ldp1 A_l, A_h, src, #16 - stp1 A_l, A_h, dst, #16 - ldp1 B_l, B_h, src, #16 - ldp1 C_l, C_h, src, #16 - stp1 B_l, B_h, dst, #16 - stp1 C_l, C_h, dst, #16 - ldp1 D_l, D_h, src, #16 - stp1 D_l, D_h, dst, #16 - - tst count, #0x3f - b.ne .Ltail63 - b .Lexitfunc - - /* - * Critical loop. Start at a new cache line boundary. Assuming - * 64 bytes per line this ensures the entire loop is in one line. - */ - .p2align 6 -.Lcpy_body_large: - /* pre-get 64 bytes data. */ - ldp1 A_l, A_h, src, #16 - ldp1 B_l, B_h, src, #16 - ldp1 C_l, C_h, src, #16 - ldp1 D_l, D_h, src, #16 -1: - /* - * interlace the load of next 64 bytes data block with store of the last - * loaded 64 bytes data. - */ - stp1 A_l, A_h, dst, #16 - ldp1 A_l, A_h, src, #16 - stp1 B_l, B_h, dst, #16 - ldp1 B_l, B_h, src, #16 - stp1 C_l, C_h, dst, #16 - ldp1 C_l, C_h, src, #16 - stp1 D_l, D_h, dst, #16 - ldp1 D_l, D_h, src, #16 - subs count, count, #64 - b.ge 1b - stp1 A_l, A_h, dst, #16 - stp1 B_l, B_h, dst, #16 - stp1 C_l, C_h, dst, #16 - stp1 D_l, D_h, dst, #16 - - tst count, #0x3f - b.ne .Ltail63 -.Lexitfunc: - ret diff --git a/kernel/memory_func.cpp b/kernel/memory_func.cpp index 4bc4c75df..ce7ab9e78 100644 --- a/kernel/memory_func.cpp +++ b/kernel/memory_func.cpp @@ -13,3 +13,12 @@ void *memcpy(void *dest, const void *src, size_t n) { } return dest; } + +int memcmp(const void *s1, const void *s2, size_t n) { + char *c1 = (char*) s1, *c2 = (char*) s2; + for (int i = 0; i < n; i++) { + int val = *c1 - *c2; + if (val != 0) return val; + } + return 0; +} diff --git a/kernel/memset.S_ b/kernel/memset.S_ deleted file mode 100644 index 8d61b08f7..000000000 --- a/kernel/memset.S_ +++ /dev/null @@ -1,128 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2013 ARM Ltd. - * Copyright (C) 2013 Linaro. - * - * This code is based on glibc cortex strings work originally authored by Linaro - * be found @ - * - * http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/ - * files/head:/src/aarch64/ - */ - - /* - * Fill in the buffer with character c (alignment handled by the hardware) - * - * Parameters: - * x0 - buf - * x1 - c - * x2 - n - * Returns: - * x0 - buf - */ - -dstin .req x0 -val .req w1 -count .req x2 -tmp1 .req x3 -tmp1w .req w3 -tmp2 .req x4 -tmp2w .req w4 -zva_len_x .req x5 -zva_len .req w5 -zva_bits_x .req x6 - -A_l .req x7 -A_lw .req w7 -dst .req x8 -tmp3w .req w9 -tmp3 .req x9 - -.global memset -memset: - mov dst, dstin /* Preserve return value. */ - and A_lw, val, #255 - orr A_lw, A_lw, A_lw, lsl #8 - orr A_lw, A_lw, A_lw, lsl #16 - orr A_l, A_l, A_l, lsl #32 - - cmp count, #15 - b.hi .Lover16_proc - /*All store maybe are non-aligned..*/ - tbz count, #3, 1f - str A_l, [dst], #8 -1: - tbz count, #2, 2f - str A_lw, [dst], #4 -2: - tbz count, #1, 3f - strh A_lw, [dst], #2 -3: - tbz count, #0, 4f - strb A_lw, [dst] -4: - ret - -.Lover16_proc: - /*Whether the start address is aligned with 16.*/ - neg tmp2, dst - ands tmp2, tmp2, #15 - b.eq .Laligned -/* -* The count is not less than 16, we can use stp to store the start 16 bytes, -* then adjust the dst aligned with 16.This process will make the current -* memory address at alignment boundary. -*/ - stp A_l, A_l, [dst] /*non-aligned store..*/ - /*make the dst aligned..*/ - sub count, count, tmp2 - add dst, dst, tmp2 - -.Laligned: - -.Ltail_maybe_long: - cmp count, #64 - b.ge .Lnot_short -.Ltail63: - ands tmp1, count, #0x30 - b.eq 3f - cmp tmp1w, #0x20 - b.eq 1f - b.lt 2f - stp A_l, A_l, [dst], #16 -1: - stp A_l, A_l, [dst], #16 -2: - stp A_l, A_l, [dst], #16 -/* -* The last store length is less than 16,use stp to write last 16 bytes. -* It will lead some bytes written twice and the access is non-aligned. -*/ -3: - ands count, count, #15 - cbz count, 4f - add dst, dst, count - stp A_l, A_l, [dst, #-16] /* Repeat some/all of last store. */ -4: - ret - - /* - * Critical loop. Start at a new cache line boundary. Assuming - * 64 bytes per line, this ensures the entire loop is in one line. - */ - .p2align 6 -.Lnot_short: - sub dst, dst, #16/* Pre-bias. */ - sub count, count, #64 -1: - stp A_l, A_l, [dst, #16] - stp A_l, A_l, [dst, #32] - stp A_l, A_l, [dst, #48] - stp A_l, A_l, [dst, #64]! - subs count, count, #64 - b.ge 1b - tst count, #0x3f - add dst, dst, #16 - b.ne .Ltail63 -.Lexitfunc: - ret diff --git a/kernel/sdhost.cpp b/kernel/sdhost.cpp new file mode 100644 index 000000000..8cd1ea869 --- /dev/null +++ b/kernel/sdhost.cpp @@ -0,0 +1,246 @@ +#include + +// mmio +#define KVA 0xffff000000000000 +// #define KVA 0 +#define MMIO_BASE (KVA + 0x3f000000) + +// SD card command +#define GO_IDLE_STATE 0 +#define SEND_OP_CMD 1 +#define ALL_SEND_CID 2 +#define SEND_RELATIVE_ADDR 3 +#define SELECT_CARD 7 +#define SEND_IF_COND 8 + #define VOLTAGE_CHECK_PATTERN 0x1aa +#define STOP_TRANSMISSION 12 +#define SET_BLOCKLEN 16 +#define READ_SINGLE_BLOCK 17 +#define WRITE_SINGLE_BLOCK 24 +#define SD_APP_OP_COND 41 + #define SDCARD_3_3V (1 << 21) + #define SDCARD_ISHCS (1 << 30) + #define SDCARD_READY (1 << 31) +#define APP_CMD 55 + +// gpio +#define GPIO_BASE (MMIO_BASE + 0x200000) +#define GPIO_GPFSEL4 (GPIO_BASE + 0x10) +#define GPIO_GPFSEL5 (GPIO_BASE + 0x14) +#define GPIO_GPPUD (GPIO_BASE + 0x94) +#define GPIO_GPPUDCLK1 (GPIO_BASE + 0x9c) + +// sdhost +#define SDHOST_BASE (MMIO_BASE + 0x202000) +#define SDHOST_CMD (SDHOST_BASE + 0) + #define SDHOST_READ 0x40 + #define SDHOST_WRITE 0x80 + #define SDHOST_LONG_RESPONSE 0x200 + #define SDHOST_NO_REPONSE 0x400 + #define SDHOST_BUSY 0x800 + #define SDHOST_NEW_CMD 0x8000 +#define SDHOST_ARG (SDHOST_BASE + 0x4) +#define SDHOST_TOUT (SDHOST_BASE + 0x8) + #define SDHOST_TOUT_DEFAULT 0xf00000 +#define SDHOST_CDIV (SDHOST_BASE + 0xc) + #define SDHOST_CDIV_MAXDIV 0x7ff + #define SDHOST_CDIV_DEFAULT 0x148 +#define SDHOST_RESP0 (SDHOST_BASE + 0x10) +#define SDHOST_RESP1 (SDHOST_BASE + 0x14) +#define SDHOST_RESP2 (SDHOST_BASE + 0x18) +#define SDHOST_RESP3 (SDHOST_BASE + 0x1c) +#define SDHOST_HSTS (SDHOST_BASE + 0x20) + #define SDHOST_HSTS_MASK (0x7f8) + #define SDHOST_HSTS_ERR_MASK (0xf8) + #define SDHOST_HSTS_DATA (1 << 0) +#define SDHOST_PWR (SDHOST_BASE + 0x30) +#define SDHOST_DBG (SDHOST_BASE + 0x34) + #define SDHOST_DBG_FSM_DATA 1 + #define SDHOST_DBG_FSM_MASK 0xf + #define SDHOST_DBG_MASK (0x1f << 14 | 0x1f << 9) + #define SDHOST_DBG_FIFO (0x4 << 14 | 0x4 << 9) +#define SDHOST_CFG (SDHOST_BASE + 0x38) + #define SDHOST_CFG_DATA_EN (1 << 4) + #define SDHOST_CFG_SLOW (1 << 3) + #define SDHOST_CFG_INTBUS (1 << 1) +#define SDHOST_SIZE (SDHOST_BASE + 0x3c) +#define SDHOST_DATA (SDHOST_BASE + 0x40) +#define SDHOST_CNT (SDHOST_BASE + 0x50) + +// helper +#define set(io_addr, val) \ + asm volatile("str %w1, [%0]" ::"r"(io_addr), "r"(val) : "memory"); + +#define get(io_addr, val) \ + asm volatile("ldr %w0, [%1]" : "=r"(val) : "r"(io_addr) : "memory"); + +static inline void delay(unsigned long tick) { + while (tick--) { + asm volatile("nop"); + } +} + +static int is_hcs; // high capcacity(SDHC) + +static void pin_setup() { + set(GPIO_GPFSEL4, 0x24000000); + set(GPIO_GPFSEL5, 0x924); + set(GPIO_GPPUD, 0); + delay(15000); + set(GPIO_GPPUDCLK1, 0xffffffff); + delay(15000); + set(GPIO_GPPUDCLK1, 0); +} + +static void sdhost_setup() { + unsigned int tmp; + set(SDHOST_PWR, 0); + set(SDHOST_CMD, 0); + set(SDHOST_ARG, 0); + set(SDHOST_TOUT, SDHOST_TOUT_DEFAULT); + set(SDHOST_CDIV, 0); + set(SDHOST_HSTS, SDHOST_HSTS_MASK); + set(SDHOST_CFG, 0); + set(SDHOST_CNT, 0); + set(SDHOST_SIZE, 0); + get(SDHOST_DBG, tmp); + tmp &= ~SDHOST_DBG_MASK; + tmp |= SDHOST_DBG_FIFO; + set(SDHOST_DBG, tmp); + delay(250000); + set(SDHOST_PWR, 1); + delay(250000); + set(SDHOST_CFG, SDHOST_CFG_SLOW | SDHOST_CFG_INTBUS | SDHOST_CFG_DATA_EN); + set(SDHOST_CDIV, SDHOST_CDIV_DEFAULT); +} + +static int wait_sd() { + int cnt = 1000000; + unsigned int cmd; + do { + if (cnt == 0) { + return -1; + } + get(SDHOST_CMD, cmd); + --cnt; + } while (cmd & SDHOST_NEW_CMD); + return 0; +} + +static int sd_cmd(unsigned cmd, unsigned int arg) { + set(SDHOST_ARG, arg); + set(SDHOST_CMD, cmd | SDHOST_NEW_CMD); + return wait_sd(); +} + +static int sdcard_setup() { + unsigned int tmp; + sd_cmd(GO_IDLE_STATE | SDHOST_NO_REPONSE, 0); + sd_cmd(SEND_IF_COND, VOLTAGE_CHECK_PATTERN); + get(SDHOST_RESP0, tmp); + if (tmp != VOLTAGE_CHECK_PATTERN) { + return -1; + } + while (1) { + if (sd_cmd(APP_CMD, 0) == -1) { + // MMC card or invalid card status + // currently not support + continue; + } + sd_cmd(SD_APP_OP_COND, SDCARD_3_3V | SDCARD_ISHCS); + get(SDHOST_RESP0, tmp); + if (tmp & SDCARD_READY) { + break; + } + delay(1000000); + } + + is_hcs = tmp & SDCARD_ISHCS; + sd_cmd(ALL_SEND_CID | SDHOST_LONG_RESPONSE, 0); + sd_cmd(SEND_RELATIVE_ADDR, 0); + get(SDHOST_RESP0, tmp); + sd_cmd(SELECT_CARD, tmp); + sd_cmd(SET_BLOCKLEN, 512); + return 0; +} + +static int wait_fifo() { + int cnt = 1000000; + unsigned int hsts; + do { + if (cnt == 0) { + return -1; + } + get(SDHOST_HSTS, hsts); + --cnt; + } while ((hsts & SDHOST_HSTS_DATA) == 0); + return 0; +} + +static void set_block(int size, int cnt) { + set(SDHOST_SIZE, size); + set(SDHOST_CNT, cnt); +} + +static void wait_finish() { + unsigned int dbg; + do { + get(SDHOST_DBG, dbg); + } while ((dbg & SDHOST_DBG_FSM_MASK) != SDHOST_HSTS_DATA); +} + +void readblock(int block_idx, void* buf) { + unsigned int* buf_u = (unsigned int*)buf; + int succ = 0; + if (!is_hcs) { + block_idx <<= 9; + } + do{ + set_block(512, 1); + sd_cmd(READ_SINGLE_BLOCK | SDHOST_READ, block_idx); + for (int i = 0; i < 128; ++i) { + wait_fifo(); + get(SDHOST_DATA, buf_u[i]); + } + unsigned int hsts; + get(SDHOST_HSTS, hsts); + if (hsts & SDHOST_HSTS_ERR_MASK) { + set(SDHOST_HSTS, SDHOST_HSTS_ERR_MASK); + sd_cmd(STOP_TRANSMISSION | SDHOST_BUSY, 0); + } else { + succ = 1; + } + } while(!succ); + wait_finish(); +} + +void writeblock(int block_idx, void* buf) { + unsigned int* buf_u = (unsigned int*)buf; + int succ = 0; + if (!is_hcs) { + block_idx <<= 9; + } + do{ + set_block(512, 1); + sd_cmd(WRITE_SINGLE_BLOCK | SDHOST_WRITE, block_idx); + for (int i = 0; i < 128; ++i) { + wait_fifo(); + set(SDHOST_DATA, buf_u[i]); + } + unsigned int hsts; + get(SDHOST_HSTS, hsts); + if (hsts & SDHOST_HSTS_ERR_MASK) { + set(SDHOST_HSTS, SDHOST_HSTS_ERR_MASK); + sd_cmd(STOP_TRANSMISSION | SDHOST_BUSY, 0); + } else { + succ = 1; + } + } while(!succ); + wait_finish(); +} + +void sd_init() { + pin_setup(); + sdhost_setup(); + sdcard_setup(); +} diff --git a/kernel/start.S b/kernel/start.S index 5919b630b..8b955cf76 100644 --- a/kernel/start.S +++ b/kernel/start.S @@ -1,3 +1,17 @@ + +#define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16)) +#define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30)) +#define TCR_CONFIG_DEFAULT (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB) +#define MAIR_DEVICE_nGnRnE 0b00000000 +#define MAIR_NORMAL_NOCACHE 0b01000100 +#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_NORMAL_NOCACHE 1 +#define PD_TABLE 0b11 +#define PD_BLOCK 0b01 +#define PD_ACCESS (1 << 10) +#define BOOT_PGD_ATTR PD_TABLE +#define BOOT_PUD_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK) + .section ".text.boot" .global _start .global loop @@ -13,6 +27,7 @@ _start: mov x0, 0x3c5 msr spsr_el2, x0 adr x0, .Lel1 + movk x0, 0xffff, lsl #48 msr elr_el2, x0 mov x0, #1 msr cntp_ctl_el0, x0 @@ -20,13 +35,62 @@ _start: mov x0, #(3 << 20) orr x0, x1, x0 msr cpacr_el1, x0 - adr x5, exception_vector_table mov x6, #0x3c0 - msr vbar_el1, x5 msr spsr_el1, x6 msr tpidr_el1, xzr +// TLB + ldr x0, = TCR_CONFIG_DEFAULT + msr tcr_el1, x0 + ldr x0, =( \ + (MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | \ + (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8)) \ + ) + msr mair_el1, x0 + + adr x3, _start + mov x0, xzr + mov x1, xzr + mov x2, 0x5000 + mov sp, x3 + bl memset + + mov x0, 0 // PGD's page frame at 0x0 + mov x1, 0x1000 // PUD's page frame at 0x1000 + + ldr x2, = BOOT_PGD_ATTR + orr x2, x1, x2 // combine the physical address of next level page with attribute. + str x2, [x0] + + ldr x2, = BOOT_PUD_ATTR + mov x3, 0x00000000 + orr x3, x2, x3 + str x3, [x1] // 1st 1GB mapped by the 1st entry of PUD + mov x3, 0x40000000 + orr x3, x2, x3 + str x3, [x1, 8] // 2nd 1GB mapped by the 2nd entry of PUD + + //msr ttbr0_el1, x0 // load PGD to the bottom translation based register. + msr ttbr1_el1, x0 + + mov x0, 0x2000 + mov x1, 0x3000 + mov x2, 0x4000 + mov x3, PD_TABLE + orr x3, x1, x3 + str x3, [x0] + mov x3, PD_TABLE + orr x3, x2, x3 + str x3, [x1] + msr ttbr0_el1, x0 + + mrs x2, sctlr_el1 + orr x2 , x2, 1 + msr sctlr_el1, x2 // enable MMU, cache remains disabled. + eret .Lel1: + adr x5, exception_vector_table + msr vbar_el1, x5 adr x4, _start adr x0, __bss_start__ adr x3, __bss_end__ diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp index 77104540f..1537f2799 100644 --- a/kernel/syscall.cpp +++ b/kernel/syscall.cpp @@ -33,7 +33,7 @@ static void schedule_internal(bool save_current) { } } } - switch_to(save_current ? &tasks[current] : nullptr, &tasks[target], target); + switch_to(save_current ? &tasks[current].regs : nullptr, &tasks[target].regs, tasks[target].page_table, target); } static void sys_schedule() { @@ -56,7 +56,7 @@ static void sys_clone(void *func) { } -static void sys_exit() { +void sys_exit() { uint64_t current = get_tpidr_el1(); bool has_same_program = false; for (int i = 0; i < total_threads; i++) { @@ -112,6 +112,7 @@ int sys_exec(char* name, char** argv) { char *arg_final = sp_el0 + (tmp - arg); for (int i = 0; i < argc; i++) { ((char**)arg_final)[i] -= (arg - ((char*)tasks[tpidr].stack_alloc) - 0x1000 + arg_size); + ((char**)arg_final)[i] = (char*)((uint64_t(((char**)arg_final)[i]) & 0xfff) | 0x10000000); } bool has_same_program = false; for (int i = 0; i < total_threads; i++) { @@ -126,11 +127,13 @@ int sys_exec(char* name, char** argv) { tasks[tpidr].program_size = (cpio.filesize + 4095) & ~4095; // Align 4096 tasks[tpidr].regs.sp = tasks[tpidr].kernel_stack_alloc + 4096; tasks[tpidr].regs.lr = (void*)kernel_thread_start; - tasks[tpidr].regs.elr_el1 = tasks[tpidr].program_alloc = memcpy(malloc(tasks[tpidr].program_size), cpio.filecontent, cpio.filesize); - tasks[tpidr].regs.sp_el0 = sp_el0; + tasks[tpidr].program_alloc = memcpy(malloc(tasks[tpidr].program_size), cpio.filecontent, cpio.filesize); + tasks[tpidr].page_table->program_alloc = uint64_t(kernel_to_physical(tasks[tpidr].program_alloc)) | USER_FLAG; + tasks[tpidr].regs.elr_el1 = (void *)0x10001000; + tasks[tpidr].regs.sp_el0 = (void*)((uint64_t(sp_el0) & 0xfff) | 0x10000000); tasks[tpidr].sleep_until = 0; tasks[tpidr].wait_pid = 0; - switch_to(nullptr, &tasks[tpidr], tpidr, argc, arg_final); + switch_to(nullptr, &tasks[tpidr].regs, tasks[tpidr].page_table, tpidr, argc, (uint64_t(arg_final) & 0xfff) | 0x10000000); } else { cpio = CPIO(cpio.next); @@ -164,6 +167,9 @@ static uint64_t sys_fork() { tasks[child].fd_entries = malloc(4096); memcpy(tasks[child].fd_entries, tasks[parent].fd_entries, 4096); tasks[child].program_alloc = tasks[parent].program_alloc; + tasks[child].page_table = (struct page_table_struct*)malloc(4096); + tasks[child].page_table->program_alloc = uint64_t(kernel_to_physical(tasks[child].program_alloc)) | USER_FLAG; + tasks[child].page_table->stack_alloc = uint64_t(kernel_to_physical(tasks[child].stack_alloc)) | USER_FLAG | NON_EXECUTE_FLAG; tasks[child].sleep_until = 0; fork_internal(&tasks[parent], &tasks[child], tasks[parent].stack_alloc, tasks[child].stack_alloc, tasks[parent].kernel_stack_alloc, tasks[child].kernel_stack_alloc); if (tasks[get_tpidr_el1()].pid != parent_pid) { diff --git a/kernel/thread.cpp b/kernel/thread.cpp new file mode 100644 index 000000000..2d41dbafc --- /dev/null +++ b/kernel/thread.cpp @@ -0,0 +1,25 @@ +#include +#include +#include +#include + +task_struct *tasks; +extern uint64_t total_threads; +extern uint64_t pid_counter; + +void task_init() { + memset(tasks, 0xcc, sizeof(tasks[0])); + tasks[0].kernel_stack_alloc = malloc(4096); + tasks[0].fd_entries = malloc(4096); + tasks[0].program_alloc = malloc(4096); + tasks[0].stack_alloc = malloc(4096); + tasks[0].pid = ++pid_counter; + tasks[0].first_free_fd = -1; + tasks[0].first_untouched_fd = 0; + tasks[0].page_table = (struct page_table_struct*)malloc(4096); + memset(tasks[0].page_table, 0, 4096); + *(uint64_t*)PAGE_TABLE_ADDR = (uint64_t(tasks[0].page_table) & 0x0000ffffffffffff) | 3; + tasks[0].page_table->program_alloc = uint64_t(kernel_to_physical(tasks[0].program_alloc)) | USER_FLAG; + tasks[0].page_table->stack_alloc = uint64_t(kernel_to_physical(tasks[0].stack_alloc)) | USER_FLAG | NON_EXECUTE_FLAG; + total_threads++; +} diff --git a/kernel/thread_asm.S b/kernel/thread_asm.S index 584f7e9ec..8b0a626a0 100644 --- a/kernel/thread_asm.S +++ b/kernel/thread_asm.S @@ -8,9 +8,10 @@ from .req x0 to .req x1 -to_tpidr .req x2 -argc .req x3 -argv .req x4 +page .req x2 +to_tpidr .req x3 +argc .req x4 +argv .req x5 switch_to: cbz from, 1f @@ -40,9 +41,18 @@ switch_to: ldr x9, [to, 8 * 14] mov sp, x9 msr tpidr_el1, to_tpidr + mov x0, #0x4400 + movk x0, #0xffff, lsl #48 + movk page, #0, lsl #48 + orr page, page, #3 + str page, [x0] + dsb ish + tlbi vmalle1is + dsb ish + isb - mov x0, x3 - mov x1, x4 + mov x0, argc + mov x1, argv ret get_tpidr_el1: @@ -104,8 +114,8 @@ fork_internal: stp x27, x28, [child, 16 * 4] stp fp, lr, [child, 16 * 5] mrs x9, sp_el0 - sub x9, x9, x2 - add x9, x9, x3 + //sub x9, x9, x2 + //add x9, x9, x3 str x9, [child, 8 * 12] mrs x9, elr_el1 str x9, [child, 8 * 13] diff --git a/program/cat/cat.cpp b/program/cat/cat.cpp index be1b93f38..f31c0bf60 100644 --- a/program/cat/cat.cpp +++ b/program/cat/cat.cpp @@ -5,7 +5,7 @@ int main(int argc, char ** argv) { io() << "Argument not met\r\n"; return -1; } - if (strlen(argv[1]) > 10) { + if (strlen(argv[1]) > 12) { io() << "Filename too long\r\n"; return -1; } diff --git a/program/fault/test.cpp b/program/fault/test.cpp new file mode 100644 index 000000000..ad80bc44c --- /dev/null +++ b/program/fault/test.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +int main(void) { + int cnt = 0; + char buffer[20]; + int pid = fork(); + if(pid == 0) { + int pid2 = fork(); + int pid3 = fork(); + while(cnt < 10) { + io() << "pid: " << getpid() << ", sp: " << u64tohex((uint64_t)&cnt, buffer, sizeof(buffer)) << " cnt: " << (cnt++) << "\r\n"; // address should be the same, but the cnt should be increased indepndently + delay(1000000); + } + if (pid2 != 0) wait(pid2); + if (pid3 != 0) wait(pid3); + } else { + wait(pid); + int* a = 0x0; // a non-mapped address. + io() << u64tohex((uint16_t)*a, buffer, sizeof(buffer)) << "\r\n"; // trigger simple page fault. + io() << "Should not be printed\r\n"; + } +} diff --git a/program/program.ld b/program/program.ld index 92ea6720a..2f377e794 100644 --- a/program/program.ld +++ b/program/program.ld @@ -1,5 +1,5 @@ SECTIONS { - . = 0x13000000; + . = 0x10001000; .text.start : {*(.text.start)} .bss : { __bss_start__ = .; diff --git a/program/terminal/terminal.cpp b/program/terminal/terminal.cpp index 9564dd1ca..688b954fe 100644 --- a/program/terminal/terminal.cpp +++ b/program/terminal/terminal.cpp @@ -26,21 +26,23 @@ class Terminal { } argv[i] = nullptr; bool known_command = false; - for (NameFuncMap& elem : map) { - if (strcmp(elem.command, argv[0]) == 0) { - (this->*elem.func)(); - known_command = true; - break; + if (argv[0] != nullptr) { + for (NameFuncMap& elem : map) { + if (strcmp(elem.command, argv[0]) == 0) { + (this->*elem.func)(); + known_command = true; + break; + } } - } - if (argv[0] != nullptr && !known_command) { - int pid = fork(); - if (pid == 0) { - exec(argv[0], (const char**)argv); - io() << "Unknown command\r\n"; - exit(); + if (!known_command) { + int pid = fork(); + if (pid == 0) { + exec(argv[0], (const char**)argv); + io() << "Unknown command\r\n"; + exit(); + } + wait(pid); } - wait(pid); } io() << "% "; }