diff --git a/Lab3/kernel/Makefile b/Lab3/kernel/Makefile new file mode 100644 index 000000000..c37e006f5 --- /dev/null +++ b/Lab3/kernel/Makefile @@ -0,0 +1,42 @@ +ARMGNU ?= aarch64-linux-gnu + +COPS = -Iinclude -Wall -ffreestanding -fno-stack-protector -nostdlib -nostartfiles -mgeneral-regs-only +ASMOPS = -Iinclude -ggdb + +BUILD_DIR = build +SRC_DIR = src + +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) + +all : kernel8.img + +clean : + rm -rf $(BUILD_DIR)/* *.img + +run : + qemu-system-aarch64 -M raspi3b -serial null -serial stdio -display none -kernel kernel8.img -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + +test : + qemu-system-aarch64 -M raspi3b -serial null -serial stdio -display none -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb -kernel kernel8.img -S -s + +gdb : + aarch64-linux-gnu-gdb build/kernel8.elf + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ + +kernel8.img: $(SRC_DIR)/linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -Map $(BUILD_DIR)/kernel8.map -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary kernel8.img + +#qemu-system-aarch64 -M raspi3b -kernel kernel8.img -nographic -serial null -chardev stdio,id=uart1 -serial chardev:uart1 -monitor none + \ No newline at end of file diff --git a/Lab3/kernel/README.md b/Lab3/kernel/README.md new file mode 100644 index 000000000..857ff77c9 --- /dev/null +++ b/Lab3/kernel/README.md @@ -0,0 +1,31 @@ +# OSC2024 + +| Github Account | Student ID | Name | +|----------------|------------|---------------| +| nien-zhu | 312515040 | Nien-Chu Yu | + +## Requirements + +* cross-compiler: aarch64-linux-gnu-gcc +* Emulator: qemu-system-aarch64 + +## Build + +``` +make +``` + +## Debug + +``` +make test +make gdb +``` + +## Test With QEMU + +``` +make run +(qemu-system-aarch64 -M raspi3b -serial null -serial stdio -display none -kernel kernel8.img) +``` + diff --git a/Lab3/kernel/bcm2710-rpi-3-b-plus.dtb b/Lab3/kernel/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..c83b0817e Binary files /dev/null and b/Lab3/kernel/bcm2710-rpi-3-b-plus.dtb differ diff --git a/Lab3/kernel/config.txt b/Lab3/kernel/config.txt new file mode 100644 index 000000000..bc6d8507a --- /dev/null +++ b/Lab3/kernel/config.txt @@ -0,0 +1 @@ +initramfs initramfs.cpio 0x20000000 \ No newline at end of file diff --git a/Lab3/kernel/include/allocator.h b/Lab3/kernel/include/allocator.h new file mode 100644 index 000000000..705fee6f3 --- /dev/null +++ b/Lab3/kernel/include/allocator.h @@ -0,0 +1 @@ +void* simple_malloc(unsigned long size); \ No newline at end of file diff --git a/Lab3/kernel/include/cpio.h b/Lab3/kernel/include/cpio.h new file mode 100644 index 000000000..28767ac30 --- /dev/null +++ b/Lab3/kernel/include/cpio.h @@ -0,0 +1,39 @@ + +extern char * cpio_addr; + +void cpio_ls(); +void cpio_cat(char* filename); +int cpio_TRAILER_compare(const char* str1); +void cpio_load_program(char *filename); + +struct new_cpio_header { + // uses 8-byte hexadecimal fields for all numbers + char c_magic[6]; //determine whether this archive is written with little-endian or big-endian integers. + char c_ino[8]; //determine when two entries refer to the same file. + char c_mode[8]; //specifies both the regular permissions and the file type. + char c_uid[8]; // numeric user id + char c_gid[8]; // numeric group id + char c_nlink[8]; // number of links to this file. + char c_mtime[8]; // Modification time of the file + char c_filesize[8]; // size of the file + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; // number of bytes in the pathname + char c_check[8]; // always set to zero by writers and ignored by readers. +}; + +struct old_cpio_header { + char c_magic[6]; + char c_dev[6]; + char c_ino[6]; + char c_mode[6]; + char c_uid[6]; + char c_gid[6]; + char c_nlink[6]; + char c_rdev[6]; + char c_mtime[11]; + char c_namesize[6]; + char c_filesize[11]; +}; \ No newline at end of file diff --git a/Lab3/kernel/include/dtb.h b/Lab3/kernel/include/dtb.h new file mode 100644 index 000000000..7aa009d96 --- /dev/null +++ b/Lab3/kernel/include/dtb.h @@ -0,0 +1,43 @@ +#include +#include + + +#define FDT_BEGIN_NODE (0x00000001) +#define FDT_END_NODE (0x00000002) +#define FDT_PROP (0x00000003) +#define FDT_NOP (0x00000004) +#define FDT_END (0x00000009) + +typedef void (*fdt_callback)(int node,const char* name,const void* data,uint32_t size); + +uint32_t fdt_u32_le2be (const void *addr); +int fdt_traverse(fdt_callback cb, void* _dtb); +int struct_parse(fdt_callback cb, uintptr_t cur_ptr, uintptr_t strings_ptr,uint32_t totalsize); +void get_cpio_addr(int token,const char* name,const void* data,uint32_t size); +void print_dtb(int token, const char* name, const void* data, uint32_t size); +void data_parse(const char* name, const void* data, uint32_t len); + + + +struct fdt_header { + uint32_t magic; + uint32_t totalsize; + uint32_t off_dt_struct; + uint32_t off_dt_strings; + uint32_t off_mem_rsvmap; + uint32_t version; + uint32_t last_comp_version; + uint32_t boot_cpuid_phys; + uint32_t size_dt_strings; + uint32_t size_dt_struct; +}; + +struct fdt_reserve_entry { + uint64_t address; + uint64_t size; +}; + +struct fdt_property{ + uint32_t len; + uint32_t nameoff; +}; diff --git a/Lab3/kernel/include/except_c.h b/Lab3/kernel/include/except_c.h new file mode 100644 index 000000000..07fe939db --- /dev/null +++ b/Lab3/kernel/include/except_c.h @@ -0,0 +1,4 @@ +void exception_entry(); +void core_timer_exception_entry(); +void irq_exception_entry(); +void test_entry(); \ No newline at end of file diff --git a/Lab3/kernel/include/gpio.h b/Lab3/kernel/include/gpio.h new file mode 100644 index 000000000..c50ecb9d5 --- /dev/null +++ b/Lab3/kernel/include/gpio.h @@ -0,0 +1,38 @@ +#ifndef GPIO_H +#define GPIO_H + +#include + +#define MMIO_BASE 0x3F000000 + +#define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE+0x00200000)) +#define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE+0x00200004)) +#define GPFSEL2 ((volatile unsigned int*)(MMIO_BASE+0x00200008)) +#define GPFSEL3 ((volatile unsigned int*)(MMIO_BASE+0x0020000C)) +#define GPFSEL4 ((volatile unsigned int*)(MMIO_BASE+0x00200010)) +#define GPFSEL5 ((volatile unsigned int*)(MMIO_BASE+0x00200014)) +#define GPSET0 ((volatile unsigned int*)(MMIO_BASE+0x0020001C)) +#define GPSET1 ((volatile unsigned int*)(MMIO_BASE+0x00200020)) +#define GPCLR0 ((volatile unsigned int*)(MMIO_BASE+0x00200028)) +#define GPLEV0 ((volatile unsigned int*)(MMIO_BASE+0x00200034)) +#define GPLEV1 ((volatile unsigned int*)(MMIO_BASE+0x00200038)) +#define GPEDS0 ((volatile unsigned int*)(MMIO_BASE+0x00200040)) +#define GPEDS1 ((volatile unsigned int*)(MMIO_BASE+0x00200044)) +#define GPHEN0 ((volatile unsigned int*)(MMIO_BASE+0x00200064)) +#define GPHEN1 ((volatile unsigned int*)(MMIO_BASE+0x00200068)) +#define GPPUD ((volatile unsigned int*)(MMIO_BASE+0x00200094)) +#define GPPUDCLK0 ((volatile unsigned int*)(MMIO_BASE+0x00200098)) +#define GPPUDCLK1 ((volatile unsigned int*)(MMIO_BASE+0x0020009C)) + +// Helper function to write data to a memory-mapped I/O address +static inline void mmio_write(volatile uint32_t* reg, uint32_t data) { + *reg = data; +} + +// Helper function to read data from a memory-mapped I/O address +static inline uint32_t mmio_read(volatile uint32_t* reg) { + return *reg; +} + + +#endif \ No newline at end of file diff --git a/Lab3/kernel/include/interrupt.h b/Lab3/kernel/include/interrupt.h new file mode 100644 index 000000000..6ca395cde --- /dev/null +++ b/Lab3/kernel/include/interrupt.h @@ -0,0 +1,21 @@ +#include "gpio.h" + + +#define IRQ_BASIC_PENDING ((volatile unsigned int*)(MMIO_BASE+0x0000B200)) +#define IRQ_PENDING_1 ((volatile unsigned int*)(MMIO_BASE+0x0000B204)) +#define IRQ_PENDING_2 ((volatile unsigned int*)(MMIO_BASE+0x0000B208)) +#define FIQ_CONTROL ((volatile unsigned int*)(MMIO_BASE+0x0000B20C)) +#define ENABLE_IRQS_1 ((volatile unsigned int*)(MMIO_BASE+0x0000B210)) +#define ENABLE_IRQS_2 ((volatile unsigned int*)(MMIO_BASE+0x0000B214)) +#define ENABLE_BASIC_IRQS ((volatile unsigned int*)(MMIO_BASE+0x0000B218)) +#define DISABLE_IRQS_1 ((volatile unsigned int*)(MMIO_BASE+0x0000B21C)) +#define DISABLE_IRQS_2 ((volatile unsigned int*)(MMIO_BASE+0x0000B220)) +#define DISABLE_BASIC_IRQS ((volatile unsigned int*)(MMIO_BASE+0x0000B224)) + +#define SYSTEM_TIMER_IRQ_0 (1 << 0) +#define SYSTEM_TIMER_IRQ_1 (1 << 1) +#define SYSTEM_TIMER_IRQ_2 (1 << 2) +#define SYSTEM_TIMER_IRQ_3 (1 << 3) + +void enable_interrupt(); +void disable_interrupt(); \ No newline at end of file diff --git a/Lab3/kernel/include/mailbox.h b/Lab3/kernel/include/mailbox.h new file mode 100644 index 000000000..628076e5e --- /dev/null +++ b/Lab3/kernel/include/mailbox.h @@ -0,0 +1,42 @@ +#include "gpio.h" + +extern volatile unsigned int mailbox[36]; + + + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define MBOX_TAG_GETBOARD 0x00010002 +#define MBOX_REQUEST 0x00000000 +#define MBOX_TAG_GETSERIAL 0x00010004 +#define TAG_REQUEST_CODE 0x00000000 +#define MBOX_TAG_GETARMMEM 0x00010005 +#define MBOX_TAG_LAST 0x00000000 +#define END_TAG 0x00000000 + +int mailbox_call(); +void get_board_revision(); +void get_arm_mem(); + +#define VIDEOCORE_MBOX (MMIO_BASE+0xB880) +#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0)) +#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10)) +#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14)) +#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18)) +#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C)) +#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20)) +#define MBOX_RESPONSE 0x80000000 +#define MBOX_FULL 0x80000000 +#define MBOX_EMPTY 0x40000000 +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 \ No newline at end of file diff --git a/Lab3/kernel/include/printf.h b/Lab3/kernel/include/printf.h new file mode 100644 index 000000000..f37c1bf2d --- /dev/null +++ b/Lab3/kernel/include/printf.h @@ -0,0 +1,106 @@ +/* +File: printf.h + +Copyright (C) 2004 Kustaa Nyholm + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +This library is realy just two files: 'printf.h' and 'printf.c'. + +They provide a simple and small (+200 loc) printf functionality to +be used in embedded systems. + +I've found them so usefull in debugging that I do not bother with a +debugger at all. + +They are distributed in source form, so to use them, just compile them +into your project. + +Two printf variants are provided: printf and sprintf. + +The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'. + +Zero padding and field width are also supported. + +If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the +long specifier is also +supported. Note that this will pull in some long math routines (pun intended!) +and thus make your executable noticably longer. + +The memory foot print of course depends on the target cpu, compiler and +compiler options, but a rough guestimate (based on a H8S target) is about +1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space. +Not too bad. Your milage may vary. By hacking the source code you can +get rid of some hunred bytes, I'm sure, but personally I feel the balance of +functionality and flexibility versus code size is close to optimal for +many embedded systems. + +To use the printf you need to supply your own character output function, +something like : + + void putc ( void* p, char c) + { + while (!SERIAL_PORT_EMPTY) ; + SERIAL_PORT_TX_REGISTER = c; + } + +Before you can call printf you need to initialize it to use your +character output function with something like: + + init_printf(NULL,putc); + +Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc', +the NULL (or any pointer) you pass into the 'init_printf' will eventually be +passed to your 'putc' routine. This allows you to pass some storage space (or +anything realy) to the character output function, if necessary. +This is not often needed but it was implemented like that because it made +implementing the sprintf function so neat (look at the source code). + +The code is re-entrant, except for the 'init_printf' function, so it +is safe to call it from interupts too, although this may result in mixed output. +If you rely on re-entrancy, take care that your 'putc' function is re-entrant! + +The printf and sprintf functions are actually macros that translate to +'tfp_printf' and 'tfp_sprintf'. This makes it possible +to use them along with 'stdio.h' printf's in a single source file. +You just need to undef the names before you include the 'stdio.h'. +Note that these are not function like macros, so if you have variables +or struct members with these names, things will explode in your face. +Without variadic macros this is the best we can do to wrap these +fucnction. If it is a problem just give up the macros and use the +functions directly or rename them. + +For further details see source code. + +regs Kusti, 23.10.2004 +*/ + + +#ifndef __TFP_PRINTF__ +#define __TFP_PRINTF__ + +#include + +void init_printf(void* putp,void (*putf) (void*,char)); + +void tfp_printf(char *fmt, ...); +void tfp_sprintf(char* s,char *fmt, ...); + +void tfp_format(void* putp,void (*putf) (void*,char),char *fmt, va_list va); + +#define printf tfp_printf +#define sprintf tfp_sprintf + +#endif diff --git a/Lab3/kernel/include/reboot.h b/Lab3/kernel/include/reboot.h new file mode 100644 index 000000000..185b8da40 --- /dev/null +++ b/Lab3/kernel/include/reboot.h @@ -0,0 +1,7 @@ +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +void set(long addr, unsigned int value); +void reset(int tick); +void cancel_reset(); \ No newline at end of file diff --git a/Lab3/kernel/include/shell.h b/Lab3/kernel/include/shell.h new file mode 100644 index 000000000..7ce4cee06 --- /dev/null +++ b/Lab3/kernel/include/shell.h @@ -0,0 +1 @@ +void shell(); \ No newline at end of file diff --git a/Lab3/kernel/include/tasklist.h b/Lab3/kernel/include/tasklist.h new file mode 100644 index 000000000..49af22411 --- /dev/null +++ b/Lab3/kernel/include/tasklist.h @@ -0,0 +1,19 @@ +#include +#include + +typedef void (*task_callback)(); + +typedef struct task { + struct task *prev; + struct task *next; + task_callback callback; + uint64_t task_num; + uint64_t priority; + uint64_t elr; + uint64_t spsr; +} task_t; + +void execute_tasks(uint64_t elr,uint64_t spsr); +void create_task(task_callback callback,uint64_t priority); +void enqueue_task(task_t *new_task); +extern task_t *task_head; \ No newline at end of file diff --git a/Lab3/kernel/include/time_c.h b/Lab3/kernel/include/time_c.h new file mode 100644 index 000000000..90298cd82 --- /dev/null +++ b/Lab3/kernel/include/time_c.h @@ -0,0 +1,22 @@ +#ifndef __TIME_C_H +#define __TIME_C_H + +#define CORE0_TIMER_IRQ_CTRL ((volatile unsigned int*)(0x40000040)) +#define CORE0_INTERRUPT_SOURCE ((volatile unsigned int*)(0x40000060)) + +typedef void (*task_callback)(); + +typedef struct timer_info { + struct timer_info *prev; + struct timer_info *next; + char* msg; + task_callback callback; + unsigned long long executeTime; +}timer_info; + +extern timer_info *timer_head; + +void setTimeout(char* message, unsigned long long wait); +void timer_init(); + +#endif \ No newline at end of file diff --git a/Lab3/kernel/include/uart.h b/Lab3/kernel/include/uart.h new file mode 100644 index 000000000..29fd71954 --- /dev/null +++ b/Lab3/kernel/include/uart.h @@ -0,0 +1,43 @@ +#ifndef UART_H +#define UART_H + +#include "gpio.h" + +typedef unsigned int Reg; +void uart_init(); +void uart_send_char(unsigned int c); +char uart_get_char(); +void uart_display_string(char* s); +void uart_binary_to_hex(unsigned int d); +void uart_binary_to_int(unsigned int d); + +char uart_async_get(); +void uart_async_send_string(char *str); +void test_uart_async(); + +void uart_enable_interrupt(); +void uart_disable_interrupt(); +void set_transmit_interrupt(); +void clear_transmit_interrupt(); +void uart_handler(); +void uart_buf_init(); + +void putc ( void* p, char c); +void delay(unsigned int clock); + +#define AUX_ENABLE ((volatile unsigned int*)(MMIO_BASE+0x00215004)) +#define AUX_MU_IO_REG ((volatile unsigned int*)(MMIO_BASE+0x00215040)) +#define AUX_MU_IER_REG ((volatile unsigned int*)(MMIO_BASE+0x00215044)) +#define AUX_MU_IIR_REG ((volatile unsigned int*)(MMIO_BASE+0x00215048)) +#define AUX_MU_LCR_REG ((volatile unsigned int*)(MMIO_BASE+0x0021504C)) +#define AUX_MU_MCR_REG ((volatile unsigned int*)(MMIO_BASE+0x00215050)) +#define AUX_MU_LSR_REG ((volatile unsigned int*)(MMIO_BASE+0x00215054)) +#define AUX_MU_MSR_REG ((volatile unsigned int*)(MMIO_BASE+0x00215058)) +#define AUX_MU_SCRATCH ((volatile unsigned int*)(MMIO_BASE+0x0021505C)) +#define AUX_MU_CNTL_REG ((volatile unsigned int*)(MMIO_BASE+0x00215060)) +#define AUX_MU_STAT_REG ((volatile unsigned int*)(MMIO_BASE+0x00215064)) +#define AUX_MU_BAUD_REG ((volatile unsigned int*)(MMIO_BASE+0x00215068)) + + + +#endif \ No newline at end of file diff --git a/Lab3/kernel/include/utils.h b/Lab3/kernel/include/utils.h new file mode 100644 index 000000000..873ecffec --- /dev/null +++ b/Lab3/kernel/include/utils.h @@ -0,0 +1,15 @@ +#include +#include + +int utils_string_compare(const char* str1,const char* str2); +unsigned long utils_hex2dec(const char *s, int char_size); +void utils_align(void *size, unsigned int s); +uint32_t utils_align_up(uint32_t size, int alignment); +size_t utils_strlen(const char *s); +int utils_keyword_compare(const char* str1,const char* str2); +int utils_find_api(const char* str1); +int utils_api_compare(const char* str1,const char* str2); +char* utils_api_analysis(char* str1); +int utils_api_elem_count(const char* str1); +void utils_api_get_elem(const char* str1, char** buff1, char** buff2); +int utils_str2int(const char* s); \ No newline at end of file diff --git a/Lab3/kernel/include/utils_h.h b/Lab3/kernel/include/utils_h.h new file mode 100644 index 000000000..0dfd29785 --- /dev/null +++ b/Lab3/kernel/include/utils_h.h @@ -0,0 +1,7 @@ +#ifndef _BOOT_H +#define _BOOT_H + +extern int get_el ( void ); +extern int get_sp ( void ); + +#endif /*_BOOT_H */ \ No newline at end of file diff --git a/Lab3/kernel/initramfs.cpio b/Lab3/kernel/initramfs.cpio new file mode 100644 index 000000000..c836d2dd1 Binary files /dev/null and b/Lab3/kernel/initramfs.cpio differ diff --git a/Lab3/kernel/src/allocater.c b/Lab3/kernel/src/allocater.c new file mode 100644 index 000000000..93e87be56 --- /dev/null +++ b/Lab3/kernel/src/allocater.c @@ -0,0 +1,20 @@ +#include "allocator.h" +#include "utils.h" + +#define SIMPLE_MALLOC_BUFFER_SIZE 8192 +static unsigned char simple_malloc_buffer[SIMPLE_MALLOC_BUFFER_SIZE]; +static unsigned long simple_malloc_offset = 0; + +void* simple_malloc(unsigned long size){ + //align to 8 bytes + utils_align(&size,8); + + if(simple_malloc_offset + size > SIMPLE_MALLOC_BUFFER_SIZE) { + //Not enough space left + return (void*) 0; + } + void* allocated = (void *)&simple_malloc_buffer[simple_malloc_offset]; + simple_malloc_offset += size; + + return allocated; +} \ No newline at end of file diff --git a/Lab3/kernel/src/cpio.c b/Lab3/kernel/src/cpio.c new file mode 100644 index 000000000..1fd0bd6d7 --- /dev/null +++ b/Lab3/kernel/src/cpio.c @@ -0,0 +1,167 @@ + +#include +#include + +#include "uart.h" +#include "utils.h" +#include "cpio.h" +#include "allocator.h" +#include "printf.h" +#include "utils_h.h" + +#define USTACK_SIZE 0x2000 + +int file_num = 0; +struct file *f = NULL; + +char *cpio_addr = (char *)0x20000000; +// char *cpio_addr = (char *)0x8000000; + + +char *findFile(char *name) +{ + char *addr = (char *)cpio_addr; + while (cpio_TRAILER_compare((char *)(addr+sizeof(struct new_cpio_header))) == 0) + { + if ((utils_string_compare((char *)(addr + sizeof(struct new_cpio_header)), name) != 0)) + { + return addr; + } + struct new_cpio_header* header = (struct new_cpio_header *)addr; + unsigned long pathname_size = utils_hex2dec(header->c_namesize,(int)sizeof(header->c_namesize));; + unsigned long file_size = utils_hex2dec(header->c_filesize,(int)sizeof(header->c_filesize)); + unsigned long headerPathname_size = sizeof(struct new_cpio_header) + pathname_size; + + utils_align(&headerPathname_size,4); + utils_align(&file_size,4); + addr += (headerPathname_size + file_size); + } + return 0; +} + +void cpio_ls(){ + char* addr = (char*) cpio_addr; + // uart_display_string(addr); + // uart_display_string("\n"); + // int i = 0; + while(1){ + uart_send_char('\r'); + uart_display_string((char *)(addr+sizeof(struct new_cpio_header))); + uart_display_string("\n"); + + struct new_cpio_header* header = (struct new_cpio_header*) addr; + unsigned long filename_size = utils_hex2dec(header->c_namesize,(int)sizeof(header->c_namesize)); + unsigned long headerPathname_size = sizeof(struct new_cpio_header) + filename_size; + unsigned long file_size = utils_hex2dec(header->c_filesize,(int)sizeof(header->c_filesize)); + + utils_align(&headerPathname_size,4); + utils_align(&file_size,4); + + if(cpio_TRAILER_compare((char *)(addr+sizeof(struct new_cpio_header)))){ + break; + } + + addr += (headerPathname_size + file_size); + } +} + +void cpio_cat(char *filename) +{ + char *target = findFile(filename); + if (target) + { + struct new_cpio_header *header = (struct new_cpio_header *)target; + unsigned long pathname_size = utils_hex2dec(header->c_namesize,(int)sizeof(header->c_namesize)); + unsigned long file_size = utils_hex2dec(header->c_filesize,(int)sizeof(header->c_filesize)); + unsigned long headerPathname_size = sizeof(struct new_cpio_header) + pathname_size; + + utils_align(&headerPathname_size,4); + utils_align(&file_size,4); + + char *file_content = target + headerPathname_size; + uart_send_char('\r'); + for (unsigned int i = 0; i < file_size; i++) + { + uart_send_char(file_content[i]); + } + uart_display_string("\n"); + } + else + { + uart_display_string("\rNot found the file\n"); + } +} + +int cpio_TRAILER_compare(const char* str1){ + const char* str2 = "TRAILER!!!"; + for(;*str1 !='\0'||*str2 !='\0';str1++,str2++){ + + if(*str1 != *str2){ + return 0; + } + else if(*str1 == '!' && *str2 =='!'){ + return 1; + } + } + return 1; +} + +void cpio_load_program(char *filename) +{ + // 查找文件,返回該文件的地址,如果找到了,prog_addr 就不為空 + char *prog_addr = findFile(filename); + + // 定義變量 put_addr,將目標地址設置為 0x200000 + void *put_addr = (void *)0x200000; + + // 如果找到了文件 + if (prog_addr) + { + struct new_cpio_header* header = (struct new_cpio_header*) prog_addr; + + unsigned int pathname_size = utils_hex2dec(header->c_namesize,(int)sizeof(header->c_namesize)); + unsigned int file_size = utils_hex2dec(header->c_filesize,(int)sizeof(header->c_filesize)); + + unsigned int headerPathname_size = sizeof(struct new_cpio_header) + pathname_size; + + utils_align(&headerPathname_size, 4); + utils_align(&file_size, 4); + + uart_display_string("\r----------------"); + uart_display_string(prog_addr + sizeof(struct new_cpio_header)); + uart_display_string("----------------\n"); + + // 將文件內容從源地址放到目標地址上 + // 將二進制內容讀出來從0x200000開始放,所以linker script裡寫的0x200000不代表檔案就真的會load入0x20000 + char *file_content = prog_addr + headerPathname_size; + unsigned char *target = (unsigned char *)put_addr; + + uart_display_string("put the target to 0x200000\n"); + + while (file_size--) + { + *target = *file_content; + target++; + file_content++; + } + + + asm volatile("mov x0, 0x3c0 \n"); + asm volatile("msr SPSR_EL1, x0 \n"); + asm volatile("msr ELR_EL1, %0 \n" ::"r"(put_addr)); + asm volatile("mov x0, 0x200000"); + asm volatile("msr SP_EL0, x0 \n"); + asm volatile("mov x0, 0x0 \n"); + asm volatile("msr SPSR_EL1, x0 \n"); + asm volatile("eret \n"); + + // 在這段程式碼中,關鍵字 volatile 的作用是告訴編譯器不要對這些指令進行優化或重排, + // 以確保它們按照指定的順序執行。 + // 這是因為這些指令是直接操作 CPU 寄存器和系統狀態的,如果出現任何錯誤或異常行為, + // 可能會導致系統崩潰或不正常運行。 + } + else{ + // 如果沒有找到該文件,使用串口打印信息 + uart_display_string("Not found the program\n"); + } +} \ No newline at end of file diff --git a/Lab3/kernel/src/dtb.c b/Lab3/kernel/src/dtb.c new file mode 100644 index 000000000..06b0b4416 --- /dev/null +++ b/Lab3/kernel/src/dtb.c @@ -0,0 +1,172 @@ +#include "dtb.h" +#include "uart.h" +#include "utils.h" + +#define UNUSED(x) ( (void)(x) ) + +char* cpio_addr; +int space = 0; + +void send_space(int n) { + while(n--) uart_display_string("\t"); +} + +uint32_t fdt_u32_le2be (const void *addr) { + const uint8_t *bytes = (const uint8_t *) addr; + uint32_t ret = (uint32_t)bytes[0] << 24 |(uint32_t)bytes[1] << 16 |(uint32_t)bytes[2] << 8 |(uint32_t)bytes[3]; + return ret; +} + +int fdt_traverse(fdt_callback cb, void* _dtb){ + uintptr_t dtb_ptr = (uintptr_t) _dtb; + uart_send_char('\n'); + uart_send_char('\r'); + uart_display_string("dtb loading at "); + uart_binary_to_hex(dtb_ptr); + uart_send_char('\n'); + struct fdt_header* header = (struct fdt_header*) dtb_ptr; + uint32_t magic = fdt_u32_le2be(&(header->magic)); + + if (magic != 0xd00dfeed){ + uart_send_char('\r'); + uart_display_string("The header magic is wrong\n"); + return -1; + } + else{ + uart_send_char('\r'); + uart_display_string("magic == "); + uart_binary_to_hex(magic); + uart_send_char('\n'); + } + + uintptr_t struct_ptr = dtb_ptr + fdt_u32_le2be(&(header->off_dt_struct)); + uintptr_t strings_ptr = dtb_ptr + fdt_u32_le2be(&(header->off_dt_strings)); + uint32_t totalsize = fdt_u32_le2be(&header->totalsize); + uart_send_char('\r'); + uart_display_string("Structure offset is "); + uart_binary_to_hex(struct_ptr); + uart_send_char('\n'); + uart_send_char('\r'); + uart_display_string("Strings offset is at"); + uart_binary_to_hex(strings_ptr); + uart_send_char('\n'); + // uart_display_string("total size is "); + // uart_binary_to_hex(totalsize); + // uart_send_char('\n'); + uart_send_char('\n'); + + struct_parse(cb, struct_ptr, strings_ptr, totalsize); + + return 1; +} + +int struct_parse(fdt_callback cb, uintptr_t cur_ptr, uintptr_t strings_ptr,uint32_t totalsize){ + + uintptr_t end_ptr = cur_ptr + totalsize; + // int count = 0; + while(cur_ptr < end_ptr){ + + + uint32_t token = fdt_u32_le2be((char*) cur_ptr); + cur_ptr += 4; + + switch(token){ + case FDT_BEGIN_NODE: + // count += 1; + cb(token, (char*)cur_ptr, NULL, 0); + cur_ptr += utils_align_up(utils_strlen((char*)cur_ptr),4); + break; + case FDT_END_NODE: + cb(token, NULL, NULL,0); + break; + case FDT_PROP:{ + uint32_t len = fdt_u32_le2be((char*)cur_ptr); + cur_ptr += 4; + uint32_t nameoff = fdt_u32_le2be((char*)cur_ptr); + cur_ptr += 4; + cb(token,(char*)(strings_ptr + nameoff), (char*)cur_ptr, len); + cur_ptr += utils_align_up(len,4); + } + break; + case FDT_NOP: + cb(token,NULL,NULL,0); + break; + case FDT_END: + cb(token,NULL,NULL,0); + break; + } + // if (count > 10 && token == FDT_END_NODE){ + // break; + // } + } + return 0; + +} + +void print_dtb(int token, const char* name, const void* data, uint32_t len) { + // UNUSED(size); + + switch(token){ + case FDT_BEGIN_NODE: + uart_display_string("\n"); + send_space(space); + uart_display_string((char*)name); + uart_display_string("{\n "); + space++; + break; + case FDT_END_NODE: + uart_display_string("\n"); + space--; + if(space >0) send_space(space); + uart_display_string("}\n"); + break; + case FDT_NOP: + break; + case FDT_PROP: + send_space(space); + uart_display_string((char*)name); + uart_display_string(" : "); + data_parse((char*)name, data, len); + uart_display_string("\n"); + break; + case FDT_END: + break; + } +} + +void get_cpio_addr(int token,const char* name,const void* data,uint32_t size){ + UNUSED(size); + if(token==FDT_PROP && utils_string_compare((char *)name,"linux,initrd-start")){ + cpio_addr = (char*)(uintptr_t)fdt_u32_le2be(data); + uart_send_char('\r'); + uart_display_string("cpio address is at: "); + uart_binary_to_hex((uintptr_t)fdt_u32_le2be(data)); + uart_send_char('\n'); + } +} + +void data_parse(const char* name, const void* data, uint32_t len){ + + if(utils_keyword_compare(name, "microchip") || utils_string_compare(name, "reg") || utils_string_compare(name, "virtual-reg") || utils_string_compare(name, "ranges") || utils_string_compare(name, "size") || utils_string_compare(name, "reusable")){ + if(len == 0){ + uart_display_string(""); + } + while(len>0){ + uart_send_char('<'); + uart_binary_to_hex((uintptr_t)fdt_u32_le2be(data)); + uart_send_char('>'); + uart_send_char(' '); + len -= 4; + } + + } + else if(utils_string_compare(name, "compatible") || utils_string_compare(name, "clocks") || utils_keyword_compare(name, "assigned") || utils_keyword_compare(name, "linux") || name[0] == '#' || utils_string_compare(name, "phandle") || utils_keyword_compare(name, "interrupt")){ + uart_send_char('<'); + uart_binary_to_hex((uintptr_t)fdt_u32_le2be(data)); + uart_send_char('>'); + uart_send_char(' '); + } + else{ + uart_display_string((char*) data); + } +} diff --git a/Lab3/kernel/src/except.c b/Lab3/kernel/src/except.c new file mode 100644 index 000000000..5dafe1b7a --- /dev/null +++ b/Lab3/kernel/src/except.c @@ -0,0 +1,133 @@ +#include "uart.h" +#include "shell.h" +#include "time_c.h" +#include "except_c.h" +#include "interrupt.h" +#include "tasklist.h" +#include "printf.h" +#include "utils_h.h" +#include "utils.h" + +#include + +#define CNTPSIRQ_BIT_POSITION 0x02 +#define AUXINIT_BIT_POSTION 1<<29 + +void core_timer_exception_entry() { + + unsigned long long cntpct_el0 = 0;//The register count secs with frequency + asm volatile("mrs %0,cntpct_el0":"=r"(cntpct_el0)); + unsigned long long cntfrq_el0 = 0;//The base frequency + asm volatile("mrs %0,cntfrq_el0":"=r"(cntfrq_el0)); + + unsigned long long sec = cntpct_el0 / cntfrq_el0; + + uart_display_string("\r"); + uart_display_string(timer_head->msg); + printf(" <- show in %d sec (after booting up)",sec); + uart_display_string("\n"); + + + // timer_head->msg = ""; + + if (timer_head->next){ + timer_head = timer_head->next; + task_head->prev = NULL; + asm volatile ("msr cntp_cval_el0, %0"::"r"(timer_head->executeTime));//set new timer + asm volatile ("bl core_timer_irq_enable"); + } + else{ + timer_head = NULL; + asm volatile ("bl core_timer_irq_disable"); + } + +} +uint32_t count = 0; +uint64_t elr; +uint64_t spsr; +uint64_t nest_elr; +uint64_t nest_spsr; + +void irq_exception_entry(){ + disable_interrupt(); + // printf("IN IRQ\n"); + count++; + if(count == 1){ + asm volatile("mrs %0,elr_el1":"=r"(elr)); + asm volatile("mrs %0,spsr_el1":"=r"(spsr)); + } + else if(count == 2){ + asm volatile("mrs %0,elr_el1":"=r"(nest_elr)); + asm volatile("mrs %0,spsr_el1":"=r"(nest_spsr)); + } + + uint32_t irq_pending1 = *IRQ_PENDING_1; + uint32_t core0_interrupt_source = *CORE0_INTERRUPT_SOURCE; + uint32_t uart = irq_pending1 & AUXINIT_BIT_POSTION; + uint32_t core = core0_interrupt_source & 0x2; + + if(uart || core){ + if(uart) { + uart_disable_interrupt(); + create_task(uart_handler, 2); + // uart_handler(); + } + if(core){ + asm volatile("bl core_timer_irq_disable"); + create_task(core_timer_exception_entry,1); + // core_timer_exception_entry(); + } + } + else{ + asm volatile("bl core_timer_irq_disable"); + uart_disable_interrupt(); + } + + enable_interrupt(); + if(task_head && count == 1){ + execute_tasks(elr,spsr); + } + // printf("OUT IRQ\n"); + count--; +} + +void exception_entry() { + uart_display_string("\rIn Exception handler\n"); + + //read spsr_el1 + unsigned long long spsr_el1 = 0; + asm volatile("mrs %0, spsr_el1":"=r"(spsr_el1)); + uart_display_string("spsr_el1: "); + uart_binary_to_hex(spsr_el1); + uart_display_string("\n"); + + //read elr_el1 + unsigned long long elr_el1 = 0; + asm volatile("mrs %0, elr_el1":"=r"(elr_el1)); + uart_display_string("elr_el1: "); + uart_binary_to_hex(elr_el1); + uart_display_string("\n"); + + //esr_el1 + unsigned long long esr_el1 = 0; + asm volatile("mrs %0, esr_el1":"=r"(esr_el1)); + uart_display_string("esr_el1: "); + uart_binary_to_hex(esr_el1); + uart_display_string("\n"); + + //ec + unsigned ec = (esr_el1 >> 26) & 0x3F; // 0x3F == 0b111111(6) + uart_display_string("ec: "); + uart_binary_to_hex(ec); + uart_display_string("\n"); // SVC instruction execution in AArch64 state. +} + +void test_entry(){ + uart_display_string("I'm in the test entry\n"); +} + + + + + + diff --git a/Lab3/kernel/src/interrupt.c b/Lab3/kernel/src/interrupt.c new file mode 100644 index 000000000..11290118b --- /dev/null +++ b/Lab3/kernel/src/interrupt.c @@ -0,0 +1,9 @@ +#include "interrupt.h" +#include "printf.h" + +void enable_interrupt() { + asm volatile("msr DAIFClr, 0xf"); + } +void disable_interrupt() { + asm volatile("msr DAIFSet, 0xf"); + } \ No newline at end of file diff --git a/Lab3/kernel/src/linker.ld b/Lab3/kernel/src/linker.ld new file mode 100644 index 000000000..831b003bf --- /dev/null +++ b/Lab3/kernel/src/linker.ld @@ -0,0 +1,19 @@ +SECTIONS +{ + . = 0x80000; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start) >> 3; diff --git a/Lab3/kernel/src/mailbox.c b/Lab3/kernel/src/mailbox.c new file mode 100644 index 000000000..c1ccd5032 --- /dev/null +++ b/Lab3/kernel/src/mailbox.c @@ -0,0 +1,50 @@ +#include "mailbox.h" +#include "uart.h" + +volatile unsigned int __attribute__((aligned(16))) mailbox[36]; + +int mailbox_call() +{ + unsigned int r = (((unsigned int)((unsigned long)&mailbox)&~0xF) | (MBOX_CH_PROP&0xF)); + /* wait until we can write to the mailbox */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL); + /* write the address of our message to the mailbox with channel identifier */ + *MBOX_WRITE = r; + /* now wait for the response */ + while(1) { + /* is there a response? */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY); + /* is it a response to our message? */ + if(r == *MBOX_READ){ + return mailbox[1]==MBOX_RESPONSE; + } + } + return 0; +} + +void get_board_revision(){ + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = MBOX_REQUEST; + // tags begin + mailbox[2] = MBOX_TAG_GETBOARD; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = MBOX_TAG_LAST; + // mailbox_call(); // message passing procedure call, we should implement it following the 6 steps provided above. +} + +void get_arm_mem(){ + mailbox[0] = 8 * 4; // buffer size in bytes + mailbox[1] = MBOX_REQUEST; + // tags begin + mailbox[2] = MBOX_TAG_GETARMMEM; // tag identifier + mailbox[3] = 8; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + mailbox[6] = 0; // value buffer + // tags end + mailbox[7] = MBOX_TAG_LAST; + // mailbox_call(); // message passing procedure call, we should implement it following the 6 steps provided above. +} \ No newline at end of file diff --git a/Lab3/kernel/src/main.c b/Lab3/kernel/src/main.c new file mode 100644 index 000000000..1e2298d15 --- /dev/null +++ b/Lab3/kernel/src/main.c @@ -0,0 +1,34 @@ +#include "printf.h" +#include "uart.h" +#include "shell.h" +#include "dtb.h" +#include "utils.h" +#include "utils_h.h" +#include "time_c.h" +#include "interrupt.h" + +extern void *_dtb_ptr; + +void main() +{ + uart_init(); // Set up the Uart + + init_printf(0, putc); + int el = get_el(); + int s = get_sp(); + printf("\r\nIn Exception level: %d \r\n", el); + printf("Stack Pinter Select is %d \r\n", s); + + // say hello + fdt_traverse(get_cpio_addr, _dtb_ptr); + uart_display_string("\r\n"); + + timer_init(); + + uart_display_string("\r\n"); + uart_display_string("Type in \"help\" to get instruction menu!\n"); + + + // echo everything back + shell(); +} \ No newline at end of file diff --git a/Lab3/kernel/src/printf.c b/Lab3/kernel/src/printf.c new file mode 100644 index 000000000..1383039a5 --- /dev/null +++ b/Lab3/kernel/src/printf.c @@ -0,0 +1,233 @@ +/* +File: printf.c + +Copyright (C) 2004 Kustaa Nyholm + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "printf.h" + +typedef void (*putcf) (void*,char); +static putcf stdout_putf; +static void* stdout_putp; + + +#ifdef PRINTF_LONG_SUPPORT + +static void uli2a(unsigned long int num, unsigned int base, int uc,char * bf) + { + int n=0; + unsigned int d=1; + while (num/d >= base) + d*=base; + while (d!=0) { + int dgt = num / d; + num%=d; + d/=base; + if (n || dgt>0|| d==0) { + *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10); + ++n; + } + } + *bf=0; + } + +static void li2a (long num, char * bf) + { + if (num<0) { + num=-num; + *bf++ = '-'; + } + uli2a(num,10,0,bf); + } + +#endif + +static void ui2a(unsigned int num, unsigned int base, int uc,char * bf) + { + int n=0; + unsigned int d=1; + while (num/d >= base) + d*=base; + while (d!=0) { + int dgt = num / d; + num%= d; + d/=base; + if (n || dgt>0 || d==0) { + *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10); + ++n; + } + } + *bf=0; + } + +static void i2a (int num, char * bf) + { + if (num<0) { + num=-num; + *bf++ = '-'; + } + ui2a(num,10,0,bf); + } + +static int a2d(char ch) + { + if (ch>='0' && ch<='9') + return ch-'0'; + else if (ch>='a' && ch<='f') + return ch-'a'+10; + else if (ch>='A' && ch<='F') + return ch-'A'+10; + else return -1; + } + +static char a2i(char ch, char** src,int base,int* nump) + { + char* p= *src; + int num=0; + int digit; + while ((digit=a2d(ch))>=0) { + if (digit>base) break; + num=num*base+digit; + ch=*p++; + } + *src=p; + *nump=num; + return ch; + } + +static void putchw(void* putp,putcf putf,int n, char z, char* bf) + { + char fc=z? '0' : ' '; + char ch; + char* p=bf; + while (*p++ && n > 0) + n--; + while (n-- > 0) + putf(putp,fc); + while ((ch= *bf++)) + putf(putp,ch); + } + +void tfp_format(void* putp,putcf putf,char *fmt, va_list va) + { + char bf[12]; + + char ch; + + + while ((ch=*(fmt++))) { + if (ch!='%') + putf(putp,ch); + else { + char lz=0; +#ifdef PRINTF_LONG_SUPPORT + char lng=0; +#endif + int w=0; + ch=*(fmt++); + if (ch=='0') { + ch=*(fmt++); + lz=1; + } + if (ch>='0' && ch<='9') { + ch=a2i(ch,&fmt,10,&w); + } +#ifdef PRINTF_LONG_SUPPORT + if (ch=='l') { + ch=*(fmt++); + lng=1; + } +#endif + switch (ch) { + case 0: + goto abort; + case 'u' : { +#ifdef PRINTF_LONG_SUPPORT + if (lng) + uli2a(va_arg(va, unsigned long int),10,0,bf); + else +#endif + ui2a(va_arg(va, unsigned int),10,0,bf); + putchw(putp,putf,w,lz,bf); + break; + } + case 'd' : { +#ifdef PRINTF_LONG_SUPPORT + if (lng) + li2a(va_arg(va, unsigned long int),bf); + else +#endif + i2a(va_arg(va, int),bf); + putchw(putp,putf,w,lz,bf); + break; + } + case 'x': case 'X' : +#ifdef PRINTF_LONG_SUPPORT + if (lng) + uli2a(va_arg(va, unsigned long int),16,(ch=='X'),bf); + else +#endif + ui2a(va_arg(va, unsigned int),16,(ch=='X'),bf); + putchw(putp,putf,w,lz,bf); + break; + case 'c' : + putf(putp,(char)(va_arg(va, int))); + break; + case 's' : + putchw(putp,putf,w,0,va_arg(va, char*)); + break; + case '%' : + putf(putp,ch); + default: + break; + } + } + } + abort:; + } + + +void init_printf(void* putp,void (*putf) (void*,char)) + { + stdout_putf=putf; + stdout_putp=putp; + } + +void tfp_printf(char *fmt, ...) + { + va_list va; + va_start(va,fmt); + tfp_format(stdout_putp,stdout_putf,fmt,va); + va_end(va); + } + +static void putcp(void* p,char c) + { + *(*((char**)p))++ = c; + } + + + +void tfp_sprintf(char* s,char *fmt, ...) + { + va_list va; + va_start(va,fmt); + tfp_format(&s,putcp,fmt,va); + putcp(&s,0); + va_end(va); + } diff --git a/Lab3/kernel/src/reboot.c b/Lab3/kernel/src/reboot.c new file mode 100644 index 000000000..133e7284f --- /dev/null +++ b/Lab3/kernel/src/reboot.c @@ -0,0 +1,16 @@ +#include "reboot.h" + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +void reset(int tick) { // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick +} + +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // cancel reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} \ No newline at end of file diff --git a/Lab3/kernel/src/shell.c b/Lab3/kernel/src/shell.c new file mode 100644 index 000000000..23beef50c --- /dev/null +++ b/Lab3/kernel/src/shell.c @@ -0,0 +1,180 @@ +#include "shell.h" +#include "uart.h" +#include "mailbox.h" +#include "utils.h" +#include "reboot.h" +#include "cpio.h" +#include "allocator.h" +#include "dtb.h" +#include "interrupt.h" +#include "time_c.h" +#include "printf.h" + +extern void *_dtb_ptr; + +#define BUFFER_MAX_SIZE 256u + +void read_command(char* buffer) { + int index = 0; + while(1) { + buffer[index] = uart_get_char(); + uart_send_char(buffer[index]); + if(buffer[index] == '\n') { + buffer[index] = '\0'; + buffer[index+1] = '\n'; + break; + } + index++; + } +} + +void shell(){ + + char buffer[BUFFER_MAX_SIZE]; + + + while(1) { + uart_buf_init(); + + + + uart_display_string("\r"); + uint32_t now; + asm volatile("adr %0,#0":"=r"(now)); + printf("0x%x",now); + uart_display_string(">>"); + read_command(buffer); + + char * input_string = buffer; + + if(!utils_find_api(input_string)){ + + if(utils_string_compare(input_string,"help")) { + uart_display_string("\r"); + uart_display_string("help : Print this help menu\n"); + uart_display_string("hello : Print Hello World!\n"); + uart_display_string("info : Get the hardware's information\n"); + uart_display_string("reboot : Reboot the device\n"); + uart_display_string("ls : List the file\n"); + uart_display_string("cat : show a file content\n"); + uart_display_string("malloc : give dynamic memory space\n"); + uart_display_string("dtb : read dtb\n"); + uart_display_string("exe : execute the user program & print Spec-info \n"); + uart_display_string("coretimer : coretimer testing\n"); + uart_display_string("async_print : print the message out of sync\n"); + uart_display_string("async_get : get the message out of sync and print the message\n"); + uart_display_string("addtimer(msg, time) : the message will print after five seconds\n"); + } + else if (utils_string_compare(input_string,"hello")) { + uart_display_string("\rHello World!\n"); + } + else if (utils_string_compare(input_string,"info")) { + get_board_revision(); + if (mailbox_call()) { + uart_display_string("\rMy board revision is: "); + uart_binary_to_hex(mailbox[5]); + uart_display_string("\n"); + } + else { + uart_display_string("Unable to query serial!\n"); + } + + get_arm_mem(); + if(mailbox_call()) { + uart_display_string("My ARM memory base address is: "); + uart_binary_to_hex(mailbox[5]); + uart_display_string("\n"); + uart_display_string("My ARM memory size is: "); + uart_binary_to_hex(mailbox[6]); + uart_display_string("\n"); + } + else { + uart_display_string("Unable to query serial!\n"); + } + } + else if (utils_string_compare(input_string,"reboot")) { + uart_display_string("Rebooting....\n"); + reset(1000); + } + else if (utils_string_compare(input_string,"ls")) { + cpio_ls(); + } + else if (utils_string_compare(input_string,"cat")){ + uart_send_char('\r'); + uart_display_string("Filename: "); + char filename[BUFFER_MAX_SIZE]; + read_command(filename); + cpio_cat(filename); + } + else if (utils_string_compare(input_string,"malloc")){ + char *a = simple_malloc(sizeof("allocater")); + char *b = simple_malloc(sizeof("345")); + a[0] = 'a'; a[1] = 'l'; a[2] = 'l'; a[3] = 'o'; + a[4] = 'c'; a[5] = 't'; a[6] = 'a'; a[7] = 'r'; + a[8] = '\0'; + b[0] = '3'; b[1] = '4'; b[2] = '5'; + b[3] = '\0'; + uart_send_char('\r'); + uart_display_string(a); + uart_send_char('\n'); + uart_send_char('\r'); + uart_display_string(b); + uart_send_char('\n'); + } + else if (utils_string_compare(input_string,"dtb")){ + fdt_traverse(print_dtb, _dtb_ptr); + } + else if (utils_string_compare(input_string, "exe")){ + uart_display_string("program name: "); + char buffer[BUFFER_MAX_SIZE]; + read_command(buffer); + cpio_load_program(buffer); + } + + else if (utils_string_compare(input_string, "async_print") || utils_string_compare(input_string, "ap")){ + uart_display_string("\r"); + uart_async_send_string("|---------->async test<----------|"); + uart_async_send_string("| | | o |"); + uart_async_send_string("| |----| | |"); + uart_async_send_string("| | | | ........... |"); + uart_async_send_string("|--------------------------------|"); + } + else if (utils_string_compare(input_string, "async_get")){ + test_uart_async(); + } + else if (utils_string_compare(input_string, "3timer")){ + setTimeout("This is 10", 10); + setTimeout("This is 5", 5); + setTimeout("This is 4", 4); + setTimeout("execute", 0); + } + else{ + uart_display_string("\rNo instruction\n"); + } + } + else{ + if(utils_api_compare(input_string,"addtimer()")){ + + + char* api_buff = (char*) simple_malloc(sizeof(input_string)); + char* message = (char*) simple_malloc(sizeof(input_string)); + char* delaytime = (char*) simple_malloc(sizeof(input_string)); + + api_buff = utils_api_analysis(input_string); + + utils_api_get_elem(api_buff, &message, &delaytime); + + char*msg = (char*) simple_malloc(sizeof(message)); + for(int i=0;i<=sizeof(message);i++){ + msg[i]=message[i]; + } + + setTimeout(msg,utils_str2int(delaytime)); + setTimeout("api executing",0); + } + else{ + uart_display_string("\rYou input a INVAILD function\n"); + } + } + } +} \ No newline at end of file diff --git a/Lab3/kernel/src/start.S b/Lab3/kernel/src/start.S new file mode 100644 index 000000000..8c4e0f58e --- /dev/null +++ b/Lab3/kernel/src/start.S @@ -0,0 +1,186 @@ +.section ".text.boot" + +.global _start + +_start: + ldr x1, =_dtb_ptr + str x0, [x1] + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 //Check processor id + cbz x1, exception //if CPU id = 0, jump to 2f + b hang + +hang: + wfe + b hang + +exception: + bl from_el2_to_el1 + bl set_exception_vector_table + +setup: + ldr x1, =_start + mov sp, x1 + ldr x1, =__bss_start + ldr w2, =__bss_size + +cleanBSS: + cbz w2, master + str xzr, [x1], #8 // x1* = xzr, x1 += 8 (write xzr represents discard, read xzr == 0) + sub w2, w2, #1 + cbnz w2, cleanBSS + +master: + bl core_timer_enable + bl main + b hang + +from_el2_to_el1: + mov x3, (1 << 31) // RW, bit [31] + msr hcr_el2, x3 // Execution state control for lower Exception levels (EL1) + mov x3, 0x3c5 // EL1h (SPSel = 1) with interrupt disabled + msr spsr_el2, x3 // 0x3c5 == 0b1111000101 + msr elr_el2, x30 // x30 is LR + eret // return to EL1 + +// save general registers to stack +.macro save_all + sub sp, sp, 32 * 8 + stp x0, x1, [sp ,16 * 0] + stp x2, x3, [sp ,16 * 1] + stp x4, x5, [sp ,16 * 2] + stp x6, x7, [sp ,16 * 3] + stp x8, x9, [sp ,16 * 4] + stp x10, x11, [sp ,16 * 5] + stp x12, x13, [sp ,16 * 6] + stp x14, x15, [sp ,16 * 7] + stp x16, x17, [sp ,16 * 8] + stp x18, x19, [sp ,16 * 9] + stp x20, x21, [sp ,16 * 10] + stp x22, x23, [sp ,16 * 11] + stp x24, x25, [sp ,16 * 12] + stp x26, x27, [sp ,16 * 13] + stp x28, x29, [sp ,16 * 14] + str x30, [sp, 16 * 15] +.endm + +// load general registers from stack +.macro load_all + ldp x0, x1, [sp ,16 * 0] + ldp x2, x3, [sp ,16 * 1] + ldp x4, x5, [sp ,16 * 2] + ldp x6, x7, [sp ,16 * 3] + ldp x8, x9, [sp ,16 * 4] + ldp x10, x11, [sp ,16 * 5] + ldp x12, x13, [sp ,16 * 6] + ldp x14, x15, [sp ,16 * 7] + ldp x16, x17, [sp ,16 * 8] + ldp x18, x19, [sp ,16 * 9] + ldp x20, x21, [sp ,16 * 10] + ldp x22, x23, [sp ,16 * 11] + ldp x24, x25, [sp ,16 * 12] + ldp x26, x27, [sp ,16 * 13] + ldp x28, x29, [sp ,16 * 14] + ldr x30, [sp, 16 * 15] + add sp, sp, 32 * 8 +.endm + +exception_handler: + save_all + bl exception_entry + load_all + eret + +irq_exception_handler: + save_all + bl irq_exception_entry + load_all + eret +.global exception_reload_all +exception_reload_all: + load_all + ret + +test_exception_handler: + save_all + bl test_entry + load_all + eret + +.align 11 // vector table should be aligned to 0x800 +.global exception_vector_table +exception_vector_table: + //同級exception level遷移,使用SP_EL0。 + b exception_handler // branch to a handler function. + .align 7 // entry size is 0x80, .align will pad 0 + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + //同級exception level遷移,使用SP_ELx。 + b exception_handler + .align 7 + b irq_exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + //ELx遷移到ELy,其中y>x且ELx處於AArch64狀態 + b exception_handler + .align 7 + b test_exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + //ELx遷移到ELy,其中y>x且ELx處於AArch32狀態 + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + +set_exception_vector_table: + adr x1, exception_vector_table + msr vbar_el1, x1 + ret + +#define CORE0_TIMER_IRQ_CTRL 0x40000040 + +.global core_timer_enable +core_timer_enable: + mov x0, 1 + msr cntp_ctl_el0, x0 // unmask timer interrupt + ret + +.global core_timer_disable +core_timer_disable: + mov x0, 0 + msr cntp_ctl_el0,x0 + ret + +.global core_timer_irq_enable +core_timer_irq_enable: + mov x0, 2 // control timer in non-secure mode + ldr x1, =CORE0_TIMER_IRQ_CTRL + str w0, [x1] // unmask timer interrupt + ret + +.global core_timer_irq_disable +core_timer_irq_disable: + mov x0, 0 // control timer in non-secure mode + ldr x1, =CORE0_TIMER_IRQ_CTRL + str w0, [x1] // unmask timer interrupt + ret + +.global _dtb_ptr //define a global variable _dtb_ptr +.section .data //_dtb_ptr is in data section +_dtb_ptr: .dc.a 0x0 //it defines _dtb_ptr to be a 8-byte constant with a value of 0x0 \ No newline at end of file diff --git a/Lab3/kernel/src/tasklist.c b/Lab3/kernel/src/tasklist.c new file mode 100644 index 000000000..0d07d0629 --- /dev/null +++ b/Lab3/kernel/src/tasklist.c @@ -0,0 +1,86 @@ +#include "tasklist.h" +#include "allocator.h" +#include "uart.h" +#include "printf.h" +#include "interrupt.h" + +task_t *task_head = NULL; +uint64_t task_count = 0; + +void enqueue_task(task_t *new_task) { + if (!task_head) { + new_task->next = task_head; + new_task->prev = NULL; + task_head = new_task; + } + else{ + + if (new_task->priority <= task_head->priority){ //new_task的優先級比開頭的任務還大 + // new_task->callback(); + new_task->next = task_head; + new_task->prev = NULL; + task_head->prev = new_task; + task_head = new_task; + } + else { + // Find the correct position in the list + task_t *current = task_head; + while (current->next && current->next->priority <= new_task->priority) { + current = current->next; + } + // Insert the new task + new_task->next = current->next; + new_task->prev = current; + if (current->next) { + current->next->prev = new_task; + } + current->next = new_task; + } + + } +} + + +void create_task(task_callback callback, uint64_t priority) { + disable_interrupt(); + task_count++; + task_t* task = simple_malloc(sizeof(task_t)); + if(!task) { + return; + } + + task->callback = callback; + task->priority = priority; + task->task_num = task_count; + + enqueue_task(task); +} + + +void execute_tasks(uint64_t elr,uint64_t spsr) { + + while (task_head) { + int exetasknum = task_head->task_num; + // printf("execute \n"); + task_head->callback(); + // printf("execute completed\n"); + if(exetasknum != task_head->task_num){ + continue; + } + else if (task_head->next) { + // printf("task_head->next\n"); + task_head = task_head->next; + task_head->prev = NULL; + + } + else{ + // printf("ELSE\n"); + asm volatile("msr elr_el1,%0"::"r"(elr)); + asm volatile("msr spsr_el1,%0"::"r"(spsr)); + // asm volatile("msr elr_el1,%0"::"r"(task_head->elr)); + // asm volatile("msr spsr_el1,%0"::"r"(task_head->spsr)); + task_head = NULL; + task_count = 0; + } + } +} \ No newline at end of file diff --git a/Lab3/kernel/src/time.c b/Lab3/kernel/src/time.c new file mode 100644 index 000000000..9bb63b797 --- /dev/null +++ b/Lab3/kernel/src/time.c @@ -0,0 +1,89 @@ +#include "time_c.h" +#include "uart.h" +#include "interrupt.h" +#include "printf.h" +#include "utils.h" +#include "allocator.h" + +timer_info *timer_head = NULL; + + +void enqueue_timer(timer_info *newTimer){ + + if(!timer_head){ + newTimer->next = timer_head; + newTimer->prev = NULL; + timer_head = newTimer; + } + else{ + if(newTimer->executeTime < timer_head->executeTime){ + newTimer->next = timer_head; + newTimer->prev = NULL; + timer_head = newTimer; + } + else if(newTimer->executeTime >= timer_head->executeTime){ + timer_info* current = timer_head; + + while(current->next && newTimer->executeTime >= current->next->executeTime){ + current = current->next; + } + newTimer->next = current->next; + newTimer->prev = current; + if (current->next) { + current->next->prev = newTimer; + } + current->next = newTimer; + } + } + +} + +void add_timer(char* msg, unsigned long long wait){ + unsigned long long cntfrq_el0 = 0;//The base frequency + asm volatile("mrs %0,cntfrq_el0":"=r"(cntfrq_el0)); + wait = cntfrq_el0*wait;// wait 2 seconds + unsigned long long current = 0; + asm volatile("mrs %0,cntpct_el0":"=r"(current)); + + // asm volatile ("msr cntp_tval_el0, %0"::"r"(wait));//set new timer + // unsigned long long cntp_cval = 0;//The base frequency + // asm volatile("mrs %0,cntp_cval_el0":"=r"(cntp_cval)); + + timer_info* timer = simple_malloc(sizeof(timer_info)); + timer->msg = msg; + timer->executeTime = current+wait; + enqueue_timer(timer); +} + +void setTimeout(char* message, unsigned long long wait){ + // timer_head->msg = msg; + // unsigned long long cntfrq_el0 = 0;//The base frequency + // asm volatile("mrs %0,cntfrq_el0":"=r"(cntfrq_el0)); + // wait = cntfrq_el0*wait;// wait 2 seconds + // asm volatile ("msr cntp_tval_el0, %0"::"r"(wait));//set new timer + + // delay(1); + add_timer(message, wait); + asm volatile ("msr cntp_cval_el0, %0"::"r"(timer_head->executeTime));//set new timer + + asm volatile("bl core_timer_irq_enable"); + // enable_interrupt(); + + if(timer_head){ + asm volatile ("bl core_timer_irq_enable"); + } + + // while(!(utils_string_compare(timer_head->msg,""))); +} + +void timer_init(){ + // unsigned long long wait; + // timer_head->msg = "The computer has finished booting up"; + // asm volatile("bl core_timer_irq_enable"); + // unsigned long long cntfrq_el0 = 0;//The base frequency + // asm volatile("mrs %0,cntfrq_el0":"=r"(cntfrq_el0)); + // wait = cntfrq_el0*2;// wait 2 seconds + // asm volatile ("msr cntp_tval_el0, %0"::"r"(wait));//set new timer + setTimeout("The computer has finished booting up", 2); + enable_interrupt(); +} \ No newline at end of file diff --git a/Lab3/kernel/src/uart.c b/Lab3/kernel/src/uart.c new file mode 100644 index 000000000..605055541 --- /dev/null +++ b/Lab3/kernel/src/uart.c @@ -0,0 +1,241 @@ +#include "uart.h" +#include +#include +#include +#include "interrupt.h" +#include "utils.h" +#include "except_c.h" +#include "shell.h" +#include "printf.h" +#include "time_c.h" +#include "tasklist.h" + +#define RX_INTERRUPT_BIT 0x01 +#define TX_INTERRUPT_BIT 0x02 + +#define AUXINIT_BIT_POSTION 1<<29 + +#define BUFFER_MAX_SIZE 256u + +// Create a Uart read buffer +char read_buf[BUFFER_MAX_SIZE]; +// Create a Uart write buffer +char write_buf[BUFFER_MAX_SIZE]; + +char empty_buf[BUFFER_MAX_SIZE]; + +// Buffer state +int read_buf_start, read_buf_end; +int write_buf_start, write_buf_end; + +void uart_buf_init(){ + for(int i = 0; i < BUFFER_MAX_SIZE; i++){ + write_buf[i] = empty_buf[i]; + read_buf[i] = empty_buf[i]; + } + read_buf_start = read_buf_end = 0; + write_buf_start = write_buf_end = 0; +} + +void delay(unsigned int clock) +{ + while (clock--) + { + asm volatile("nop"); + } +} + +void uart_init(){ + register unsigned int r; + + r=*GPFSEL1; + r&=~((7<<12)|(7<<15)); // gpio14, gpio15 clear to 0 + r|=(2<<12)|(2<<15); // set gpio14 and 15 to 010/010 which is alt5 + *GPFSEL1 = r; // from here activate Trasmitter&Receiver + + *GPPUD = 0; + r=150; while(r--){ asm volatile("nop"); } //delay(150) + *GPPUDCLK0 = (1<<14)|(1<<15); + // GPIO control 54 pins + // GPPUDCLK0 controls 0-31 pins + // GPPUDCLK1 controls 32-53 pins + // set 14,15 bits = 1 which means we will modify these two bits + // trigger: set pins to 1 and wait for one clock + + r=150; while(r--){ asm volatile("nop"); } //delay(150) + *GPPUDCLK0 = 0; // flush GPIO setup + r=500; while(r--){ asm volatile("nop"); } //delay(500) + + /* initialize UART */ + *AUX_ENABLE |= 1; //Enable mini uart + *AUX_MU_CNTL_REG = 0; //Disable auto flow control, reciver, and transmitter + *AUX_MU_IER_REG = 0; //Disable receive and transmit interrupts + *AUX_MU_LCR_REG = 3; //Enalbe 8 bit mode + *AUX_MU_MCR_REG = 0; //Set RTS line to be always high + *AUX_MU_BAUD_REG = 270; //Set baud rate to 115200 + *AUX_MU_IIR_REG = 0x6; //0xc6 = 000110 + //bit 6 bit 7 No FIFO. Sacrifice reliability(buffer) to get low latency + //Writing with bit 1 set will clear the receive FIFO + //Writing with bit 2 set will clear the transmit FIFO + *AUX_MU_CNTL_REG = 3; //enable transmitter and receiver + + read_buf_start = read_buf_end = 0; + write_buf_start = write_buf_end = 0; +} + +void uart_send_char(unsigned int c){ + while(!(*AUX_MU_LSR_REG&0x20)); + *AUX_MU_IO_REG=c; +} + +char uart_get_char(){ + char r; + while(!(*AUX_MU_LSR_REG&0x01)); + r=(char)(*AUX_MU_IO_REG); + return r=='\r'?'\n':r; +} + +void uart_display_string(char* s){ + while(*s) { + if(*s=='\n'){ + uart_send_char('\r'); + } + uart_send_char(*s++); + } +} + +void uart_binary_to_hex(unsigned int d) { + unsigned int n; + int c; + uart_display_string("0x"); + for(c=28;c>=0;c-=4) { + // get highest tetrad(4 bits) + n=(d>>c)&0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n += n>9 ? 0x37 : 0x30; + uart_send_char(n); + } +} + +void uart_binary_to_int(unsigned int d) { + unsigned int n; + int c = 0; + while(1){ + n = d - 10*c; + if(n<10){ + uart_send_char(n); + break; + } + c = 0; + while(n>10){ + n = n/10; + c++; + } + uart_send_char(n); + } +} + +void uart_enable_interrupt() { + uintptr_t enable_irqs1 = (uintptr_t) ENABLE_IRQS_1; + enable_irqs1 |= AUXINIT_BIT_POSTION; // Set bit29 + mmio_write(ENABLE_IRQS_1, enable_irqs1); +} + +void uart_disable_interrupt() { + uintptr_t disable_irqs1 = (uintptr_t) DISABLE_IRQS_1; + disable_irqs1 |= AUXINIT_BIT_POSTION; // Set bit29 + mmio_write(DISABLE_IRQS_1, disable_irqs1); +} + +void set_transmit_interrupt() { *AUX_MU_IER_REG |= 0x2; } + +void clear_transmit_interrupt() { *AUX_MU_IER_REG &= ~(0x2); } + + +void uart_handler() +{ + int RX = (*AUX_MU_IIR_REG & 0x4); // 檢查 RX 中斷是否觸發 + int TX = (*AUX_MU_IIR_REG & 0x2); // 檢查 TX 中斷是否觸發 + int tasknum = task_head->task_num; + + + if (RX){ + uart_display_string("*"); + char c; + c = uart_get_char(); + read_buf[read_buf_end++] = c; + uart_disable_interrupt(); + *AUX_MU_IER_REG &= ~(0x1); + } + else if (TX) // 如果 TX 中斷觸發 + { + while(write_buf_start != write_buf_end){ + printf("%d", task_head->task_num); + if(task_head->task_num != tasknum){ + break; + } + char c = write_buf[write_buf_start++]; + uart_send_char(c); + delay(10000); + } + uart_disable_interrupt(); + clear_transmit_interrupt(); + } +} + +char uart_async_get() { + + *AUX_MU_IER_REG |= (0x1); + + while (read_buf_start == read_buf_end) + { + uart_enable_interrupt(); + // enable_interrupt(); + } + char c = read_buf[read_buf_start++]; + return c; +} + +void uart_async_send_string(char *str) { + write_buf[write_buf_end++] = '\r'; + + for (int i = 0; str[i]; i++){ + // printf("\rwrite_buf_end = %d\r\n", write_buf_end); + if (write_buf_end == BUFFER_MAX_SIZE) + write_buf_end = 0; + write_buf[write_buf_end++] = str[i]; + } + + if(write_buf[write_buf_end-1] != '\n'){ + write_buf[write_buf_end++] = '\n'; + } + // uart_display_string("\r*****************************\r\n"); + while(write_buf_start != write_buf_end){ + uart_enable_interrupt(); + set_transmit_interrupt(); + // enable_interrupt(); + } +} + +void test_uart_async() +{ + char buffer[BUFFER_MAX_SIZE]; + size_t index = 0; + uart_display_string("\r"); + while(1){ + buffer[index] = uart_async_get(); + if(buffer[index]=='\n'){ + break; + } + index++; + } + uart_display_string("\r\n"); + uart_async_send_string(read_buf); + +} + +// This function is required by printf function +void putc ( void* p, char c) +{ + uart_send_char(c); +} \ No newline at end of file diff --git a/Lab3/kernel/src/utils.S b/Lab3/kernel/src/utils.S new file mode 100644 index 000000000..24999d0b5 --- /dev/null +++ b/Lab3/kernel/src/utils.S @@ -0,0 +1,9 @@ +.global get_el +get_el: + mrs x0, CurrentEL + lsr x0, x0, #2 + ret +.global get_sp +get_sp: + mrs x0, SPSel + ret \ No newline at end of file diff --git a/Lab3/kernel/src/utils.c b/Lab3/kernel/src/utils.c new file mode 100644 index 000000000..1d68c9cc4 --- /dev/null +++ b/Lab3/kernel/src/utils.c @@ -0,0 +1,156 @@ +#include "utils.h" +#include "uart.h" +#include +#include + +int utils_string_compare(const char* str1,const char* str2) { + + for(;*str1 !='\n'||*str2 !='\0';str1++,str2++){ + + if(*str1 != *str2){ + return 0; + } + else if(*str1 == '\n' || *str2 =='\0'){ + return 1; + } + + } + return 1; + +} + +char* utils_api_analysis(char* str1){ + + while(*str1){ + + if(*str1 == '('){ + break; + } + str1++; + } + return str1; +} + +int utils_api_compare(const char* str1,const char* str2) { + + for(;*str1 !='('||*str2 !='(';str1++,str2++){ + + if(*str1 != *str2){ + return 0; + } + } + return 1; + +} + +int utils_api_elem_count(const char* str1){ + int count = 0; + if(*(str1+1) == ')'){ + return 0; + } + while(*str1){ + if(*str1 == ',' || *str1 == ')'){ + count++; + } + str1++; + } + return count; +} + +int utils_find_api(const char* str1) { + int bracket_before = 0; + int bracket_after = 0; + while(*str1 !='\n'){ + + if(*str1 == '('){ + bracket_before = 1; + } + else if(bracket_before && *str1 == ')'){ + bracket_after = 1; + } + + if(bracket_after && bracket_after){ + return 1; + } + + str1++; + } + return 0; +} + +void utils_api_get_elem(const char* str1, char** buff1, char** buff2){ + char* copy = (char*) str1; + char* commaPos = copy; + char* bracketPos = copy; + while (*commaPos != ',') { + ++commaPos; + } + while (*bracketPos != ')') { + ++bracketPos; + } + + if(*commaPos ==','){ + *commaPos = '\0'; + *bracketPos = '\0'; + *buff1 = copy+1; + *buff2 = commaPos+1; + } +} + +unsigned long utils_hex2dec(const char *s, int char_size) { + unsigned long num = 0; + for (int i = 0; i < char_size; i++) { + num = num * 16; + if (*s >= '0' && *s <= '9') { + num += (*s - '0'); + } else if (*s >= 'A' && *s <= 'F') { + num += (*s - 'A' + 10); + } else if (*s >= 'a' && *s <= 'f') { + num += (*s - 'a' + 10); + } + s++; + } + return num; +} + +void utils_align(void *size, unsigned int s) { + unsigned long* x = (unsigned long*) size; + unsigned long mask = s-1; + *x = ((*x) + mask) & (~mask); +} + +uint32_t utils_align_up(uint32_t size, int alignment) { + return (size + alignment - 1) & ~(alignment-1); +} + +size_t utils_strlen(const char *s) { + size_t i = 0; + while (s[i]) i++; + return i+1; +} + +int utils_keyword_compare(const char* str1,const char* str2) { + + while(*str1 !='\0' && *str2 !='\0'){ + + if(*str1 != *str2){ + return 0; + } + else{ + str1++; + str2++; + } + } + return 1; +} + +int utils_str2int(const char* s){ + int num = 0; + while(*s){ + if(*s == '\0' || *s == '\n') break; + num = num *10; + num = num + (*s - '0'); + s++; + } + return num; +} \ No newline at end of file diff --git a/Lab3/kernel/uploader.py b/Lab3/kernel/uploader.py new file mode 100644 index 000000000..0be5daa8a --- /dev/null +++ b/Lab3/kernel/uploader.py @@ -0,0 +1,54 @@ +import serial +import os +import os.path +import sys +import time + +BAUD_RATE = 115200 + +def read_line(s): + received_string = "" + while True: + try: + c = s.read(1).decode() + except UnicodeDecodeError: + c = s.read(1).decode() + + if c=="\r": + continue + if c=="\n": + break + received_string += c + return received_string + +def send_img(ser, kernel): + print(read_line(ser)) + + kernel_size = os.stat(kernel).st_size + print((str(kernel_size) + "\n").encode()) + ser.write(("."+ str(kernel_size) + "\n").encode()) + + print("kernel size is ", read_line(ser)) + # print(read_line(ser)) + print(read_line(ser)) + + # 將映像檔逐一傳輸到對方端 + with open(kernel, "rb") as image: + while kernel_size > 0: + ser.write(image.read(1)) + kernel_size -= 1 + # ser.read_until(b".") + # 讀取對方端傳來的結束訊息 + print(read_line(ser)) + print(read_line(ser)) + print(ser.read_until("> ").decode(), end="") + return + +# 程式進入點 +if __name__ == "__main__": + # 設定串列通訊的埠號和傳輸速率,以及逾時時間 + # ser = serial.Serial("/dev/ttyUSB0", BAUD_RATE, timeout=5) + ser = serial.Serial("COM10", BAUD_RATE, timeout=5) + + # 傳輸映像檔 + send_img(ser, "kernel8.img") \ No newline at end of file diff --git a/README.md b/README.md index e08226b3a..0d4abe531 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# OSC2024 +# OSC2024 Lab3 | Github Account | Student ID | Name | |----------------|------------|---------------|