diff --git a/lab3_ADEX2/ReadMe.md b/lab3_ADEX2/ReadMe.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/lab3_ADEX2/ReadMe.md @@ -0,0 +1 @@ + diff --git a/lab3_ADEX2/shell/Makefile b/lab3_ADEX2/shell/Makefile new file mode 100644 index 000000000..beea4a7b2 --- /dev/null +++ b/lab3_ADEX2/shell/Makefile @@ -0,0 +1,22 @@ +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) +CFLAGS = -Iinclude -fno-stack-protector -Wall -Wextra -Wpedantic -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles +# CFLAGS += -I../../../opt/lib/gcc/aarch64-linux-gnu/12.2.0/include +CFLAGS += -I /usr/aarch64-linux-gnu/include +all: kernel8.img + +start.o: start.S + aarch64-linux-gnu-gcc $(CFLAGS) -c start.S -o start.o + +%.o: %.c + aarch64-linux-gnu-gcc $(CFLAGS) -c $< -o $@ + +kernel8.img: start.o $(OBJS) + aarch64-linux-gnu-ld start.o $(OBJS) -T linker.ld -o kernel8.elf + aarch64-linux-gnu-objcopy -O binary kernel8.elf kernel8.img + +clean: + rm kernel8.elf *.o >/dev/null 2>/dev/null || true + +run: + qemu-system-aarch64 -M raspi3b -serial null -serial stdio -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb -display none -kernel kernel8.img diff --git a/lab3_ADEX2/shell/README.md b/lab3_ADEX2/shell/README.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/lab3_ADEX2/shell/README.md @@ -0,0 +1 @@ + diff --git a/lab3_ADEX2/shell/allocator.c b/lab3_ADEX2/shell/allocator.c new file mode 100644 index 000000000..4ca648ee9 --- /dev/null +++ b/lab3_ADEX2/shell/allocator.c @@ -0,0 +1,20 @@ +#include "header/allocator.h" +#include "header/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; +} diff --git a/lab3_ADEX2/shell/allocator.o b/lab3_ADEX2/shell/allocator.o new file mode 100644 index 000000000..42047e4bf Binary files /dev/null and b/lab3_ADEX2/shell/allocator.o differ diff --git a/lab3_ADEX2/shell/bcm2710-rpi-3-b-plus.dtb b/lab3_ADEX2/shell/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..0dd0e2f43 Binary files /dev/null and b/lab3_ADEX2/shell/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab3_ADEX2/shell/cpio.c b/lab3_ADEX2/shell/cpio.c new file mode 100644 index 000000000..a38879c9c --- /dev/null +++ b/lab3_ADEX2/shell/cpio.c @@ -0,0 +1,96 @@ +#include "header/cpio.h" +#include "header/uart.h" +#include "header/utils.h" +#include "header/allocator.h" + +int file_num = 0; +struct file *f = NULL; + +void allocate_file_array() { + if (f == NULL) { + f = (struct file *)simple_malloc(MAX_FILE_NUM * sizeof(struct file)); + if (f == NULL) { + uart_send_string("Memory allocation error\n"); + // Handle memory allocation error + } + } +} + +void traverse_file() +{ + allocate_file_array(); + char* addr = (char *)cpio_addr; + + + while(utils_string_compare((char *)(addr+sizeof(struct cpio_header)),"TRAILER!!!") == 0){ + + struct cpio_header *header = (struct cpio_header *)addr; + unsigned long filename_size = utils_atoi(header->c_namesize, (int)sizeof(header->c_namesize)); + unsigned long headerPathname_size = sizeof(struct cpio_header) + filename_size; + unsigned long file_size = utils_atoi(header->c_filesize, (int)sizeof(header->c_filesize)); + + utils_align(&headerPathname_size, 4); + utils_align(&file_size, 4); + + f[file_num].file_header = header; + f[file_num].filename_size = filename_size; + f[file_num].headerPathname_size = headerPathname_size; + f[file_num].file_size = file_size; + f[file_num].file_content_head = (char*) header + headerPathname_size; + + addr += (headerPathname_size + file_size); + file_num += 1; + } +} + +int findfile(char* filename) { + for(int n=0;n<=file_num;n++) { + if ((utils_string_compare(((char *)f[n].file_header)+sizeof(struct cpio_header), filename) != 0)){ + return n; + } + } + return -1; +} + +void cpio_ls() +{ + for(int n=0;n<=file_num;n++) { + uart_send_string(((char *)f[n].file_header)+sizeof(struct cpio_header)); + uart_send_string("\n"); + } +} + + +void cpio_cat(char *filename) +{ + int targetfile_num = findfile(filename); + + if(targetfile_num != -1) { + for (unsigned int i = 0; i < f[targetfile_num].file_size; i++) + { + uart_send_char(f[targetfile_num].file_content_head[i]); + } + uart_send_string("\n"); + + } else { + uart_send_string("Can not Find the file\n"); + } + +} + +void cpio_exec_program(char* filename) { + int targetfile_num = findfile(filename); + + char* target = (char*) 0x20000; + for(unsigned i = 0; imagic)); + + if (magic != 0xd00dfeed){ + + uart_send_string("The header magic is wrong\n"); + return -1; + } + + /* + +-----------------+ + | fdt_header | <- dtb_ptr + +-----------------+ + | reserved memory | + +-----------------+ + | structure block | <- dtb_ptr + header->off_dt_struct (struct_ptr) + +-----------------+ + | strings block | <- dtb_ptr + header->off_dt_strings (strings_ptr) + +-----------------+ + */ + + 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); + parse_struct(cb, struct_ptr,strings_ptr,totalsize); + return 1; + +} + +//5. Implement the initramfs_callback function: +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_string("cpio address is at: "); + uart_hex((uintptr_t)fdt_u32_le2be(data)); + // uart_send_char('\n'); + uart_send_string("\r\n"); + } +} + +//6. Implement print_dtb callback function: + +void print_dtb(int token, const char* name, const void* data, uint32_t size) { + UNUSED(data); + UNUSED(size); + + switch(token){ + case FDT_BEGIN_NODE: + uart_send_string("\n"); + send_space(space); + uart_send_string((char*)name); + uart_send_string("{\n "); + space++; + break; + case FDT_END_NODE: + uart_send_string("\n"); + space--; + if(space >0) send_space(space); + uart_send_string("}\n"); + break; + case FDT_NOP: + break; + case FDT_PROP: + send_space(space); + uart_send_string((char*)name); + break; + case FDT_END: + break; + } +} diff --git a/lab3_ADEX2/shell/dtb.o b/lab3_ADEX2/shell/dtb.o new file mode 100644 index 000000000..52e6b26dd Binary files /dev/null and b/lab3_ADEX2/shell/dtb.o differ diff --git a/lab3_ADEX2/shell/except.c b/lab3_ADEX2/shell/except.c new file mode 100644 index 000000000..9f056fb17 --- /dev/null +++ b/lab3_ADEX2/shell/except.c @@ -0,0 +1,201 @@ + +#include "header/uart.h" +#include "header/irq.h" +#include "header/shell.h" +#include "header/timer.h" +#include "header/tasklist.h" +#include "header/utils.h" + +#define CNTPSIRQ_BIT_POSITION 0x02 +#define AUXINIT_BIT_POSTION 1<<29 + + +void except_handler_c() { + uart_send_string("In Exception handle\n"); + + //read spsr_el1 + unsigned long long spsr_el1 = 0; + asm volatile("mrs %0, spsr_el1":"=r"(spsr_el1)); + uart_send_string("spsr_el1: "); + uart_hex(spsr_el1); + uart_send_string("\n"); + + //read elr_el1 + unsigned long long elr_el1 = 0; + asm volatile("mrs %0, elr_el1":"=r"(elr_el1)); + uart_send_string("elr_el1: "); + uart_hex(elr_el1); + uart_send_string("\n"); + + //esr_el1 + unsigned long long esr_el1 = 0; + asm volatile("mrs %0, esr_el1":"=r"(esr_el1)); + uart_hex(esr_el1); + uart_send_string("\n"); + + //ec + unsigned ec = (esr_el1 >> 26) & 0x3F; //0x3F = 0b111111(6) + uart_send_string("ec: "); + uart_hex(ec); + uart_send_string("\n"); + + while(1){ + + } +} +int a = 6; +void timer_irq_handler() +{ + uart_send_string("in timer_irq_handler\n"); + uart_hex(a); + uart_send_string("\r\n"); + //enable core_0_timer + unsigned int* address = (unsigned int*) CORE0_TIMER_IRQ_CTRL; + *address = 2; + + asm volatile("msr cntp_ctl_el0,%0"::"r"(0)); + // Disable interrupts to protect critical section + // asm volatile("msr DAIFSet, 0xf"); + + asm volatile("msr DAIFClr,0xf"); + + uint64_t current_time; + asm volatile("mrs %0, cntpct_el0":"=r"(current_time)); + + while(timer_head && timer_head->expiry <= current_time) { + timer_t *timer = timer_head; + + // Remove timer from the list + timer_head = timer->next; + if (timer_head) { + timer_head->prev = NULL; + } + + //free timer + + // Reprogram the hardware timer if there are still timers left + if(timer_head) { + asm volatile("msr cntp_cval_el0, %0"::"r"(timer_head->expiry)); + asm volatile("msr cntp_ctl_el0,%0"::"r"(1)); + } else { + asm volatile("msr cntp_ctl_el0,%0"::"r"(0)); + } + + //Execute the callback + timer->callback(timer->data); + + //enable interrupt + asm volatile("msr DAIFClr,0xf"); + } + +} + +void uart_transmit_handler() { + //uart_send_string("in uart trans handler \n"); + mmio_write(AUX_MU_IER, mmio_read(AUX_MU_IER) | (0x2)); // enable transmit inte + + // special case (Enter) + if (uart_write_buffer[uart_write_index-1] == '\r'){ + uart_write_buffer[uart_write_index++] = '\n'; + uart_write_buffer[uart_write_index] = '\0'; + } + + // Send data from the write buffer + while (uart_write_head != uart_write_index) { + mmio_write(AUX_MU_IO, uart_write_buffer[uart_write_head++]); + if (uart_write_index >= UART_BUFFER_SIZE) { + uart_write_index = 0; + } + + + if (uart_write_head == uart_write_index) { + //uart_send_string("//////////////// \n"); + mmio_write(AUX_MU_IER, mmio_read(AUX_MU_IER) & ~0x2); + if(uart_read_buffer[uart_read_index-1] == '\r'){ + uart_read_buffer[uart_read_index-1] = '\0'; + parse_command(uart_read_buffer); + uart_read_index = 0; + uart_write_index = 0; + uart_write_head = 0; + } + } + } + mmio_write(AUX_MU_IO, 0); + mmio_write(AUX_MU_IER, mmio_read(AUX_MU_IER) | 0x1); +} + +void uart_receive_handler() { + // uart_send_string("in uart receive handler \n"); + // Read data(8 bytes) and store it in the read buffer + char data = mmio_read(AUX_MU_IO) & 0xff; + // uart_send_char(data); + // uart_send_string("\r\n"); + if (uart_read_index >= UART_BUFFER_SIZE) { + uart_read_index = 0; + } + uart_read_buffer[uart_read_index++] = data; + if (uart_read_index >= UART_BUFFER_SIZE) { + uart_read_index = 0; + } + + // Enqueue the received data into the write buffer + if (uart_write_index >= UART_BUFFER_SIZE) { + uart_write_index = 0; + } + uart_write_buffer[uart_write_index++] = data; + if (uart_write_index >= UART_BUFFER_SIZE) { + uart_write_index = 0; + } + + create_task(uart_transmit_handler,2); // for echo +} + +void irq_except_handler_c() { + + asm volatile("msr DAIFSet, 0xf"); // Disable interrupts + // unsigned long long DAIFSet = 0; + // asm volatile("mrs %0, DAIFSet":"=r"(DAIFSet)); + // uart_hex(DAIFSet); + // uart_send_string("in irq except handler \n"); + uint32_t irq_pending1 = mmio_read(IRQ_PENDING_1); + uint32_t core0_interrupt_source = mmio_read(CORE0_INTERRUPT_SOURCE); + uint32_t iir = mmio_read(AUX_MU_IIR); + + if (core0_interrupt_source & CNTPSIRQ_BIT_POSITION) { + + // uart_send_string("in core0 interrupt \n"); + //disable core 0 timer + unsigned int* address = (unsigned int*) CORE0_TIMER_IRQ_CTRL; + *address = 0; + + create_task(timer_irq_handler,a); + a = a - 1; + } + + + // Handle UART interrupt + if (irq_pending1 & AUXINIT_BIT_POSTION) { + // uart_send_string("in irq pending \n"); + if ((iir & 0x06) == 0x04) { + //Disable receive interrupt + //uart_send_string("in iir 0x04 aaaa \n"); + mmio_write(AUX_MU_IER, mmio_read(AUX_MU_IER) & ~(0x01)); + create_task(uart_receive_handler,1); + } + + if ((iir & 0x06) == 0x02) { + // uart_send_string("in iir 0x02 bbb \n"); + //Disable transmit interrupt + mmio_write(AUX_MU_IER, mmio_read(AUX_MU_IER) & ~(0x02)); + create_task(uart_transmit_handler,2); + } + } + + // asm volatile("msr DAIFClr, 0xf"); // Enable interrupts + + execute_tasks(); + //asm volatile("msr DAIFClr, 0xf"); // Enable interrupts + +} + + diff --git a/lab3_ADEX2/shell/except.o b/lab3_ADEX2/shell/except.o new file mode 100644 index 000000000..daa6bcb83 Binary files /dev/null and b/lab3_ADEX2/shell/except.o differ diff --git a/lab3_ADEX2/shell/header/README.md b/lab3_ADEX2/shell/header/README.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/lab3_ADEX2/shell/header/README.md @@ -0,0 +1 @@ + diff --git a/lab3_ADEX2/shell/header/allocator.h b/lab3_ADEX2/shell/header/allocator.h new file mode 100644 index 000000000..56f46666f --- /dev/null +++ b/lab3_ADEX2/shell/header/allocator.h @@ -0,0 +1,7 @@ +#ifndef ALLOCATOR_H +#define ALLOCATOR_H + + +void* simple_malloc(unsigned long size); + +#endif diff --git a/lab3_ADEX2/shell/header/cpio.h b/lab3_ADEX2/shell/header/cpio.h new file mode 100644 index 000000000..be0e36b9f --- /dev/null +++ b/lab3_ADEX2/shell/header/cpio.h @@ -0,0 +1,39 @@ +//#define QEMU_CPIO_ADDR (char *)0x8000000; //qemu +//#define RASP_CPIO_ADDR (char *)0x20000000;//rasperrypi + +#define MAX_FILE_NUM 10 + +extern char* cpio_addr; + +void traverse_file(); +void cpio_ls(); +void cpio_cat(char* filename); +void cpio_exec_program(char* filename); + +struct 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 file { + struct cpio_header* file_header; + unsigned long filename_size; + unsigned long headerPathname_size; + unsigned long file_size; + char* file_content_head; +}; + diff --git a/lab3_ADEX2/shell/header/dtb.h b/lab3_ADEX2/shell/header/dtb.h new file mode 100644 index 000000000..16af25520 --- /dev/null +++ b/lab3_ADEX2/shell/header/dtb.h @@ -0,0 +1,26 @@ +#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 type,const char* name,const void *data,uint32_t size); + +struct __attribute__((packed)) fdt_header { + uint32_t magic; // contain the value 0xd00dfeed (big-endian). + uint32_t totalsize; // in byte + uint32_t off_dt_struct; // the offset in bytes of the structure block from the beginning of the header + 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; // the length in bytes of the strings block section + uint32_t size_dt_struct; +}; + +int fdt_traverse(fdt_callback cb,void *dtb_ptr); +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); diff --git a/lab3_ADEX2/shell/header/gpio.h b/lab3_ADEX2/shell/header/gpio.h new file mode 100644 index 000000000..38ca70635 --- /dev/null +++ b/lab3_ADEX2/shell/header/gpio.h @@ -0,0 +1,38 @@ +#ifndef GPIO_H +#define GPIO_H + +#include +//Page 90, Physical/bus addr diff +#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 diff --git a/lab3_ADEX2/shell/header/irq.h b/lab3_ADEX2/shell/header/irq.h new file mode 100644 index 000000000..9085cb30c --- /dev/null +++ b/lab3_ADEX2/shell/header/irq.h @@ -0,0 +1,22 @@ +#ifndef IRQ_H +#define IRQ_H + +#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 CORE0_TIMER_IRQ_CTRL ((volatile unsigned int*)(0x40000040)) +#define CORE0_INTERRUPT_SOURCE ((volatile unsigned int*)(0x40000060)) + + +#endif + diff --git a/lab3_ADEX2/shell/header/mailbox.h b/lab3_ADEX2/shell/header/mailbox.h new file mode 100644 index 000000000..d13ac3ce9 --- /dev/null +++ b/lab3_ADEX2/shell/header/mailbox.h @@ -0,0 +1,38 @@ +#include "gpio.h" + +extern volatile unsigned int mailbox[36]; + +#define MBOX_REQUEST 0 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define TAG_REQUEST_CODE 0x00000000 +#define MBOX_TAG_GETSERIAL 0x00010004 +#define MBOX_TAG_GETBOARD 0x00010002 +#define MBOX_TAG_GETARMMEM 0x00010005 +#define MBOX_TAG_LAST 0x00000000 + +int mailbox_call(); +void get_board_revision(); +void get_arm_mem(); + +#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880) +#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0)) +#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10)) +#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14)) +#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18)) +#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C)) +#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20)) +#define MBOX_RESPONSE 0x80000000 +#define MBOX_FULL 0x80000000 +#define MBOX_EMPTY 0x40000000 diff --git a/lab3_ADEX2/shell/header/reboot.h b/lab3_ADEX2/shell/header/reboot.h new file mode 100644 index 000000000..e1d44aa1b --- /dev/null +++ b/lab3_ADEX2/shell/header/reboot.h @@ -0,0 +1,8 @@ +#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(); diff --git a/lab3_ADEX2/shell/header/shell.h b/lab3_ADEX2/shell/header/shell.h new file mode 100644 index 000000000..9784c1ccb --- /dev/null +++ b/lab3_ADEX2/shell/header/shell.h @@ -0,0 +1,2 @@ +void shell(); +void parse_command(char* buffer); diff --git a/lab3_ADEX2/shell/header/tasklist.h b/lab3_ADEX2/shell/header/tasklist.h new file mode 100644 index 000000000..de876b84c --- /dev/null +++ b/lab3_ADEX2/shell/header/tasklist.h @@ -0,0 +1,21 @@ +#ifndef TASKLIST_H +#define TASKLIST_H + +// #include +#include + +typedef void (*task_callback)(); + +typedef struct task { + struct task *prev; + struct task *next; + task_callback callback; + uint64_t priority; +} task_t; + +void execute_tasks(); +void create_task(task_callback callback,uint64_t priority); +void enqueue_task(task_t *new_task); +extern task_t *task_head; + +#endif diff --git a/lab3_ADEX2/shell/header/timer.h b/lab3_ADEX2/shell/header/timer.h new file mode 100644 index 000000000..a9a8c65da --- /dev/null +++ b/lab3_ADEX2/shell/header/timer.h @@ -0,0 +1,20 @@ +#ifndef TIMER_H +#define TIMER_H + +#include +// #include + +typedef void (*timer_callback)(void *data); + +typedef struct timer { + struct timer *prev; // previous timer in the list + struct timer *next; // next timer in the list + timer_callback callback; // the function to call when the timer expires + void *data; // data to be passed to the callback + uint64_t expiry; // the time at which the timer will expire +} timer_t; + +extern timer_t *timer_head; // head of the timer list + +void setTimeout(char *message,uint64_t seconds); +#endif diff --git a/lab3_ADEX2/shell/header/uart.h b/lab3_ADEX2/shell/header/uart.h new file mode 100644 index 000000000..0c3ff1bd8 --- /dev/null +++ b/lab3_ADEX2/shell/header/uart.h @@ -0,0 +1,39 @@ +#ifndef UART_H +#define UART_H + +#include "gpio.h" +#include +#define UART_BUFFER_SIZE 1024 + +void uart_init(); +void uart_send_char(unsigned int c); +char uart_get_char(); +void uart_send_string(char* s); +void uart_hex(unsigned long long d); +void uart_enable_interrupt(); +int uart_async_read(char *buffer); +void uart_async_write(const char *buffer, int length); +void uart_async_send(const char *str); + + +extern char uart_read_buffer[UART_BUFFER_SIZE]; +extern char uart_write_buffer[UART_BUFFER_SIZE]; +extern int uart_read_index; +extern int uart_read_head; +extern int uart_write_index; +extern int uart_write_head; + +#define AUX_ENABLE ((volatile unsigned int*)(MMIO_BASE+0x00215004)) +#define AUX_MU_IO ((volatile unsigned int*)(MMIO_BASE+0x00215040)) +#define AUX_MU_IER ((volatile unsigned int*)(MMIO_BASE+0x00215044)) +#define AUX_MU_IIR ((volatile unsigned int*)(MMIO_BASE+0x00215048)) +#define AUX_MU_LCR ((volatile unsigned int*)(MMIO_BASE+0x0021504C)) +#define AUX_MU_MCR ((volatile unsigned int*)(MMIO_BASE+0x00215050)) +#define AUX_MU_LSR ((volatile unsigned int*)(MMIO_BASE+0x00215054)) +#define AUX_MU_MSR ((volatile unsigned int*)(MMIO_BASE+0x00215058)) +#define AUX_MU_SCRATCH ((volatile unsigned int*)(MMIO_BASE+0x0021505C)) +#define AUX_MU_CNTL ((volatile unsigned int*)(MMIO_BASE+0x00215060)) +#define AUX_MU_STAT ((volatile unsigned int*)(MMIO_BASE+0x00215064)) +#define AUX_MU_BAUD ((volatile unsigned int*)(MMIO_BASE+0x00215068)) + +#endif diff --git a/lab3_ADEX2/shell/header/utils.h b/lab3_ADEX2/shell/header/utils.h new file mode 100644 index 000000000..3ba6dd719 --- /dev/null +++ b/lab3_ADEX2/shell/header/utils.h @@ -0,0 +1,25 @@ +#include +// #include + +#define nop asm volatile("nop") + +#ifdef _cplusplus +#define NULL 0 +#else +#define NULL (void*)0 +#endif + +#ifndef __SIZE_TYPE__ +#define __SIZE_TYPE__ long unsigned int +#endif +// #if !(defined (__GNUG__) && defined (size_t)) +typedef __SIZE_TYPE__ size_t; + + +int utils_string_compare(const char* i, const char* j); +unsigned long utils_atoi(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); +char *utils_strcpy(char* dst, const char *src); +char *utils_strdup(const char *src); diff --git a/lab3_ADEX2/shell/initramfs.cpio b/lab3_ADEX2/shell/initramfs.cpio new file mode 100644 index 000000000..faf47b52f Binary files /dev/null and b/lab3_ADEX2/shell/initramfs.cpio differ diff --git a/lab3_ADEX2/shell/kernel8.elf b/lab3_ADEX2/shell/kernel8.elf new file mode 100644 index 000000000..241ffd815 Binary files /dev/null and b/lab3_ADEX2/shell/kernel8.elf differ diff --git a/lab3_ADEX2/shell/kernel8.img b/lab3_ADEX2/shell/kernel8.img new file mode 100644 index 000000000..ff30a435f Binary files /dev/null and b/lab3_ADEX2/shell/kernel8.img differ diff --git a/lab3_ADEX2/shell/linker.ld b/lab3_ADEX2/shell/linker.ld new file mode 100644 index 000000000..5018defb6 --- /dev/null +++ b/lab3_ADEX2/shell/linker.ld @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +SECTIONS +{ + . = 0x80000; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { . = ALIGN(16); *(.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_ADEX2/shell/mailbox.c b/lab3_ADEX2/shell/mailbox.c new file mode 100644 index 000000000..7e0c5d99c --- /dev/null +++ b/lab3_ADEX2/shell/mailbox.c @@ -0,0 +1,51 @@ +#include "header/mailbox.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){ + /* is it a valid successful response? */ + if(mailbox[1] == MBOX_RESPONSE) + return 1; + } + } + 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. +} diff --git a/lab3_ADEX2/shell/mailbox.o b/lab3_ADEX2/shell/mailbox.o new file mode 100644 index 000000000..8e2118f24 Binary files /dev/null and b/lab3_ADEX2/shell/mailbox.o differ diff --git a/lab3_ADEX2/shell/main.c b/lab3_ADEX2/shell/main.c new file mode 100644 index 000000000..979b9fc57 --- /dev/null +++ b/lab3_ADEX2/shell/main.c @@ -0,0 +1,78 @@ +#include "header/uart.h" +#include "header/shell.h" +#include "header/dtb.h" +#include "header/utils.h" +#include "header/cpio.h" +#include "header/timer.h" + +void test_read_command(char* buffer) { + int index = 0; + while(1) { + buffer[index] = uart_get_char(); + if(buffer[index] == '\n') { + buffer[index] = '\0'; + buffer[index+1] = '\n'; + uart_send_string("\r\n"); + break; + } + else + { + uart_send_char(buffer[index]); + } + index++; + } +} + +extern void *_dtb_ptr; +void main() +{ + + uart_init(); + // pre test ////////////////////////// + char buffer[256]; + while(1) + { + uart_send_string("# "); + test_read_command(buffer); + char * input_string = buffer; + if(utils_string_compare(input_string,"in")) + { + break; + } + else + { + // uart_send_hex((uintptr_t) _dtb_addr); + uart_send_string("The instruct is not exist.\n"); + } + } + ///////////////////////////////////////// + + // set up serial console + uart_init(); + + unsigned long el = 0; + asm volatile ("mrs %0, CurrentEL":"=r"(el)); + uart_send_string("Current exception level: "); + uart_hex(el>>2); // CurrentEL store el level at [3:2] + uart_send_string("\r\n"); + + asm volatile("mov %0, sp"::"r"(el)); + uart_send_string("Current stack pointer address: "); + uart_hex(el); + uart_send_string("\r\n"); + + fdt_traverse(get_cpio_addr,_dtb_ptr); + traverse_file(); + uart_send_string("Type in `help` to get instruction menu!\n"); + + uart_enable_interrupt(); + + + while(1){ + asm volatile("nop"); + } + //echo everything back + //shell(); +} + + diff --git a/lab3_ADEX2/shell/main.o b/lab3_ADEX2/shell/main.o new file mode 100644 index 000000000..c80fdbc74 Binary files /dev/null and b/lab3_ADEX2/shell/main.o differ diff --git a/lab3_ADEX2/shell/reboot.c b/lab3_ADEX2/shell/reboot.c new file mode 100644 index 000000000..048f2d348 --- /dev/null +++ b/lab3_ADEX2/shell/reboot.c @@ -0,0 +1,16 @@ +#include "header/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); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick +} + +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} diff --git a/lab3_ADEX2/shell/reboot.o b/lab3_ADEX2/shell/reboot.o new file mode 100644 index 000000000..dda9e2825 Binary files /dev/null and b/lab3_ADEX2/shell/reboot.o differ diff --git a/lab3_ADEX2/shell/shell.c b/lab3_ADEX2/shell/shell.c new file mode 100644 index 000000000..eddcdba81 --- /dev/null +++ b/lab3_ADEX2/shell/shell.c @@ -0,0 +1,151 @@ +#include "header/shell.h" +#include "header/uart.h" +#include "header/utils.h" +#include "header/mailbox.h" +#include "header/reboot.h" +#include "header/cpio.h" +#include "header/allocator.h" +#include "header/dtb.h" +#include "header/irq.h" +#include "header/timer.h" +#define BUFFER_MAX_SIZE 256u + + +extern void *_dtb_ptr; + +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 async_read_command(char* buffer) { + int index = 0; + char tmp[1]; + + while (1) { + if (uart_async_read(tmp) > 0) { + buffer[index] = tmp[0]; + uart_send_char(tmp[0]); + if (tmp[0] == '\r') { + buffer[index] = '\0'; + break; + } + index++; + } + } +} +*/ + +void parse_command(char* buffer){ + uart_send_string("in parse command\n"); + char* input_string = buffer; + char* parameter[5]; //5 is the available parameter length + int para_idx = 0; + int input_string_len = utils_strlen(input_string); + for(int i=0; i < input_string_len; i++){ + if(*(input_string+i) == ' '){ + *(input_string+i) = '\0'; + parameter[para_idx++] = (input_string+i+1); + } + } + + if(utils_string_compare(input_string,"help")) { + uart_send_string("help :print this help menu\n"); + uart_send_string("hello :print Hello World!\n"); + uart_send_string("info :Get the hardware's information\n"); + uart_send_string("reboot :reboot the device\n"); + uart_send_string("ls :list the file\n"); + uart_send_string("cat :print file content\n"); + uart_send_string("malloc :give dynamic memory space\n"); + uart_send_string("dtb :print device tree\n"); + uart_send_string("exec :execute user program\n"); + uart_send_string("timer or settimeout :demo timer interrupt\n"); + } else if (utils_string_compare(input_string,"hello")) { + uart_send_string("Hello World!\n"); + } else if (utils_string_compare(input_string,"info")) { + get_board_revision(); + uart_send_string("My board revision is: "); + uart_hex(mailbox[5]); + uart_send_string("\n"); + get_arm_mem(); + uart_send_string("My ARM memory base address is: "); + uart_hex(mailbox[5]); + uart_send_string("\n"); + uart_send_string("My ARM memory size is: "); + uart_hex(mailbox[6]); + uart_send_string("\n"); + } else if (utils_string_compare(input_string,"reboot")) { + uart_send_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_string("Filename: "); + //char filename[BUFFER_MAX_SIZE]; + //read_command(filename); + //cpio_cat(filename); + cpio_cat(parameter[0]); + } else if (utils_string_compare(input_string,"malloc")){ + char *a = simple_malloc(sizeof("9876")); + char *b = simple_malloc(sizeof("345")); + a[0] = '9'; + a[1] = '8'; + a[2] = '7'; + a[3] = '6'; + a[4] = '\0'; + b[0] = '3'; + b[1] = '4'; + b[2] = '5'; + b[3] = '\0'; + uart_send_string(a); + uart_send_char('\n'); + uart_send_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,"exec")) { + //uart_send_string("Program name: "); + //char buffer[BUFFER_MAX_SIZE]; + //read_command(buffer); + cpio_exec_program(parameter[0]); + } else if (utils_string_compare(input_string,"timer")) { + + setTimeout("hello 1",3); + setTimeout("hello 2",6); + setTimeout("hello 3",9); + + } else if (utils_string_compare(input_string,"set")) { + char *message = (char *)parameter[0]; + size_t second_str_len = utils_strlen(parameter[1]); + uint64_t seconds = (uint64_t) utils_atoi(parameter[1],second_str_len-1); + setTimeout(message,seconds); + } else { + uart_send_string("The instruction "); + uart_send_string(input_string); + uart_send_string(" is not exist.\n"); + } +} + +void shell(){ + /* + while(1) { + char buffer[BUFFER_MAX_SIZE]; + uart_send_string("# "); + //async_read_command(buffer); + parse_command(buffer); + } + */ + +} + + + diff --git a/lab3_ADEX2/shell/shell.o b/lab3_ADEX2/shell/shell.o new file mode 100644 index 000000000..ab152e7fc Binary files /dev/null and b/lab3_ADEX2/shell/shell.o differ diff --git a/lab3_ADEX2/shell/start.S b/lab3_ADEX2/shell/start.S new file mode 100644 index 000000000..d930d2213 --- /dev/null +++ b/lab3_ADEX2/shell/start.S @@ -0,0 +1,152 @@ + +.section ".text.kernel" + +.global _start + + + +_start: + ldr x1, =_dtb_ptr //put _dtb_ptr into register1 + str x0, [x1] //store dtb address from x0 to _dtb_ptr + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, 2f + // cpu id > 0, stop +1: wfe + b 1b +2: // cpu id == 0 + + ldr x1, =_start + bl from_el2_to_el1 + mov sp, x1 + + + /* set exception vector table */ + adr x0, exception_vector_table + msr vbar_el1, x0 // vbar -> Vector Base Address Register + + //bl core_timer_enable + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size + +3: cbz w2, 4f + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, 3b + //bl core_timer_enable + // jump to C code, should not return +4: bl main + // for failsafe, halt this core too + b 1b + +from_el2_to_el1: + mov x0,#(1<<31) + msr hcr_el2,x0 // set EL1 runs in AARCH64 + mov x0,#0x345 // 0x3c5 [4:0]->ELH1 / ASH(SEerr) IRQ FRQ disable + msr spsr_el2,x0 // spsr -> saved program status register + msr elr_el2,lr // lr->link register elr->Eeception Link Register + eret + +// save general registers to stack +// user program and the exception handler share the same general purpose reg +.macro save_all + sub sp, sp, 32 * 8 + stp x0, x1, [sp ,16 * 0] //stp -> store paire + 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 except_handler_c + load_all + eret + +irq_exception_handler: + save_all + bl irq_except_handler_c + load_all + eret + +.align 11 // vector table should be aligned to 0x800 +.global exception_vector_table +exception_vector_table: + 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 + + b exception_handler + .align 7 + b irq_exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + b exception_handler + .align 7 + b irq_exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + +.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 + diff --git a/lab3_ADEX2/shell/start.o b/lab3_ADEX2/shell/start.o new file mode 100644 index 000000000..e072c076b Binary files /dev/null and b/lab3_ADEX2/shell/start.o differ diff --git a/lab3_ADEX2/shell/tasklist.c b/lab3_ADEX2/shell/tasklist.c new file mode 100644 index 000000000..91e1eeadc --- /dev/null +++ b/lab3_ADEX2/shell/tasklist.c @@ -0,0 +1,67 @@ +#include "header/tasklist.h" +#include "header/allocator.h" +#include "header/uart.h" +#include "header/utils.h" + +task_t *task_head = NULL; + +void enqueue_task(task_t *new_task) { + // uart_send_string("in enqueue_task\n"); + // Disable interrupts to protect the critical section + asm volatile("msr DAIFSet, 0xf"); + // Special case: the list is empty or the new task has higher priority + if (!task_head || new_task->priority < task_head->priority) { + new_task->next = task_head; + new_task->prev = NULL; + if (task_head) { + 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; + } + + // Enable interrupts + asm volatile("msr DAIFClr, 0xf"); +} + +void create_task(task_callback callback, uint64_t priority) { + // uart_send_string("in create_tasks\n"); + task_t* task = simple_malloc(sizeof(task_t)); + if(!task) { + return; + } + + task->callback = callback; + task->priority = priority; + + enqueue_task(task); +} + +void execute_tasks() { + // uart_send_string("in execute_tasks\n"); + while (task_head) { + task_head->callback(); + task_head = task_head->next; + if (task_head) { + task_head->prev = NULL; + } + asm volatile("msr DAIFSet, 0xf"); // Disable interrupts + //simple_free(task); + } + + asm volatile("msr DAIFClr, 0xf"); // Enable interrupts +} + diff --git a/lab3_ADEX2/shell/tasklist.o b/lab3_ADEX2/shell/tasklist.o new file mode 100644 index 000000000..3ecce4a61 Binary files /dev/null and b/lab3_ADEX2/shell/tasklist.o differ diff --git a/lab3_ADEX2/shell/timer.c b/lab3_ADEX2/shell/timer.c new file mode 100644 index 000000000..629b95a0f --- /dev/null +++ b/lab3_ADEX2/shell/timer.c @@ -0,0 +1,134 @@ +#include "header/timer.h" +#include "header/allocator.h" +#include "header/uart.h" +#include "header/irq.h" +#include "header/utils.h" + +timer_t *timer_head = NULL; + +void add_timer(timer_t *new_timer) { + + timer_t *current = timer_head; + + // Disable interrupts to protect the critical section + asm volatile("msr DAIFSet, 0xf"); + // Special case: the list is empty or the new timer is the earliest + if (!timer_head || new_timer->expiry < timer_head->expiry) { + new_timer->next = timer_head; + new_timer->prev = NULL; + if (timer_head) { + timer_head->prev = new_timer; + } + timer_head = new_timer; + + // Reprogram the hardware timer + asm volatile ("msr cntp_cval_el0, %0"::"r"(new_timer->expiry)); + asm volatile("msr cntp_ctl_el0,%0"::"r"(1)); + + // Enable interrupts + asm volatile("msr DAIFClr, 0xf"); + return; + } + + // Find the correct position in the list + while (current->next && current->next->expiry < new_timer->expiry) { + current = current->next; + } + + // Insert the new timer + new_timer->next = current->next; + new_timer->prev = current; + if (current->next) { + current->next->prev = new_timer; + } + current->next = new_timer; + // Enable interrupts + asm volatile("msr DAIFClr, 0xf"); +} + + +void create_timer(timer_callback callback, void* data, uint64_t after) { + //Allocate memory for the timer + timer_t* timer = simple_malloc(sizeof(timer_t)); + if(!timer) { + return; + } + + //Set the callback and data + timer->callback = callback; + timer->data = data; + + //Calculate the expiry time + uint64_t current_time, cntfrq; + asm volatile("mrs %0, cntpct_el0":"=r"(current_time)); + asm volatile("mrs %0, cntfrq_el0":"=r"(cntfrq)); + timer->expiry = current_time + after * cntfrq; + //Add the time to the list + add_timer(timer); +} + + +void print_message(void *data) { + char *message = data; + uint64_t current_time, cntfrq; + asm volatile("mrs %0, cntpct_el0" : "=r"(current_time)); + asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq)); + uint64_t seconds = current_time / cntfrq; + + uart_send_string("Timeout message: "); + uart_send_string(message); + uart_send_string(" occurs at "); + uart_hex(seconds); + uart_send_string("\n"); +} + +void repeat_message(void *data) +{ + char *message = data; + /* + while(1) + { + char *message = data; + uart_send_string(message); + uart_send_string("\r\n"); + } + */ + for(int i=0; i< 5000; i++) + { + char *message = data; + uart_send_string(message); + uart_send_string("\r\n"); + uart_send_string("========================="); + uart_send_string("\r\n"); + } +} + +void repeat_nop(void *data) +{ + char *message = data; + while(1) + { + asm volatile("nop"); + } + +} + + +void setTimeout(char *message,uint64_t seconds) { + + char *message_copy = utils_strdup(message); + + if(!message_copy){ + return; + } + + if (!timer_head) { + //enable core_timer_interrupt + unsigned int value = 2; + unsigned int* address = (unsigned int*) CORE0_TIMER_IRQ_CTRL; // unmask timer interrupt + *address = value; + } + + create_timer(repeat_message,message_copy,seconds); +} + diff --git a/lab3_ADEX2/shell/timer.o b/lab3_ADEX2/shell/timer.o new file mode 100644 index 000000000..ed5fd917b Binary files /dev/null and b/lab3_ADEX2/shell/timer.o differ diff --git a/lab3_ADEX2/shell/uart.c b/lab3_ADEX2/shell/uart.c new file mode 100644 index 000000000..2bb53d9a9 --- /dev/null +++ b/lab3_ADEX2/shell/uart.c @@ -0,0 +1,196 @@ +#include "header/uart.h" +#include "header/irq.h" +#include "header/utils.h" + +#define RX_INTERRUPT_BIT 0x01 +#define TX_INTERRUPT_BIT 0x02 + +#define AUXINIT_BIT_POSTION 1<<29 + +char uart_read_buffer[UART_BUFFER_SIZE]; +char uart_write_buffer[UART_BUFFER_SIZE]; +int uart_read_head = 0; +int uart_read_index = 0; +int uart_write_index = 0; +int uart_write_head = 0; + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init() +{ + register unsigned int r; + // P.104 Since I need UART 1 Transmit/Receive Data -> TXD1/RXD1 + // p.102 I find These two in GPIO 14/15 Fun5 + // Since each GPFSEL controls 10 pin, GPFSEL1 controls 10-19 + // That's why I need GPFSEL1 + 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 + + //Since We've set alt5, we want to disable basic input/output + //To achieve this, we need diable pull-up and pull-dwon + *GPPUD = 0; // P101 top. 00- = off - disable pull-up/down + //Wait 150 cycles + //this provides the required set-up time for the control signal + r=150; while(r--) { asm volatile("nop"); } + // 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 + *GPPUDCLK0 = (1<<14)|(1<<15); + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = 0; // flush GPIO setup + + + r=1000; while(r--) { asm volatile("nop"); } + + /* initialize UART */ + *AUX_ENABLE |=1; + //P.9: If set the mini UART is enabled. The UART will + //immediately start receiving data, especially if the + //UART1_RX line is low. + //If clear the mini UART is disabled. That also disables + //any mini UART register access + *AUX_MU_CNTL = 0; + //P.17 If this bit is set the mini UART receiver is enabled. + //If this bit is clear the mini UART receiver is disabled + //Prevent data exchange in initialization process + *AUX_MU_IER = 0; + //Set AUX_MU_IER_REG to 0. + //Disable interrupt because currently you don’t need interrupt. + *AUX_MU_LCR = 3; + //P.14: 00 : the UART works in 7-bit mode + //11(3) : the UART works in 8-bit mode + //Cause 8 bits can use in ASCII, Unicode, Char + *AUX_MU_MCR = 0; + //Don’t need auto flow control. + //AUX_MU_MCR is for basic serial communication. Don't be too smart + *AUX_MU_BAUD = 270; + //set BAUD rate to 115200(transmit speed) + //so we need set AUX_MU_BAUD to 270 to meet the goal + *AUX_MU_IIR = 0xc6; + // bit 6 bit 7 No FIFO. Sacrifice reliability(buffer) to get low latency // 0xc6 = 11000110 + // Writing with bit 1 set will clear the receive FIFO + // Writing with bit 2 set will clear the transmit FIFO + // Both bits always read as 1 as the FIFOs are always enabled + /* map UART1 to GPIO pins */ + *AUX_MU_CNTL = 3; // enable Transmitter,Receiver + +} + + +/** + * Send a character + */ +void uart_send_char(unsigned int c) { + /* wait until we can send */ + // P.15 AUX_MU_LSR register shows the data(line) status + // AUX_MU_LSR bit 5 => 0x20 = 00100000 + // bit 5 is set if the transmit FIFO can accept at least one byte. + // &0x20 can preserve 5th bit, if bit 5 set 1 can get !true = false leave loop + // else FIFO can not accept at lease one byte then still wait + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); + /* write the character to the buffer */ + //P.11 The AUX_MU_IO_REG register is primary used to write data to and read data from the + //UART FIFOs. + //communicate with(send to) the minicom and print to the screen + *AUX_MU_IO=c; +} + +/** + * Display a string + */ +void uart_send_string(char* s) { + while(*s) { + /* convert newline to carriage return + newline */ + if(*s=='\n') + uart_send_char('\r'); + uart_send_char(*s++); + } +} + +/** + * Receive a character + */ +char uart_get_char() { + char r; + /* wait until something is in the buffer */ + //bit 0 is set if the receive FIFO holds at least 1 symbol. + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01)); + /* read it and return */ + r=(char)(*AUX_MU_IO); + /* convert carriage return to newline */ + return r=='\r'?'\n':r; +} + + +/** + * Display a binary value in hexadecimal + */ +void uart_hex(unsigned long long d) { + unsigned long long n; + int c; + uart_send_string("0x"); + for(c=28;c>=0;c-=4) { + // get highest tetrad + n=(d>>c)&0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n+=n>9?0x57:0x30; + uart_send_char(n); + } +} + +void uart_enable_interrupt() { + + // Enable RX and TX interrupt for mini UART + uint32_t ier = mmio_read(AUX_MU_IER); + ier |= RX_INTERRUPT_BIT; + //ier |= (RX_INTERRUPT_BIT | TX_INTERRUPT_BIT); + mmio_write(AUX_MU_IER, ier); + + // Enable the mini UART interrupt in the second-level interrupt controller + // uint32_t enable_irqs1 = (uint32_t) ENABLE_IRQS_1; + uint32_t enable_irqs1 = mmio_read(ENABLE_IRQS_1); + enable_irqs1 |= AUXINIT_BIT_POSTION; // Set bit29 (Auxiliary device)->mini uart + mmio_write(ENABLE_IRQS_1, enable_irqs1); +} + +void uart_disable_interrupt() { + // uint32_t disable_irqs1 = (uint32_t) DISABLE_IRQS_1; + uint32_t disable_irqs1 = mmio_read(DISABLE_IRQS_1); + disable_irqs1 |= AUXINIT_BIT_POSTION; + mmio_write(DISABLE_IRQS_1,disable_irqs1); +} + +int uart_async_read(char *buffer) { + if (uart_read_head == uart_read_index) { + // No characters available + return 0; + } else { + buffer[0] = uart_read_buffer[uart_read_head++]; + if (uart_read_head >= UART_BUFFER_SIZE) { + uart_read_head = 0; + } + return 1; + } +} +void uart_async_write(const char *buffer, int length) { + for (int i = 0; i < length; i++) { + uart_write_buffer[uart_write_head++] = buffer[i]; + if (uart_write_head >= UART_BUFFER_SIZE) { + uart_write_head = 0; + } + } + // Trigger TX interrupt + mmio_write(AUX_MU_IER, mmio_read(AUX_MU_IER) | 0x2); +} + +void uart_async_send(const char *str) { + int length = utils_strlen(str); + uart_async_write(str, length); +} + + diff --git a/lab3_ADEX2/shell/uart.o b/lab3_ADEX2/shell/uart.o new file mode 100644 index 000000000..bcdb54e4d Binary files /dev/null and b/lab3_ADEX2/shell/uart.o differ diff --git a/lab3_ADEX2/shell/userprogram/Makefile b/lab3_ADEX2/shell/userprogram/Makefile new file mode 100644 index 000000000..19cefe3cf --- /dev/null +++ b/lab3_ADEX2/shell/userprogram/Makefile @@ -0,0 +1,11 @@ +all: one.img + +one.o: one.S + aarch64-linux-gnu-gcc -c one.S -o one.o + +one.img: one.o + aarch64-linux-gnu-ld one.o -T linker.ld -o one.elf + aarch64-linux-gnu-objcopy -O binary one.elf one.img + +clean: + rm one.o one.elf > /dev/null 2>/dev/null || true diff --git a/lab3_ADEX2/shell/userprogram/README.md b/lab3_ADEX2/shell/userprogram/README.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/lab3_ADEX2/shell/userprogram/README.md @@ -0,0 +1 @@ + diff --git a/lab3_ADEX2/shell/userprogram/linker.ld b/lab3_ADEX2/shell/userprogram/linker.ld new file mode 100644 index 000000000..ab70a30ea --- /dev/null +++ b/lab3_ADEX2/shell/userprogram/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 : { . = ALIGN(16); *(.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_ADEX2/shell/userprogram/one.S b/lab3_ADEX2/shell/userprogram/one.S new file mode 100644 index 000000000..4acf6f4dd --- /dev/null +++ b/lab3_ADEX2/shell/userprogram/one.S @@ -0,0 +1,7 @@ +.section ".text" +.global _start +_start: + svc 0x1337 +1: + nop + b 1b diff --git a/lab3_ADEX2/shell/userprogram/one.elf b/lab3_ADEX2/shell/userprogram/one.elf new file mode 100644 index 000000000..b13e36ed9 Binary files /dev/null and b/lab3_ADEX2/shell/userprogram/one.elf differ diff --git a/lab3_ADEX2/shell/userprogram/one.img b/lab3_ADEX2/shell/userprogram/one.img new file mode 100644 index 000000000..13bb5c616 Binary files /dev/null and b/lab3_ADEX2/shell/userprogram/one.img differ diff --git a/lab3_ADEX2/shell/userprogram/one.o b/lab3_ADEX2/shell/userprogram/one.o new file mode 100644 index 000000000..c00c28e5b Binary files /dev/null and b/lab3_ADEX2/shell/userprogram/one.o differ diff --git a/lab3_ADEX2/shell/utils.c b/lab3_ADEX2/shell/utils.c new file mode 100644 index 000000000..8242d820c --- /dev/null +++ b/lab3_ADEX2/shell/utils.c @@ -0,0 +1,63 @@ +#include "header/utils.h" +#include "header/allocator.h" + +int utils_string_compare(const char* str1,const char* str2) { + for(;*str1 !='\0'||*str2 !='\0';str1++,str2++){ + if(*str1 != *str2) return 0; + else if(*str1 == '\0' && *str2 =='\0') return 1; + } + return 1; +} + +unsigned long utils_atoi(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); +} + +//with null-terminator -> "hello" return 6 +size_t utils_strlen(const char *s) { + size_t i = 0; + while (s[i]) i++; + return i+1; +} + + +char *utils_strcpy(char* dst, const char *src) { + char *save = dst; + while((*dst++ = *src++)); + return save; +} + + +char *utils_strdup(const char *src) { + size_t len = utils_strlen(src); + char *dst = simple_malloc(len); + if (dst == NULL) { // Check if the memory has been successfully allocated + return NULL; + } + utils_strcpy(dst, src); // Copy the string + return dst; +} + + diff --git a/lab3_ADEX2/shell/utils.o b/lab3_ADEX2/shell/utils.o new file mode 100644 index 000000000..74670709c Binary files /dev/null and b/lab3_ADEX2/shell/utils.o differ diff --git a/lab4/readme.md b/lab4/readme.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/lab4/readme.md @@ -0,0 +1 @@ + diff --git a/lab4/shell/Makefile b/lab4/shell/Makefile new file mode 100644 index 000000000..beea4a7b2 --- /dev/null +++ b/lab4/shell/Makefile @@ -0,0 +1,22 @@ +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) +CFLAGS = -Iinclude -fno-stack-protector -Wall -Wextra -Wpedantic -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles +# CFLAGS += -I../../../opt/lib/gcc/aarch64-linux-gnu/12.2.0/include +CFLAGS += -I /usr/aarch64-linux-gnu/include +all: kernel8.img + +start.o: start.S + aarch64-linux-gnu-gcc $(CFLAGS) -c start.S -o start.o + +%.o: %.c + aarch64-linux-gnu-gcc $(CFLAGS) -c $< -o $@ + +kernel8.img: start.o $(OBJS) + aarch64-linux-gnu-ld start.o $(OBJS) -T linker.ld -o kernel8.elf + aarch64-linux-gnu-objcopy -O binary kernel8.elf kernel8.img + +clean: + rm kernel8.elf *.o >/dev/null 2>/dev/null || true + +run: + qemu-system-aarch64 -M raspi3b -serial null -serial stdio -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb -display none -kernel kernel8.img diff --git a/lab4/shell/allocator.c b/lab4/shell/allocator.c new file mode 100644 index 000000000..9faebde17 --- /dev/null +++ b/lab4/shell/allocator.c @@ -0,0 +1,406 @@ +#include "header/allocator.h" +#include "header/utils.h" +#include "header/uart.h" +#include "header/dtb.h" + +#define SIMPLE_MALLOC_BUFFER_SIZE 8192 +static unsigned char simple_malloc_buffer[SIMPLE_MALLOC_BUFFER_SIZE]; +static unsigned long simple_malloc_offset = 0; +struct buddy_alloc *_global_allocator = 0; +void *(*balloc_nalloc)(uint64_t); + +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; +} + +void buddy_alloc_reserve(void *start, void *end) +{ + uart_send_string("\nreserve start address: "); + uart_hexll((uint64_t)start);ENDL; + uart_send_string("reserve end address: "); + uart_hexll((uint64_t)end);ENDL; + uart_send_string("\nRESERVED =============================\n"); + + for (uint64_t i = (uint64_t)start >> 12; + i < ((uint64_t) utils_ret_align(end, (1<<12))) >> 12; + i++) { + _global_allocator->entries[i] = -1; + } +} + + + +void buddy_alloc_preinit(struct buddy_alloc *header) +{ + uint64_t page_count = header->size / header->page_size; + uint64_t header_size = sizeof(struct buddy_alloc); + + uint64_t entries_size = page_count * sizeof(buddy_alloc_entry); + uart_send_string("Entries size: "); + uart_hex(entries_size);ENDL; + uint64_t freelist_size = (header->order + 1) * sizeof(uint64_t); + header->entries = (buddy_alloc_entry *) ((uint64_t) header + header_size); + header->freelist = (struct buddy_alloc_node **) (((uint64_t) header->entries) + entries_size); + header->mem = 0; + _global_allocator = header; + for (int i = 0; i <= header->order; i++) + header->freelist[i] = 0; + for (uint64_t i = 0; i < page_count; i++) + header->entries[i] = 0; + buddy_alloc_reserve(header, header + header_size + entries_size + freelist_size); +} + +void node_alloc_init(void *p, uint64_t size, uint32_t unit_size) +{ + struct node_alloc_node *cur = (struct node_alloc_node *) p; // get the nn address + cur->next = 0; + cur->size = unit_size; + + uint64_t full_size = sizeof(struct node_alloc_node) + unit_size; + for (uint64_t i = full_size; i < size; i += full_size) // nn1+bn1 -- nn2+bn2 -- nn3+bn3 -- ... + { // nn1+mmsp1 -- nn2+mmsp2 -- nn3+mmsp3 + struct node_alloc_node *h = (struct node_alloc_node *)(p + i); + h->size = unit_size; + h->next = 0; + cur->next = h; + cur = h; + } +} + +void *node_alloc(struct node_alloc_node *head) +{ + struct node_alloc_node *cur = head->next; + if (cur) { + head->next = cur->next; + //current start address of node + header_sz so it will be storage addr + return (void *) (((uint64_t) cur) + sizeof(struct node_alloc_node)); + } +} + +void *internal_node_alloc(uint64_t dontcare) { + return node_alloc(_global_allocator->nhead); +} + +void nfree(struct node_alloc_node *head, void *p) // p-->bn +{ + struct node_alloc_node *n = (struct node_alloc_node *)(p - sizeof(struct node_alloc_node)); + n->next = head->next; + head->next = n; +} + + +void buddy_alloc_mem_init() +{ + uart_send_string("in buddy_alloc_mem_init\n"); + struct buddy_alloc *h = _global_allocator; + uint64_t page_count = h->size / h->page_size, frame = 0; + uart_send_string("total frame: \n"); + uart_hex(page_count); + h->order = MIN(63 - __builtin_clzll(page_count), h->order); + + // initialize a node-specialized allocator at the first page available + // the nallacator will be hooked up with generic malloc after it is available + struct node_alloc_node *nhead; + { + // find the first available page + for (; h->entries[frame] < 0; frame++); // find avaiable frame + nhead = (struct node_alloc_node *) (frame << 12); // get the frame address + node_alloc_init((void *) nhead, 1 << 12, sizeof(struct buddy_alloc_node)); + balloc_nalloc = internal_node_alloc; + h->entries[frame++] = -1; // reserve this frame + h->nhead = nhead; + } + for (; frame < page_count;) { + // find next available page + uart_send_string("\nframe occupy: "); + uart_hex(frame);ENDL; + + for (; h->entries[frame] < 0; frame++); // find avaiable frame + + uart_send_string("\nStart of available frame: "); + uart_hex(frame);ENDL;ENDL; + + + // find next unavailable page + uint64_t e = frame + 1; + for (; h->entries[e] >= 0; e++){ + if(e==page_count)break; + } + uart_send_string("End of available frame: "); + uart_hex(e);ENDL;ENDL; + + // divide the avaiable frame with order + for (uint64_t cur_order = h->order; frame < e;) { + uint64_t fcount = (1 << cur_order); + if (frame + fcount > e) + { + cur_order--; + continue; + } + h->entries[frame] = (buddy_alloc_entry) cur_order; + + // TODO: linked list + struct buddy_alloc_node **cur = &h->freelist[cur_order]; + while (*cur) // find the last freelist[cur_order] address + cur = &(*cur)->next; + // balloc_nalloc = internal_node_alloc; + struct buddy_alloc_node *n = balloc_nalloc(sizeof(struct buddy_alloc_node)); + n->idx = frame; + n->next = 0; + *cur = n; + + for (uint64_t j = frame + 1; j < frame + fcount; j++) + h->entries[j] = BRANCH; + frame += fcount; + } + uart_send_string("current frame: "); + uart_hex(frame); + uart_send_string("\r\n"); + uart_send_string("free! ==============================\n"); + } +} + + + +void buddy_alloc_state(struct buddy_alloc *b) +{ + void *_p_args[2] = {0, 0}; + uint64_t size = 0; + for (int32_t i = 0; i <= b->order; i++) { + struct buddy_alloc_node *cur = b->freelist[i]; + uint32_t cnt = 0; + while (cur) // how many block can use in freelist[i] + { + cnt++; + cur = cur->next; + } + size += (1 << i) * cnt; // how many pages can use in freelist[i] + _p_args[0] = (void *) i; _p_args[1] = (void *) cnt; + uart_send_string("ORDER "); + uart_hex(_p_args[0]); + uart_send_string(" has "); + uart_hex(_p_args[1]); + uart_send_string(" blocks available.");ENDL; + //utils_printf("ORDER %u has %u blocks available.\r\n", _p_args); + } + uart_send_string("AVAILABLE PAGES: "); + uart_hex(size);ENDL;ENDL; +} + +uint32_t mpool[4] = {sizeof(struct buddy_alloc_node), 64, 128, 256}; +struct node_alloc_node *bins[4]; + +// allocate buddy memory (page base) +void *buddy_alloc(uint64_t size) +{ + uint64_t pc = size / _global_allocator->page_size + ((size % _global_allocator->page_size) > 0); // get page index + uint64_t h = 63 - __builtin_clzll(pc); + uint64_t order = MIN(h + ((pc - (1 << h)) > 0), _global_allocator->order); // find 2^?order + int32_t lowest_avail_order = -1; + for (uint32_t c = order; c <= _global_allocator->order; c++) + if (_global_allocator->freelist[c]) // get from freelist(if have free m) from ordr base + { + lowest_avail_order = (int32_t) c; + break; + } + if (lowest_avail_order < 0) // no avalable free space in freelist + return NULL; + + for (uint32_t c = lowest_avail_order; c > order; c--) // divid the block if c > order(ori need) + { + struct buddy_alloc_node *n = _global_allocator->freelist[c]; + if (!n) break; + + _global_allocator->freelist[c] = n->next; // free this order block in freelist + struct buddy_alloc_node *n1 = balloc_nalloc(sizeof(struct buddy_alloc_node)); + struct buddy_alloc_node *n2 = balloc_nalloc(sizeof(struct buddy_alloc_node)); + n1->idx = n->idx; + n1->next = n2; + n2->idx = n1->idx + (1 << (c - 1)); + n2->next = _global_allocator->freelist[c - 1]; // from now get two new block(order-1) + _global_allocator->freelist[c - 1] = n1; + _global_allocator->entries[n1->idx] = (buddy_alloc_entry) (c - 1); + _global_allocator->entries[n2->idx] = (buddy_alloc_entry) (c - 1); + nfree(_global_allocator->nhead, n); + } + struct buddy_alloc_node *n = _global_allocator->freelist[order]; // clear freelist[order=order] it has been used + if (!n) + return NULL; + _global_allocator->freelist[order] = n->next; + _global_allocator->entries[n->idx] = (buddy_alloc_entry) (((int32_t) _global_allocator->entries[n->idx] * -1) - 1); // let entries be -a + void *ret = (void *) (n->idx * (_global_allocator->page_size)); // get mapped address + nfree(_global_allocator->nhead, n); + return ret; +} + + +void *buddy_malloc(uint64_t x) +{ + //i will be in [balloc_node, 64, 96, 128] + for (int i = 0; i < sizeof(mpool)/sizeof(mpool[0]); i++) { + //if current size of malloc is bigger than required size then use that malloc + if (mpool[i] > x) { + void *ret = node_alloc(bins[i]); + if (ret) + return ret; + if (rejuv_node_alloc(i) < 0) { + uart_send_string("!!!BUG!!!: CANT REJUV BINS\r\n"); + while(1); + } + ret = node_alloc(bins[i]); + if (!ret) { + uart_send_string("!!!BUG!!!: CANT REJUV BINS\r\n"); + while(1); + } + return ret; + } + } + // small allocator can't provide, propagate to balloc + return buddy_alloc(x); +} + + +int rejuv_node_alloc(int order) +{ + // assumption: bins[order]->next = NULL; bins[order] != NULL; + //because current page is full occupied, so next of nalloc node will be in new page + //new page will be allocated by balloc and init it with size captured by bins[order] + struct node_alloc_node *next = buddy_alloc(4096); + if (!next) + return -1; + node_alloc_init(next, 4096, bins[order]->size); + bins[order]->next = next; + uart_send_string("you are here for rejuv_nalloc\n"); + return 0; +} + +void buddy_malloc_init() +{ + // merge balloc_nallocator together with bins[0] + bins[0] = _global_allocator->nhead; + for (int i = 1; i < sizeof(mpool)/sizeof(mpool[0]); i++) { + void *m = buddy_alloc(4096); // allocate one page + // m is location, 4096 is page_sz and binsize[i] is size for that allocator + node_alloc_init(m, 4096, mpool[i]); + bins[i] = m; + } + //after finish malloc_init balloc_nalloc become y_malloc + balloc_nalloc = buddy_malloc; +} + +void buddy_free(void *ptr) { + + uint32_t idx =((uint64_t)ptr) / _global_allocator->page_size; + int32_t order = ((int32_t) _global_allocator->entries[idx] + 1) * -1; + + struct buddy_alloc_node *n = balloc_nalloc(sizeof(struct buddy_alloc_node)); + n->idx = idx; + uint32_t neighbor_idx = n->idx ^ (1<entries[neighbor_idx] == order) // neighbor block nor use -> merge + { + // find it from freelist + struct buddy_alloc_node *c = _global_allocator->freelist[order], **prev_slot = &_global_allocator->freelist[order]; + while(c){ + if(c->idx == neighbor_idx) { + struct buddy_alloc_node *merged = balloc_nalloc(sizeof(struct buddy_alloc_node)); + _global_allocator->entries[neighbor_idx] = BRANCH; + merged->idx = MIN(n->idx,neighbor_idx); + *prev_slot = c->next; + nfree(_global_allocator->nhead,n); + nfree(_global_allocator->nhead,c); + n = merged; + goto next_order; + } + prev_slot = &c->next; + c = c->next; + } + while(1); + next_order: + order++; + neighbor_idx = n->idx ^ (1<next = _global_allocator->freelist[order]; + _global_allocator->entries[n->idx] = (buddy_alloc_entry) order; + _global_allocator->freelist[order] = n; +} + + + +void node_free(void *ptr) +{ + if (__builtin_ctzll((uint64_t) ptr) >= 12) // if size bigger than one page -> use buddy_free + { + uart_send_string("Use buddy_free");ENDL; + buddy_free(ptr); + return; + } + struct node_alloc_node *header = ptr - sizeof(struct node_alloc_node); + for (int i = 0; i < sizeof(mpool)/sizeof(mpool[0]); i++) { + if (mpool[i] == header->size) { + nfree(bins[i], ptr); + return; + } + } + uart_send_string("!!BUG!!\n"); + ENDL; + +} + + +void buddy_system_init(void * _dtb) { + + char *dtb_addr = (char *)_dtb; + + //allocator location + void *mem = (void *)0x10000000; + //locate at 0x10000000 + struct buddy_alloc *bhead = mem; + bhead->order = 11; + bhead->page_size = 4096; + bhead->size = 0x3C000000; + buddy_alloc_preinit(bhead); + + uart_send_string("After buddy alloc preinit\n"); + + + buddy_alloc_reserve(0, (void *) 0x1000); + buddy_alloc_reserve((void *) 0x1000, (void *) 0x80000); + buddy_alloc_reserve((void *) 0x80000, (void *) 0x80000 + 30000); + buddy_alloc_reserve(cpio_addr, cpio_addr + 30000); + buddy_alloc_reserve(dtb_addr, dtb_addr + 60000); + + buddy_alloc_mem_init(); // divide avaliable memmory in free-list + uart_send_string("\nAfter buddy alloc init\n"); + buddy_malloc_init(); + + buddy_alloc_state(bhead); + + uart_send_string("\nallocate 4000bytes:\n"); + void* test1_malloc = buddy_alloc(4000); // return m address // nn--(sp) + buddy_alloc_state(bhead); + + uart_send_string("\nfree 5000 bytes\n"); + node_free(test1_malloc); + buddy_alloc_state(bhead); + + uart_send_string("\nallocate 10000bytes:\n"); + void* test2_malloc = buddy_alloc(10000); + buddy_alloc_state(bhead); + + uart_send_string("\nfree 10000 bytes\n"); + node_free(test2_malloc); + buddy_alloc_state(bhead); + +} + diff --git a/lab4/shell/allocator.o b/lab4/shell/allocator.o new file mode 100644 index 000000000..a058f22d5 Binary files /dev/null and b/lab4/shell/allocator.o differ diff --git a/lab4/shell/bcm2710-rpi-3-b-plus.dtb b/lab4/shell/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..0dd0e2f43 Binary files /dev/null and b/lab4/shell/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab4/shell/cpio.c b/lab4/shell/cpio.c new file mode 100644 index 000000000..a38879c9c --- /dev/null +++ b/lab4/shell/cpio.c @@ -0,0 +1,96 @@ +#include "header/cpio.h" +#include "header/uart.h" +#include "header/utils.h" +#include "header/allocator.h" + +int file_num = 0; +struct file *f = NULL; + +void allocate_file_array() { + if (f == NULL) { + f = (struct file *)simple_malloc(MAX_FILE_NUM * sizeof(struct file)); + if (f == NULL) { + uart_send_string("Memory allocation error\n"); + // Handle memory allocation error + } + } +} + +void traverse_file() +{ + allocate_file_array(); + char* addr = (char *)cpio_addr; + + + while(utils_string_compare((char *)(addr+sizeof(struct cpio_header)),"TRAILER!!!") == 0){ + + struct cpio_header *header = (struct cpio_header *)addr; + unsigned long filename_size = utils_atoi(header->c_namesize, (int)sizeof(header->c_namesize)); + unsigned long headerPathname_size = sizeof(struct cpio_header) + filename_size; + unsigned long file_size = utils_atoi(header->c_filesize, (int)sizeof(header->c_filesize)); + + utils_align(&headerPathname_size, 4); + utils_align(&file_size, 4); + + f[file_num].file_header = header; + f[file_num].filename_size = filename_size; + f[file_num].headerPathname_size = headerPathname_size; + f[file_num].file_size = file_size; + f[file_num].file_content_head = (char*) header + headerPathname_size; + + addr += (headerPathname_size + file_size); + file_num += 1; + } +} + +int findfile(char* filename) { + for(int n=0;n<=file_num;n++) { + if ((utils_string_compare(((char *)f[n].file_header)+sizeof(struct cpio_header), filename) != 0)){ + return n; + } + } + return -1; +} + +void cpio_ls() +{ + for(int n=0;n<=file_num;n++) { + uart_send_string(((char *)f[n].file_header)+sizeof(struct cpio_header)); + uart_send_string("\n"); + } +} + + +void cpio_cat(char *filename) +{ + int targetfile_num = findfile(filename); + + if(targetfile_num != -1) { + for (unsigned int i = 0; i < f[targetfile_num].file_size; i++) + { + uart_send_char(f[targetfile_num].file_content_head[i]); + } + uart_send_string("\n"); + + } else { + uart_send_string("Can not Find the file\n"); + } + +} + +void cpio_exec_program(char* filename) { + int targetfile_num = findfile(filename); + + char* target = (char*) 0x20000; + for(unsigned i = 0; imagic)); + + if (magic != 0xd00dfeed){ + + uart_send_string("The header magic is wrong\n"); + return -1; + } + + /* + +-----------------+ + | fdt_header | <- dtb_ptr + +-----------------+ + | reserved memory | + +-----------------+ + | structure block | <- dtb_ptr + header->off_dt_struct (struct_ptr) + +-----------------+ + | strings block | <- dtb_ptr + header->off_dt_strings (strings_ptr) + +-----------------+ + */ + + 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); + parse_struct(cb, struct_ptr,strings_ptr,totalsize); + return 1; + +} + +//5. Implement the initramfs_callback function: +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_string("cpio address is at: "); + uart_hex((uintptr_t)fdt_u32_le2be(data)); + uart_send_string("\r\n"); + } +} + +//6. Implement print_dtb callback function: + +void print_dtb(int token, const char* name, const void* data, uint32_t size) { + UNUSED(data); + UNUSED(size); + + switch(token){ + case FDT_BEGIN_NODE: + uart_send_string("\n"); + send_space(space); + uart_send_string((char*)name); + uart_send_string("{\n "); + space++; + break; + case FDT_END_NODE: + uart_send_string("\n"); + space--; + if(space >0) send_space(space); + uart_send_string("}\n"); + break; + case FDT_NOP: + break; + case FDT_PROP: + send_space(space); + uart_send_string((char*)name); + break; + case FDT_END: + break; + } +} diff --git a/lab4/shell/dtb.o b/lab4/shell/dtb.o new file mode 100644 index 000000000..52e6b26dd Binary files /dev/null and b/lab4/shell/dtb.o differ diff --git a/lab4/shell/except.c b/lab4/shell/except.c new file mode 100644 index 000000000..0387973d7 --- /dev/null +++ b/lab4/shell/except.c @@ -0,0 +1,227 @@ + +#include "header/uart.h" +#include "header/irq.h" +#include "header/shell.h" +#include "header/timer.h" +#include "header/tasklist.h" + +#define CNTPSIRQ_BIT_POSITION 0x02 +#define AUXINIT_BIT_POSTION 1<<29 + + +void except_handler_c() { + uart_send_string("In Exception handle\n"); + + //read spsr_el1 + unsigned long long spsr_el1 = 0; + asm volatile("mrs %0, spsr_el1":"=r"(spsr_el1)); + uart_send_string("spsr_el1: "); + uart_hex(spsr_el1); + uart_send_string("\n"); + + //read elr_el1 + unsigned long long elr_el1 = 0; + asm volatile("mrs %0, elr_el1":"=r"(elr_el1)); + uart_send_string("elr_el1: "); + uart_hex(elr_el1); + uart_send_string("\n"); + + //esr_el1 + unsigned long long esr_el1 = 0; + asm volatile("mrs %0, esr_el1":"=r"(esr_el1)); + uart_hex(esr_el1); + uart_send_string("\n"); + + //ec + unsigned ec = (esr_el1 >> 26) & 0x3F; //0x3F = 0b111111(6) + uart_send_string("ec: "); + uart_hex(ec); + uart_send_string("\n"); + + while(1){ + + } +} + +void timer_irq_handler() { + //enable core_0_timer + unsigned int* address = (unsigned int*) CORE0_TIMER_IRQ_CTRL; + *address = 2; + + asm volatile("msr cntp_ctl_el0,%0"::"r"(0)); + // Disable interrupts to protect critical section + asm volatile("msr DAIFSet, 0xf"); + + uint64_t current_time; + asm volatile("mrs %0, cntpct_el0":"=r"(current_time)); + + while(timer_head && timer_head->expiry <= current_time) { + timer_t *timer = timer_head; + + //Execute the callback + timer->callback(timer->data); + + // Remove timer from the list + timer_head = timer->next; + if (timer_head) { + timer_head->prev = NULL; + } + + //free timer + + // Reprogram the hardware timer if there are still timers left + if(timer_head) { + asm volatile("msr cntp_cval_el0, %0"::"r"(timer_head->expiry)); + asm volatile("msr cntp_ctl_el0,%0"::"r"(1)); + } else { + asm volatile("msr cntp_ctl_el0,%0"::"r"(0)); + } + + + //enable interrupt + asm volatile("msr DAIFClr,0xf"); + } + +} + +void uart_transmit_handler() { + mmio_write(AUX_MU_IER, mmio_read(AUX_MU_IER) | (0x2)); + + if (uart_write_buffer[uart_write_index-1] == '\r'){ + uart_write_buffer[uart_write_index++] = '\n'; + uart_write_buffer[uart_write_index] = '\0'; + } + + // Send data from the write buffer + while (uart_write_head != uart_write_index) { + mmio_write(AUX_MU_IO, uart_write_buffer[uart_write_head++]); + if (uart_write_index >= UART_BUFFER_SIZE) { + uart_write_index = 0; + } + + + if (uart_write_head == uart_write_index) { + mmio_write(AUX_MU_IER, mmio_read(AUX_MU_IER) & ~0x2); + if(uart_read_buffer[uart_read_index-1] == '\r'){ + uart_read_buffer[uart_read_index-1] = '\0'; + parse_command(uart_read_buffer); + uart_read_index = 0; + uart_write_index = 0; + uart_write_head = 0; + } + } + } + mmio_write(AUX_MU_IER, mmio_read(AUX_MU_IER) | 0x1); +} + +void uart_receive_handler() { + + // Read data(8 bytes) and store it in the read buffer + char data = mmio_read(AUX_MU_IO) & 0xff; + if (uart_read_index >= UART_BUFFER_SIZE) { + uart_read_index = 0; + } + uart_read_buffer[uart_read_index++] = data; + if (uart_read_index >= UART_BUFFER_SIZE) { + uart_read_index = 0; + } + + // Enqueue the received data into the write buffer + if (uart_write_index >= UART_BUFFER_SIZE) { + uart_write_index = 0; + } + uart_write_buffer[uart_write_index++] = data; + if (uart_write_index >= UART_BUFFER_SIZE) { + uart_write_index = 0; + } + + create_task(uart_transmit_handler,2); +} + +void irq_except_handler_c() { + + + asm volatile("msr DAIFSet, 0xf"); // Disable interrupts + + uint32_t irq_pending1 = mmio_read(IRQ_PENDING_1); + uint32_t core0_interrupt_source = mmio_read(CORE0_INTERRUPT_SOURCE); + uint32_t iir = mmio_read(AUX_MU_IIR); + + if (core0_interrupt_source & CNTPSIRQ_BIT_POSITION) { + + //djsable core 0 timer + unsigned int* address = (unsigned int*) CORE0_TIMER_IRQ_CTRL; + *address = 0; + + create_task(timer_irq_handler,3); + } + + // Handle UART interrupt + if (irq_pending1 & AUXINIT_BIT_POSTION) { + if ((iir & 0x06) == 0x04) { + //Disable receive interrupt + mmio_write(AUX_MU_IER, mmio_read(AUX_MU_IER) & ~(0x01)); + create_task(uart_receive_handler,1); + } + + if ((iir & 0x06) == 0x02) { + //Disable transmit interrupt + //mmio_write(AUX_MU_IER, mmio_read(AUX_MU_IER) & ~(0x02)); + //create_task(uart_transmit_handler,2); + } + } + + asm volatile("msr DAIFClr, 0xf"); // Enable interrupts + + execute_tasks(); + //asm volatile("msr DAIFClr, 0xf"); // Enable interrupts + +} + +/* +void uart_irq_handler(){ + uint32_t iir = mmio_read(AUX_MU_IIR); + + // Check if it is a receive interrupt + if ((iir & 0x06) == 0x04) { + // Read data(8 bytes) and store it in the read buffer + char data = mmio_read(AUX_MU_IO) & 0xff; + uart_read_buffer[uart_read_index++] = data; + if (uart_read_index >= UART_BUFFER_SIZE) { + uart_read_index = 0; + } + + // Enqueue the received data into the write buffer + uart_write_buffer[uart_write_index++] = data; + if (uart_write_index >= UART_BUFFER_SIZE) { + uart_write_index = 0; + } + + // Enable tx interrupt + mmio_write(AUX_MU_IER, mmio_read(AUX_MU_IER) | 0x2); + } + + // Check if it is a transmit interrupt + if ((iir & 0x06) == 0x02) { + // Send data from the write buffer + if (uart_write_head != uart_write_index) { + mmio_write(AUX_MU_IO, uart_write_buffer[uart_write_head++]); + if (uart_write_index >= UART_BUFFER_SIZE) { + uart_write_index = 0; + } + } else { + // Disable tx interrupt when there is no data left to send + mmio_write(AUX_MU_IER, mmio_read(AUX_MU_IER) & ~0x2); + + if(uart_read_buffer[uart_read_index-1] == '\r'){ + uart_read_buffer[uart_read_index-1] = '\0'; + parse_command(uart_read_buffer); + uart_read_index = 0; + uart_write_index = 0; + uart_write_head = 0; + } + } + } +} + +*/ diff --git a/lab4/shell/except.o b/lab4/shell/except.o new file mode 100644 index 000000000..fac20f6a2 Binary files /dev/null and b/lab4/shell/except.o differ diff --git a/lab4/shell/header/allocator.h b/lab4/shell/header/allocator.h new file mode 100644 index 000000000..d117fa8f9 --- /dev/null +++ b/lab4/shell/header/allocator.h @@ -0,0 +1,39 @@ +#ifndef ALLOCATOR_H +#define ALLOCATOR_H + +#include + +void* simple_malloc(unsigned long size); +void buddy_system_init(); + +struct node_alloc_node +{ + struct node_alloc_node *next; + uint32_t size; +}; + +struct buddy_alloc_node { + uint32_t idx; + struct buddy_alloc_node *next; +}; + +typedef enum +{ + BRANCH = -9999, +} buddy_alloc_val; + +typedef buddy_alloc_val buddy_alloc_entry; + +struct buddy_alloc +{ + unsigned order; + unsigned long long size; + unsigned page_size; + struct node_alloc_node *nhead; + buddy_alloc_entry *entries; + struct buddy_alloc_node **freelist; + void *mem; +}; + +extern struct buddy_alloc *_global_allocator; +#endif diff --git a/lab4/shell/header/cpio.h b/lab4/shell/header/cpio.h new file mode 100644 index 000000000..be0e36b9f --- /dev/null +++ b/lab4/shell/header/cpio.h @@ -0,0 +1,39 @@ +//#define QEMU_CPIO_ADDR (char *)0x8000000; //qemu +//#define RASP_CPIO_ADDR (char *)0x20000000;//rasperrypi + +#define MAX_FILE_NUM 10 + +extern char* cpio_addr; + +void traverse_file(); +void cpio_ls(); +void cpio_cat(char* filename); +void cpio_exec_program(char* filename); + +struct 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 file { + struct cpio_header* file_header; + unsigned long filename_size; + unsigned long headerPathname_size; + unsigned long file_size; + char* file_content_head; +}; + diff --git a/lab4/shell/header/dtb.h b/lab4/shell/header/dtb.h new file mode 100644 index 000000000..85e813ddf --- /dev/null +++ b/lab4/shell/header/dtb.h @@ -0,0 +1,28 @@ +#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 type,const char* name,const void *data,uint32_t size); + +struct __attribute__((packed)) fdt_header { + uint32_t magic; // contain the value 0xd00dfeed (big-endian). + uint32_t totalsize; // in byte + uint32_t off_dt_struct; // the offset in bytes of the structure block from the beginning of the header + 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; // the length in bytes of the strings block section + uint32_t size_dt_struct; +}; + +int fdt_traverse(fdt_callback cb,void *dtb_ptr); +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); + +extern char* cpio_addr; diff --git a/lab4/shell/header/gpio.h b/lab4/shell/header/gpio.h new file mode 100644 index 000000000..38ca70635 --- /dev/null +++ b/lab4/shell/header/gpio.h @@ -0,0 +1,38 @@ +#ifndef GPIO_H +#define GPIO_H + +#include +//Page 90, Physical/bus addr diff +#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 diff --git a/lab4/shell/header/irq.h b/lab4/shell/header/irq.h new file mode 100644 index 000000000..9085cb30c --- /dev/null +++ b/lab4/shell/header/irq.h @@ -0,0 +1,22 @@ +#ifndef IRQ_H +#define IRQ_H + +#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 CORE0_TIMER_IRQ_CTRL ((volatile unsigned int*)(0x40000040)) +#define CORE0_INTERRUPT_SOURCE ((volatile unsigned int*)(0x40000060)) + + +#endif + diff --git a/lab4/shell/header/mailbox.h b/lab4/shell/header/mailbox.h new file mode 100644 index 000000000..d13ac3ce9 --- /dev/null +++ b/lab4/shell/header/mailbox.h @@ -0,0 +1,38 @@ +#include "gpio.h" + +extern volatile unsigned int mailbox[36]; + +#define MBOX_REQUEST 0 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define TAG_REQUEST_CODE 0x00000000 +#define MBOX_TAG_GETSERIAL 0x00010004 +#define MBOX_TAG_GETBOARD 0x00010002 +#define MBOX_TAG_GETARMMEM 0x00010005 +#define MBOX_TAG_LAST 0x00000000 + +int mailbox_call(); +void get_board_revision(); +void get_arm_mem(); + +#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880) +#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0)) +#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10)) +#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14)) +#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18)) +#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C)) +#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20)) +#define MBOX_RESPONSE 0x80000000 +#define MBOX_FULL 0x80000000 +#define MBOX_EMPTY 0x40000000 diff --git a/lab4/shell/header/reboot.h b/lab4/shell/header/reboot.h new file mode 100644 index 000000000..e1d44aa1b --- /dev/null +++ b/lab4/shell/header/reboot.h @@ -0,0 +1,8 @@ +#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(); diff --git a/lab4/shell/header/shell.h b/lab4/shell/header/shell.h new file mode 100644 index 000000000..9784c1ccb --- /dev/null +++ b/lab4/shell/header/shell.h @@ -0,0 +1,2 @@ +void shell(); +void parse_command(char* buffer); diff --git a/lab4/shell/header/tasklist.h b/lab4/shell/header/tasklist.h new file mode 100644 index 000000000..0aaca4ae1 --- /dev/null +++ b/lab4/shell/header/tasklist.h @@ -0,0 +1,33 @@ +#ifndef TASKLIST_H +#define TASKLIST_H + +// #include +#include + +#ifdef _cplusplus +#define NULL 0 +#else +#define NULL (void*)0 +#endif + +#ifndef __SIZE_TYPE__ +#define __SIZE_TYPE__ long unsigned int +#endif +// #if !(defined (__GNUG__) && defined (size_t)) +typedef __SIZE_TYPE__ size_t; + +typedef void (*task_callback)(); + +typedef struct task { + struct task *prev; + struct task *next; + task_callback callback; + uint64_t priority; +} task_t; + +void execute_tasks(); +void create_task(task_callback callback,uint64_t priority); +void enqueue_task(task_t *new_task); +extern task_t *task_head; + +#endif diff --git a/lab4/shell/header/timer.h b/lab4/shell/header/timer.h new file mode 100644 index 000000000..2fac7a24f --- /dev/null +++ b/lab4/shell/header/timer.h @@ -0,0 +1,33 @@ +#ifndef TIMER_H +#define TIMER_H + +#include +// #include + +#ifdef _cplusplus +#define NULL 0 +#else +#define NULL (void*)0 +#endif + +#ifndef __SIZE_TYPE__ +#define __SIZE_TYPE__ long unsigned int +#endif +// #if !(defined (__GNUG__) && defined (size_t)) +typedef __SIZE_TYPE__ size_t; + +typedef void (*timer_callback)(void *data); + +typedef struct timer { + struct timer *prev; // previous timer in the list + struct timer *next; // next timer in the list + timer_callback callback; // the function to call when the timer expires + void *data; // data to be passed to the callback + uint64_t expiry; // the time at which the timer will expire +} timer_t; + +extern timer_t *timer_head; // head of the timer list + +void setTimeout(char *message,uint64_t seconds); +#endif + diff --git a/lab4/shell/header/uart.h b/lab4/shell/header/uart.h new file mode 100644 index 000000000..ac6dab007 --- /dev/null +++ b/lab4/shell/header/uart.h @@ -0,0 +1,41 @@ +#ifndef UART_H +#define UART_H + +#include "gpio.h" +#include +#define UART_BUFFER_SIZE 1024 +#define ENDL uart_send_char('\r');uart_send_char('\n'); + +void uart_init(); +void uart_send_char(unsigned int c); +char uart_get_char(); +void uart_send_string(char* s); +void uart_hex(unsigned long long d); +void uart_hexll(uint64_t d); +void uart_enable_interrupt(); +int uart_async_read(char *buffer); +void uart_async_write(const char *buffer, int length); +void uart_async_send(const char *str); + + +extern char uart_read_buffer[UART_BUFFER_SIZE]; +extern char uart_write_buffer[UART_BUFFER_SIZE]; +extern int uart_read_index; +extern int uart_read_head; +extern int uart_write_index; +extern int uart_write_head; + +#define AUX_ENABLE ((volatile unsigned int*)(MMIO_BASE+0x00215004)) +#define AUX_MU_IO ((volatile unsigned int*)(MMIO_BASE+0x00215040)) +#define AUX_MU_IER ((volatile unsigned int*)(MMIO_BASE+0x00215044)) +#define AUX_MU_IIR ((volatile unsigned int*)(MMIO_BASE+0x00215048)) +#define AUX_MU_LCR ((volatile unsigned int*)(MMIO_BASE+0x0021504C)) +#define AUX_MU_MCR ((volatile unsigned int*)(MMIO_BASE+0x00215050)) +#define AUX_MU_LSR ((volatile unsigned int*)(MMIO_BASE+0x00215054)) +#define AUX_MU_MSR ((volatile unsigned int*)(MMIO_BASE+0x00215058)) +#define AUX_MU_SCRATCH ((volatile unsigned int*)(MMIO_BASE+0x0021505C)) +#define AUX_MU_CNTL ((volatile unsigned int*)(MMIO_BASE+0x00215060)) +#define AUX_MU_STAT ((volatile unsigned int*)(MMIO_BASE+0x00215064)) +#define AUX_MU_BAUD ((volatile unsigned int*)(MMIO_BASE+0x00215068)) + +#endif diff --git a/lab4/shell/header/utils.h b/lab4/shell/header/utils.h new file mode 100644 index 000000000..64643444e --- /dev/null +++ b/lab4/shell/header/utils.h @@ -0,0 +1,26 @@ +#include +// #include + +#ifdef _cplusplus +#define NULL 0 +#else +#define NULL (void*)0 +#endif + +#ifndef __SIZE_TYPE__ +#define __SIZE_TYPE__ long unsigned int +#endif +// #if !(defined (__GNUG__) && defined (size_t)) +typedef __SIZE_TYPE__ size_t; + +#define nop asm volatile("nop") +#define MIN(a,b) (a <= b) ? a : b + +int utils_string_compare(const char* i, const char* j); +unsigned long utils_atoi(const char *s, int char_size); +void utils_align(void *size, unsigned int s); +char *utils_ret_align(char *addr, unsigned alignment); +uint32_t utils_align_up(uint32_t size, int alignment); +size_t utils_strlen(const char *s); +char *utils_strcpy(char* dst, const char *src); +char *utils_strdup(const char *src); diff --git a/lab4/shell/initramfs.cpio b/lab4/shell/initramfs.cpio new file mode 100644 index 000000000..faf47b52f Binary files /dev/null and b/lab4/shell/initramfs.cpio differ diff --git a/lab4/shell/kernel8.elf b/lab4/shell/kernel8.elf new file mode 100644 index 000000000..ff3732352 Binary files /dev/null and b/lab4/shell/kernel8.elf differ diff --git a/lab4/shell/kernel8.img b/lab4/shell/kernel8.img new file mode 100644 index 000000000..f7e2d4f59 Binary files /dev/null and b/lab4/shell/kernel8.img differ diff --git a/lab4/shell/linker.ld b/lab4/shell/linker.ld new file mode 100644 index 000000000..5018defb6 --- /dev/null +++ b/lab4/shell/linker.ld @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +SECTIONS +{ + . = 0x80000; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { . = ALIGN(16); *(.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/lab4/shell/mailbox.c b/lab4/shell/mailbox.c new file mode 100644 index 000000000..7e0c5d99c --- /dev/null +++ b/lab4/shell/mailbox.c @@ -0,0 +1,51 @@ +#include "header/mailbox.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){ + /* is it a valid successful response? */ + if(mailbox[1] == MBOX_RESPONSE) + return 1; + } + } + 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. +} diff --git a/lab4/shell/mailbox.o b/lab4/shell/mailbox.o new file mode 100644 index 000000000..8e2118f24 Binary files /dev/null and b/lab4/shell/mailbox.o differ diff --git a/lab4/shell/main.c b/lab4/shell/main.c new file mode 100644 index 000000000..c1f840898 --- /dev/null +++ b/lab4/shell/main.c @@ -0,0 +1,116 @@ +#include "header/uart.h" +#include "header/shell.h" +#include "header/dtb.h" +#include "header/utils.h" +#include "header/cpio.h" +#include "header/timer.h" +#include "header/allocator.h" + +void test_read_command(char* buffer) { + int index = 0; + while(1) { + buffer[index] = uart_get_char(); + if(buffer[index] == '\n') { + buffer[index] = '\0'; + buffer[index+1] = '\n'; + uart_send_string("\r\n"); + break; + } + else + { + uart_send_char(buffer[index]); + } + index++; + } +} + + +extern void *_dtb_ptr; +void main() +{ + + // set up serial console + uart_init(); + + // pre test /////////////////////////////// + char buffer[256]; + while(1) + { + uart_send_string("# "); + test_read_command(buffer); + char * input_string = buffer; + if(utils_string_compare(input_string,"in")) + { + break; + } + else + { + // uart_send_hex((uintptr_t) _dtb_addr); + uart_send_string("The instruct is not exist.\n"); + } + } + ////////////////////////////////////////////// + + uart_init(); + // device tree traverse + fdt_traverse(get_cpio_addr,_dtb_ptr); + traverse_file(); + + // buddy system init + buddy_system_init(_dtb_ptr); + + unsigned long el = 0; + asm volatile ("mrs %0, CurrentEL":"=r"(el)); + uart_send_string("Current exception level: "); + uart_hex(el>>2); // CurrentEL store el level at [3:2] + uart_send_string("\n"); + + asm volatile("mov %0, sp"::"r"(el)); + uart_send_string("Current stack pointer address: "); + uart_hex(el); + uart_send_string("\n"); + + // say hello + uart_send_string("Type in `help` to get instruction menu!\n"); + + uart_enable_interrupt(); + + + while(1){ + asm volatile("nop"); + } + //echo everything back + //shell(); +} + + +/* +void except_handle() { + uart_send_string("In exception"); + + unsigned long long esr_el1 = 0; + asm volatile ("mrs %0, esr_el1" :: "r" (esr_el1)); + unsigned ec = (esr_el1 >> 26) & 0x3F; //0x3F = 0b111111(6) + unsigned imm16 = esr_el1 & 65535; //65535 = 0x1111111111111111(16) + + uart_send_string("\nec: "); + uart_hex(ec); + uart_send_string("\n"); + uart_send_string("imm16: "); + uart_hex(imm16); + uart_send_string("\n"); + + if (ec != 0x15){ // SVC from AArch64 + while(1) nop; + } + + switch (imm16) { + case 0x1337: { // exit from EL0 + // update spsr to make eret jumps back to loop + // set EL1h and mask all interrupts + uart_send_string("In the svc execution"); + return; + } + } +} +*/ diff --git a/lab4/shell/main.o b/lab4/shell/main.o new file mode 100644 index 000000000..0bda17501 Binary files /dev/null and b/lab4/shell/main.o differ diff --git a/lab4/shell/reboot.c b/lab4/shell/reboot.c new file mode 100644 index 000000000..048f2d348 --- /dev/null +++ b/lab4/shell/reboot.c @@ -0,0 +1,16 @@ +#include "header/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); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick +} + +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} diff --git a/lab4/shell/reboot.o b/lab4/shell/reboot.o new file mode 100644 index 000000000..dda9e2825 Binary files /dev/null and b/lab4/shell/reboot.o differ diff --git a/lab4/shell/rootfs/file1.txt b/lab4/shell/rootfs/file1.txt new file mode 100644 index 000000000..5c275ef57 --- /dev/null +++ b/lab4/shell/rootfs/file1.txt @@ -0,0 +1 @@ +This is file one. diff --git a/lab4/shell/rootfs/one.img b/lab4/shell/rootfs/one.img new file mode 100644 index 000000000..13bb5c616 Binary files /dev/null and b/lab4/shell/rootfs/one.img differ diff --git a/lab4/shell/rootfs/pack.sh b/lab4/shell/rootfs/pack.sh new file mode 100644 index 000000000..d837d685d --- /dev/null +++ b/lab4/shell/rootfs/pack.sh @@ -0,0 +1,2 @@ +find . | cpio -o -H newc > ../initramfs.cpio + diff --git a/lab4/shell/rootfs/thisisfile2.txt b/lab4/shell/rootfs/thisisfile2.txt new file mode 100644 index 000000000..0a8a2c0d7 --- /dev/null +++ b/lab4/shell/rootfs/thisisfile2.txt @@ -0,0 +1 @@ +Here is file two with longer size. diff --git a/lab4/shell/shell.c b/lab4/shell/shell.c new file mode 100644 index 000000000..89cbe18c8 --- /dev/null +++ b/lab4/shell/shell.c @@ -0,0 +1,146 @@ +#include "header/shell.h" +#include "header/uart.h" +#include "header/utils.h" +#include "header/mailbox.h" +#include "header/reboot.h" +#include "header/cpio.h" +#include "header/allocator.h" +#include "header/dtb.h" +#include "header/irq.h" +#include "header/timer.h" +#define BUFFER_MAX_SIZE 256u + + +extern void *_dtb_ptr; + +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 async_read_command(char* buffer) { + int index = 0; + char tmp[1]; + + while (1) { + if (uart_async_read(tmp) > 0) { + buffer[index] = tmp[0]; + uart_send_char(tmp[0]); + if (tmp[0] == '\r') { + buffer[index] = '\0'; + break; + } + index++; + } + } +} +*/ + +void parse_command(char* buffer){ + char* input_string = buffer; + char* parameter[5]; //5 is the available parameter length + int para_idx = 0; + int input_string_len = utils_strlen(input_string); + for(int i=0; i < input_string_len; i++){ + if(*(input_string+i) == ' '){ + *(input_string+i) = '\0'; + parameter[para_idx++] = (input_string+i+1); + } + } + + if(utils_string_compare(input_string,"help")) { + uart_send_string("help :print this help menu\n"); + uart_send_string("hello :print Hello World!\n"); + uart_send_string("info :Get the hardware's information\n"); + uart_send_string("reboot :reboot the device\n"); + uart_send_string("ls :list the file\n"); + uart_send_string("cat :print file content\n"); + uart_send_string("malloc :give dynamic memory space\n"); + uart_send_string("dtb :print device tree\n"); + uart_send_string("exec :execute user program\n"); + } else if (utils_string_compare(input_string,"hello")) { + uart_send_string("Hello World!\n"); + } else if (utils_string_compare(input_string,"info")) { + get_board_revision(); + uart_send_string("My board revision is: "); + uart_hex(mailbox[5]); + uart_send_string("\n"); + get_arm_mem(); + uart_send_string("My ARM memory base address is: "); + uart_hex(mailbox[5]); + uart_send_string("\n"); + uart_send_string("My ARM memory size is: "); + uart_hex(mailbox[6]); + uart_send_string("\n"); + } else if (utils_string_compare(input_string,"reboot")) { + uart_send_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_string("Filename: "); + //char filename[BUFFER_MAX_SIZE]; + //read_command(filename); + //cpio_cat(filename); + cpio_cat(parameter[0]); + } else if (utils_string_compare(input_string,"malloc")){ + char *a = simple_malloc(sizeof("9876")); + char *b = simple_malloc(sizeof("345")); + a[0] = '9'; + a[1] = '8'; + a[2] = '7'; + a[3] = '6'; + a[4] = '\0'; + b[0] = '3'; + b[1] = '4'; + b[2] = '5'; + b[3] = '\0'; + uart_send_string(a); + uart_send_char('\n'); + uart_send_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,"exec")) { + //uart_send_string("Program name: "); + //char buffer[BUFFER_MAX_SIZE]; + //read_command(buffer); + cpio_exec_program(parameter[0]); + } else if (utils_string_compare(input_string,"timer")) { + + setTimeout("hello world1",3); + setTimeout("hello world2",6); + setTimeout("hello world3",9); + + } else if (utils_string_compare(input_string,"settimeout")) { + char *message = (char *)parameter[0]; + size_t second_str_len = utils_strlen(parameter[1]); + uint64_t seconds = (uint64_t) utils_atoi(parameter[1],second_str_len-1); + setTimeout(message,seconds); + } else { + uart_send_string("The instruction "); + uart_send_string(input_string); + uart_send_string(" is not exist.\n"); + } +} + +void shell(){ + /* + while(1) { + char buffer[BUFFER_MAX_SIZE]; + uart_send_string("# "); + //async_read_command(buffer); + parse_command(buffer); + } + */ + +} diff --git a/lab4/shell/shell.o b/lab4/shell/shell.o new file mode 100644 index 000000000..716286e80 Binary files /dev/null and b/lab4/shell/shell.o differ diff --git a/lab4/shell/start.S b/lab4/shell/start.S new file mode 100644 index 000000000..00f6e7bd7 --- /dev/null +++ b/lab4/shell/start.S @@ -0,0 +1,163 @@ + +.section ".text.kernel" + +.global _start + + + +_start: + ldr x1, =_dtb_ptr //put _dtb_ptr into register1 + str x0, [x1] //store dtb address from x0 to _dtb_ptr + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, 2f + // cpu id > 0, stop +1: wfe + b 1b +2: // cpu id == 0 + + ldr x1, =_start + bl from_el2_to_el1 + mov sp, x1 + + + /* set exception vector table */ + adr x0, exception_vector_table + msr vbar_el1, x0 + + //bl core_timer_enable + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size + +3: cbz w2, 4f + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, 3b + //bl core_timer_enable + // jump to C code, should not return +4: bl main + // for failsafe, halt this core too + b 1b + +from_el2_to_el1: + mov x0,#(1<<31) + msr hcr_el2,x0 + mov x0,#0x345 // 0x3c5 + msr spsr_el2,x0 + msr elr_el2,lr + eret +/* +core_timer_enable: + //mov x0,1 + //msr cntp_ctl_el0, x0 //enable + //mrs x0, cntfrq_el0 + //mov x3,5 + //mul x0, x0, x3 + //msr cntp_tval_el0,x0 // set expired time + //mov x0,2 + //ldr x1, =CORE0_TIMER_IRQ_CTRL + //str w0,[x1] //unmask timer interrupt + //ret +*/ +// 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 except_handler_c + load_all + eret + +irq_exception_handler: + save_all + bl irq_except_handler_c + load_all + eret + +.align 11 // vector table should be aligned to 0x800 +.global exception_vector_table +exception_vector_table: + 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 + + b exception_handler + .align 7 + b irq_exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + b exception_handler + .align 7 + b irq_exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + +.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 + diff --git a/lab4/shell/start.o b/lab4/shell/start.o new file mode 100644 index 000000000..e072c076b Binary files /dev/null and b/lab4/shell/start.o differ diff --git a/lab4/shell/tasklist.c b/lab4/shell/tasklist.c new file mode 100644 index 000000000..8d79c6f3d --- /dev/null +++ b/lab4/shell/tasklist.c @@ -0,0 +1,66 @@ +#include "header/tasklist.h" +#include "header/allocator.h" +#include "header/uart.h" + +task_t *task_head = NULL; + +void enqueue_task(task_t *new_task) { + // Disable interrupts to protect the critical section + asm volatile("msr DAIFSet, 0xf"); + // Special case: the list is empty or the new task has higher priority + if (!task_head || new_task->priority < task_head->priority) { + new_task->next = task_head; + new_task->prev = NULL; + if (task_head) { + 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; + } + + // Enable interrupts + asm volatile("msr DAIFClr, 0xf"); +} + +void create_task(task_callback callback, uint64_t priority) { + + task_t* task = simple_malloc(sizeof(task_t)); + if(!task) { + return; + } + + task->callback = callback; + task->priority = priority; + + enqueue_task(task); +} + +void execute_tasks() { + + + while (task_head) { + task_head->callback(); + task_head = task_head->next; + if (task_head) { + task_head->prev = NULL; + } + asm volatile("msr DAIFSet, 0xf"); // Disable interrupts + //simple_free(task); + } + + asm volatile("msr DAIFClr, 0xf"); // Enable interrupts +} + diff --git a/lab4/shell/tasklist.o b/lab4/shell/tasklist.o new file mode 100644 index 000000000..3ecce4a61 Binary files /dev/null and b/lab4/shell/tasklist.o differ diff --git a/lab4/shell/timer.c b/lab4/shell/timer.c new file mode 100644 index 000000000..dfab3c3d0 --- /dev/null +++ b/lab4/shell/timer.c @@ -0,0 +1,102 @@ +#include "header/timer.h" +#include "header/allocator.h" +#include "header/uart.h" +#include "header/irq.h" +#include "header/utils.h" + +timer_t *timer_head = NULL; + +void add_timer(timer_t *new_timer) { + + timer_t *current = timer_head; + + // Disable interrupts to protect the critical section + asm volatile("msr DAIFSet, 0xf"); + // Special case: the list is empty or the new timer is the earliest + if (!timer_head || new_timer->expiry < timer_head->expiry) { + new_timer->next = timer_head; + new_timer->prev = NULL; + if (timer_head) { + timer_head->prev = new_timer; + } + timer_head = new_timer; + + // Reprogram the hardware timer + asm volatile ("msr cntp_cval_el0, %0"::"r"(new_timer->expiry)); + asm volatile("msr cntp_ctl_el0,%0"::"r"(1)); + + // Enable interrupts + asm volatile("msr DAIFClr, 0xf"); + return; + } + + // Find the correct position in the list + while (current->next && current->next->expiry < new_timer->expiry) { + current = current->next; + } + + // Insert the new timer + new_timer->next = current->next; + new_timer->prev = current; + if (current->next) { + current->next->prev = new_timer; + } + current->next = new_timer; + // Enable interrupts + asm volatile("msr DAIFClr, 0xf"); +} + + +void create_timer(timer_callback callback, void* data, uint64_t after) { + //Allocate memory for the timer + timer_t* timer = simple_malloc(sizeof(timer_t)); + if(!timer) { + return; + } + + //Set the callback and data + timer->callback = callback; + timer->data = data; + + //Calculate the expiry time + uint64_t current_time, cntfrq; + asm volatile("mrs %0, cntpct_el0":"=r"(current_time)); + asm volatile("mrs %0, cntfrq_el0":"=r"(cntfrq)); + timer->expiry = current_time + after * cntfrq; + //Add the time to the list + add_timer(timer); +} + + +void print_message(void *data) { + char *message = data; + uint64_t current_time, cntfrq; + asm volatile("mrs %0, cntpct_el0" : "=r"(current_time)); + asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq)); + uint64_t seconds = current_time / cntfrq; + + uart_send_string("Timeout message: "); + uart_send_string(message); + uart_send_string(" occurs at "); + uart_hex(seconds); + uart_send_string("\n"); +} + +void setTimeout(char *message,uint64_t seconds) { + + char *message_copy = utils_strdup(message); + + if(!message_copy){ + return; + } + + if (!timer_head) { + //enable core_timer_interrupt + unsigned int value = 2; + unsigned int* address = (unsigned int*) CORE0_TIMER_IRQ_CTRL; + *address = value; + } + + create_timer(print_message,message_copy,seconds); +} + diff --git a/lab4/shell/timer.o b/lab4/shell/timer.o new file mode 100644 index 000000000..2073fbde9 Binary files /dev/null and b/lab4/shell/timer.o differ diff --git a/lab4/shell/uart.c b/lab4/shell/uart.c new file mode 100644 index 000000000..4d0df7857 --- /dev/null +++ b/lab4/shell/uart.c @@ -0,0 +1,209 @@ +#include "header/uart.h" +#include "header/irq.h" +#include "header/utils.h" + +#define RX_INTERRUPT_BIT 0x01 +#define TX_INTERRUPT_BIT 0x02 + +#define AUXINIT_BIT_POSTION 1<<29 + +char uart_read_buffer[UART_BUFFER_SIZE]; +char uart_write_buffer[UART_BUFFER_SIZE]; +int uart_read_head = 0; +int uart_read_index = 0; +int uart_write_index = 0; +int uart_write_head = 0; + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init() +{ + register unsigned int r; + // P.104 Since I need UART 1 Transmit/Receive Data -> TXD1/RXD1 + // p.102 I find These two in GPIO 14/15 Fun5 + // Since each GPFSEL controls 10 pin, GPFSEL1 controls 10-19 + // That's why I need GPFSEL1 + 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 + + //Since We've set alt5, we want to disable basic input/output + //To achieve this, we need diable pull-up and pull-dwon + *GPPUD = 0; // P101 top. 00- = off - disable pull-up/down + //Wait 150 cycles + //this provides the required set-up time for the control signal + r=150; while(r--) { asm volatile("nop"); } + // 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 + *GPPUDCLK0 = (1<<14)|(1<<15); + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = 0; // flush GPIO setup + + + r=1000; while(r--) { asm volatile("nop"); } + + /* initialize UART */ + *AUX_ENABLE |=1; + //P.9: If set the mini UART is enabled. The UART will + //immediately start receiving data, especially if the + //UART1_RX line is low. + //If clear the mini UART is disabled. That also disables + //any mini UART register access + *AUX_MU_CNTL = 0; + //P.17 If this bit is set the mini UART receiver is enabled. + //If this bit is clear the mini UART receiver is disabled + //Prevent data exchange in initialization process + *AUX_MU_IER = 0; + //Set AUX_MU_IER_REG to 0. + //Disable interrupt because currently you don’t need interrupt. + *AUX_MU_LCR = 3; + //P.14: 00 : the UART works in 7-bit mode + //11(3) : the UART works in 8-bit mode + //Cause 8 bits can use in ASCII, Unicode, Char + *AUX_MU_MCR = 0; + //Don’t need auto flow control. + //AUX_MU_MCR is for basic serial communication. Don't be too smart + *AUX_MU_BAUD = 270; + //set BAUD rate to 115200(transmit speed) + //so we need set AUX_MU_BAUD to 270 to meet the goal + *AUX_MU_IIR = 0xc6; + // bit 6 bit 7 No FIFO. Sacrifice reliability(buffer) to get low latency // 0xc6 = 11000110 + // Writing with bit 1 set will clear the receive FIFO + // Writing with bit 2 set will clear the transmit FIFO + // Both bits always read as 1 as the FIFOs are always enabled + /* map UART1 to GPIO pins */ + *AUX_MU_CNTL = 3; // enable Transmitter,Receiver + +} + + +/** + * Send a character + */ +void uart_send_char(unsigned int c) { + /* wait until we can send */ + // P.15 AUX_MU_LSR register shows the data(line) status + // AUX_MU_LSR bit 5 => 0x20 = 00100000 + // bit 5 is set if the transmit FIFO can accept at least one byte. + // &0x20 can preserve 5th bit, if bit 5 set 1 can get !true = false leave loop + // else FIFO can not accept at lease one byte then still wait + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); + /* write the character to the buffer */ + //P.11 The AUX_MU_IO_REG register is primary used to write data to and read data from the + //UART FIFOs. + //communicate with(send to) the minicom and print to the screen + *AUX_MU_IO=c; +} + +/** + * Display a string + */ +void uart_send_string(char* s) { + while(*s) { + /* convert newline to carriage return + newline */ + if(*s=='\n') + uart_send_char('\r'); + uart_send_char(*s++); + } +} + +/** + * Receive a character + */ +char uart_get_char() { + char r; + /* wait until something is in the buffer */ + //bit 0 is set if the receive FIFO holds at least 1 symbol. + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01)); + /* read it and return */ + r=(char)(*AUX_MU_IO); + /* convert carriage return to newline */ + return r=='\r'?'\n':r; +} + + +/** + * Display a binary value in hexadecimal + */ +void uart_hex(unsigned long long d) { + unsigned long long n; + int c; + uart_send_string("0x"); + for(c=28;c>=0;c-=4) { + // get highest tetrad + n=(d>>c)&0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n+=n>9?0x57:0x30; + uart_send_char(n); + } +} + +void uart_hexll(uint64_t d) { + uart_send_string("0x"); + unsigned int n; + int c; + for (c = 60; c >= 0; c -= 4) { + // get highest tetrad + n = (d >> c) & 0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n += n > 9 ? 0x37 : 0x30; + uart_send_char(n); + } +} + + + +void uart_enable_interrupt() { + + // Enable RX and TX interrupt for mini UART + uint32_t ier = mmio_read(AUX_MU_IER); + ier |= RX_INTERRUPT_BIT; + //ier |= (RX_INTERRUPT_BIT | TX_INTERRUPT_BIT); + mmio_write(AUX_MU_IER, ier); + + // Enable the mini UART interrupt in the second-level interrupt controller + uint32_t enable_irqs1 = (uint32_t) ENABLE_IRQS_1; + enable_irqs1 |= AUXINIT_BIT_POSTION; // Set bit29 + mmio_write(ENABLE_IRQS_1, enable_irqs1); +} + +void uart_disable_interrupt() { + uint32_t disable_irqs1 = (uint32_t) DISABLE_IRQS_1; + disable_irqs1 |= AUXINIT_BIT_POSTION; + mmio_write(DISABLE_IRQS_1,disable_irqs1); +} + +int uart_async_read(char *buffer) { + if (uart_read_head == uart_read_index) { + // No characters available full! + return 0; + } else { + buffer[0] = uart_read_buffer[uart_read_head++]; + if (uart_read_head >= UART_BUFFER_SIZE) { + uart_read_head = 0; + } + return 1; + } +} +void uart_async_write(const char *buffer, int length) { + for (int i = 0; i < length; i++) { + uart_write_buffer[uart_write_head++] = buffer[i]; + if (uart_write_head >= UART_BUFFER_SIZE) { + uart_write_head = 0; + } + } + // Trigger TX interrupt + mmio_write(AUX_MU_IER, mmio_read(AUX_MU_IER) | 0x2); +} + +void uart_async_send(const char *str) { + int length = utils_strlen(str); + uart_async_write(str, length); +} + + diff --git a/lab4/shell/uart.o b/lab4/shell/uart.o new file mode 100644 index 000000000..34201a823 Binary files /dev/null and b/lab4/shell/uart.o differ diff --git a/lab4/shell/userprogram/Makefile b/lab4/shell/userprogram/Makefile new file mode 100644 index 000000000..19cefe3cf --- /dev/null +++ b/lab4/shell/userprogram/Makefile @@ -0,0 +1,11 @@ +all: one.img + +one.o: one.S + aarch64-linux-gnu-gcc -c one.S -o one.o + +one.img: one.o + aarch64-linux-gnu-ld one.o -T linker.ld -o one.elf + aarch64-linux-gnu-objcopy -O binary one.elf one.img + +clean: + rm one.o one.elf > /dev/null 2>/dev/null || true diff --git a/lab4/shell/userprogram/linker.ld b/lab4/shell/userprogram/linker.ld new file mode 100644 index 000000000..ab70a30ea --- /dev/null +++ b/lab4/shell/userprogram/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 : { . = ALIGN(16); *(.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/lab4/shell/userprogram/one.S b/lab4/shell/userprogram/one.S new file mode 100644 index 000000000..4acf6f4dd --- /dev/null +++ b/lab4/shell/userprogram/one.S @@ -0,0 +1,7 @@ +.section ".text" +.global _start +_start: + svc 0x1337 +1: + nop + b 1b diff --git a/lab4/shell/userprogram/one.elf b/lab4/shell/userprogram/one.elf new file mode 100644 index 000000000..b13e36ed9 Binary files /dev/null and b/lab4/shell/userprogram/one.elf differ diff --git a/lab4/shell/userprogram/one.img b/lab4/shell/userprogram/one.img new file mode 100644 index 000000000..13bb5c616 Binary files /dev/null and b/lab4/shell/userprogram/one.img differ diff --git a/lab4/shell/userprogram/one.o b/lab4/shell/userprogram/one.o new file mode 100644 index 000000000..c00c28e5b Binary files /dev/null and b/lab4/shell/userprogram/one.o differ diff --git a/lab4/shell/utils.c b/lab4/shell/utils.c new file mode 100644 index 000000000..d2fc5ac4d --- /dev/null +++ b/lab4/shell/utils.c @@ -0,0 +1,68 @@ +#include "header/utils.h" +#include "header/allocator.h" + +int utils_string_compare(const char* str1,const char* str2) { + for(;*str1 !='\0'||*str2 !='\0';str1++,str2++){ + if(*str1 != *str2) return 0; + else if(*str1 == '\0' && *str2 =='\0') return 1; + } + return 1; +} + +unsigned long utils_atoi(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); +} + +char *utils_ret_align(char *addr, unsigned alignment) +{ + return (char *) (((unsigned long long) addr + alignment - 1) & ~((unsigned long long) alignment - 1)); +} + +uint32_t utils_align_up(uint32_t size, int alignment) { + return (size + alignment - 1) & ~(alignment-1); +} + +//with null-terminator -> "hello" return 6 +size_t utils_strlen(const char *s) { + size_t i = 0; + while (s[i]) i++; + return i+1; +} + + +char *utils_strcpy(char* dst, const char *src) { + char *save = dst; + while((*dst++ = *src++)); + return save; +} + + +char *utils_strdup(const char *src) { + size_t len = utils_strlen(src); + char *dst = simple_malloc(len); + if (dst == NULL) { // Check if the memory has been successfully allocated + return NULL; + } + utils_strcpy(dst, src); // Copy the string + return dst; +} + + diff --git a/lab4/shell/utils.o b/lab4/shell/utils.o new file mode 100644 index 000000000..a954be0cd Binary files /dev/null and b/lab4/shell/utils.o differ diff --git a/lab5/Makefile b/lab5/Makefile new file mode 100644 index 000000000..527f6f735 --- /dev/null +++ b/lab5/Makefile @@ -0,0 +1,102 @@ +CFLAG = -Iinclude -Wall -ffreestanding -fno-stack-protector -nostdlib -nostartfiles -mgeneral-regs-only +K8=kernel8 +BL=bootloader +LINKER=linker.ld +START=start +CPIO:=archive/initramfs.cpio +TA_CPIO:=archive/TA/initramfs.cpio + +DTB:=archive/bcm2710-rpi-3-b-plus.dtb +USER_DIR:=users/user +USER1:=user1 +USER2:=user2 +BUILD:=build/ + +BUILD_ELF:=$(shell find build/ -name '*.elf') +BUILD_IMG:=$(shell find build/ -name '*.img') +ARC_IMG:=$(shell find archive/ -name '*.img') + +SRC_C:=$(shell find src/ -name '*.c') +SRC_S:=$(shell find src/ -name '*.s') + +KER_C:=$(shell find kernel/ -name '*.c') +KER_S:=$(shell find kernel/ -name '*.s') + +BL_C:=$(shell find bootloader/ -name '*.c') +BL_S:=$(shell find bootloader/ -name '*.s') + +USER1_C:=$(shell find users/user1/ -name '*.c') +USER1_OBJS:= $(USER1_C:%.c=%.o) + +USER2_C:=$(shell find users/user2/ -name '*.c') +USER2_OBJS:= $(USER2_C:%.c=%.o) + +OBJS:= $(SRC_C:%.c=%.o) \ + $(SRC_S:%.s=%.o) \ + rd.o + + +KERNEL_OBJS:=$(KER_C:%.c=%.o) \ + $(KER_S:%.s=%.o) + + + +BL_OBJS:=$(BL_C:%.c=%.o) \ + $(BL_S:%.s=%.o) \ + src/mini_uart.o src/utils_c.o src/utils_s.o src/memzero.o src/sprintf.o + + + + +all: $(BUILD)$(USER1).img\ + $(BUILD)$(USER2).img \ + $(BUILD)$(K8).img \ + $(BUILD)$(BL).img + + + +rd.o:$(CPIO) + aarch64-linux-gnu-ld -r -b binary -o rd.o $(CPIO) + + +%.o: %.s + aarch64-linux-gnu-gcc -g -o $@ -c $< + +%.o: %.c + aarch64-linux-gnu-gcc -g -o $@ $(CFLAG) -c $< + + +$(BUILD)$(K8).img: $(OBJS) $(KERNEL_OBJS) + aarch64-linux-gnu-ld -T kernel/$(LINKER) -o $(BUILD)$(K8).elf $^ + aarch64-linux-gnu-objcopy -O binary $(BUILD)$(K8).elf $@ + +$(BUILD)$(BL).img: $(BL_OBJS) + aarch64-linux-gnu-ld -T bootloader/$(LINKER) -o $(BUILD)$(BL).elf $^ + aarch64-linux-gnu-objcopy -O binary $(BUILD)$(BL).elf $@ + +$(BUILD)$(USER1).img:$(USER1_OBJS) + aarch64-linux-gnu-ld -T $(USER_DIR)1/$(LINKER) -o $(BUILD)$(USER1).elf $< + aarch64-linux-gnu-objcopy -O binary $(BUILD)$(USER1).elf $@ + cp $@ archive/rootfs/ + +$(BUILD)$(USER2).img:$(USER2_OBJS) + aarch64-linux-gnu-ld -T $(USER_DIR)2/$(LINKER) -o $(BUILD)$(USER2).elf $< + aarch64-linux-gnu-objcopy -O binary $(BUILD)$(USER2).elf $@ + cp $@ archive/rootfs/ + +$(CPIO): + cd archive/rootfs&&find . | cpio -o -H newc > ../initramfs.cpio + +on: + sudo screen /dev/ttyUSB0 115200 +qe: $(BUILD)$(K8).img + qemu-system-aarch64 -M raspi3b -kernel $< \ + -serial null -serial stdio -s \ + -initrd $(TA_CPIO) \ + -dtb $(DTB) \ + +clean: + $(RM) $(BUILD_ELF) $(CPIO) \ + $(OBJS) $(KERNEL_OBJS) $(BL_OBJS) $(USER1_OBJS) $(USER2_OBJS)\ + $(BUILD_IMG) $(ARC_IMG) + \ No newline at end of file diff --git a/lab5/ReaMe.md b/lab5/ReaMe.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/lab5/ReaMe.md @@ -0,0 +1 @@ + diff --git a/lab5/archive/TA/initramfs.cpio b/lab5/archive/TA/initramfs.cpio new file mode 100644 index 000000000..0676fb158 Binary files /dev/null and b/lab5/archive/TA/initramfs.cpio differ diff --git a/lab5/archive/TA/initramfs/syscall.img b/lab5/archive/TA/initramfs/syscall.img new file mode 100644 index 000000000..70d4a5539 Binary files /dev/null and b/lab5/archive/TA/initramfs/syscall.img differ diff --git a/lab5/archive/bcm2710-rpi-3-b-plus.dtb b/lab5/archive/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..3934b3a26 Binary files /dev/null and b/lab5/archive/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab5/archive/initramfs.cpio b/lab5/archive/initramfs.cpio new file mode 100644 index 000000000..36a1383f3 Binary files /dev/null and b/lab5/archive/initramfs.cpio differ diff --git a/lab5/archive/rootfs/one b/lab5/archive/rootfs/one new file mode 100644 index 000000000..50ecbb596 --- /dev/null +++ b/lab5/archive/rootfs/one @@ -0,0 +1,3 @@ +1 2 3 +4 5 6 +7 8 9 diff --git a/lab5/archive/rootfs/two b/lab5/archive/rootfs/two new file mode 100644 index 000000000..599c97676 --- /dev/null +++ b/lab5/archive/rootfs/two @@ -0,0 +1,3 @@ +hello + world + !!!!! diff --git a/lab5/archive/rootfs/user1.img b/lab5/archive/rootfs/user1.img new file mode 100644 index 000000000..894965657 Binary files /dev/null and b/lab5/archive/rootfs/user1.img differ diff --git a/lab5/archive/rootfs/user2.img b/lab5/archive/rootfs/user2.img new file mode 100644 index 000000000..5458f0d37 Binary files /dev/null and b/lab5/archive/rootfs/user2.img differ diff --git a/lab5/bootloader/linker.ld b/lab5/bootloader/linker.ld new file mode 100644 index 000000000..2efc319db --- /dev/null +++ b/lab5/bootloader/linker.ld @@ -0,0 +1,28 @@ +ENTRY(_start) +SECTIONS +{ + . = 0x60000; + _stext = .; + .text : { + *(.text.relo) + _bl_entry = .; + *(.text.boot) + *(.text) + *(.rodata) + } + . = ALIGN(0x1000); + _etext = .; + + _sdata = .; + .data : { *(.data) } + . = ALIGN(0x1000); + _edata = .; + + + _sbss = .; + .bss : { *(.bss*) } + . = ALIGN(0x1000); + _ebss = .; + + _blsize = _ebss - _stext; +} diff --git a/lab5/bootloader/main.c b/lab5/bootloader/main.c new file mode 100644 index 000000000..a18076e82 --- /dev/null +++ b/lab5/bootloader/main.c @@ -0,0 +1,48 @@ +#include "mini_uart.h" +#include "utils_c.h" +#include "utils_s.h" +#include +#define BUFFER_MAX_SIZE 256u + +extern char *_dtb; +void load_img() +{ + char * kernel_addr = (char *)0x80000; + uart_send_string("Please sent the kernel image size:"); + char buffer[BUFFER_MAX_SIZE]; + // read_command(buffer); + size_t index = 0; + while (1) + { + buffer[index] = uart_recv(); + uart_send(buffer[index]); + if (buffer[index] == '\n') + { + break; + } + index++; + } + buffer[index + 1] = '\0'; + utils_newline2end(buffer); + uart_send('\r'); + unsigned int img_size = utils_str2uint_dec(buffer); + uart_send_string("Start to load the kernel image... \n"); + + unsigned char *current = (unsigned char *)kernel_addr; + while (img_size--) + { + *current = uart_recv_raw(); + current++; + uart_send('.'); + } + uart_send_string("loading...\n"); + // branchAddr(kernel_addr); + ((void (*)(char *))kernel_addr)(_dtb); +} + +void bootloader_main(void) +{ + uart_init(); + uart_send_string("In bootloader_main!\n"); + load_img(); +} \ No newline at end of file diff --git a/lab5/bootloader/main.o b/lab5/bootloader/main.o new file mode 100644 index 000000000..53e3b561c Binary files /dev/null and b/lab5/bootloader/main.o differ diff --git a/lab5/bootloader/start.o b/lab5/bootloader/start.o new file mode 100644 index 000000000..c28f9afa5 Binary files /dev/null and b/lab5/bootloader/start.o differ diff --git a/lab5/bootloader/start.s b/lab5/bootloader/start.s new file mode 100644 index 000000000..549ee4109 --- /dev/null +++ b/lab5/bootloader/start.s @@ -0,0 +1,46 @@ +.section ".text.relo" +.globl _start + +# need to relocate the bootloader from 0x80000 to 0x60000 +_start: + adr x10, . //x10=0x80000 + ldr x11, =_blsize + add x11, x11, x10 + ldr x12, =_stext // x12=0x60000 + +moving_relo: + cmp x10, x11 //without bootloader + b.eq end_relo + ldr x13, [x10] + str x13, [x12] //move 0x80000 data to 0x60000 + add x12, x12, #8 + add x10, x10, #8 + b moving_relo +end_relo: + ldr x14, =_bl_entry //jump to boot part + br x14 + + +.section ".text.boot" +.globl _start_bl + ldr x20, =_dtb + str x0, [x20] + mrs x20, mpidr_el1 + and x20, x20,#0xFF // Check processor id + cbz x20, master // Hang for all non-primary CPU + +hang: + b hang + +master: + adr x20, _sbss + adr x21, _ebss + sub x21, x21, x20 + bl memzero + + mov sp, #0x400000 // 4MB + bl bootloader_main + +.global _dtb +.section .data +_dtb: .dc.a 0x0 diff --git a/lab5/build/bootloader.elf b/lab5/build/bootloader.elf new file mode 100644 index 000000000..a147fd407 Binary files /dev/null and b/lab5/build/bootloader.elf differ diff --git a/lab5/build/bootloader.img b/lab5/build/bootloader.img new file mode 100644 index 000000000..84926c044 Binary files /dev/null and b/lab5/build/bootloader.img differ diff --git a/lab5/build/kernel8.elf b/lab5/build/kernel8.elf new file mode 100644 index 000000000..d83575f59 Binary files /dev/null and b/lab5/build/kernel8.elf differ diff --git a/lab5/build/kernel8.img b/lab5/build/kernel8.img new file mode 100644 index 000000000..21aa21a68 Binary files /dev/null and b/lab5/build/kernel8.img differ diff --git a/lab5/build/user1.elf b/lab5/build/user1.elf new file mode 100644 index 000000000..10dbd68d8 Binary files /dev/null and b/lab5/build/user1.elf differ diff --git a/lab5/build/user1.img b/lab5/build/user1.img new file mode 100644 index 000000000..894965657 Binary files /dev/null and b/lab5/build/user1.img differ diff --git a/lab5/build/user2.elf b/lab5/build/user2.elf new file mode 100644 index 000000000..cb3056ccf Binary files /dev/null and b/lab5/build/user2.elf differ diff --git a/lab5/build/user2.img b/lab5/build/user2.img new file mode 100644 index 000000000..5458f0d37 Binary files /dev/null and b/lab5/build/user2.img differ diff --git a/lab5/include/_cpio.h b/lab5/include/_cpio.h new file mode 100644 index 000000000..1fe9877c8 --- /dev/null +++ b/lab5/include/_cpio.h @@ -0,0 +1,31 @@ +#ifndef __CPIO_H +#define __CPIO_H +#include +/* + cpio archive comprises a header record with basic numeric metadata followed by + the full pathname of the entry and the file data. +*/ +typedef struct 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. +} cpio_header; + +void cpio_ls(); +void cpio_cat(const char *filename); +char *findFile(const char *name); +size_t cpio_load_program(const char *filename, void **put_addr); +#endif \ No newline at end of file diff --git a/lab5/include/current.h b/lab5/include/current.h new file mode 100644 index 000000000..9cc1e993a --- /dev/null +++ b/lab5/include/current.h @@ -0,0 +1,16 @@ +#ifndef _CURRENT_H +#define _CURRENT_H + +#include "thread.h" + +static inline struct task *get_thread_ds() +{ + return (struct task *)read_sysreg(tpidr_el1); +} +static inline void set_thread_ds(struct task *cur) +{ + write_sysreg(tpidr_el1, cur); +} +#define current get_thread_ds() + +#endif diff --git a/lab5/include/dtb.h b/lab5/include/dtb.h new file mode 100644 index 000000000..38f0d3612 --- /dev/null +++ b/lab5/include/dtb.h @@ -0,0 +1,39 @@ +#ifndef _DTB_H +#define _DTB_H +#include +#include +/* + structure block: located at a 4-byte aligned offset from the beginning of the devicetree blob + token is a big-endian 32-bit integer, alligned on 32bit(padding 0) + +*/ + +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + +typedef struct fdt_header +{ + uint32_t magic; // contain the value 0xd00dfeed (big-endian). + uint32_t totalsize; // in byte + uint32_t off_dt_struct; // the offset in bytes of the structure block from the beginning of the header + 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; // the length in bytes of the strings block section + uint32_t size_dt_struct; +} fdt_header; + +typedef void (*fdt_callback)(int type, const char *name, const void *data, uint32_t size); +void print_dtb(int type, const char *name, const void *data, uint32_t size); +void get_initramfs_addr(int type, const char *name, const void *data, uint32_t size); +int fdt_traverse(fdt_callback cb, void *dtb_ptr); + +extern uintptr_t dtb_end, dtb_start; +extern char *initramfs_start, *initramfs_end; + +#endif \ No newline at end of file diff --git a/lab5/include/exception_c.h b/lab5/include/exception_c.h new file mode 100644 index 000000000..c47caa49c --- /dev/null +++ b/lab5/include/exception_c.h @@ -0,0 +1,17 @@ +#ifndef _EXCEPTION_C_H +#define _EXCEPTION_C_H +#include +#include "trap_frame.h" +typedef void (*task_callback)(void *); + +void enable_interrupt(); +void disable_interrupt(); +unsigned long disable_irq(); +void irq_restore(unsigned long flag); + +void default_handler(); +void lower_sync_handler(TrapFrame *_regs); +void irq_handler(); +void curr_sync_handler(); + +#endif diff --git a/lab5/include/exception_s.h b/lab5/include/exception_s.h new file mode 100644 index 000000000..fd2409595 --- /dev/null +++ b/lab5/include/exception_s.h @@ -0,0 +1,6 @@ +#ifndef _EXCEPTION_S_H +#define _EXCEPTION_S_H + +void restore_regs_eret(); + +#endif diff --git a/lab5/include/exec.h b/lab5/include/exec.h new file mode 100644 index 000000000..2676c33ae --- /dev/null +++ b/lab5/include/exec.h @@ -0,0 +1,7 @@ +#ifndef __EXEC_H_ +#define __EXEC_H_ + +void exe_new_prog(char *filename); +int do_exec(const char *path, const char *argv[]); + +#endif \ No newline at end of file diff --git a/lab5/include/fork.h b/lab5/include/fork.h new file mode 100644 index 000000000..3fa7d5d3b --- /dev/null +++ b/lab5/include/fork.h @@ -0,0 +1,8 @@ +#ifndef __FORK_H_ +#define __FORK_H_ +#include +#include "trap_frame.h" + +size_t do_fork(TrapFrame *regs); + +#endif \ No newline at end of file diff --git a/lab5/include/list.h b/lab5/include/list.h new file mode 100644 index 000000000..0f886e233 --- /dev/null +++ b/lab5/include/list.h @@ -0,0 +1,45 @@ +#ifndef __LIST_H +#define __LIST_H +#include +#include + +typedef struct list +{ + struct list *next, *prev; +} list; + +#define container_of(ptr, type, member) ({ \ + void *__mptr = (void *)(ptr); \ + ((type *)(__mptr - offsetof(type, member))); }) + +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +#define list_for_each_entry(entry, head, member) \ + for (entry = list_entry((head)->next, __typeof__(*entry), member); \ + &entry->member != (head); \ + entry = list_entry(entry->member.next, __typeof__(*entry), member)) + +#define LIST_HEAD_INIT(name) \ + { \ + &(name), &(name) \ + } + +static inline int list_empty(const list *head) +{ + return head->next == head; +} + +void list_init(list *node); +void insert_head(list *head, list *v); +void insert_tail(list *head, list *v); +list *remove_head(list *head); +list *remove_tail(list *head); +void unlink(list *node); +#endif diff --git a/lab5/include/mini_uart.h b/lab5/include/mini_uart.h new file mode 100644 index 000000000..2c17055b3 --- /dev/null +++ b/lab5/include/mini_uart.h @@ -0,0 +1,22 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + + +void delay(unsigned int clock); +void enable_uart_interrupt(); +void disable_uart_interrupt(); +void uart_init(); +void uart_send_string(const char* str); +void uart_send(const char c); +char uart_recv(); +char uart_recv_raw(); +void uart_hex(unsigned int d); +void uart_dec(unsigned int num); +void uart_handler(); +void test_uart_async(); +char uart_async_recv(); +void uart_async_send_string(char *str); +void uart_async_send(char c); + +unsigned int uart_printf(char* fmt, ...); +#endif \ No newline at end of file diff --git a/lab5/include/mm.h b/lab5/include/mm.h new file mode 100644 index 000000000..756755aa4 --- /dev/null +++ b/lab5/include/mm.h @@ -0,0 +1,47 @@ +#ifndef _MM_H +#define _MM_H + +#include +#include + +#define STARTUP_MEM_START 0x07000000 +#define STARTUP_MEM_END 0x07ffffff + +typedef struct FrameFlag +{ + unsigned char flag; + unsigned char order; + unsigned short ref_count; + unsigned char chunk_order; +} FrameFlag; + +typedef struct Chunk +{ + struct Chunk *next; +} Chunk; + +// buddy system +void init_buddy(); +void *alloc_pages(unsigned int pages); +void free_pages(void *victim); + +// dynamic mem allocate +void *kmalloc(unsigned int size); +void *kcalloc(unsigned int size); +void kfree(void *ptr); + +// test +void test_buddy(); +void test_dynamic_alloc(); + +// others +void memory_reserve(uintptr_t start, uintptr_t end); +void mm_init(); +void merge_useful_pages(); + +// start up allocation +void *smalloc(size_t size); + + +#endif + diff --git a/lab5/include/peripheral/base.h b/lab5/include/peripheral/base.h new file mode 100644 index 000000000..1eb154198 --- /dev/null +++ b/lab5/include/peripheral/base.h @@ -0,0 +1,7 @@ +#ifndef _PERIPHERAL_BASE_H +#define _PERIPHERAL_BASE_H + +#define MMIO_BASE 0x3F000000 +#define MAILBOX_BASE MMIO_BASE + 0xb880 + +#endif \ No newline at end of file diff --git a/lab5/include/peripheral/gpio.h b/lab5/include/peripheral/gpio.h new file mode 100644 index 000000000..8246c40ae --- /dev/null +++ b/lab5/include/peripheral/gpio.h @@ -0,0 +1,12 @@ +#ifndef _PERIPHERAL_GPIO_H +#define _PERIPHERAL_GPIO_H + +#include "peripheral/base.h" + +#define GPFSEL1 ((volatile unsigned int *)(MMIO_BASE+0x00200004)) +#define GPSET0 ((volatile unsigned int *)(MMIO_BASE+0x0020001C)) +#define GPCLR0 ((volatile unsigned int *)(MMIO_BASE+0x00200028)) +#define GPPUD ((volatile unsigned int *)(MMIO_BASE+0x00200094)) +#define GPPUDCLK0 ((volatile unsigned int *)(MMIO_BASE+0x00200098)) + +#endif \ No newline at end of file diff --git a/lab5/include/peripheral/mailbox.h b/lab5/include/peripheral/mailbox.h new file mode 100644 index 000000000..fc26769a9 --- /dev/null +++ b/lab5/include/peripheral/mailbox.h @@ -0,0 +1,36 @@ +#ifndef _MAILBOX_H +#define _MAILBOX_H + +#include "peripheral/base.h" + +#define MAILBOX_READ ((volatile unsigned int *)(MAILBOX_BASE)) +#define MAILBOX_STATUS ((volatile unsigned int *)(MAILBOX_BASE + 0x18)) +#define MAILBOX_WRITE ((volatile unsigned int *)(MAILBOX_BASE + 0x20)) + +#define MAILBOX_EMPTY 0x40000000 +#define MAILBOX_FULL 0x80000000 +#define MAILBOX_RESPONSE 0x80000000 +#define ARM_MEMORY 0x00010005 + +#define GET_BOARD_REVISION 0x00010002 +#define REQUEST_CODE 0x00000000 +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +#define MAILBOX_CH_POWER 0 +#define MAILBOX_CH_FB 1 +#define MAILBOX_CH_VUART 2 +#define MAILBOX_CH_VCHIQ 3 +#define MAILBOX_CH_LEDS 4 +#define MAILBOX_CH_BTNS 5 +#define MAILBOX_CH_TOUCH 6 +#define MAILBOX_CH_COUNT 7 +#define MAILBOX_CH_PROP 8 + +unsigned int mailbox_call(unsigned char channel, unsigned int *_mailbox); +unsigned int get_board_revision(); +void get_arm_memory(); + +#endif \ No newline at end of file diff --git a/lab5/include/peripheral/mini_uart.h b/lab5/include/peripheral/mini_uart.h new file mode 100644 index 000000000..0ac714e1c --- /dev/null +++ b/lab5/include/peripheral/mini_uart.h @@ -0,0 +1,30 @@ +#ifndef _PERIPHERAL_MINI_UART_H +#define _PERIPHERAL_MINI_UART_H + +#include "peripheral/base.h" + +#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)) + + + +#define ARM_IRQ_REG_BASE ((volatile unsigned int*)(MMIO_BASE + 0x0000b000)) +#define IRQ_PENDING_1 ((volatile unsigned int*)(MMIO_BASE + 0x0000b204)) +#define ENB_IRQS1 ((volatile unsigned int*)(MMIO_BASE + 0x0000b210)) +#define DISABLE_IRQS1 ((volatile unsigned int*)(MMIO_BASE + 0x0000b21c)) +#define AUX_IRQ (1 << 29) + + + + +#endif \ No newline at end of file diff --git a/lab5/include/sche.h b/lab5/include/sche.h new file mode 100644 index 000000000..349ed3d15 --- /dev/null +++ b/lab5/include/sche.h @@ -0,0 +1,62 @@ +#ifndef __SCHE_H +#define __SCHE_H +#include "list.h" +#include "signal.h" + +typedef unsigned long pid_t; +typedef enum +{ + TASK_RUNNING, + TASK_WAITING, + TASK_STOPPED, + TASK_INIT, +} state_t; + +struct cpu_context +{ + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + unsigned long fp; + unsigned long sp; + unsigned long lr; +}; + +struct task +{ + struct cpu_context cpu_context; + char *kernel_stack; + char *user_stack; + char *user_prog; + size_t user_prog_size; + state_t state; + pid_t pid; + unsigned need_resched; + int exitcode; + unsigned long timeout; + list list; + struct signal *signal; + struct signal_context *sig_context; +}; + +extern list running_queue, waiting_queue, stopped_queue; +void add_task(struct task *t); +void kill_task(struct task *_task, int status); +void restart_task(struct task *_task); +void pause_task(struct task *_task); +void sleep_task(size_t ms); +void free_task(struct task *victim); +struct task *create_task(); +void switch_task(struct task *next); +struct task *pick_next_task(); +int get_the_cur_count(); +struct task *get_task(pid_t target); +extern pid_t task_count; +#endif \ No newline at end of file diff --git a/lab5/include/shell.h b/lab5/include/shell.h new file mode 100644 index 000000000..08f251990 --- /dev/null +++ b/lab5/include/shell.h @@ -0,0 +1,7 @@ +#ifndef _SHELL_H +#define _SHELL_H + +void shell(); +void read_command(char *str); +void parse_command(char *str); +#endif \ No newline at end of file diff --git a/lab5/include/signal.h b/lab5/include/signal.h new file mode 100644 index 000000000..768e13b87 --- /dev/null +++ b/lab5/include/signal.h @@ -0,0 +1,27 @@ +#ifndef __SIGNAL_H +#define __SIGNAL_H + +#define SIGKILL 9 + +#include "list.h" +#include "trap_frame.h" +#define SIG_NUM (sizeof(signal_table) / sizeof(signal_table[0])) +typedef void (*signal_handler)(int); + +struct signal +{ + unsigned int sig_num; + signal_handler handler; + struct list list; +}; +struct signal_context +{ + TrapFrame *trapframe; + char *user_stack; +}; + +extern signal_handler signal_table[]; + +void sig_context_update(TrapFrame *_regs, void (*handler)()); +void sig_context_restore(TrapFrame *_regs); +#endif diff --git a/lab5/include/sprintf.h b/lab5/include/sprintf.h new file mode 100644 index 000000000..a7c47f848 --- /dev/null +++ b/lab5/include/sprintf.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +#ifndef __SPRINT_H +#define __SPRINT_H + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); + +#endif \ No newline at end of file diff --git a/lab5/include/stddef.h b/lab5/include/stddef.h new file mode 100644 index 000000000..5e498773a --- /dev/null +++ b/lab5/include/stddef.h @@ -0,0 +1,463 @@ +/* Copyright (C) 1989-2024 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC 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 General Public License for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ + +/* + * ISO C Standard: 7.17 Common definitions + */ +#if (!defined(_STDDEF_H) && !defined(_STDDEF_H_) && !defined(_ANSI_STDDEF_H) \ + && !defined(__STDDEF_H__)) \ + || defined(__need_wchar_t) || defined(__need_size_t) \ + || defined(__need_ptrdiff_t) || defined(__need_NULL) \ + || defined(__need_wint_t) + +/* Any one of these symbols __need_* means that GNU libc + wants us just to define one data type. So don't define + the symbols that indicate this file's entire job has been done. */ +#if (!defined(__need_wchar_t) && !defined(__need_size_t) \ + && !defined(__need_ptrdiff_t) && !defined(__need_NULL) \ + && !defined(__need_wint_t)) +#define _STDDEF_H +#define _STDDEF_H_ +/* snaroff@next.com says the NeXT needs this. */ +#define _ANSI_STDDEF_H +#endif + +#ifndef __sys_stdtypes_h +/* This avoids lossage on SunOS but only if stdtypes.h comes first. + There's no way to win with the other order! Sun lossage. */ + +#if defined(__NetBSD__) +#include +#endif + +#if defined (__FreeBSD__) +#include +#endif + +#if defined(__NetBSD__) +#if !defined(_SIZE_T_) && !defined(_BSD_SIZE_T_) +#define _SIZE_T +#endif +#if !defined(_PTRDIFF_T_) && !defined(_BSD_PTRDIFF_T_) +#define _PTRDIFF_T +#endif +/* On BSD/386 1.1, at least, machine/ansi.h defines _BSD_WCHAR_T_ + instead of _WCHAR_T_. */ +#if !defined(_WCHAR_T_) && !defined(_BSD_WCHAR_T_) +#ifndef _BSD_WCHAR_T_ +#define _WCHAR_T +#endif +#endif +/* Undef _FOO_T_ if we are supposed to define foo_t. */ +#if defined (__need_ptrdiff_t) || defined (_STDDEF_H_) +#undef _PTRDIFF_T_ +#undef _BSD_PTRDIFF_T_ +#endif +#if defined (__need_size_t) || defined (_STDDEF_H_) +#undef _SIZE_T_ +#undef _BSD_SIZE_T_ +#endif +#if defined (__need_wchar_t) || defined (_STDDEF_H_) +#undef _WCHAR_T_ +#undef _BSD_WCHAR_T_ +#endif +#endif /* defined(__NetBSD__) */ + +/* Sequent's header files use _PTRDIFF_T_ in some conflicting way. + Just ignore it. */ +#if defined (__sequent__) && defined (_PTRDIFF_T_) +#undef _PTRDIFF_T_ +#endif + +/* On VxWorks, may have defined macros like + _TYPE_size_t which will typedef size_t. fixincludes patched the + vxTypesBase.h so that this macro is only defined if _GCC_SIZE_T is + not defined, and so that defining this macro defines _GCC_SIZE_T. + If we find that the macros are still defined at this point, we must + invoke them so that the type is defined as expected. */ +#if defined (_TYPE_ptrdiff_t) && (defined (__need_ptrdiff_t) || defined (_STDDEF_H_)) +_TYPE_ptrdiff_t; +#undef _TYPE_ptrdiff_t +#endif +#if defined (_TYPE_size_t) && (defined (__need_size_t) || defined (_STDDEF_H_)) +_TYPE_size_t; +#undef _TYPE_size_t +#endif +#if defined (_TYPE_wchar_t) && (defined (__need_wchar_t) || defined (_STDDEF_H_)) +_TYPE_wchar_t; +#undef _TYPE_wchar_t +#endif + +/* In case nobody has defined these types, but we aren't running under + GCC 2.00, make sure that __PTRDIFF_TYPE__, __SIZE_TYPE__, and + __WCHAR_TYPE__ have reasonable values. This can happen if the + parts of GCC is compiled by an older compiler, that actually + include gstddef.h, such as collect2. */ + +/* Signed type of difference of two pointers. */ + +/* Define this type if we are doing the whole job, + or if we want this type in particular. */ +#if defined (_STDDEF_H) || defined (__need_ptrdiff_t) +#ifndef _PTRDIFF_T /* in case has defined it. */ +#ifndef _T_PTRDIFF_ +#ifndef _T_PTRDIFF +#ifndef __PTRDIFF_T +#ifndef _PTRDIFF_T_ +#ifndef _BSD_PTRDIFF_T_ +#ifndef ___int_ptrdiff_t_h +#ifndef _GCC_PTRDIFF_T +#ifndef _PTRDIFF_T_DECLARED /* DragonFly */ +#ifndef __DEFINED_ptrdiff_t /* musl libc */ +#define _PTRDIFF_T +#define _T_PTRDIFF_ +#define _T_PTRDIFF +#define __PTRDIFF_T +#define _PTRDIFF_T_ +#define _BSD_PTRDIFF_T_ +#define ___int_ptrdiff_t_h +#define _GCC_PTRDIFF_T +#define _PTRDIFF_T_DECLARED +#define __DEFINED_ptrdiff_t +#ifndef __PTRDIFF_TYPE__ +#define __PTRDIFF_TYPE__ long int +#endif +typedef __PTRDIFF_TYPE__ ptrdiff_t; +#endif /* __DEFINED_ptrdiff_t */ +#endif /* _PTRDIFF_T_DECLARED */ +#endif /* _GCC_PTRDIFF_T */ +#endif /* ___int_ptrdiff_t_h */ +#endif /* _BSD_PTRDIFF_T_ */ +#endif /* _PTRDIFF_T_ */ +#endif /* __PTRDIFF_T */ +#endif /* _T_PTRDIFF */ +#endif /* _T_PTRDIFF_ */ +#endif /* _PTRDIFF_T */ + +/* If this symbol has done its job, get rid of it. */ +#undef __need_ptrdiff_t + +#endif /* _STDDEF_H or __need_ptrdiff_t. */ + +/* Unsigned type of `sizeof' something. */ + +/* Define this type if we are doing the whole job, + or if we want this type in particular. */ +#if defined (_STDDEF_H) || defined (__need_size_t) +#ifndef __size_t__ /* BeOS */ +#ifndef __SIZE_T__ /* Cray Unicos/Mk */ +#ifndef _SIZE_T /* in case has defined it. */ +#ifndef _SYS_SIZE_T_H +#ifndef _T_SIZE_ +#ifndef _T_SIZE +#ifndef __SIZE_T +#ifndef _SIZE_T_ +#ifndef _BSD_SIZE_T_ +#ifndef _SIZE_T_DEFINED_ +#ifndef _SIZE_T_DEFINED +#ifndef _BSD_SIZE_T_DEFINED_ /* Darwin */ +#ifndef _SIZE_T_DECLARED /* FreeBSD 5 */ +#ifndef __DEFINED_size_t /* musl libc */ +#ifndef ___int_size_t_h +#ifndef _GCC_SIZE_T +#ifndef _SIZET_ +#ifndef __size_t +#define __size_t__ /* BeOS */ +#define __SIZE_T__ /* Cray Unicos/Mk */ +#define _SIZE_T +#define _SYS_SIZE_T_H +#define _T_SIZE_ +#define _T_SIZE +#define __SIZE_T +#define _SIZE_T_ +#define _BSD_SIZE_T_ +#define _SIZE_T_DEFINED_ +#define _SIZE_T_DEFINED +#define _BSD_SIZE_T_DEFINED_ /* Darwin */ +#define _SIZE_T_DECLARED /* FreeBSD 5 */ +#define __DEFINED_size_t /* musl libc */ +#define ___int_size_t_h +#define _GCC_SIZE_T +#define _SIZET_ +#if defined (__FreeBSD__) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD_kernel__) \ + || defined(__VMS__) +/* __size_t is a typedef, must not trash it. */ +#else +#define __size_t +#endif +#ifndef __SIZE_TYPE__ +#define __SIZE_TYPE__ long unsigned int +#endif +#if !(defined (__GNUG__) && defined (size_t)) +typedef __SIZE_TYPE__ size_t; +#ifdef __BEOS__ +typedef long ssize_t; +#endif /* __BEOS__ */ +#endif /* !(defined (__GNUG__) && defined (size_t)) */ +#endif /* __size_t */ +#endif /* _SIZET_ */ +#endif /* _GCC_SIZE_T */ +#endif /* ___int_size_t_h */ +#endif /* __DEFINED_size_t */ +#endif /* _SIZE_T_DECLARED */ +#endif /* _BSD_SIZE_T_DEFINED_ */ +#endif /* _SIZE_T_DEFINED */ +#endif /* _SIZE_T_DEFINED_ */ +#endif /* _BSD_SIZE_T_ */ +#endif /* _SIZE_T_ */ +#endif /* __SIZE_T */ +#endif /* _T_SIZE */ +#endif /* _T_SIZE_ */ +#endif /* _SYS_SIZE_T_H */ +#endif /* _SIZE_T */ +#endif /* __SIZE_T__ */ +#endif /* __size_t__ */ +#undef __need_size_t +#endif /* _STDDEF_H or __need_size_t. */ + + +/* Wide character type. + Locale-writers should change this as necessary to + be big enough to hold unique values not between 0 and 127, + and not (wchar_t) -1, for each defined multibyte character. */ + +/* Define this type if we are doing the whole job, + or if we want this type in particular. */ +#if defined (_STDDEF_H) || defined (__need_wchar_t) +#ifndef __wchar_t__ /* BeOS */ +#ifndef __WCHAR_T__ /* Cray Unicos/Mk */ +#ifndef _WCHAR_T +#ifndef _T_WCHAR_ +#ifndef _T_WCHAR +#ifndef __WCHAR_T +#ifndef _WCHAR_T_ +#ifndef _BSD_WCHAR_T_ +#ifndef _BSD_WCHAR_T_DEFINED_ /* Darwin */ +#ifndef _BSD_RUNE_T_DEFINED_ /* Darwin */ +#ifndef _WCHAR_T_DECLARED /* FreeBSD 5 */ +#ifndef __DEFINED_wchar_t /* musl libc */ +#ifndef _WCHAR_T_DEFINED_ +#ifndef _WCHAR_T_DEFINED +#ifndef _WCHAR_T_H +#ifndef ___int_wchar_t_h +#ifndef __INT_WCHAR_T_H +#ifndef _GCC_WCHAR_T +#define __wchar_t__ /* BeOS */ +#define __WCHAR_T__ /* Cray Unicos/Mk */ +#define _WCHAR_T +#define _T_WCHAR_ +#define _T_WCHAR +#define __WCHAR_T +#define _WCHAR_T_ +#define _BSD_WCHAR_T_ +#define _WCHAR_T_DEFINED_ +#define _WCHAR_T_DEFINED +#define _WCHAR_T_H +#define ___int_wchar_t_h +#define __INT_WCHAR_T_H +#define _GCC_WCHAR_T +#define _WCHAR_T_DECLARED +#define __DEFINED_wchar_t + +/* On BSD/386 1.1, at least, machine/ansi.h defines _BSD_WCHAR_T_ + instead of _WCHAR_T_, and _BSD_RUNE_T_ (which, unlike the other + symbols in the _FOO_T_ family, stays defined even after its + corresponding type is defined). If we define wchar_t, then we + must undef _WCHAR_T_; for BSD/386 1.1 (and perhaps others), if + we undef _WCHAR_T_, then we must also define rune_t, since + headers like runetype.h assume that if machine/ansi.h is included, + and _BSD_WCHAR_T_ is not defined, then rune_t is available. + machine/ansi.h says, "Note that _WCHAR_T_ and _RUNE_T_ must be of + the same type." */ +#ifdef _BSD_WCHAR_T_ +#undef _BSD_WCHAR_T_ +#ifdef _BSD_RUNE_T_ +#if !defined (_ANSI_SOURCE) && !defined (_POSIX_SOURCE) +typedef _BSD_RUNE_T_ rune_t; +#define _BSD_WCHAR_T_DEFINED_ +#define _BSD_RUNE_T_DEFINED_ /* Darwin */ +#if defined (__FreeBSD__) && (__FreeBSD__ < 5) +/* Why is this file so hard to maintain properly? In contrast to + the comment above regarding BSD/386 1.1, on FreeBSD for as long + as the symbol has existed, _BSD_RUNE_T_ must not stay defined or + redundant typedefs will occur when stdlib.h is included after this file. */ +#undef _BSD_RUNE_T_ +#endif +#endif +#endif +#endif +/* FreeBSD 5 can't be handled well using "traditional" logic above + since it no longer defines _BSD_RUNE_T_ yet still desires to export + rune_t in some cases... */ +#if defined (__FreeBSD__) && (__FreeBSD__ >= 5) +#if !defined (_ANSI_SOURCE) && !defined (_POSIX_SOURCE) +#if __BSD_VISIBLE +#ifndef _RUNE_T_DECLARED +typedef __rune_t rune_t; +#define _RUNE_T_DECLARED +#endif +#endif +#endif +#endif + +#ifndef __WCHAR_TYPE__ +#define __WCHAR_TYPE__ int +#endif +#ifndef __cplusplus +typedef __WCHAR_TYPE__ wchar_t; +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif /* __DEFINED_wchar_t */ +#endif /* _WCHAR_T_DECLARED */ +#endif /* _BSD_RUNE_T_DEFINED_ */ +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif /* __WCHAR_T__ */ +#endif /* __wchar_t__ */ +#undef __need_wchar_t +#endif /* _STDDEF_H or __need_wchar_t. */ + +#if defined (__need_wint_t) +#ifndef _WINT_T +#define _WINT_T + +#ifndef __WINT_TYPE__ +#define __WINT_TYPE__ unsigned int +#endif +typedef __WINT_TYPE__ wint_t; +#endif +#undef __need_wint_t +#endif + +#if defined(__NetBSD__) +/* The references to _GCC_PTRDIFF_T_, _GCC_SIZE_T_, and _GCC_WCHAR_T_ + are probably typos and should be removed before 2.8 is released. */ +#ifdef _GCC_PTRDIFF_T_ +#undef _PTRDIFF_T_ +#undef _BSD_PTRDIFF_T_ +#endif +#ifdef _GCC_SIZE_T_ +#undef _SIZE_T_ +#undef _BSD_SIZE_T_ +#endif +#ifdef _GCC_WCHAR_T_ +#undef _WCHAR_T_ +#undef _BSD_WCHAR_T_ +#endif +/* The following ones are the real ones. */ +#ifdef _GCC_PTRDIFF_T +#undef _PTRDIFF_T_ +#undef _BSD_PTRDIFF_T_ +#endif +#ifdef _GCC_SIZE_T +#undef _SIZE_T_ +#undef _BSD_SIZE_T_ +#endif +#ifdef _GCC_WCHAR_T +#undef _WCHAR_T_ +#undef _BSD_WCHAR_T_ +#endif +#endif /* __NetBSD__ */ + +#endif /* __sys_stdtypes_h */ + +/* A null pointer constant. */ + +#if defined (_STDDEF_H) || defined (__need_NULL) +#undef NULL /* in case has defined it. */ +#ifdef __GNUG__ +#define NULL __null +#else /* G++ */ +#ifndef __cplusplus +#define NULL ((void *)0) +#else /* C++ */ +#define NULL 0 +#endif /* C++ */ +#endif /* G++ */ +#endif /* NULL not defined and or need NULL. */ +#undef __need_NULL + +#ifdef _STDDEF_H + +/* Offset of member MEMBER in a struct of type TYPE. */ +#undef offsetof /* in case a system header has defined it. */ +#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER) + +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \ + || (defined(__cplusplus) && __cplusplus >= 201103L) +#ifndef _GCC_MAX_ALIGN_T +#define _GCC_MAX_ALIGN_T +/* Type whose alignment is supported in every context and is at least + as great as that of any standard type not using alignment + specifiers. */ +typedef struct { + long long __max_align_ll __attribute__((__aligned__(__alignof__(long long)))); + long double __max_align_ld __attribute__((__aligned__(__alignof__(long double)))); + /* _Float128 is defined as a basic type, so max_align_t must be + sufficiently aligned for it. This code must work in C++, so we + use __float128 here; that is only available on some + architectures, but only on i386 is extra alignment needed for + __float128. */ +#ifdef __i386__ + __float128 __max_align_f128 __attribute__((__aligned__(__alignof(__float128)))); +#endif +} max_align_t; +#endif +#endif /* C11 or C++11. */ + +#if defined(__cplusplus) && __cplusplus >= 201103L +#ifndef _GXX_NULLPTR_T +#define _GXX_NULLPTR_T + typedef decltype(nullptr) nullptr_t; +#endif +#endif /* C++11. */ + +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L) +#ifndef _GCC_NULLPTR_T +#define _GCC_NULLPTR_T + typedef __typeof__(nullptr) nullptr_t; +/* ??? This doesn't define __STDC_VERSION_STDDEF_H__ yet. */ +#endif +#endif /* C23. */ + +#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L +#define unreachable() (__builtin_unreachable ()) +#define __STDC_VERSION_STDDEF_H__ 202311L +#endif + +#endif /* _STDDEF_H was defined this time */ + +#endif /* !_STDDEF_H && !_STDDEF_H_ && !_ANSI_STDDEF_H && !__STDDEF_H__ + || __need_XXX was not defined before */ \ No newline at end of file diff --git a/lab5/include/stdint.h b/lab5/include/stdint.h new file mode 100644 index 000000000..2d666f79f --- /dev/null +++ b/lab5/include/stdint.h @@ -0,0 +1,319 @@ +/* Copyright (C) 1997-2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C 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. + + The GNU C 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 the GNU C Library; if not, see + . */ + +/* + * ISO C99: 7.18 Integer types + */ + +#ifndef _STDINT_H +#define _STDINT_H 1 + +#define __GLIBC_INTERNAL_STARTING_HEADER_IMPLEMENTATION +#include +#include +#include +#include + +/* Exact integral types. */ + +/* Signed. */ +#include + +/* Unsigned. */ +#include + + +/* Small types. */ + +/* Signed. */ +typedef __int_least8_t int_least8_t; +typedef __int_least16_t int_least16_t; +typedef __int_least32_t int_least32_t; +typedef __int_least64_t int_least64_t; + +/* Unsigned. */ +typedef __uint_least8_t uint_least8_t; +typedef __uint_least16_t uint_least16_t; +typedef __uint_least32_t uint_least32_t; +typedef __uint_least64_t uint_least64_t; + + +/* Fast types. */ + +/* Signed. */ +typedef signed char int_fast8_t; +#if __WORDSIZE == 64 +typedef long int int_fast16_t; +typedef long int int_fast32_t; +typedef long int int_fast64_t; +#else +typedef int int_fast16_t; +typedef int int_fast32_t; +__extension__ +typedef long long int int_fast64_t; +#endif + +/* Unsigned. */ +typedef unsigned char uint_fast8_t; +#if __WORDSIZE == 64 +typedef unsigned long int uint_fast16_t; +typedef unsigned long int uint_fast32_t; +typedef unsigned long int uint_fast64_t; +#else +typedef unsigned int uint_fast16_t; +typedef unsigned int uint_fast32_t; +__extension__ +typedef unsigned long long int uint_fast64_t; +#endif + + +/* Types for `void *' pointers. */ +#if __WORDSIZE == 64 +# ifndef __intptr_t_defined +typedef long int intptr_t; +# define __intptr_t_defined +# endif +typedef unsigned long int uintptr_t; +#else +# ifndef __intptr_t_defined +typedef int intptr_t; +# define __intptr_t_defined +# endif +typedef unsigned int uintptr_t; +#endif + + +/* Largest integral types. */ +typedef __intmax_t intmax_t; +typedef __uintmax_t uintmax_t; + + +# if __WORDSIZE == 64 +# define __INT64_C(c) c ## L +# define __UINT64_C(c) c ## UL +# else +# define __INT64_C(c) c ## LL +# define __UINT64_C(c) c ## ULL +# endif + +/* Limits of integral types. */ + +/* Minimum of signed integral types. */ +# define INT8_MIN (-128) +# define INT16_MIN (-32767-1) +# define INT32_MIN (-2147483647-1) +# define INT64_MIN (-__INT64_C(9223372036854775807)-1) +/* Maximum of signed integral types. */ +# define INT8_MAX (127) +# define INT16_MAX (32767) +# define INT32_MAX (2147483647) +# define INT64_MAX (__INT64_C(9223372036854775807)) + +/* Maximum of unsigned integral types. */ +# define UINT8_MAX (255) +# define UINT16_MAX (65535) +# define UINT32_MAX (4294967295U) +# define UINT64_MAX (__UINT64_C(18446744073709551615)) + + +/* Minimum of signed integral types having a minimum size. */ +# define INT_LEAST8_MIN (-128) +# define INT_LEAST16_MIN (-32767-1) +# define INT_LEAST32_MIN (-2147483647-1) +# define INT_LEAST64_MIN (-__INT64_C(9223372036854775807)-1) +/* Maximum of signed integral types having a minimum size. */ +# define INT_LEAST8_MAX (127) +# define INT_LEAST16_MAX (32767) +# define INT_LEAST32_MAX (2147483647) +# define INT_LEAST64_MAX (__INT64_C(9223372036854775807)) + +/* Maximum of unsigned integral types having a minimum size. */ +# define UINT_LEAST8_MAX (255) +# define UINT_LEAST16_MAX (65535) +# define UINT_LEAST32_MAX (4294967295U) +# define UINT_LEAST64_MAX (__UINT64_C(18446744073709551615)) + + +/* Minimum of fast signed integral types having a minimum size. */ +# define INT_FAST8_MIN (-128) +# if __WORDSIZE == 64 +# define INT_FAST16_MIN (-9223372036854775807L-1) +# define INT_FAST32_MIN (-9223372036854775807L-1) +# else +# define INT_FAST16_MIN (-2147483647-1) +# define INT_FAST32_MIN (-2147483647-1) +# endif +# define INT_FAST64_MIN (-__INT64_C(9223372036854775807)-1) +/* Maximum of fast signed integral types having a minimum size. */ +# define INT_FAST8_MAX (127) +# if __WORDSIZE == 64 +# define INT_FAST16_MAX (9223372036854775807L) +# define INT_FAST32_MAX (9223372036854775807L) +# else +# define INT_FAST16_MAX (2147483647) +# define INT_FAST32_MAX (2147483647) +# endif +# define INT_FAST64_MAX (__INT64_C(9223372036854775807)) + +/* Maximum of fast unsigned integral types having a minimum size. */ +# define UINT_FAST8_MAX (255) +# if __WORDSIZE == 64 +# define UINT_FAST16_MAX (18446744073709551615UL) +# define UINT_FAST32_MAX (18446744073709551615UL) +# else +# define UINT_FAST16_MAX (4294967295U) +# define UINT_FAST32_MAX (4294967295U) +# endif +# define UINT_FAST64_MAX (__UINT64_C(18446744073709551615)) + + +/* Values to test for integral types holding `void *' pointer. */ +# if __WORDSIZE == 64 +# define INTPTR_MIN (-9223372036854775807L-1) +# define INTPTR_MAX (9223372036854775807L) +# define UINTPTR_MAX (18446744073709551615UL) +# else +# define INTPTR_MIN (-2147483647-1) +# define INTPTR_MAX (2147483647) +# define UINTPTR_MAX (4294967295U) +# endif + + +/* Minimum for largest signed integral type. */ +# define INTMAX_MIN (-__INT64_C(9223372036854775807)-1) +/* Maximum for largest signed integral type. */ +# define INTMAX_MAX (__INT64_C(9223372036854775807)) + +/* Maximum for largest unsigned integral type. */ +# define UINTMAX_MAX (__UINT64_C(18446744073709551615)) + + +/* Limits of other integer types. */ + +/* Limits of `ptrdiff_t' type. */ +# if __WORDSIZE == 64 +# define PTRDIFF_MIN (-9223372036854775807L-1) +# define PTRDIFF_MAX (9223372036854775807L) +# else +# if __WORDSIZE32_PTRDIFF_LONG +# define PTRDIFF_MIN (-2147483647L-1) +# define PTRDIFF_MAX (2147483647L) +# else +# define PTRDIFF_MIN (-2147483647-1) +# define PTRDIFF_MAX (2147483647) +# endif +# endif + +/* Limits of `sig_atomic_t'. */ +# define SIG_ATOMIC_MIN (-2147483647-1) +# define SIG_ATOMIC_MAX (2147483647) + +/* Limit of `size_t' type. */ +# if __WORDSIZE == 64 +# define SIZE_MAX (18446744073709551615UL) +# else +# if __WORDSIZE32_SIZE_ULONG +# define SIZE_MAX (4294967295UL) +# else +# define SIZE_MAX (4294967295U) +# endif +# endif + +/* Limits of `wchar_t'. */ +# ifndef WCHAR_MIN +/* These constants might also be defined in . */ +# define WCHAR_MIN __WCHAR_MIN +# define WCHAR_MAX __WCHAR_MAX +# endif + +/* Limits of `wint_t'. */ +# define WINT_MIN (0u) +# define WINT_MAX (4294967295u) + +/* Signed. */ +# define INT8_C(c) c +# define INT16_C(c) c +# define INT32_C(c) c +# if __WORDSIZE == 64 +# define INT64_C(c) c ## L +# else +# define INT64_C(c) c ## LL +# endif + +/* Unsigned. */ +# define UINT8_C(c) c +# define UINT16_C(c) c +# define UINT32_C(c) c ## U +# if __WORDSIZE == 64 +# define UINT64_C(c) c ## UL +# else +# define UINT64_C(c) c ## ULL +# endif + +/* Maximal type. */ +# if __WORDSIZE == 64 +# define INTMAX_C(c) c ## L +# define UINTMAX_C(c) c ## UL +# else +# define INTMAX_C(c) c ## LL +# define UINTMAX_C(c) c ## ULL +# endif + +#if __GLIBC_USE (IEC_60559_BFP_EXT_C2X) + +# define INT8_WIDTH 8 +# define UINT8_WIDTH 8 +# define INT16_WIDTH 16 +# define UINT16_WIDTH 16 +# define INT32_WIDTH 32 +# define UINT32_WIDTH 32 +# define INT64_WIDTH 64 +# define UINT64_WIDTH 64 + +# define INT_LEAST8_WIDTH 8 +# define UINT_LEAST8_WIDTH 8 +# define INT_LEAST16_WIDTH 16 +# define UINT_LEAST16_WIDTH 16 +# define INT_LEAST32_WIDTH 32 +# define UINT_LEAST32_WIDTH 32 +# define INT_LEAST64_WIDTH 64 +# define UINT_LEAST64_WIDTH 64 + +# define INT_FAST8_WIDTH 8 +# define UINT_FAST8_WIDTH 8 +# define INT_FAST16_WIDTH __WORDSIZE +# define UINT_FAST16_WIDTH __WORDSIZE +# define INT_FAST32_WIDTH __WORDSIZE +# define UINT_FAST32_WIDTH __WORDSIZE +# define INT_FAST64_WIDTH 64 +# define UINT_FAST64_WIDTH 64 + +# define INTPTR_WIDTH __WORDSIZE +# define UINTPTR_WIDTH __WORDSIZE + +# define INTMAX_WIDTH 64 +# define UINTMAX_WIDTH 64 + +# define PTRDIFF_WIDTH __WORDSIZE +# define SIG_ATOMIC_WIDTH 32 +# define SIZE_WIDTH __WORDSIZE +# define WCHAR_WIDTH 32 +# define WINT_WIDTH 32 + +#endif + +#endif /* stdint.h */ diff --git a/lab5/include/syscall.h b/lab5/include/syscall.h new file mode 100644 index 000000000..f556cf61f --- /dev/null +++ b/lab5/include/syscall.h @@ -0,0 +1,29 @@ +#ifndef __SYSCALL_H +#define __SYSCALL_H + +#include "trap_frame.h" + +#define _STR(x) #x +#define STR(s) _STR(s) + +typedef void (*syscall)(TrapFrame *); + +enum { + SYS_GETPID, //0 + SYS_UART_RECV, + SYS_UART_WRITE, + SYS_EXEC, + SYS_FORK, + SYS_EXIT, //5 + SYS_MBOX, + SYS_KILL_PID, + SYS_SIGNAL, + SYS_SIGKILL, + SYS_SIGRETURN, //10 + NUM_syscalls +}; + +extern syscall syscall_table[]; +void syscall_handler(TrapFrame *regs); + +#endif \ No newline at end of file diff --git a/lab5/include/thread.h b/lab5/include/thread.h new file mode 100644 index 000000000..69dcbe3ff --- /dev/null +++ b/lab5/include/thread.h @@ -0,0 +1,13 @@ +#ifndef _THREAD_H +#define _THREAD_H +#include "list.h" +#include "utils_s.h" +#include "sche.h" +#define STACK_SIZE 0x2000 + +void thread_kill_zombies(); +void thread_schedule(size_t _); +void thread_init(); +struct task *thread_create(void *func); +void test_thread(); +#endif diff --git a/lab5/include/timer.h b/lab5/include/timer.h new file mode 100644 index 000000000..48edf58a6 --- /dev/null +++ b/lab5/include/timer.h @@ -0,0 +1,38 @@ +#ifndef __TIMER_H +#define __TIMER_H +#define CORE0_TIMER_IRQ_CTRL ((volatile unsigned int *)(0x40000040)) +#define CORE0_INTERRUPT_SOURCE ((volatile unsigned int *)(0x40000060)) +#define DEFAULT_TIMEOUT 30LL +#define SCHE_CYCLE 30LL +#define SYSTEM_TIMER_MSG "system_timeout" +#define S(n) (n * 1000LL) +#define MS(n) (n * 1LL) +#define GET_S(n) (n / 1000LL) +#define GET_MS(n) (n % 1000LL) +#include "stddef.h" + +typedef void (*timer_callback)(size_t); + +void core_timer_enable(); +void core_timer_disable(); +void set_expired_time(unsigned long duration); +unsigned long get_current_time(); +void core_timer_handler(); +void set_timeout(char *message, unsigned long time); +void print_message(char *msg); +void add_timer(void (*cb)(size_t), size_t arg, unsigned long duraction); +void timeout_event_init(); +void timer_handler(); + +typedef struct timeout_event +{ + unsigned long register_time; + unsigned long duration; + timer_callback callback; + size_t arg; + struct timeout_event *prev, *next; +} timeout_event; + +extern timeout_event *timeout_queue_head, *timeout_queue_tail; + +#endif diff --git a/lab5/include/trap_frame.h b/lab5/include/trap_frame.h new file mode 100644 index 000000000..593c45d50 --- /dev/null +++ b/lab5/include/trap_frame.h @@ -0,0 +1,12 @@ +#ifndef __TRAP_FRAME_H +#define __TRAP_FRAME_H + +typedef struct +{ + unsigned long regs[31]; // general purpose regs x0~x30 + unsigned long sp; // sp_el0 + unsigned long pc; // elr_el1 + unsigned long pstate; // spsr_el1 +}TrapFrame; + +#endif \ No newline at end of file diff --git a/lab5/include/utils_c.h b/lab5/include/utils_c.h new file mode 100644 index 000000000..b648ec8c9 --- /dev/null +++ b/lab5/include/utils_c.h @@ -0,0 +1,32 @@ +#ifndef _UTILS_C_H +#define _UTILS_C_H + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 +#include +#include + +/* string */ +int utils_str_compare(const char *a, const char *b); +int utils_strncmp(const char *a, const char *b, size_t n); +void utils_newline2end(char *str); +char utils_int2char(int a); +void utils_int2str_dec(int a, char *str); +void utils_uint2str_dec(unsigned int num, char *str); +unsigned int utils_str2uint_dec(const char *str); +void align(void *size, size_t s); // aligned to 4 byte +size_t utils_strlen(const char *s); +uint32_t align_up(uint32_t size, int alignment); + +/* reboot */ +void set(long addr, unsigned int value); +void reset(int tick); +void cancel_reset(); + +/* others */ +void delay(unsigned int clock); +void memcpy(void *dst, const void *src, size_t n); +void *memset(void *s, int c, size_t n); + +#endif diff --git a/lab5/include/utils_s.h b/lab5/include/utils_s.h new file mode 100644 index 000000000..6f5a01825 --- /dev/null +++ b/lab5/include/utils_s.h @@ -0,0 +1,41 @@ +#ifndef __UTILS_S_H +#define __UTILS_S_H + +#define read_sysreg(r) ({ \ + unsigned long __val; \ + asm volatile("mrs %0, " #r \ + : "=r"(__val)); \ + __val; \ +}) + +#define write_sysreg(r, __val) ({ \ + asm volatile("msr " #r ", %0" ::"r"(__val)); \ +}) + +#define read_gpreg(r) ({ \ + unsigned long __val; \ + asm volatile("mov %0, " #r \ + : "=r"(__val)); \ + __val; \ +}) + +#define write_gpreg(r, __val) ({ \ + asm volatile("mov " #r ", %0" ::"r"(__val)); \ +}) + + +// EC,bits[31:26] +#define ESR_ELx_EC(esr) ((esr & 0xFC000000) >> 26) +// ISS,bits[24:0] +#define ESR_ELx_ISS(esr) (esr & 0x03FFFFFF) + +#define ESR_ELx_EC_SVC64 0b010101 +#define ESR_ELx_EC_DABT_LOW 0b100100 +#define ESR_ELx_EC_IABT_LOW 0b100000 + + +void branchAddr(void *addr); +int get_el(); +void switch_to(void *, void *); + +#endif diff --git a/lab5/kernel/exception_c.c b/lab5/kernel/exception_c.c new file mode 100644 index 000000000..a8086d6f5 --- /dev/null +++ b/lab5/kernel/exception_c.c @@ -0,0 +1,94 @@ +#include "utils_s.h" +#include "mini_uart.h" +#include "timer.h" +#include "peripheral/mini_uart.h" +#include "exception_c.h" +#include "current.h" +#include "thread.h" +#include "syscall.h" +#define AUX_IRQ (1 << 29) + +void enable_interrupt() { asm volatile("msr DAIFClr, 0xf"); } +void disable_interrupt() { asm volatile("msr DAIFSet, 0xf"); } +unsigned long disable_irq() +{ + unsigned long flag = read_sysreg(DAIF); + disable_interrupt(); + return flag; +} +void irq_restore(unsigned long flag) +{ + write_sysreg(DAIF, flag); +} + +void default_handler() +{ + unsigned long spsr = read_sysreg(spsr_el1); + unsigned long elr = read_sysreg(elr_el1); + unsigned long esr = read_sysreg(esr_el1); + uart_printf("spsr_el1: %x\n", spsr); + uart_printf("elr_el1: %x\n", elr); + uart_printf("esr_el1: %x\n\n", esr); +} + +void lower_irq_handler() +{ + unsigned long current_time = get_current_time(); + uart_printf("After booting: %d seconds\n\n", current_time); + set_expired_time(2); +} + +void lower_sync_handler(TrapFrame *_regs) +{ + unsigned long esr = read_sysreg(esr_el1); // cause of that exception + unsigned int ec = ESR_ELx_EC(esr); + switch (ec) + { + case ESR_ELx_EC_SVC64: + enable_interrupt(); + syscall_handler(_regs); + disable_interrupt(); + break; + case ESR_ELx_EC_DABT_LOW: + uart_send_string("in Data Abort\n"); + break; + case ESR_ELx_EC_IABT_LOW: + uart_send_string("in Instruction Abort\n"); + break; + default: + return; + } +} + +void irq_handler() +{ + unsigned int irq_is_pending = (*IRQ_PENDING_1 & AUX_IRQ); + unsigned int uart = (*AUX_MU_IIR_REG & 0x1) == 0; + unsigned int core_timer = (*CORE0_INTERRUPT_SOURCE & 0x2); + if (irq_is_pending && uart) + { + uart_handler(); + } + else if (core_timer) + { + timer_handler(); + } +} + +void curr_sync_handler() +{ + uart_send_string("!!! in current sync handler !!!\n"); + return; +} + +void curr_fiq_handler() +{ + uart_send_string("!!! in current fiq handler !!!\n"); + return; +} + +void curr_serr_handler() +{ + uart_send_string("!!! in current serr handler !!!\n"); + return; +} diff --git a/lab5/kernel/exception_c.o b/lab5/kernel/exception_c.o new file mode 100644 index 000000000..bd836a7f4 Binary files /dev/null and b/lab5/kernel/exception_c.o differ diff --git a/lab5/kernel/exception_s.o b/lab5/kernel/exception_s.o new file mode 100644 index 000000000..ae92e084f Binary files /dev/null and b/lab5/kernel/exception_s.o differ diff --git a/lab5/kernel/exception_s.s b/lab5/kernel/exception_s.s new file mode 100644 index 000000000..928f8a663 --- /dev/null +++ b/lab5/kernel/exception_s.s @@ -0,0 +1,213 @@ +// save general registers to stack +.macro save_gp_reg + 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_gp_reg + 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 + + +// save all gp_regs and exc_regs +.macro kernel_entry el + sub sp, sp, 17 * 16 + stp x0, x1, [sp ,16 * 0] + stp x2, x3, [sp ,16 * 1] + stp x4, x5, [sp ,16 * 2] + stp x6, x7, [sp ,16 * 3] + stp x8, x9, [sp ,16 * 4] + stp x10, x11, [sp ,16 * 5] + stp x12, x13, [sp ,16 * 6] + stp x14, x15, [sp ,16 * 7] + stp x16, x17, [sp ,16 * 8] + stp x18, x19, [sp ,16 * 9] + stp x20, x21, [sp ,16 * 10] + stp x22, x23, [sp ,16 * 11] + stp x24, x25, [sp ,16 * 12] + stp x26, x27, [sp ,16 * 13] + stp x28, x29, [sp ,16 * 14] + + .if \el == 0 + mrs x0, sp_el0 + stp x30, x0, [sp, 16 * 15] + .else + str x30, [sp, 16 * 15] + .endif + + mrs x0, elr_el1 + mrs x1, spsr_el1 + stp x0, x1, [sp, 16 * 16] + + mov x0, sp +.endm + + +// load all gp_regs and exc_regs +.macro kernel_exit el + ldp x0, x1, [sp, 16 * 16] + msr elr_el1, x0 + msr spsr_el1, x1 + + .if \el ==0 + ldp x30, x0, [sp, 16 * 15] + msr sp_el0, x0 + .else + ldr x30, [sp, 16 * 15] + .endif + + ldp x28, x29, [sp ,16 * 14] + ldp x26, x27, [sp ,16 * 13] + ldp x24, x25, [sp ,16 * 12] + ldp x22, x23, [sp ,16 * 11] + ldp x20, x21, [sp ,16 * 10] + ldp x18, x19, [sp ,16 * 9] + ldp x16, x17, [sp ,16 * 8] + ldp x14, x15, [sp ,16 * 7] + ldp x12, x13, [sp ,16 * 6] + ldp x10, x11, [sp ,16 * 5] + ldp x8, x9, [sp ,16 * 4] + ldp x6, x7, [sp ,16 * 3] + ldp x4, x5, [sp ,16 * 2] + ldp x2, x3, [sp ,16 * 1] + ldp x0, x1, [sp ,16 * 0] + add sp, sp, 17 * 16 + + eret +.endm + +.global restore_regs_eret +restore_regs_eret: + ldp x0, x1, [sp, 16 * 16] + msr elr_el1, x0 + msr spsr_el1, x1 + + ldp x30, x0, [sp, 16 * 15] + msr sp_el0, x0 + + ldp x28, x29, [sp ,16 * 14] + ldp x26, x27, [sp ,16 * 13] + ldp x24, x25, [sp ,16 * 12] + ldp x22, x23, [sp ,16 * 11] + ldp x20, x21, [sp ,16 * 10] + ldp x18, x19, [sp ,16 * 9] + ldp x16, x17, [sp ,16 * 8] + ldp x14, x15, [sp ,16 * 7] + ldp x12, x13, [sp ,16 * 6] + ldp x10, x11, [sp ,16 * 5] + ldp x8, x9, [sp ,16 * 4] + ldp x6, x7, [sp ,16 * 3] + ldp x4, x5, [sp ,16 * 2] + ldp x2, x3, [sp ,16 * 1] + ldp x0, x1, [sp ,16 * 0] + add sp, sp, 17 * 16 + + eret + + + +.macro exception_entry label + .align 7 + b \label // branch to a handler function. + +.endm + + +.global el1_vector_base + +.align 11 +el1_vector_base: + exception_entry exception_handler + exception_entry exception_handler + exception_entry exception_handler + exception_entry exception_handler + + + exception_entry _el1_curr_el_spx_sync + exception_entry _el1_curr_el_spx_irq + exception_entry _el1_curr_el_spx_fiq + exception_entry _el1_curr_el_spx_serr + + + exception_entry _el1_lower_el_aarch64_sync + exception_entry _el1_lower_el_aarch64_irq + exception_entry exception_handler + exception_entry exception_handler + + + exception_entry exception_handler + exception_entry exception_handler + exception_entry exception_handler + exception_entry exception_handler + + +_el1_lower_el_aarch64_sync: + kernel_entry 0 + bl lower_sync_handler + kernel_exit 0 + +_el1_lower_el_aarch64_irq: + kernel_entry 0 + bl irq_handler + kernel_exit 0 + +_el1_curr_el_spx_sync: + save_gp_reg + bl curr_sync_handler + load_gp_reg + eret + +_el1_curr_el_spx_irq: + kernel_entry 1 + bl irq_handler + kernel_exit 1 + +_el1_curr_el_spx_fiq: + save_gp_reg + bl curr_fiq_handler + load_gp_reg + eret + +_el1_curr_el_spx_serr: + save_gp_reg + bl curr_serr_handler + load_gp_reg + eret + +exception_handler: + save_gp_reg + bl default_handler + load_gp_reg + eret diff --git a/lab5/kernel/linker.ld b/lab5/kernel/linker.ld new file mode 100644 index 000000000..47396ee4d --- /dev/null +++ b/lab5/kernel/linker.ld @@ -0,0 +1,32 @@ +_skernel = 0x80000; +_ekernel = 0x400000; + + +ENTRY(_start) +SECTIONS +{ + . = _skernel; + + _stext = .; + .text : { + *(.text.kernel) + *(.text) + *(.rodata) + } + . = ALIGN(0x1000); + _etext = .; + + _sdata = .; + .data : { *(.data) } + . = ALIGN(0x1000); + _edata = .; + + + _sbss = .; + .bss : { *(.bss*) } + . = ALIGN(0x1000); + _ebss = .; + + . = _ekernel; + +} \ No newline at end of file diff --git a/lab5/kernel/main.c b/lab5/kernel/main.c new file mode 100644 index 000000000..1aedc8ae4 --- /dev/null +++ b/lab5/kernel/main.c @@ -0,0 +1,32 @@ +#include "mini_uart.h" +#include "dtb.h" +#include "exception_c.h" +#include "utils_s.h" +#include "shell.h" +#include "mm.h" +#include "timer.h" +#include "thread.h" +#include "sche.h" +#include "exec.h" + +static void idle(void) +{ + while (1) + { + thread_kill_zombies(); + thread_schedule(0); + } +} + +void kernel_main(void) +{ + uart_send_string("Hello, world!\n"); + mm_init(); + thread_init(); + // thread_create(&shell); + exe_new_prog("syscall.img"); + timeout_event_init(); + add_timer((timer_callback)thread_schedule, (size_t)0, MS(SCHE_CYCLE)); + enable_interrupt(); + idle(); +} \ No newline at end of file diff --git a/lab5/kernel/main.o b/lab5/kernel/main.o new file mode 100644 index 000000000..9ca8a3129 Binary files /dev/null and b/lab5/kernel/main.o differ diff --git a/lab5/kernel/start.o b/lab5/kernel/start.o new file mode 100644 index 000000000..3b475cc18 Binary files /dev/null and b/lab5/kernel/start.o differ diff --git a/lab5/kernel/start.s b/lab5/kernel/start.s new file mode 100644 index 000000000..d14942556 --- /dev/null +++ b/lab5/kernel/start.s @@ -0,0 +1,36 @@ +.section ".text.kernel" +.globl _start + +_start: + ldr x1, =_dtb_ptr + str x0, [x1] + + /* cpu id pass */ + mrs x20, mpidr_el1 + and x20, x20,#0xFF // Check processor id + cbz x20, master // Hang for all non-primary CPU + +hang: + b hang + +master: + bl from_el2_to_el1 + + /* setup interrupt vector base */ + ldr x0, =el1_vector_base + msr vbar_el1, x0 + + adr x20, _sbss + adr x21, _ebss + sub x21, x21, x20 + bl memzero + + mov sp, #0x400000 + bl kernel_main + +hang2: + b hang2 + +.global _dtb_ptr +.section .data +_dtb_ptr: .dc.a 0x0 diff --git a/lab5/loadImg/loadImg.py b/lab5/loadImg/loadImg.py new file mode 100644 index 000000000..6fb3542ce --- /dev/null +++ b/lab5/loadImg/loadImg.py @@ -0,0 +1,30 @@ +#! /usr/bin/python3 + +import os +from socket import timeout +import time +import sys +import serial +from time import sleep + +BAUD_RATE = 115200 + +def send_img(ser,kernel): + print("Please sent the kernel image size:") + kernel_size=os.stat(kernel).st_size + ser.write((str(kernel_size)+"\n").encode()) + print(ser.read_until(b"Start to load the kernel image... \r\n").decode(), end="") + + with open(kernel, "rb") as image: + while kernel_size > 0: + kernel_size -= ser.write(image.read(1)) + ser.read_until(b".") + print(ser.read_until(b"$ ").decode(), end="") + return + +if __name__ == "__main__": + ser = serial.Serial("/dev/ttyUSB0", BAUD_RATE, timeout=5) + send_img(ser,"../build/kernel8.img") + + + diff --git a/lab5/loadImg/loadImg.sh b/lab5/loadImg/loadImg.sh new file mode 100644 index 000000000..171507561 --- /dev/null +++ b/lab5/loadImg/loadImg.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +sudo chmod 666 /dev/ttyUSB0 +source ../.env/bin/activate +python3 ./loadImg.py \ No newline at end of file diff --git a/lab5/rd.o b/lab5/rd.o new file mode 100644 index 000000000..2845a800f Binary files /dev/null and b/lab5/rd.o differ diff --git a/lab5/requirements.txt b/lab5/requirements.txt new file mode 100644 index 000000000..4d1aaa2b8 --- /dev/null +++ b/lab5/requirements.txt @@ -0,0 +1 @@ +pyserial==3.5 \ No newline at end of file diff --git a/lab5/src/_cpio.c b/lab5/src/_cpio.c new file mode 100644 index 000000000..bb0b05af7 --- /dev/null +++ b/lab5/src/_cpio.c @@ -0,0 +1,119 @@ +#include "_cpio.h" +#include "utils_c.h" +#include "dtb.h" +#include "mini_uart.h" +#include "timer.h" +#include "mm.h" + +#define KSTACK_SIZE 0x2000 +#define USTACK_SIZE 0x2000 + +unsigned int hex2dec(char *s) +{ + unsigned int r = 0; + for (int i = 0; i < 8; ++i) + { + if (s[i] >= '0' && s[i] <= '9') + { + r = r * 16 + s[i] - '0'; + } + else + { + r = r * 16 + s[i] - 'A' + 10; + } + } + return r; +} + +char *findFile(const char *name) +{ + char *addr = initramfs_start; + while (utils_str_compare((char *)(addr + sizeof(cpio_header)), "TRAILER!!!") != 0) + { + if ((utils_str_compare((char *)(addr + sizeof(cpio_header)), name) == 0)) + { + return addr; + } + cpio_header *header = (cpio_header *)addr; + unsigned int pathname_size = hex2dec(header->c_namesize); + unsigned int file_size = hex2dec(header->c_filesize); + unsigned int headerPathname_size = sizeof(cpio_header) + pathname_size; + + align(&headerPathname_size, 4); + align(&file_size, 4); + addr += (headerPathname_size + file_size); + } + return 0; +} +void cpio_ls() +{ + char *addr = initramfs_start; + while (utils_str_compare((char *)(addr + sizeof(cpio_header)), "TRAILER!!!") != 0) + { + cpio_header *header = (cpio_header *)addr; + unsigned int pathname_size = hex2dec(header->c_namesize); + unsigned int file_size = hex2dec(header->c_filesize); + unsigned int headerPathname_size = sizeof(cpio_header) + pathname_size; + + align(&headerPathname_size, 4); + align(&file_size, 4); + + uart_send_string(addr + sizeof(cpio_header)); // print the file name + uart_send_string("\n"); + + addr += (headerPathname_size + file_size); + } +} + +void cpio_cat(const char *filename) +{ + char *target = findFile(filename); + if (target) + { + cpio_header *header = (cpio_header *)target; + unsigned int pathname_size = hex2dec(header->c_namesize); + unsigned int file_size = hex2dec(header->c_filesize); + unsigned int headerPathname_size = sizeof(cpio_header) + pathname_size; + + align(&headerPathname_size, 4); + align(&file_size, 4); + + char *file_content = target + headerPathname_size; + for (unsigned int i = 0; i < file_size; i++) + { + uart_send(file_content[i]); // print the file content + } + uart_send_string("\n"); + } + else + { + uart_send_string("Not found the file\n"); + } +} + +size_t cpio_load_program(const char *filename, void **target_addr) +{ + char *prog_addr = findFile(filename); + if (prog_addr) + { + cpio_header *header = (cpio_header *)prog_addr; + unsigned int pathname_size = hex2dec(header->c_namesize); + unsigned int file_size = hex2dec(header->c_filesize); + unsigned int headerPathname_size = sizeof(cpio_header) + pathname_size; + + align(&headerPathname_size, 4); + align(&file_size, 4); + + uart_printf("load the %s\n",prog_addr + sizeof(cpio_header)); + + char *file_content = prog_addr + headerPathname_size; + *target_addr = kcalloc(file_size); + memcpy(*target_addr, file_content, file_size); + return file_size; + } + else + { + uart_send_string("Not found the program\n"); + return -1; + } +} diff --git a/lab5/src/_cpio.o b/lab5/src/_cpio.o new file mode 100644 index 000000000..fcf10e186 Binary files /dev/null and b/lab5/src/_cpio.o differ diff --git a/lab5/src/dtb.c b/lab5/src/dtb.c new file mode 100644 index 000000000..74eb92d36 --- /dev/null +++ b/lab5/src/dtb.c @@ -0,0 +1,146 @@ +#include "dtb.h" +#include "_cpio.h" +#include "mini_uart.h" +#include "utils_c.h" +/* + It consists of + a small header + + the memory reservation block + space(aligned) + + the structure block + space(aligned) + + the strings block + space(aligned) +*/ +int space = 0; +char *initramfs_start, *initramfs_end; + +uint32_t get_le2be_uint(const void *p) +{ + // transfer little endian to big endian + const unsigned char *bytes = p; + uint32_t res = bytes[3]; + res |= bytes[2] << 8; + res |= bytes[1] << 16; + res |= bytes[0] << 24; + return res; +} + +void send_sapce(int n) +{ + while (n--) + uart_send_string(" "); +} + +int parse_struct(fdt_callback cb, uintptr_t cur_ptr, uintptr_t strings_ptr, uint32_t totalsize) +{ + uintptr_t end_ptr = cur_ptr + totalsize; + + while (cur_ptr < end_ptr) + { + uint32_t token = get_le2be_uint((char *)cur_ptr); + cur_ptr += 4; + switch (token) + { + case FDT_BEGIN_NODE: + // uart_send_string("In FDT_BEGIN_NODE\n"); + cb(token, (char *)cur_ptr, NULL, 0); + cur_ptr += align_up(utils_strlen((char *)cur_ptr), 4); + break; + case FDT_END_NODE: + // uart_send_string("In FDT_END_NODE\n"); + cb(token, NULL, NULL, 0); + break; + case FDT_PROP: + { + // uart_send_string("In FDT_PROP\n"); + uint32_t len = get_le2be_uint((char *)cur_ptr); + cur_ptr += 4; + uint32_t nameoff = get_le2be_uint((char *)cur_ptr); + cur_ptr += 4; + cb(token, (char *)(strings_ptr + nameoff), (void *)cur_ptr, len); + cur_ptr += align_up(len, 4); + ; + break; + } + case FDT_NOP: + // uart_send_string("In FDT_NOP\n"); + cb(token, NULL, NULL, 0); + break; + case FDT_END: + // uart_send_string("In FDT_END\n"); + cb(token, NULL, NULL, 0); + return 0; + default:; + return -1; + } + } + return 0; +} + +void print_dtb(int type, const char *name, const void *data, uint32_t size) +{ + switch (type) + { + case FDT_BEGIN_NODE: + uart_send_string("\n"); + send_sapce(space); + uart_send_string(name); + uart_send_string("{\n "); + space++; + break; + + case FDT_END_NODE: + uart_send_string("\n"); + space--; + if (space > 0) + send_sapce(space); + + uart_send_string("}\n"); + break; + + case FDT_NOP: + break; + + case FDT_PROP: + send_sapce(space); + uart_send_string(name); + break; + + case FDT_END: + break; + } +} + +void get_initramfs_addr(int type, const char *name, const void *data, uint32_t size) +{ + if (type == FDT_PROP && !utils_str_compare(name, "linux,initrd-start")) + { + initramfs_start = (char *)(uintptr_t)get_le2be_uint(data); + } + else if (type == FDT_PROP && !utils_str_compare(name, "linux,initrd-end")) + { + initramfs_end = (char *)(uintptr_t)get_le2be_uint(data); + } +} + +uintptr_t dtb_end,dtb_start; + +int fdt_traverse(fdt_callback cb, void *_dtb) +{ + dtb_start = (uintptr_t)_dtb; + // uart_send_string("\ndtb loading at:"); + // uart_hex(dtb_start); + // uart_send('\n'); + fdt_header *header = (fdt_header *)dtb_start; + + if (get_le2be_uint(&(header->magic)) != 0xd00dfeed) + { + uart_printf("header magic ==%x != 0xd00dfeed\n",get_le2be_uint(&(header->magic))); + return -1; + } + uint32_t totalsize = get_le2be_uint(&(header->totalsize)); + uintptr_t struct_ptr = dtb_start + get_le2be_uint(&(header->off_dt_struct)); + uintptr_t strings_ptr = dtb_start + get_le2be_uint(&(header->off_dt_strings)); + parse_struct(cb, struct_ptr, strings_ptr, totalsize); + + dtb_end = dtb_start + get_le2be_uint(&(header->totalsize)); + return 0; +} diff --git a/lab5/src/dtb.o b/lab5/src/dtb.o new file mode 100644 index 000000000..e2978fb21 Binary files /dev/null and b/lab5/src/dtb.o differ diff --git a/lab5/src/exec.c b/lab5/src/exec.c new file mode 100644 index 000000000..6fbef01bf --- /dev/null +++ b/lab5/src/exec.c @@ -0,0 +1,75 @@ +#include "exec.h" +#include "_cpio.h" +#include "sche.h" +#include "mm.h" +#include "trap_frame.h" +#include "utils_c.h" +#include "current.h" +#include "thread.h" +#include "mini_uart.h" + +static void replace_user_context(void *prog, size_t data_size) +{ + struct task *_task = current; + + memset(_task->user_stack, 0, STACK_SIZE); + kfree(_task->user_prog); + _task->user_prog = prog; + _task->user_prog_size = data_size; + + TrapFrame *trapframe = (TrapFrame *)((char *)_task->kernel_stack + STACK_SIZE - sizeof(TrapFrame)); + memset(trapframe, 0, sizeof(TrapFrame)); + + trapframe->sp = (unsigned long)_task->user_stack + STACK_SIZE - 0x10; +} + +void jump_user_prog(void *target_addr, char *kernel_sp, char *user_sp) +{ + asm volatile("mov x0, 0 \n"); + asm volatile("msr spsr_el1, x0 \n"); // daif=0 + asm volatile("msr elr_el1, %0 \n" ::"r"(target_addr)); + asm volatile("msr sp_el0, %0 \n" ::"r"(user_sp)); + if (kernel_sp) + { + asm volatile("mov sp, %0 \n" ::"r"(kernel_sp)); + } + asm volatile("eret \n"); +} + +static void init_user_prog() +{ + jump_user_prog(current->user_prog, 0, (char *)current->user_stack + STACK_SIZE - 0x10); +} + +int do_exec(const char *path, const char *argv[]) +{ + void *target_addr; + size_t data_size = cpio_load_program(path, &target_addr); + if (data_size == -1) + { + uart_send_string("!! do_exec fail !!\n"); + return -1; + } + + replace_user_context(target_addr, data_size); + jump_user_prog(current->user_prog, current->kernel_stack + STACK_SIZE - sizeof(TrapFrame), current->user_stack + STACK_SIZE - 0x10); + return 0; +} + +void exe_new_prog(char *filename) +{ + void *target_addr; + size_t data_size = cpio_load_program(filename, &target_addr); + if (data_size == -1) + { + uart_send_string("!! exe_new_prog fail !!\n"); + return; + } + struct task *prog = thread_create(init_user_prog); + prog->user_stack = kmalloc(STACK_SIZE); + memset(prog->user_stack, 0, STACK_SIZE); + + prog->user_prog = target_addr; + prog->user_prog_size = data_size; + return; +} diff --git a/lab5/src/exec.o b/lab5/src/exec.o new file mode 100644 index 000000000..3c78725f3 Binary files /dev/null and b/lab5/src/exec.o differ diff --git a/lab5/src/fork.c b/lab5/src/fork.c new file mode 100644 index 000000000..666208ba2 --- /dev/null +++ b/lab5/src/fork.c @@ -0,0 +1,47 @@ +#include "fork.h" +#include "stddef.h" +#include "sche.h" +#include "thread.h" +#include "exception_c.h" +#include "exception_s.h" +#include "utils_c.h" +#include "current.h" +#include "mm.h" + +static struct task *fork_context(TrapFrame *_regs) +{ + struct task *child = kmalloc(sizeof(struct task)); + + unsigned long flags = disable_irq(); + *child = *current; // copy the current to child entirely + child->pid = task_count++; + irq_restore(flags); + + child->need_resched = 0; + + child->user_stack = kmalloc(STACK_SIZE); + memcpy(child->user_stack, current->user_stack, STACK_SIZE); + + child->kernel_stack = kmalloc(STACK_SIZE); + TrapFrame *trapframe = (TrapFrame *)((unsigned long)child->kernel_stack + STACK_SIZE - sizeof(TrapFrame)); + memcpy(trapframe, _regs, sizeof(TrapFrame)); + + child->user_prog = kmalloc(current->user_prog_size); + memcpy(child->user_prog, current->user_prog, current->user_prog_size); + + trapframe->regs[30] = (unsigned long)child->user_prog + (_regs->regs[30] - (unsigned long)current->user_prog); // using x30 as link return register while function call on AArch64 + trapframe->sp = (unsigned long)child->user_stack + (_regs->sp - (unsigned long)current->user_stack); + trapframe->pc = (unsigned long)child->user_prog + (_regs->pc - (unsigned long)current->user_prog); + trapframe->regs[0] = 0; // child process : return 0 + + child->cpu_context.sp = (unsigned long)trapframe; + child->cpu_context.lr = (unsigned long)restore_regs_eret; + return child; +} + +size_t do_fork(TrapFrame *_regs) +{ + struct task *child = fork_context(_regs); + add_task(child); + return child->pid; +} diff --git a/lab5/src/fork.o b/lab5/src/fork.o new file mode 100644 index 000000000..de3a36aee Binary files /dev/null and b/lab5/src/fork.o differ diff --git a/lab5/src/list.c b/lab5/src/list.c new file mode 100644 index 000000000..9d3ab1fe3 --- /dev/null +++ b/lab5/src/list.c @@ -0,0 +1,47 @@ +#include "list.h" + +void list_init(list *node) { + node->next = node; + node->prev = node; +} + +void insert_head(list *head, list *v) { + v->next = head->next; + v->prev = head; + head->next->prev = v; + head->next = v; +} + +void insert_tail(list *head, list *v) { + v->next = head; + v->prev = head->prev; + head->prev->next = v; + head->prev = v; +} + +list *remove_head(list *head) { + list *ptr; + ptr = head->next; + head->next = head->next->next; + head->next->prev = head; + + return ptr; +} + +list *remove_tail(list *head) { + list *ptr; + ptr = head->prev; + head->prev = head->prev->prev; + head->prev->next = head; + + return ptr; +} + +void unlink(list *node) { + list *next, *prev; + next = node->next; + prev = node->prev; + + next->prev = prev; + prev->next = next; +} \ No newline at end of file diff --git a/lab5/src/list.o b/lab5/src/list.o new file mode 100644 index 000000000..9b4f46bd7 Binary files /dev/null and b/lab5/src/list.o differ diff --git a/lab5/src/mailbox.c b/lab5/src/mailbox.c new file mode 100644 index 000000000..83bbd7e5c --- /dev/null +++ b/lab5/src/mailbox.c @@ -0,0 +1,65 @@ +#include "peripheral/mailbox.h" +#include "utils_c.h" +#include "mini_uart.h" + +unsigned int __attribute__((aligned(16))) mailbox[8]; + +unsigned int mailbox_call(unsigned char channel, unsigned int *_mailbox) +{ + unsigned int readChannel = (((unsigned int)((unsigned long)_mailbox) & ~0xF) | (channel & 0xF)); + while (*MAILBOX_STATUS & MAILBOX_FULL) + { + } + *MAILBOX_WRITE = readChannel; + while (1) + { + while (*MAILBOX_STATUS & MAILBOX_EMPTY) + { + } + if (readChannel == *MAILBOX_READ) + { + return _mailbox[1] == MAILBOX_RESPONSE; + } + } + return 0; +} + +unsigned int get_board_revision() +{ + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = END_TAG; + mailbox_call(MAILBOX_CH_PROP, mailbox); // message passing procedure call, you should implement it following the 6 steps provided above. + // printf("0x%x\n", mailbox[5]); // it should be 0xa020d3 for rpi3 b+ + uart_hex(mailbox[5]); + uart_send_string("\n"); + return mailbox[5]; +} + + +void get_arm_memory() +{ + mailbox[0] = 8 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = ARM_MEMORY; // tag identifier + mailbox[3] = 8; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + mailbox[6] = 0; // value buffer + // tags end + mailbox[7] = END_TAG; + mailbox_call(MAILBOX_CH_PROP, mailbox); // message passing procedure call, you should implement it following the 6 steps provided above. + uart_send_string("Arm base address: "); + uart_hex(mailbox[5]); + uart_send_string("\n"); + uart_send_string("Arm memory size: "); + uart_hex(mailbox[6]); + uart_send_string("\n"); +} diff --git a/lab5/src/mailbox.o b/lab5/src/mailbox.o new file mode 100644 index 000000000..75eb9d551 Binary files /dev/null and b/lab5/src/mailbox.o differ diff --git a/lab5/src/memzero.o b/lab5/src/memzero.o new file mode 100644 index 000000000..701048ad2 Binary files /dev/null and b/lab5/src/memzero.o differ diff --git a/lab5/src/memzero.s b/lab5/src/memzero.s new file mode 100644 index 000000000..c3720caf7 --- /dev/null +++ b/lab5/src/memzero.s @@ -0,0 +1,7 @@ +.globl memzero +memzero: + str xzr, [x20], #8 + subs x21, x21, #8 + b.gt memzero + ret + \ No newline at end of file diff --git a/lab5/src/mini_uart.c b/lab5/src/mini_uart.c new file mode 100644 index 000000000..0d0d73605 --- /dev/null +++ b/lab5/src/mini_uart.c @@ -0,0 +1,258 @@ +#include "peripheral/mini_uart.h" +#include "peripheral/gpio.h" +#include "sprintf.h" +#include "utils_c.h" +#include +#include +#include "mini_uart.h" + +#define ENABLE_RECEIVE_INTERRUPTS_BIT (1 << 0) +#define ENABLE_TRANSMIT_INTERRUPTS_BIT (1 << 1) +#define AUX_INT_BIT (1 << 29) + +#define BUFFER_MAX_SIZE 256u + +char read_buf[BUFFER_MAX_SIZE]; +char write_buf[BUFFER_MAX_SIZE]; +int read_buf_start, read_buf_end; +int write_buf_start, write_buf_end; + + +void enable_uart_interrupt() { *ENB_IRQS1 = AUX_IRQ; } + +void disable_uart_interrupt() { *DISABLE_IRQS1 = AUX_IRQ; } + +void set_transmit_interrupt() { *AUX_MU_IER_REG |= 0x2; } + +void clear_transmit_interrupt() { *AUX_MU_IER_REG &= ~(0x2); } + +void uart_init() +{ + unsigned int selector; + + selector = *GPFSEL1; + selector &= ~(7u << 12); // clean gpio14 + selector |= 2u << 12; // set alt5 for gpio14 + selector &= ~(7u << 15); // clean gpio15 + selector |= 2u << 15; // set alt5 for gpio 15 + *GPFSEL1 = selector; + + *GPPUD = 0; // set the required control signal (i.e. Pull-up or Pull-Down ) + delay(150u); // provides the required set-up time for the control signal + *GPPUDCLK0 = (1u << 14) | (1u << 15); + delay(150u); + *GPPUDCLK0 = 0u; + *AUX_ENABLE = 1u; // Enable mini uart (this also enables access to its registers) + *AUX_MU_CNTL_REG = 0u; // Disable auto flow control and disable receiver and transmitter (for now) + *AUX_MU_IER_REG = 1u; // Enable receive + *AUX_MU_LCR_REG = 3u; // Enable 8 bit mode + *AUX_MU_MCR_REG = 0u; // Set RTS line to be always high + *AUX_MU_BAUD_REG = 270u; // Set baud rate to 115200 + *AUX_MU_IIR_REG = 6; + + *AUX_MU_CNTL_REG = 3; // Finally, enable transmitter and receiver + + read_buf_start = read_buf_end = 0; + write_buf_start = write_buf_end = 0; + // enable_uart_interrupt(); +} + +void uart_send(const char c) +{ + /* + bit_5 == 1 -> writable + 0x20 = 0000 0000 0010 0000 + ref BCM2837-ARM-Peripherals p5 + */ + if (c == '\n') + { + uart_send('\r'); + } + while (!(*(AUX_MU_LSR_REG)&0x20)) + { + } + *AUX_MU_IO_REG = c; +} +char uart_recv() +{ + /* + bit_0 == 1 -> readable + 0x01 = 0000 0000 0000 0001 + ref BCM2837-ARM-Peripherals p5 + */ + while (!(*(AUX_MU_LSR_REG)&0x01)) + { + } + char temp = *(AUX_MU_IO_REG)&0xFF; + return temp == '\r' ? '\n' : temp; +} + +char uart_recv_raw() +{ + /* + bit_0 == 1 -> readable + 0x01 = 0000 0000 0000 0001 + ref BCM2837-ARM-Peripherals p5 + */ + while (!(*(AUX_MU_LSR_REG)&0x01)) + { + } + char temp = *(AUX_MU_IO_REG)&0xFF; + return temp; +} + +void uart_send_string(const char *str) +{ + while (*str) + { + uart_send(*str++); + } +} + +void uart_send_uint(unsigned int num, int newline) +{ + char str[256]; + utils_uint2str_dec(num, str); + uart_send_string(str); + if (newline) + { + uart_send_string("\n"); + } +} + +void uart_hex(unsigned int d) +{ + unsigned int n; + int c; + uart_send_string("0x"); + for (c = 28; c >= 0; c -= 4) + { + n = (d >> c) & 0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n += n > 9 ? 0x57 : 0x30; + uart_send(n); + } +} +void uart_dec(unsigned int num) +{ + if (num == 0) + uart_send('0'); + else + { + if (num >= 10) + uart_dec(num / 10); + uart_send(num % 10 + '0'); + } +} + +unsigned int uart_printf(char *fmt, ...) +{ + char dst[100]; + // __builtin_va_start(args, fmt): "..." is pointed by args + // __builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + unsigned int ret = vsprintf(dst, fmt, args); + uart_send_string(dst); + return ret; +} + +/* + async part +*/ + +void uart_handler() +{ + disable_uart_interrupt(); + int RX = (*AUX_MU_IIR_REG & 0x4); + int TX = (*AUX_MU_IIR_REG & 0x2); + if (RX) + { + char c = (char)(*AUX_MU_IO_REG); + read_buf[read_buf_end++] = c; + if (read_buf_end == BUFFER_MAX_SIZE) + read_buf_end = 0; + } + else if (TX) + { + while (*AUX_MU_LSR_REG & 0x20) + { + if (write_buf_start == write_buf_end) + { + clear_transmit_interrupt(); + break; + } + char c = write_buf[write_buf_start++]; + *AUX_MU_IO_REG = c; + if (write_buf_start == BUFFER_MAX_SIZE) + write_buf_start = 0; + } + } + enable_uart_interrupt(); +} + +char uart_async_recv() +{ + // wait until there are new data + while (read_buf_start == read_buf_end) + { + asm volatile("nop"); + } + char c = read_buf[read_buf_start++]; + if (read_buf_start == BUFFER_MAX_SIZE) + read_buf_start = 0; + return c == '\r' ? '\n' : c; +} + +void uart_async_send_string(char *str) +{ + + for (int i = 0; str[i]; i++) + { + if (str[i] == '\n') + { + write_buf[write_buf_end++] = '\r'; + write_buf[write_buf_end++] = '\n'; + continue; + } + write_buf[write_buf_end++] = str[i]; + if (write_buf_end == BUFFER_MAX_SIZE) + write_buf_end = 0; + } + set_transmit_interrupt(); +} + +void uart_async_send(char c) +{ + if (c == '\n') + { + write_buf[write_buf_end++] = '\r'; + write_buf[write_buf_end++] = '\n'; + set_transmit_interrupt(); + return; + } + write_buf[write_buf_end++] = c; + if (write_buf_end == BUFFER_MAX_SIZE) + write_buf_end = 0; + set_transmit_interrupt(); +} + +void test_uart_async() +{ + enable_uart_interrupt(); + delay(15000); + char buffer[BUFFER_MAX_SIZE]; + size_t index = 0; + while (1) + { + buffer[index] = uart_async_recv(); + if (buffer[index] == '\n') + { + break; + } + index++; + } + buffer[index + 1] = '\0'; + uart_async_send_string(buffer); + disable_uart_interrupt(); +} diff --git a/lab5/src/mini_uart.o b/lab5/src/mini_uart.o new file mode 100644 index 000000000..f4471833b Binary files /dev/null and b/lab5/src/mini_uart.o differ diff --git a/lab5/src/mm.c b/lab5/src/mm.c new file mode 100644 index 000000000..892aba206 --- /dev/null +++ b/lab5/src/mm.c @@ -0,0 +1,450 @@ +#include "mm.h" +#include "mini_uart.h" +#include "list.h" +#include "utils_c.h" +#include "_cpio.h" +#include "dtb.h" +#include "exception_c.h" + +// #define DEBUG + +#define FRAME_BASE ((uintptr_t)0x0) +// get from mailbox's arm memory +#define FRAME_END ((uintptr_t)0x3b400000) + +#define PAGE_SIZE 0x1000 // 4KB +#define FRAME_BINS_SIZE 12 +#define MAX_ORDER (FRAME_BINS_SIZE - 1) +#define FRAME_MAX_SIZE ORDER2SIZE(MAX_ORDER) +#define ORDER2SIZE(order) (PAGE_SIZE * (1 << (order))) + +#define FRAME_ARRAY_SIZE ((FRAME_END - FRAME_BASE) / PAGE_SIZE) + +#define CHUNK_MIN_SIZE 32 +#define CHUNK_BINS 7 +#define CHUNK_MAX_ORDER (CHUNK_BINS - 1) + +#define FRAME_FREE 0x8 +#define FRAME_INUSE 0x4 +#define FRAME_MEM_CHUNK 0x2 +#define IS_INUSE(frame) (frame.flag & FRAME_INUSE) +#define IS_MEM_CHUNK(frame) (frame.flag & FRAME_MEM_CHUNK) + +// for mm_int +extern char _skernel, _ekernel; +extern void *_dtb_ptr; + +FrameFlag *frames; +list frame_bins[FRAME_BINS_SIZE]; +Chunk *chunk_bins[CHUNK_BINS]; + +unsigned long *smalloc_cur = (unsigned long *)STARTUP_MEM_START; + +//////////////////////////////////////////////////////////////////////////////////////////////// +// utils // +//////////////////////////////////////////////////////////////////////////////////////////////// +static unsigned align_up_exp(unsigned n) +{ + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n++; + return n; +} +static int addr2idx(void *addr) +{ + return (((uintptr_t)addr & -PAGE_SIZE) - FRAME_BASE) / PAGE_SIZE; +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// startUp // +//////////////////////////////////////////////////////////////////////////////////////////////// + +void *smalloc(size_t size) +{ + align(&size, 4); // allocated the memory size is mutiple of 4 byte; + unsigned long *smalloc_ret = smalloc_cur; + if ((uint64_t)smalloc_cur + size > (uint64_t)STARTUP_MEM_END) + { + uart_printf("[!] No enough space!\r\n"); + return NULL; + } + smalloc_cur += (unsigned int)size; + // uart_printf("return addr at %x\n",smalloc_ret); + return smalloc_ret; +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// others // +//////////////////////////////////////////////////////////////////////////////////////////////// + +void mm_init() +{ + init_buddy(); + memory_reserve((uintptr_t)0, (uintptr_t)0x1000); // Spin tables for multicore boot + + memory_reserve((uintptr_t)&_skernel, (uintptr_t)&_ekernel); // Kernel image in the physical memory + + fdt_traverse(get_initramfs_addr, _dtb_ptr); + memory_reserve((uintptr_t)initramfs_start, (uintptr_t)initramfs_end); // Kernel image in the physical memory + + memory_reserve((uintptr_t)STARTUP_MEM_START, (uintptr_t)STARTUP_MEM_END); // simple simple_allocator + + memory_reserve(dtb_start, dtb_end); // Devicetree + + merge_useful_pages(); +} + +void memory_reserve(uintptr_t start, uintptr_t end) +{ + + start = start & ~(PAGE_SIZE - 1); + end = align_up(end, PAGE_SIZE); + for (uintptr_t i = start; i < end; i += PAGE_SIZE) + { + int idx = addr2idx((void *)i); + frames[idx].flag |= FRAME_INUSE; + frames[idx].order = 0; + } +#ifdef DEBUG + uart_printf("reserve addr from %x ~ %x\n", (unsigned long)start, (unsigned long)end); +#endif +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// buddy system // +//////////////////////////////////////////////////////////////////////////////////////////////// + +static int pages_to_frame_order(unsigned pages) +{ + pages = align_up_exp(pages); + return __builtin_ctz(pages); +} + +void init_buddy() +{ + frames = (FrameFlag *)smalloc(sizeof(FrameFlag) * FRAME_ARRAY_SIZE); + for (int i = 0; i < FRAME_BINS_SIZE; i++) + { + list_init(&frame_bins[i]); + } + for (int i = 0; i < FRAME_ARRAY_SIZE; i++) + { + frames[i].flag = 0; + frames[i].order = 0; + } +} + +void merge_useful_pages() +{ + for (int order = 0; order < MAX_ORDER; order++) + { + int page_idx = 0; + void *page_addr = 0; + int buddy_page_idx = 0; + while (1) + { + buddy_page_idx = page_idx ^ (1 << order); + if (!IS_INUSE(frames[page_idx])) + { + if (!IS_INUSE(frames[buddy_page_idx]) && + order == frames[buddy_page_idx].order && + buddy_page_idx < FRAME_ARRAY_SIZE) + { + insert_tail(&frame_bins[order + 1], page_addr); + frames[page_idx].order = order + 1; + } + else + { + insert_tail(&frame_bins[order], page_addr); + frames[page_idx].order = order; + } + } + else + { + if (buddy_page_idx < FRAME_ARRAY_SIZE && + !IS_INUSE(frames[buddy_page_idx])) + { + insert_tail(&frame_bins[order], (list *)(FRAME_BASE + buddy_page_idx * PAGE_SIZE)); + frames[buddy_page_idx].order = order; + } + } + + page_idx += (1 << (order + 1)); + if (page_idx >= FRAME_ARRAY_SIZE) + { + break; + } + page_addr = (void *)(FRAME_BASE + page_idx * PAGE_SIZE); + } + } +} + +static void *split_frames(int order, int target_order) +{ + list *ptr = remove_head(&frame_bins[order]); + +#ifdef DEBUG + uart_printf("split frame: %x\n", (unsigned long)ptr); +#endif + + for (int i = order; i > target_order; i--) + { /* insert splitted frame to bin list */ + list *half_right = (list *)((char *)ptr + ORDER2SIZE(i - 1)); + + insert_head(&frame_bins[i - 1], half_right); + frames[((uintptr_t)half_right - FRAME_BASE) / PAGE_SIZE].order = i - 1; + +#ifdef DEBUG + uart_printf("insert frame at %x\n", (unsigned long)half_right); +#endif + } + int idx = addr2idx(ptr); + frames[idx].order = target_order; + frames[idx].flag |= FRAME_INUSE; + return ptr; +} + +void *alloc_pages(unsigned int pages) +{ + int target_order = pages_to_frame_order(pages); + if (frame_bins[target_order].next != &frame_bins[target_order]) + { + list *ptr = remove_head(&frame_bins[target_order]); +#ifdef DEBUG + uart_printf("return page at: %x\n", (unsigned long)ptr); +#endif + int idx = addr2idx(ptr); + frames[idx].order = target_order; + frames[idx].flag |= FRAME_INUSE; + return ptr; + } + else + { + for (int i = target_order; i < FRAME_BINS_SIZE; i++) + { + if (frame_bins[i].next != &frame_bins[i]) + { + return split_frames(i, target_order); + } + } + } + + uart_send_string("alloc page return NULL"); + return NULL; +} + +void free_pages(void *victim) +{ + int page_idx = ((uintptr_t)victim - FRAME_BASE) / PAGE_SIZE; + if (!IS_INUSE(frames[page_idx])) + { + uart_printf("Error! double free the memory at %x\n", (uintptr_t)victim); + return; + } + unsigned int order = frames[page_idx].order; + int buddy_page_idx = page_idx ^ (1 << order); + frames[page_idx].flag &= ~FRAME_INUSE; + + while (order <= MAX_ORDER && + !IS_INUSE(frames[buddy_page_idx]) && + order == frames[buddy_page_idx].order) + { + void *buddy_victim = (void *)(FRAME_BASE + buddy_page_idx * PAGE_SIZE); + unlink((list *)buddy_victim); + +#ifdef DEBUG + uart_printf("merge buddy frame: %x \n", (unsigned long)buddy_victim); +#endif + order += 1; + victim = page_idx < buddy_page_idx ? victim : buddy_victim; + page_idx = page_idx < buddy_page_idx ? page_idx : buddy_page_idx; + buddy_page_idx = page_idx ^ (1 << order); + } + + insert_head(&frame_bins[order], victim); + frames[page_idx].order = order; + +#ifdef DEBUG + uart_printf("attach frame: %x \n\n", (unsigned long)victim); +#endif +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// chunks // +//////////////////////////////////////////////////////////////////////////////////////////////// + +static int size_to_chunk_order(unsigned int size) +{ + size = align_up_exp(size); + size /= CHUNK_MIN_SIZE; + return __builtin_ctz(size); +} + +static void *get_chunk(uint32_t size) +{ + int order = size_to_chunk_order(size); + + void *ptr = chunk_bins[order]; + if (ptr) + { + chunk_bins[order] = chunk_bins[order]->next; + int idx = addr2idx(ptr); + frames[idx].ref_count += 1; + +#ifdef DEBUG + uart_printf("detach chunk at %x\n", (unsigned long)ptr); +#endif + } + + return ptr; +} + +static void alloc_chunk(void *mem, int size) +{ + int count = PAGE_SIZE / size; + int idx = addr2idx(mem); + int order = size_to_chunk_order(size); + frames[idx].flag |= FRAME_MEM_CHUNK; + frames[idx].ref_count = 0; + frames[idx].chunk_order = order; + for (int i = 0; i < count; i++) + { + Chunk *ptr = (Chunk *)((uintptr_t)mem + i * size); + ptr->next = chunk_bins[order]; + chunk_bins[order] = ptr; + +#ifdef DEBUG + uart_printf("insert chunk at %x\n", (unsigned long)ptr); +#endif + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// dynamic memory simple_allocator // +//////////////////////////////////////////////////////////////////////////////////////////////// + +void *kmalloc(unsigned int size) +{ + unsigned int aligned_page_size = align_up(size, PAGE_SIZE); + if (aligned_page_size > FRAME_MAX_SIZE) + { + return NULL; + } + + size = size < CHUNK_MIN_SIZE ? CHUNK_MIN_SIZE : size; + + size_t flag = disable_irq(); + + void *ptr; + if (align_up_exp(size) < PAGE_SIZE) // just allocate a small chunk + { + size = align_up_exp(size); + ptr = get_chunk(size); + + if (!ptr) + { + void *mem = alloc_pages(1); + alloc_chunk(mem, size); + ptr = get_chunk(size); + } + } + else + { + unsigned int pages = aligned_page_size / PAGE_SIZE; + ptr = alloc_pages(pages); + } + irq_restore(flag); + return ptr; +} +void *kcalloc(unsigned int size) +{ + void *p = kmalloc(size); + if (!p) + { + return NULL; + } + if (size < PAGE_SIZE) + { + size = align_up_exp(size); + } + else + { + size = align_up(size, PAGE_SIZE); + } + memset(p, 0, size); + + return p; +} + +void kfree(void *ptr) +{ + int idx = addr2idx(ptr); + if (idx >= FRAME_ARRAY_SIZE) + { + uart_send_string("Error! kfree wrong address\n"); + return; + } + size_t flag = disable_irq(); + if (IS_MEM_CHUNK(frames[idx])) + { + int order = frames[idx].chunk_order; + ((Chunk *)ptr)->next = chunk_bins[order]; + chunk_bins[order] = ptr; + frames[idx].ref_count -= 1; + +#ifdef DEBUG + uart_printf("free chunk at %x\n", (unsigned long)ptr); +#endif + } + else + { + free_pages(ptr); + } + irq_restore(flag); +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// test // +//////////////////////////////////////////////////////////////////////////////////////////////// + +void test_buddy() +{ + int test_size = 5; + void *a[test_size]; + uart_send_string("\n\n----- Malloc -----\n"); + for (int i = 0; i < test_size; i++) + { + a[i] = alloc_pages(test_size); + } + uart_send_string("\n\n----- Free -----\n"); + for (int i = 0; i < test_size; i++) + { + free_pages(a[i]); + } +} + +struct test_b +{ + double b1, b2, b3, b4, b5, b6; +}; + +void test_dynamic_alloc() +{ + uart_send_string("allocate a1\n"); + int *a1 = kmalloc(sizeof(int)); + uart_send_string("allocate a2\n"); + int *a2 = kmalloc(sizeof(int)); + uart_send_string("allocate b\n"); + struct test_b *b = kmalloc(sizeof(struct test_b)); + + uart_send_string("free a1\n"); + kfree(a1); + uart_send_string("free b\n"); + kfree(b); + uart_send_string("free a2\n"); + kfree(a2); +} diff --git a/lab5/src/mm.o b/lab5/src/mm.o new file mode 100644 index 000000000..30856205e Binary files /dev/null and b/lab5/src/mm.o differ diff --git a/lab5/src/sche.c b/lab5/src/sche.c new file mode 100644 index 000000000..ce483527a --- /dev/null +++ b/lab5/src/sche.c @@ -0,0 +1,151 @@ +#include "sche.h" +#include "current.h" +#include "timer.h" +#include "exception_c.h" +#include "mini_uart.h" +#include "mm.h" + +pid_t task_count = 0; + +list running_queue = LIST_HEAD_INIT(running_queue); +list waiting_queue = LIST_HEAD_INIT(waiting_queue); +list stopped_queue = LIST_HEAD_INIT(stopped_queue); + +int get_the_cur_count() +{ + int count = 0; + list *head = &running_queue; + while (head->next != &running_queue) + { + count++; + head = head->next; + } + return count; +} + +void add_task(struct task *t) +{ + size_t flags = disable_irq(); + insert_tail(&running_queue, &t->list); + irq_restore(flags); +} + +void kill_task(struct task *_task, int status) +{ + size_t flags = disable_irq(); + + _task->state = TASK_STOPPED; + _task->need_resched = 1; + unlink(&_task->list); + _task->exitcode = status; + insert_head(&stopped_queue, &_task->list); + + irq_restore(flags); + thread_schedule(0); +} + +void restart_task(struct task *_task) +{ + size_t flags = disable_irq(); + + if (_task->state != TASK_WAITING) + { + uart_send_string("---- task state inconsistent ----\n"); + return; + } + _task->state = TASK_RUNNING; + unlink(&_task->list); + insert_tail(&running_queue, &_task->list); + + irq_restore(flags); +} + +void pause_task(struct task *_task) +{ + size_t flags = disable_irq(); + + if (_task->state != TASK_RUNNING) + { + uart_send_string("---- task state inconsistent ----\n"); + return; + } + _task->state = TASK_WAITING; + _task->need_resched = 1; + unlink(&_task->list); + insert_head(&waiting_queue, &_task->list); + + irq_restore(flags); +} + +void sleep_task(size_t ms) +{ + size_t flags = disable_irq(); + + add_timer((timer_callback)restart_task, (size_t)current, ms); + pause_task(current); + irq_restore(flags); + + thread_schedule(0); +} + +void free_task(struct task *victim) +{ + if (victim->kernel_stack) + kfree(victim->kernel_stack); + kfree(victim); +} + +struct task *create_task() +{ + struct task *new_task = kmalloc(sizeof(struct task)); + new_task->cpu_context.lr = new_task->cpu_context.sp = new_task->cpu_context.fp = 0; + new_task->kernel_stack = NULL; + new_task->user_stack = NULL; + new_task->user_prog = NULL; + new_task->user_prog_size = 0; + new_task->state = TASK_INIT; + new_task->pid = task_count++; + new_task->need_resched = 0; + new_task->exitcode = 0; + new_task->timeout = get_current_time() + DEFAULT_TIMEOUT; + new_task->signal = NULL; + new_task->sig_context = NULL; + return new_task; +} + +struct task *pick_next_task() +{ + if (list_empty(&running_queue)) + { + while (1) + { + }; + } + struct task *next_task = list_first_entry(&running_queue, struct task, list); + unlink(&next_task->list); + insert_tail(&running_queue, &next_task->list); + + return next_task; +} + +void switch_task(struct task *next) +{ + if (current == next) + { + return; + } + switch_to(¤t->cpu_context, &next->cpu_context); +} + +struct task *get_task(pid_t target) +{ + struct task *_task; + list_for_each_entry(_task, &running_queue, list) + { + if (_task->pid == target) + { + return _task; + } + } + return NULL; +} \ No newline at end of file diff --git a/lab5/src/sche.o b/lab5/src/sche.o new file mode 100644 index 000000000..896030018 Binary files /dev/null and b/lab5/src/sche.o differ diff --git a/lab5/src/shell.c b/lab5/src/shell.c new file mode 100644 index 000000000..676ff1760 --- /dev/null +++ b/lab5/src/shell.c @@ -0,0 +1,226 @@ +#include "shell.h" +#include "mini_uart.h" +#include "utils_c.h" +#include "utils_s.h" +#include "peripheral/mailbox.h" +#include "_cpio.h" +#include "exception_c.h" +#include "timer.h" +#include "dtb.h" +#include "mm.h" +#include "exec.h" +#include "thread.h" +#include +#define BUFFER_MAX_SIZE 256u +#define COMMNAD_LENGTH_MAX 20u + +extern void *_dtb_ptr; + +int split(const char *buf, char *outbuf[], int n) +{ + const char *ps, *pe; + int idx = 0; + ps = pe = buf; + + while (idx < n) + { + while (*pe && *pe != ' ') + { + pe++; + } + + int size = pe - ps; + if (size) + { + outbuf[idx] = kmalloc(size + 1); + memcpy(outbuf[idx], ps, size); + outbuf[idx][size] = '\0'; + idx++; + } + + if (*pe) + { + while (*pe == ' ') + pe++; + ps = pe; + } + else + { + break; + } + } + + return idx; +} + +void read_command(char *buffer) +{ + size_t index = 0; + while (1) + { + buffer[index] = uart_recv(); + uart_send(buffer[index]); + if (buffer[index] == '\n') + { + break; + } + index++; + } + buffer[index + 1] = '\0'; + utils_newline2end(buffer); + uart_send('\r'); +} + +void parse_arg(char *buffer, int *argi) +{ + int i = 0; + int argi_index = 0; + argi[argi_index] = i; + while (buffer[i] != '\0') + { + if (buffer[i] == ' ') + { + buffer[i] = '\0'; + argi[++argi_index] = ++i; + continue; + } + i++; + } +} + +void help() +{ + uart_send_string("help :"); + uart_send_string("print this help menu\n"); + uart_send_string("hello :"); + uart_send_string("print Hello World!\n"); + uart_send_string("reboot : "); + uart_send_string("reboot the device\n"); + uart_send_string("info : "); + uart_send_string("the mailbox hardware info\n"); + uart_send_string("ls : "); + uart_send_string("list the all file\n"); + uart_send_string("cat : "); + uart_send_string("print the file content\n"); + uart_send_string("dtb : "); + uart_send_string("print the device name tree \n"); + uart_send_string("async : "); + uart_send_string("test uart async send and recv\n"); + uart_send_string("set : "); + uart_send_string("set the timeout (set message second)\n"); + uart_send_string("buddy : "); + uart_send_string("test the page allocate and free\n"); + uart_send_string("dynamic : "); + uart_send_string("test the dynamic memory simple_allocator\n"); +} + +void hello() +{ + uart_send_string("Hello World!\n"); +} + +void info() +{ + get_board_revision(); + get_arm_memory(); +} + +void parse_command(char *buffer) +{ + // int argi[BUFFER_MAX_SIZE]; + if (utils_str_compare(buffer, "") == 0) + { + return; + } + else if (utils_str_compare(buffer, "help") == 0) + { + help(); + } + else if (utils_str_compare(buffer, "hello") == 0) + { + hello(); + } + else if (utils_str_compare(buffer, "ls") == 0) + { + cpio_ls(); + } + else if (utils_str_compare(buffer, "cat") == 0) + { + uart_send_string("Filename: "); + char buffer[BUFFER_MAX_SIZE]; + read_command(buffer); + cpio_cat(buffer); + } + else if (utils_str_compare(buffer, "exe") == 0) + { + exe_new_prog("user2.img"); + } + else if (utils_str_compare(buffer, "wtf") == 0) + { + uart_printf("Current task count :%d\n",get_the_cur_count()); + } + else if (utils_str_compare(buffer, "thread") == 0) + { + test_thread(); + uart_async_send_string("exit the test_thread\n"); + } + else if (utils_str_compare(buffer, "reboot") == 0) + { + uart_send_string("rebooting...\n"); + reset(1000); + } + else if (utils_str_compare(buffer, "info") == 0) + { + info(); + } + else if (utils_str_compare(buffer, "dtb") == 0) + { + fdt_traverse(print_dtb, _dtb_ptr); + } + + else if (utils_str_compare(buffer, "async") == 0) + { + test_uart_async(); + } + else if (utils_strncmp(buffer, "set", 3) == 0) + { + char *args[3]; + split(buffer, args, 3); + unsigned long time = (unsigned long)utils_str2uint_dec(args[2]); + set_timeout(args[1], S(time)); + } + else if (utils_str_compare(buffer, "buddy") == 0) + { + test_buddy(); + } + else if (utils_str_compare(buffer, "dynamic") == 0) + { + test_dynamic_alloc(); + } + else + { + uart_send_string("commnad '"); + uart_send_string(buffer); + uart_send_string("' not found\n"); + } +} + +void clear_buffer(char *buf) +{ + for (int i = 0; i < BUFFER_MAX_SIZE; i++) + { + buf[i] = '\0'; + } +} + +void shell() +{ + while (1) + { + char buffer[BUFFER_MAX_SIZE]; + clear_buffer(buffer); + uart_send_string("$ "); + read_command(buffer); + parse_command(buffer); + } +} \ No newline at end of file diff --git a/lab5/src/shell.o b/lab5/src/shell.o new file mode 100644 index 000000000..d1b68ea33 Binary files /dev/null and b/lab5/src/shell.o differ diff --git a/lab5/src/signal.c b/lab5/src/signal.c new file mode 100644 index 000000000..1b46aa58b --- /dev/null +++ b/lab5/src/signal.c @@ -0,0 +1,63 @@ +#include "signal.h" +#include "sche.h" +#include "current.h" +#include "mm.h" +#include "trap_frame.h" +#include "mini_uart.h" +#include "utils_c.h" + +static void sig_ignore(int _) +{ + return; +} +void sigkill_handler(int target) +{ + if (current->pid == target) + { + kill_task(current, target); + return; + } + struct task *victim = get_task(target); + if (victim) + { + kill_task(victim, 0); + } +} +void sig_return(void) +{ + asm volatile( + "mov x8, 10\n" + "svc 0\n"); +} + +void sig_context_update(TrapFrame *_regs, void (*handler)()) +{ + struct signal_context *sig_context = kmalloc(sizeof(struct signal_context)); + sig_context->trapframe = kmalloc(sizeof(TrapFrame)); + sig_context->user_stack = kmalloc(STACK_SIZE); + memcpy(sig_context->trapframe, _regs, sizeof(TrapFrame)); + + current->sig_context = sig_context; + + _regs->regs[30] = (unsigned long)&sig_return; + _regs->pc = (unsigned long)handler; + _regs->sp = (unsigned long)sig_context->user_stack + STACK_SIZE - 0x10; +} + +void sig_context_restore(TrapFrame *_regs) +{ + memcpy(_regs, current->sig_context->trapframe, sizeof(TrapFrame)); +} + +signal_handler signal_table[] = { + [0] = &sig_ignore, + [1] = &sig_ignore, + [2] = &sig_ignore, + [3] = &sig_ignore, + [4] = &sig_ignore, + [5] = &sig_ignore, + [6] = &sig_ignore, + [7] = &sig_ignore, + [8] = &sig_ignore, + [SIGKILL] = &sigkill_handler, +}; \ No newline at end of file diff --git a/lab5/src/signal.o b/lab5/src/signal.o new file mode 100644 index 000000000..6382ab857 Binary files /dev/null and b/lab5/src/signal.o differ diff --git a/lab5/src/sprintf.c b/lab5/src/sprintf.c new file mode 100644 index 000000000..246748b62 --- /dev/null +++ b/lab5/src/sprintf.c @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +/** + * minimal sprintf implementation + */ +#include "../include/sprintf.h" + +unsigned int vsprintf(char *dst, char* fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig=dst, tmpstr[19]; + + // failsafes + if(dst==(void*)0 || fmt==(void*)0) { + return 0; + } + + // main loop + arg = 0; + while(*fmt) { + // argument access + if(*fmt=='%') { + fmt++; + // literal % + if(*fmt=='%') { + goto put; + } + len=0; + // size modifier + while(*fmt>='0' && *fmt<='9') { + len *= 10; + len += *fmt-'0'; + fmt++; + } + // skip long modifier + if(*fmt=='l') { + fmt++; + } + // character + if(*fmt=='c') { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } else + // decimal number + if(*fmt=='d') { + arg = __builtin_va_arg(args, int); + // check input + sign=0; + if((int)arg<0) { + arg*=-1; + sign++; + } + if(arg>99999999999999999L) { + arg=99999999999999999L; + } + // convert to string + i=18; + tmpstr[i]=0; + do { + tmpstr[--i]='0'+(arg%10); + arg/=10; + } while(arg!=0 && i>0); + if(sign) { + tmpstr[--i]='-'; + } + // padding, only space + if(len>0 && len<18) { + while(i>18-len) { + tmpstr[--i]=' '; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // hex number + if(*fmt=='x') { + arg = __builtin_va_arg(args, long int); + // convert to string + i=16; + tmpstr[i]=0; + do { + char n=arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i]=n+(n>9?0x37:0x30); + arg>>=4; + } while(arg!=0 && i>0); + // padding, only leading zeros + if(len>0 && len<=16) { + while(i>16-len) { + tmpstr[--i]='0'; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // string + if(*fmt=='s') { + p = __builtin_va_arg(args, char*); +copystring: if(p==(void*)0) { + p="(null)"; + } + while(*p) { + *dst++ = *p++; + } + } + } else { +put: *dst++ = *fmt; + } + fmt++; + } + *dst=0; + // number of bytes written + return dst-orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char* fmt, ...) +{ + //__builtin_va_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst,fmt,args); +} \ No newline at end of file diff --git a/lab5/src/sprintf.o b/lab5/src/sprintf.o new file mode 100644 index 000000000..7b8641a48 Binary files /dev/null and b/lab5/src/sprintf.o differ diff --git a/lab5/src/syscall.c b/lab5/src/syscall.c new file mode 100644 index 000000000..efd12341b --- /dev/null +++ b/lab5/src/syscall.c @@ -0,0 +1,149 @@ +#include "syscall.h" +#include "stddef.h" +#include "trap_frame.h" +#include "current.h" +#include "peripheral/mailbox.h" +#include "mini_uart.h" +#include "signal.h" +#include "exec.h" +#include "exception_c.h" +#include "mm.h" +#include "fork.h" + +void sys_getpid(TrapFrame *_regs) +{ + _regs->regs[0] = current->pid; +} +void sys_uartrecv(TrapFrame *_regs) +{ + char *buf = (char *)_regs->regs[0]; + int count = _regs->regs[1]; + for (int i = 0; i < count; i++) + { + buf[i] = uart_recv(); + } + _regs->regs[0] = count; +} +void sys_uartwrite(TrapFrame *_regs) +{ + char *buf = (char *)_regs->regs[0]; + int count = _regs->regs[1]; + for (int i = 0; i < count; i++) + { + uart_send(buf[i]); + } + _regs->regs[0] = count; +} +void sys_exec(TrapFrame *_regs) +{ + const char *path = (char *)_regs->regs[0]; + const char **args = (const char **)_regs->regs[1]; + _regs->regs[0] = do_exec(path, args); +} +void sys_fork(TrapFrame *_regs) +{ + _regs->regs[0] = do_fork(_regs); +} +void sys_exit(TrapFrame *_regs) +{ + kill_task(current, _regs->regs[0]); +} +void sys_mbox_call(TrapFrame *_regs) +{ + unsigned int channel = _regs->regs[0]; + unsigned int *mailbox = (unsigned int *)_regs->regs[1]; + mailbox_call(channel, mailbox); +} +void sys_kill_pid(TrapFrame *_regs) +{ + pid_t target = _regs->regs[0]; + if (current->pid == target) + { + kill_task(current, target); + return; + } + struct task *victim = get_task(target); + if (victim) + { + kill_task(victim, 0); + } +} +void sys_signal(TrapFrame *_regs) +{ + int sig_num = _regs->regs[0]; + signal_handler _hand = (signal_handler)_regs->regs[1]; + + struct signal *new_signal = kmalloc(sizeof(struct signal)); + new_signal->sig_num = sig_num; + new_signal->handler = _hand; + new_signal->list.next = new_signal->list.prev = &new_signal->list; + + if (!current->signal) + { + current->signal = new_signal; + } + else + { + insert_tail(¤t->signal->list, &new_signal->list); + } +} + +void sys_sigkill(TrapFrame *_regs) +{ + int target = _regs->regs[0]; + int SIGNAL = _regs->regs[1]; + int is_find = 0; + if (current->signal) + { + struct signal *cur = current->signal; + do + { + if (cur->sig_num == SIGNAL) + { + is_find = 1; + sig_context_update(_regs, cur->handler); + break; + } + cur = list_entry(cur->list.next, struct signal, list); + } while (cur != current->signal); + } + else if (!current->signal && !is_find) + { + (signal_table[SIGNAL])(target); + } +} +void sys_sigreturn(TrapFrame *_regs) +{ + sig_context_restore(_regs); + + disable_interrupt(); + kfree(current->sig_context->trapframe); + kfree(current->sig_context->user_stack); + kfree(current->sig_context); + current->sig_context = NULL; + enable_interrupt(); +} +syscall syscall_table[NUM_syscalls] = { + [SYS_GETPID] = &sys_getpid, + [SYS_UART_RECV] = &sys_uartrecv, + [SYS_UART_WRITE] = &sys_uartwrite, + [SYS_EXEC] = &sys_exec, + [SYS_FORK] = &sys_fork, + [SYS_EXIT] = &sys_exit, + [SYS_MBOX] = &sys_mbox_call, + [SYS_KILL_PID] = &sys_kill_pid, + [SYS_SIGNAL] = &sys_signal, + [SYS_SIGKILL] = &sys_sigkill, + [SYS_SIGRETURN] = &sys_sigreturn, +}; + +void syscall_handler(TrapFrame *_regs) +{ + unsigned int sys_index = _regs->regs[8]; + if (sys_index >= NUM_syscalls) + { + uart_send_string("!!! Invalid system call !!!\n"); + return; + } + (syscall_table[sys_index])(_regs); +} diff --git a/lab5/src/syscall.o b/lab5/src/syscall.o new file mode 100644 index 000000000..b929ca1ff Binary files /dev/null and b/lab5/src/syscall.o differ diff --git a/lab5/src/thread.c b/lab5/src/thread.c new file mode 100644 index 000000000..b647e65c0 --- /dev/null +++ b/lab5/src/thread.c @@ -0,0 +1,76 @@ +#include "thread.h" +#include "mini_uart.h" +#include "timer.h" +#include "sche.h" +#include "list.h" +#include "mm.h" +#include "exception_c.h" +#include "current.h" +#include "trap_frame.h" + +void thread_kill_zombies() +{ + unsigned long flags = disable_irq(); + while (!list_empty(&stopped_queue)) + { + struct task *victim = list_first_entry(&stopped_queue, struct task, list); + unlink(&victim->list); + free_task(victim); + } + irq_restore(flags); +} + +void thread_schedule(size_t _) +{ + if (!current->need_resched) + { + return; + } + + unsigned long flags = disable_irq(); + struct task *next = pick_next_task(); + next->need_resched = 0; + irq_restore(flags); + + switch_task(next); +} + +void thread_init() +{ + struct task *init = create_task(); + set_thread_ds(init); // init the thread structure +} + +static void foo() +{ + for (int i = 0; i < 5; ++i) + { + uart_printf("Thread id: %d i=%d\n", current->pid, i); + // sleep_task(500); + delay(1000000); + } + kill_task(current, 0); + thread_schedule(0); +} + +struct task *thread_create(void *func) +{ + struct task *new_thread = create_task(); + new_thread->kernel_stack = kmalloc(STACK_SIZE); + new_thread->state = TASK_RUNNING; + new_thread->cpu_context.lr = (unsigned long)func; + new_thread->cpu_context.sp = (unsigned long)new_thread->kernel_stack + STACK_SIZE - sizeof(TrapFrame); + + add_task(new_thread); + + return new_thread; +} + +void test_thread() +{ + for (int i = 0; i < 3; ++i) + { + thread_create(&foo); + } + uart_printf("end of test_thread\n"); +} diff --git a/lab5/src/thread.o b/lab5/src/thread.o new file mode 100644 index 000000000..3d6dc080c Binary files /dev/null and b/lab5/src/thread.o differ diff --git a/lab5/src/timer.c b/lab5/src/timer.c new file mode 100644 index 000000000..a17bc0ccd --- /dev/null +++ b/lab5/src/timer.c @@ -0,0 +1,155 @@ +#include "timer.h" +#include "utils_s.h" +#include "mm.h" +#include "mini_uart.h" +#include "utils_c.h" +#include "thread.h" +#include "exception_c.h" +#include "current.h" + +timeout_event *timeout_queue_head = 0, *timeout_queue_tail = 0; +void core_timer_enable() +{ + /* + cntpct_el0 >= cntp_cval_el0 -> interrupt + cntp_tval_el0 = cntpct_el0 - cntp_cval_el0 + */ + write_sysreg(cntp_ctl_el0, 1); // enable + unsigned long frq = read_sysreg(cntfrq_el0) / 1000; + write_sysreg(cntp_tval_el0, frq * MS(SCHE_CYCLE)); // set expired time + *CORE0_TIMER_IRQ_CTRL = 2; // unmask timer interrupt +} + +void core_timer_disable() +{ + write_sysreg(cntp_ctl_el0, 0); // disable + *CORE0_TIMER_IRQ_CTRL = 0; // mask timer interrupt +} + +void set_expired_time(unsigned long duration) +{ + unsigned long frq = read_sysreg(cntfrq_el0) / 1000; + write_sysreg(cntp_tval_el0, frq * MS(duration)); // ms +} + +unsigned long get_current_time() +{ + // cntpct_el0: The timer’s current count. + unsigned long frq = read_sysreg(cntfrq_el0) / 1000; + unsigned long current_count = read_sysreg(cntpct_el0); + return (unsigned long)(current_count / frq); +} + +void set_timeout(char *message, unsigned long time) +{ + add_timer((timer_callback)print_message, (size_t)message, time); +} + +void print_message(char *msg) +{ + unsigned long current_time = get_current_time(); + uart_printf("\ncurrent time : %d.%ds\n", GET_S(current_time), GET_MS(current_time)); +} + +void timeout_event_init() +{ + timeout_queue_head = 0; + timeout_queue_tail = 0; + unsigned long cntkctl_el1; + cntkctl_el1 = read_sysreg(CNTKCTL_EL1); + cntkctl_el1 |= 1; + write_sysreg(CNTKCTL_EL1, cntkctl_el1); +} + +void add_timer(void (*cb)(size_t), size_t arg, unsigned long duration) +{ + timeout_event *new_event = (timeout_event *)kmalloc(sizeof(timeout_event)); + new_event->register_time = get_current_time(); + new_event->duration = duration; + new_event->callback = cb; + new_event->arg = arg; + new_event->next = 0; + new_event->prev = 0; + + size_t flag = disable_irq(); + if (timeout_queue_head == 0) + { + timeout_queue_head = new_event; + timeout_queue_tail = new_event; + core_timer_enable(); + set_expired_time(duration); + } + else + { + unsigned long timeout = new_event->register_time + new_event->duration; + timeout_event *cur = timeout_queue_head; + while (cur) + { + if ((cur->register_time + cur->duration) > timeout) + break; + cur = cur->next; + } + + if (cur == 0) + { // cur at end + new_event->prev = timeout_queue_tail; + timeout_queue_tail->next = new_event; + timeout_queue_tail = new_event; + } + else if (cur->prev == 0) + { // cur at head + new_event->next = cur; + (timeout_queue_head)->prev = new_event; + timeout_queue_head = new_event; + set_expired_time(duration); + } + else + { // cur at middle + new_event->next = cur; + new_event->prev = cur->prev; + (cur->prev)->next = new_event; + cur->prev = new_event; + } + } + irq_restore(flag); +} + +static inline void set_resched(unsigned long current_time) +{ + if (current_time >= current->timeout) + { + current->need_resched = 1; + } +} + +void timer_handler() +{ + unsigned long current_time = get_current_time(); + timeout_event *cur_event = timeout_queue_head; + timeout_event *next_event = cur_event->next; + if (next_event) + { + next_event->prev = 0; + timeout_queue_head = next_event; + set_expired_time(next_event->register_time + next_event->duration - current_time); + } + else + { + timeout_queue_head = timeout_queue_tail = 0; + core_timer_disable(); + } + + if (cur_event->callback == (timer_callback)&thread_schedule) + { + set_resched(current_time); + add_timer((timer_callback)thread_schedule, (size_t)0, MS(SCHE_CYCLE)); + enable_interrupt(); + thread_schedule(0); + disable_interrupt(); + } + else if (cur_event->callback) + { + cur_event->callback(cur_event->arg); + } + kfree(cur_event); +} \ No newline at end of file diff --git a/lab5/src/timer.o b/lab5/src/timer.o new file mode 100644 index 000000000..ab117ef2d Binary files /dev/null and b/lab5/src/timer.o differ diff --git a/lab5/src/trans_el.o b/lab5/src/trans_el.o new file mode 100644 index 000000000..650f01c7c Binary files /dev/null and b/lab5/src/trans_el.o differ diff --git a/lab5/src/trans_el.s b/lab5/src/trans_el.s new file mode 100644 index 000000000..066bc1c7a --- /dev/null +++ b/lab5/src/trans_el.s @@ -0,0 +1,9 @@ +.globl from_el2_to_el1 +from_el2_to_el1: + mov x0, (1 << 31) // EL1 uses aarch64 + msr hcr_el2, x0 + mov x0, 0x3c5 // EL1h (SPSel = 1) with interrupt disabled + msr spsr_el2, x0 + msr elr_el2, lr + eret // return to EL1 + \ No newline at end of file diff --git a/lab5/src/utils_c.c b/lab5/src/utils_c.c new file mode 100644 index 000000000..bab9a7af5 --- /dev/null +++ b/lab5/src/utils_c.c @@ -0,0 +1,176 @@ +#include "utils_c.h" +#include "mini_uart.h" +#include + +/* + string part +*/ + +int utils_str_compare(const char *a, const char *b) +{ + char aa, bb; + do + { + aa = (char)*a++; + bb = (char)*b++; + if (aa == '\0' || bb == '\0') + { + return aa - bb; + } + } while (aa == bb); + return aa - bb; +} + +int utils_strncmp(const char *a, const char *b, size_t n) +{ + size_t i = 0; + while (i < n - 1 && a[i] == b[i] && a[i] != '\0' && b[i] != '\0') + i++; + return a[i] - b[i]; +} +void utils_newline2end(char *str) +{ + while (*str != '\0') + { + if (*str == '\n') + { + *str = '\0'; + return; + } + ++str; + } +} + +void utils_int2str_dec(int num, char *str) +{ + // num=7114 digit=4 + int digit = -1, temp = num; + while (temp > 0) + { + temp /= 10; + digit++; + } + for (int i = digit; i >= 0; i--) + { + int t = 1; + for (int j = 0; j < i; j++) + { + t *= 10; + } + *str = '0' + num / t; + num = num % t; + str++; + } + *str = '\0'; +} + +void utils_uint2str_dec(unsigned int num, char *str) +{ + // num=7114 digit=4 + unsigned int temp = num; + int digit = -1; + while (temp > 0) + { + temp /= 10; + digit++; + } + for (int i = digit; i >= 0; i--) + { + int t = 1; + for (int j = 0; j < i; j++) + { + t *= 10; + } + *str = '0' + num / t; + num = num % t; + str++; + } + *str = '\0'; +} + +unsigned int utils_str2uint_dec(const char *str) +{ + unsigned int value = 0u; + + while (*str) + { + value = value * 10u + (*str - '0'); + ++str; + } + return value; +} + +size_t utils_strlen(const char *s) +{ + size_t i = 0; + while (s[i]) + i++; + return i + 1; +} + +/* + reboot part +*/ + +void set(long addr, unsigned int value) +{ + volatile unsigned int *point = (unsigned int *)addr; + *point = value; +} + +void reset(int tick) +{ // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick +} + +void cancel_reset() +{ + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} + +/* + others +*/ + +void align(void *size, size_t s) +{ + unsigned int *x = (unsigned int *)size; + if ((*x) & (s - 1)) + { + (*x) += s - ((*x) & (s - 1)); + } +} + +uint32_t align_up(uint32_t size, int alignment) +{ + return (size + alignment - 1) & -alignment; +} + +void delay(unsigned int clock) +{ + while (clock--) + { + asm volatile("nop"); + } +} + +void memcpy(void *dst, const void *src, size_t n) +{ + char *_dst = dst; + const char *_src = src; + + while (n--) + { + *_dst++ = *_src++; + } +} + +void *memset(void *s, int c, size_t n) { + char *p = s; + for (size_t i = 0; i < n; i++) { + p[i] = c; + } + return s; +} \ No newline at end of file diff --git a/lab5/src/utils_c.o b/lab5/src/utils_c.o new file mode 100644 index 000000000..e6db5cf88 Binary files /dev/null and b/lab5/src/utils_c.o differ diff --git a/lab5/src/utils_s.o b/lab5/src/utils_s.o new file mode 100644 index 000000000..0281f89da Binary files /dev/null and b/lab5/src/utils_s.o differ diff --git a/lab5/src/utils_s.s b/lab5/src/utils_s.s new file mode 100644 index 000000000..83f30cb94 --- /dev/null +++ b/lab5/src/utils_s.s @@ -0,0 +1,32 @@ +.global branchAddr +branchAddr: + br x0 + + +.globl get_el +get_el: + mrs x0, CurrentEl + lsr x0, x0, #2 + ret + +.global switch_to +switch_to: + mov x9, sp + stp x19, x20, [x0, #0x0] + stp x21, x22, [x0, #0x10] + stp x23, x24, [x0, #0x20] + stp x25, x26, [x0, #0x30] + stp x27, x28, [x0, #0x40] + stp fp, x9, [x0, #0x50] + str lr, [x0, #0x60] + + ldp x19, x20, [x1, #0x0] + ldp x21, x22, [x1, #0x10] + ldp x23, x24, [x1, #0x20] + ldp x25, x26, [x1, #0x30] + ldp x27, x28, [x1, #0x40] + ldp fp, x9, [x1, #0x50] + ldr lr, [x1, #0x60] + mov sp, x9 + msr tpidr_el1, x1 + ret diff --git a/lab5/users/user1/linker.ld b/lab5/users/user1/linker.ld new file mode 100644 index 000000000..bac8da058 --- /dev/null +++ b/lab5/users/user1/linker.ld @@ -0,0 +1,26 @@ +SECTIONS +{ + .start : { + *(.start) + } + + _stext = .; + .text : { + *(.text) + *(.rodata) + } + . = ALIGN(0x1000); + _etext = .; + + _sdata = .; + .data : { *(.data) } + . = ALIGN(0x1000); + _edata = .; + + + _sbss = .; + .bss : { *(.bss*) } + . = ALIGN(0x1000); + _ebss = .; + +} \ No newline at end of file diff --git a/lab5/users/user1/main.c b/lab5/users/user1/main.c new file mode 100644 index 000000000..4a8ceeea0 --- /dev/null +++ b/lab5/users/user1/main.c @@ -0,0 +1,286 @@ +#include +#include + +#define SYS_GETPID 0 +#define SYS_UART_RECV 1 +#define SYS_UART_WRITE 2 +#define SYS_EXEC 3 +#define SYS_FORK 4 +#define SYS_EXIT 5 +#define SYS_MBOX_CALL 6 +#define SYS_KILL_PID 7 + +int start(void) __attribute__((section(".start"))); + +unsigned long syscall(unsigned long syscall_num, + void *x0, + void *x1, + void *x2, + void *x3, + void *x4, + void *x5) +{ + unsigned long result; + + asm volatile( + "ldr x8, %0\n" + "ldr x0, %1\n" + "ldr x1, %2\n" + "ldr x2, %3\n" + "ldr x3, %4\n" + "ldr x4, %5\n" + "ldr x5, %6\n" + "svc 0\n" ::"m"(syscall_num), + "m"(x0), "m"(x1), + "m"(x2), "m"(x3), "m"(x4), "m"(x5)); + + asm volatile( + "str x0, %0\n" + : "=m"(result)); + + return result; +} +/* system call */ +int getpid() +{ + return (int)syscall(SYS_GETPID, 0, 0, 0, 0, 0, 0); +} + +void uart_recv(const char buf[], size_t size) +{ + syscall(SYS_UART_RECV, (void *)buf, (void *)size, 0, 0, 0, 0); +} + +void uart_write(const char buf[], size_t size) +{ + syscall(SYS_UART_WRITE, (void *)buf, (void *)size, 0, 0, 0, 0); +} + +void exit(void) +{ + syscall(SYS_EXIT, 0, 0, 0, 0, 0, 0); +} +void kill_pid(unsigned long pid) +{ + syscall(SYS_KILL_PID, (void *)pid, 0, 0, 0, 0, 0); +} +void mailbox_call(unsigned char ch, unsigned int *mbox) +{ + syscall(SYS_MBOX_CALL, (void *)(unsigned long)ch, mbox, 0, 0, 0, 0); +} +void exec(const char *name, char *const argv[]) +{ + syscall(SYS_EXEC, (void *)name, (void *)argv, 0, 0, 0, 0); +} + +/* normal function */ + +static void uart_send(char c) +{ + uart_write(&c, 1); +} + +void uart_send_string(const char *str) +{ + while (*str) + { + uart_send(*str++); + } +} + +unsigned int vsprintf(char *dst, char *fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig = dst, tmpstr[19]; + + // failsafes + if (dst == (void *)0 || fmt == (void *)0) + { + return 0; + } + + // main loop + arg = 0; + while (*fmt) + { + // argument access + if (*fmt == '%') + { + fmt++; + // literal % + if (*fmt == '%') + { + goto put; + } + len = 0; + // size modifier + while (*fmt >= '0' && *fmt <= '9') + { + len *= 10; + len += *fmt - '0'; + fmt++; + } + // skip long modifier + if (*fmt == 'l') + { + fmt++; + } + // character + if (*fmt == 'c') + { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } + else + // decimal number + if (*fmt == 'd') + { + arg = __builtin_va_arg(args, int); + // check input + sign = 0; + if ((int)arg < 0) + { + arg *= -1; + sign++; + } + if (arg > 99999999999999999L) + { + arg = 99999999999999999L; + } + // convert to string + i = 18; + tmpstr[i] = 0; + do + { + tmpstr[--i] = '0' + (arg % 10); + arg /= 10; + } while (arg != 0 && i > 0); + if (sign) + { + tmpstr[--i] = '-'; + } + // padding, only space + if (len > 0 && len < 18) + { + while (i > 18 - len) + { + tmpstr[--i] = ' '; + } + } + p = &tmpstr[i]; + goto copystring; + } + else + // hex number + if (*fmt == 'x') + { + arg = __builtin_va_arg(args, long int); + // convert to string + i = 16; + tmpstr[i] = 0; + do + { + char n = arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i] = n + (n > 9 ? 0x37 : 0x30); + arg >>= 4; + } while (arg != 0 && i > 0); + // padding, only leading zeros + if (len > 0 && len <= 16) + { + while (i > 16 - len) + { + tmpstr[--i] = '0'; + } + } + p = &tmpstr[i]; + goto copystring; + } + else + // string + if (*fmt == 's') + { + p = __builtin_va_arg(args, char *); + copystring: + if (p == (void *)0) + { + p = "(null)"; + } + while (*p) + { + *dst++ = *p++; + } + } + } + else + { + put: + *dst++ = *fmt; + } + fmt++; + } + *dst = 0; + // number of bytes written + return dst - orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char *fmt, ...) +{ + //__builtin_va_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst, fmt, args); +} +unsigned int uart_printf(char *fmt, ...) +{ + char dst[100]; + // __builtin_va_start(args, fmt): "..." is pointed by args + // __builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + unsigned int ret = vsprintf(dst, fmt, args); + uart_send_string(dst); + return ret; +} + +#define MAILBOX_CH_PROP 8 +#define REQUEST_CODE 0x00000000 +#define GET_BOARD_REVISION 0x00010002 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + + +unsigned int __attribute__((aligned(16))) mailbox[8]; + + +unsigned int get_board_revision() +{ + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = END_TAG; + + mailbox_call(MAILBOX_CH_PROP, mailbox); // message passing procedure call, you should implement it following the 6 steps provided above. + return mailbox[5]; +} + +int start(void) +{ + int pid = getpid(); + uart_printf("[User1] pid:%d\n", pid); + + exit(); + return 0; +} diff --git a/lab5/users/user1/main.o b/lab5/users/user1/main.o new file mode 100644 index 000000000..4253fbe31 Binary files /dev/null and b/lab5/users/user1/main.o differ diff --git a/lab5/users/user2/linker.ld b/lab5/users/user2/linker.ld new file mode 100644 index 000000000..bac8da058 --- /dev/null +++ b/lab5/users/user2/linker.ld @@ -0,0 +1,26 @@ +SECTIONS +{ + .start : { + *(.start) + } + + _stext = .; + .text : { + *(.text) + *(.rodata) + } + . = ALIGN(0x1000); + _etext = .; + + _sdata = .; + .data : { *(.data) } + . = ALIGN(0x1000); + _edata = .; + + + _sbss = .; + .bss : { *(.bss*) } + . = ALIGN(0x1000); + _ebss = .; + +} \ No newline at end of file diff --git a/lab5/users/user2/main.c b/lab5/users/user2/main.c new file mode 100644 index 000000000..2db3521bf --- /dev/null +++ b/lab5/users/user2/main.c @@ -0,0 +1,303 @@ +#include +#include + +#define SYS_GETPID 0 +#define SYS_UART_RECV 1 +#define SYS_UART_WRITE 2 +#define SYS_EXEC 3 +#define SYS_FORK 4 +#define SYS_EXIT 5 +#define SYS_MBOX_CALL 6 +#define SYS_KILL_PID 7 + +int start(void) __attribute__((section(".start"))); + +unsigned long syscall(unsigned long syscall_num, + void *x0, + void *x1, + void *x2, + void *x3, + void *x4, + void *x5) +{ + unsigned long result; + + asm volatile( + "ldr x8, %0\n" + "ldr x0, %1\n" + "ldr x1, %2\n" + "ldr x2, %3\n" + "ldr x3, %4\n" + "ldr x4, %5\n" + "ldr x5, %6\n" + "svc 0\n" ::"m"(syscall_num), + "m"(x0), "m"(x1), + "m"(x2), "m"(x3), "m"(x4), "m"(x5)); + + asm volatile( + "str x0, %0\n" + : "=m"(result)); + + return result; +} +/* system call */ +int getpid() +{ + return (int)syscall(SYS_GETPID, 0, 0, 0, 0, 0, 0); +} + +void uart_recv(const char buf[], size_t size) +{ + syscall(SYS_UART_RECV, (void *)buf, (void *)size, 0, 0, 0, 0); +} + +void uart_write(const char buf[], size_t size) +{ + syscall(SYS_UART_WRITE, (void *)buf, (void *)size, 0, 0, 0, 0); +} + +void exit(void) +{ + syscall(SYS_EXIT, 0, 0, 0, 0, 0, 0); +} +void kill_pid(unsigned long pid) +{ + syscall(SYS_KILL_PID, (void *)pid, 0, 0, 0, 0, 0); +} +void mailbox_call(unsigned char ch, unsigned int *mbox) +{ + syscall(SYS_MBOX_CALL, (void *)(unsigned long)ch, mbox, 0, 0, 0, 0); +} +void exec(const char *name, char *const argv[]) +{ + syscall(SYS_EXEC, (void *)name, (void *)argv, 0, 0, 0, 0); +} +int fork(void) +{ + return (int)syscall(SYS_FORK, 0, 0, 0, 0, 0, 0); +} +/* normal function */ + +static void uart_send(char c) +{ + uart_write(&c, 1); +} + +void uart_send_string(const char *str) +{ + while (*str) + { + uart_send(*str++); + } +} + +unsigned int vsprintf(char *dst, char *fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig = dst, tmpstr[19]; + + // failsafes + if (dst == (void *)0 || fmt == (void *)0) + { + return 0; + } + + // main loop + arg = 0; + while (*fmt) + { + // argument access + if (*fmt == '%') + { + fmt++; + // literal % + if (*fmt == '%') + { + goto put; + } + len = 0; + // size modifier + while (*fmt >= '0' && *fmt <= '9') + { + len *= 10; + len += *fmt - '0'; + fmt++; + } + // skip long modifier + if (*fmt == 'l') + { + fmt++; + } + // character + if (*fmt == 'c') + { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } + else + // decimal number + if (*fmt == 'd') + { + arg = __builtin_va_arg(args, int); + // check input + sign = 0; + if ((int)arg < 0) + { + arg *= -1; + sign++; + } + if (arg > 99999999999999999L) + { + arg = 99999999999999999L; + } + // convert to string + i = 18; + tmpstr[i] = 0; + do + { + tmpstr[--i] = '0' + (arg % 10); + arg /= 10; + } while (arg != 0 && i > 0); + if (sign) + { + tmpstr[--i] = '-'; + } + // padding, only space + if (len > 0 && len < 18) + { + while (i > 18 - len) + { + tmpstr[--i] = ' '; + } + } + p = &tmpstr[i]; + goto copystring; + } + else + // hex number + if (*fmt == 'x') + { + arg = __builtin_va_arg(args, long int); + // convert to string + i = 16; + tmpstr[i] = 0; + do + { + char n = arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i] = n + (n > 9 ? 0x37 : 0x30); + arg >>= 4; + } while (arg != 0 && i > 0); + // padding, only leading zeros + if (len > 0 && len <= 16) + { + while (i > 16 - len) + { + tmpstr[--i] = '0'; + } + } + p = &tmpstr[i]; + goto copystring; + } + else + // string + if (*fmt == 's') + { + p = __builtin_va_arg(args, char *); + copystring: + if (p == (void *)0) + { + p = "(null)"; + } + while (*p) + { + *dst++ = *p++; + } + } + } + else + { + put: + *dst++ = *fmt; + } + fmt++; + } + *dst = 0; + // number of bytes written + return dst - orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char *fmt, ...) +{ + //__builtin_va_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst, fmt, args); +} +unsigned int uart_printf(char *fmt, ...) +{ + char dst[100]; + // __builtin_va_start(args, fmt): "..." is pointed by args + // __builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + unsigned int ret = vsprintf(dst, fmt, args); + uart_send_string(dst); + return ret; +} + +#define MAILBOX_CH_PROP 8 +#define REQUEST_CODE 0x00000000 +#define GET_BOARD_REVISION 0x00010002 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +unsigned int __attribute__((aligned(16))) mailbox[8]; + +unsigned int get_board_revision() +{ + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = END_TAG; + + mailbox_call(MAILBOX_CH_PROP, mailbox); // message passing procedure call, you should implement it following the 6 steps provided above. + return mailbox[5]; +} + +int start(void) +{ + // char buf1[0x10] = {0}; + int pid = getpid(); + uart_printf("[User2] pid:%d\n", pid); + + unsigned int revision = get_board_revision(); + uart_printf("[User2] Revision: %x\n", revision); + + pid = fork(); + + if (pid == 0) + { + uart_printf("[User2] child: exec user1.img\r\n"); + exec("user1.img", NULL); + } + else + { + uart_printf("[User2] parent: child pid: %d\n", pid); + } + uart_printf("[User2 ] exit\n"); + exit(); + return 0; +} diff --git a/lab5/users/user2/main.o b/lab5/users/user2/main.o new file mode 100644 index 000000000..e4a618f7d Binary files /dev/null and b/lab5/users/user2/main.o differ diff --git a/lab5_2/ReadMe.md b/lab5_2/ReadMe.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/lab5_2/ReadMe.md @@ -0,0 +1 @@ + diff --git a/lab6/Makefile b/lab6/Makefile new file mode 100644 index 000000000..a74042010 --- /dev/null +++ b/lab6/Makefile @@ -0,0 +1,105 @@ +CFLAG = -Iinclude -Wall -ffreestanding -fno-stack-protector -nostdlib -nostartfiles -mgeneral-regs-only +K8=kernel8 +BL=bootloader +LINKER=linker.ld +START=start +CPIO:=archive/initramfs.cpio +TA_CPIO:=archive/TA/initramfs.cpio +TA_IMG:=archive/TA/vm.img + +DTB:=archive/bcm2710-rpi-3-b-plus.dtb +USER_DIR:=users/user +USER1:=user1 +USER2:=user2 +BUILD:=build/ + +BUILD_ELF:=$(shell find build/ -name '*.elf') +BUILD_IMG:=$(shell find build/ -name '*.img') +ARC_ROOTFS_IMG:=$(shell find archive/rootfs -name '*.img') + +SRC_C:=$(shell find src/ -name '*.c') +SRC_S:=$(shell find src/ -name '*.S') + +KER_C:=$(shell find kernel/ -name '*.c') +KER_S:=$(shell find kernel/ -name '*.S') + +BL_C:=$(shell find bootloader/ -name '*.c') +BL_S:=$(shell find bootloader/ -name '*.S') + +USER1_C:=$(shell find users/user1/ -name '*.c') +USER1_OBJS:= $(USER1_C:%.c=%.o) + +USER2_C:=$(shell find users/user2/ -name '*.c') +USER2_OBJS:= $(USER2_C:%.c=%.o) + +OBJS:= $(SRC_C:%.c=%.o) \ + $(SRC_S:%.S=%.o) \ + + +KERNEL_OBJS:=$(KER_C:%.c=%.o) \ + $(KER_S:%.S=%.o) + + + +BL_OBJS:=$(BL_C:%.c=%.o) \ + $(BL_S:%.S=%.o) \ + src/mini_uart.o src/utils_c.o src/utils_s.o src/memzero.o src/sprintf.o + + + + +all: $(BUILD)$(USER1).img\ + $(BUILD)$(USER2).img \ + $(BUILD)$(K8).img \ + $(BUILD)$(BL).img \ + rd.o + + + +rd.o:$(CPIO) + aarch64-linux-gnu-ld -r -b binary -o rd.o $(CPIO) + + +%.o: %.S + aarch64-linux-gnu-gcc -g -o $@ -c $< + +%.o: %.c + aarch64-linux-gnu-gcc -g -o $@ $(CFLAG) -c $< + + +$(BUILD)$(K8).img: $(OBJS) $(KERNEL_OBJS) + aarch64-linux-gnu-ld -T kernel/$(LINKER) -o $(BUILD)$(K8).elf $^ + aarch64-linux-gnu-objcopy -O binary $(BUILD)$(K8).elf $@ + +$(BUILD)$(BL).img: $(BL_OBJS) + aarch64-linux-gnu-ld -T bootloader/$(LINKER) -o $(BUILD)$(BL).elf $^ + aarch64-linux-gnu-objcopy -O binary $(BUILD)$(BL).elf $@ + +$(BUILD)$(USER1).img:$(USER1_OBJS) + aarch64-linux-gnu-ld -T $(USER_DIR)1/$(LINKER) -o $(BUILD)$(USER1).elf $< + aarch64-linux-gnu-objcopy -O binary $(BUILD)$(USER1).elf $@ + cp $@ archive/rootfs/ + +$(BUILD)$(USER2).img:$(USER2_OBJS) + aarch64-linux-gnu-ld -T $(USER_DIR)2/$(LINKER) -o $(BUILD)$(USER2).elf $< + aarch64-linux-gnu-objcopy -O binary $(BUILD)$(USER2).elf $@ + cp $@ archive/rootfs/ + +$(CPIO): + cp $(TA_IMG) archive/rootfs + cd archive/rootfs&&find . | cpio -o -H newc > ../initramfs.cpio + +on: + sudo screen /dev/ttyUSB0 115200 +qe: $(BUILD)$(K8).img + qemu-system-aarch64 -M raspi3 -kernel $< \ + -serial null -serial stdio -s \ + -initrd $(CPIO) \ + -dtb $(DTB) \ + +clean: + $(RM) $(BUILD_ELF) $(CPIO) \ + $(OBJS) $(KERNEL_OBJS) $(BL_OBJS) $(USER1_OBJS) $(USER2_OBJS)\ + $(ARC_ROOTFS_IMG) \ + $(BUILD_IMG) \ + \ No newline at end of file diff --git a/lab6/ReadMe.md b/lab6/ReadMe.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/lab6/ReadMe.md @@ -0,0 +1 @@ + diff --git a/lab6/archive/TA/initramfs.cpio b/lab6/archive/TA/initramfs.cpio new file mode 100644 index 000000000..0676fb158 Binary files /dev/null and b/lab6/archive/TA/initramfs.cpio differ diff --git a/lab6/archive/TA/vm.img b/lab6/archive/TA/vm.img new file mode 100644 index 000000000..8ba674e6c Binary files /dev/null and b/lab6/archive/TA/vm.img differ diff --git a/lab6/archive/bcm2710-rpi-3-b-plus.dtb b/lab6/archive/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..3934b3a26 Binary files /dev/null and b/lab6/archive/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab6/archive/rootfs/one b/lab6/archive/rootfs/one new file mode 100644 index 000000000..50ecbb596 --- /dev/null +++ b/lab6/archive/rootfs/one @@ -0,0 +1,3 @@ +1 2 3 +4 5 6 +7 8 9 diff --git a/lab6/archive/rootfs/two b/lab6/archive/rootfs/two new file mode 100644 index 000000000..599c97676 --- /dev/null +++ b/lab6/archive/rootfs/two @@ -0,0 +1,3 @@ +hello + world + !!!!! diff --git a/lab6/bootloader/linker.ld b/lab6/bootloader/linker.ld new file mode 100644 index 000000000..2efc319db --- /dev/null +++ b/lab6/bootloader/linker.ld @@ -0,0 +1,28 @@ +ENTRY(_start) +SECTIONS +{ + . = 0x60000; + _stext = .; + .text : { + *(.text.relo) + _bl_entry = .; + *(.text.boot) + *(.text) + *(.rodata) + } + . = ALIGN(0x1000); + _etext = .; + + _sdata = .; + .data : { *(.data) } + . = ALIGN(0x1000); + _edata = .; + + + _sbss = .; + .bss : { *(.bss*) } + . = ALIGN(0x1000); + _ebss = .; + + _blsize = _ebss - _stext; +} diff --git a/lab6/bootloader/main.c b/lab6/bootloader/main.c new file mode 100644 index 000000000..a18076e82 --- /dev/null +++ b/lab6/bootloader/main.c @@ -0,0 +1,48 @@ +#include "mini_uart.h" +#include "utils_c.h" +#include "utils_s.h" +#include +#define BUFFER_MAX_SIZE 256u + +extern char *_dtb; +void load_img() +{ + char * kernel_addr = (char *)0x80000; + uart_send_string("Please sent the kernel image size:"); + char buffer[BUFFER_MAX_SIZE]; + // read_command(buffer); + size_t index = 0; + while (1) + { + buffer[index] = uart_recv(); + uart_send(buffer[index]); + if (buffer[index] == '\n') + { + break; + } + index++; + } + buffer[index + 1] = '\0'; + utils_newline2end(buffer); + uart_send('\r'); + unsigned int img_size = utils_str2uint_dec(buffer); + uart_send_string("Start to load the kernel image... \n"); + + unsigned char *current = (unsigned char *)kernel_addr; + while (img_size--) + { + *current = uart_recv_raw(); + current++; + uart_send('.'); + } + uart_send_string("loading...\n"); + // branchAddr(kernel_addr); + ((void (*)(char *))kernel_addr)(_dtb); +} + +void bootloader_main(void) +{ + uart_init(); + uart_send_string("In bootloader_main!\n"); + load_img(); +} \ No newline at end of file diff --git a/lab6/bootloader/start.S b/lab6/bootloader/start.S new file mode 100644 index 000000000..549ee4109 --- /dev/null +++ b/lab6/bootloader/start.S @@ -0,0 +1,46 @@ +.section ".text.relo" +.globl _start + +# need to relocate the bootloader from 0x80000 to 0x60000 +_start: + adr x10, . //x10=0x80000 + ldr x11, =_blsize + add x11, x11, x10 + ldr x12, =_stext // x12=0x60000 + +moving_relo: + cmp x10, x11 //without bootloader + b.eq end_relo + ldr x13, [x10] + str x13, [x12] //move 0x80000 data to 0x60000 + add x12, x12, #8 + add x10, x10, #8 + b moving_relo +end_relo: + ldr x14, =_bl_entry //jump to boot part + br x14 + + +.section ".text.boot" +.globl _start_bl + ldr x20, =_dtb + str x0, [x20] + mrs x20, mpidr_el1 + and x20, x20,#0xFF // Check processor id + cbz x20, master // Hang for all non-primary CPU + +hang: + b hang + +master: + adr x20, _sbss + adr x21, _ebss + sub x21, x21, x20 + bl memzero + + mov sp, #0x400000 // 4MB + bl bootloader_main + +.global _dtb +.section .data +_dtb: .dc.a 0x0 diff --git a/lab6/include/_cpio.h b/lab6/include/_cpio.h new file mode 100644 index 000000000..52e4fd260 --- /dev/null +++ b/lab6/include/_cpio.h @@ -0,0 +1,33 @@ +#ifndef __CPIO_H +#define __CPIO_H +#include +#include "mmu.h" + +/* + cpio archive comprises a header record with basic numeric metadata followed by + the full pathname of the entry and the file data. +*/ +typedef struct 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. +} cpio_header; + +void cpio_ls(); +void cpio_cat(const char *filename); +char *findFile(const char *name); +size_t cpio_load_program(const char *filename, void **put_addr, pd_t *table); +#endif \ No newline at end of file diff --git a/lab6/include/current.h b/lab6/include/current.h new file mode 100644 index 000000000..9cc1e993a --- /dev/null +++ b/lab6/include/current.h @@ -0,0 +1,16 @@ +#ifndef _CURRENT_H +#define _CURRENT_H + +#include "thread.h" + +static inline struct task *get_thread_ds() +{ + return (struct task *)read_sysreg(tpidr_el1); +} +static inline void set_thread_ds(struct task *cur) +{ + write_sysreg(tpidr_el1, cur); +} +#define current get_thread_ds() + +#endif diff --git a/lab6/include/dtb.h b/lab6/include/dtb.h new file mode 100644 index 000000000..461f32cbe --- /dev/null +++ b/lab6/include/dtb.h @@ -0,0 +1,39 @@ +#ifndef _DTB_H +#define _DTB_H +#include +#include +/* + structure block: located at a 4-byte aligned offset from the beginning of the devicetree blob + token is a big-endian 32-bit integer, alligned on 32bit(padding 0) + +*/ + +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + +typedef struct fdt_header +{ + uint32_t magic; // contain the value 0xd00dfeed (big-endian). + uint32_t totalsize; // in byte + uint32_t off_dt_struct; // the offset in bytes of the structure block from the beginning of the header + 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; // the length in bytes of the strings block section + uint32_t size_dt_struct; +} fdt_header; + +typedef void (*fdt_callback)(int type, const char *name, const void *data, uint32_t size); +void print_dtb(int type, const char *name, const void *data, uint32_t size); +void get_initramfs_addr(int type, const char *name, const void *data, uint32_t size); +int fdt_traverse(fdt_callback cb); + +extern uintptr_t dtb_end, dtb_start; +extern char *initramfs_start, *initramfs_end; + +#endif \ No newline at end of file diff --git a/lab6/include/exception_c.h b/lab6/include/exception_c.h new file mode 100644 index 000000000..c47caa49c --- /dev/null +++ b/lab6/include/exception_c.h @@ -0,0 +1,17 @@ +#ifndef _EXCEPTION_C_H +#define _EXCEPTION_C_H +#include +#include "trap_frame.h" +typedef void (*task_callback)(void *); + +void enable_interrupt(); +void disable_interrupt(); +unsigned long disable_irq(); +void irq_restore(unsigned long flag); + +void default_handler(); +void lower_sync_handler(TrapFrame *_regs); +void irq_handler(); +void curr_sync_handler(); + +#endif diff --git a/lab6/include/exception_s.h b/lab6/include/exception_s.h new file mode 100644 index 000000000..fd2409595 --- /dev/null +++ b/lab6/include/exception_s.h @@ -0,0 +1,6 @@ +#ifndef _EXCEPTION_S_H +#define _EXCEPTION_S_H + +void restore_regs_eret(); + +#endif diff --git a/lab6/include/exec.h b/lab6/include/exec.h new file mode 100644 index 000000000..2676c33ae --- /dev/null +++ b/lab6/include/exec.h @@ -0,0 +1,7 @@ +#ifndef __EXEC_H_ +#define __EXEC_H_ + +void exe_new_prog(char *filename); +int do_exec(const char *path, const char *argv[]); + +#endif \ No newline at end of file diff --git a/lab6/include/fork.h b/lab6/include/fork.h new file mode 100644 index 000000000..3fa7d5d3b --- /dev/null +++ b/lab6/include/fork.h @@ -0,0 +1,8 @@ +#ifndef __FORK_H_ +#define __FORK_H_ +#include +#include "trap_frame.h" + +size_t do_fork(TrapFrame *regs); + +#endif \ No newline at end of file diff --git a/lab6/include/list.h b/lab6/include/list.h new file mode 100644 index 000000000..0f886e233 --- /dev/null +++ b/lab6/include/list.h @@ -0,0 +1,45 @@ +#ifndef __LIST_H +#define __LIST_H +#include +#include + +typedef struct list +{ + struct list *next, *prev; +} list; + +#define container_of(ptr, type, member) ({ \ + void *__mptr = (void *)(ptr); \ + ((type *)(__mptr - offsetof(type, member))); }) + +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +#define list_for_each_entry(entry, head, member) \ + for (entry = list_entry((head)->next, __typeof__(*entry), member); \ + &entry->member != (head); \ + entry = list_entry(entry->member.next, __typeof__(*entry), member)) + +#define LIST_HEAD_INIT(name) \ + { \ + &(name), &(name) \ + } + +static inline int list_empty(const list *head) +{ + return head->next == head; +} + +void list_init(list *node); +void insert_head(list *head, list *v); +void insert_tail(list *head, list *v); +list *remove_head(list *head); +list *remove_tail(list *head); +void unlink(list *node); +#endif diff --git a/lab6/include/mini_uart.h b/lab6/include/mini_uart.h new file mode 100644 index 000000000..2c17055b3 --- /dev/null +++ b/lab6/include/mini_uart.h @@ -0,0 +1,22 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + + +void delay(unsigned int clock); +void enable_uart_interrupt(); +void disable_uart_interrupt(); +void uart_init(); +void uart_send_string(const char* str); +void uart_send(const char c); +char uart_recv(); +char uart_recv_raw(); +void uart_hex(unsigned int d); +void uart_dec(unsigned int num); +void uart_handler(); +void test_uart_async(); +char uart_async_recv(); +void uart_async_send_string(char *str); +void uart_async_send(char c); + +unsigned int uart_printf(char* fmt, ...); +#endif \ No newline at end of file diff --git a/lab6/include/mm.h b/lab6/include/mm.h new file mode 100644 index 000000000..0294a50af --- /dev/null +++ b/lab6/include/mm.h @@ -0,0 +1,47 @@ +#ifndef _MM_H +#define _MM_H + +#include +#include + +#define STARTUP_MEM_START (PHYS_OFFSET + 0x07000000) +#define STARTUP_MEM_END (PHYS_OFFSET + 0x07ffffff) + +typedef struct FrameFlag +{ + unsigned char flag; + unsigned char order; + unsigned short ref_count; + unsigned char chunk_order; +} FrameFlag; + +typedef struct Chunk +{ + struct Chunk *next; +} Chunk; + +// buddy system +void init_buddy(); +void *alloc_pages(unsigned int pages); +void free_pages(void *victim); + +// dynamic mem allocate +void *kmalloc(unsigned int size); +void *kcalloc(unsigned int size); +void kfree(void *ptr); + +// test +void test_buddy(); +void test_dynamic_alloc(); + +// others +void memory_reserve(uintptr_t start, uintptr_t end); +void mm_init(); +void merge_useful_pages(); + +// start up allocation +void *smalloc(size_t size); + + +#endif + diff --git a/lab6/include/mmu.h b/lab6/include/mmu.h new file mode 100644 index 000000000..9dd25eb32 --- /dev/null +++ b/lab6/include/mmu.h @@ -0,0 +1,53 @@ +#ifndef __MMU_H_ +#define __MMU_H_ + +#include "exception_c.h" +typedef unsigned long pd_t; + +#define PHYS_OFFSET 0xffff000000000000 +#define PAR_PA_MASK 0xffffffff000L + +#define PAGE_SIZE 0x1000 +#define USTACK_VA 0xffffffffb000 +#define STACK_SIZE 0x4000 +#define UPROG_VA 0x0 + +#define PD_TABLE 0b11 +#define PD_BLOCK 0b01 +#define PD_PAGE 0b11 +#define PD_ACCESS (1 << 10) // Flag set +#define PD_USER_RW (0b01 << 6) +#define PD_USER_R (0b11 << 6) +#define PD_UXN (1L << 54) // Unprivileged eXecute Never +#define PD_PXN (1L << 53) // Privileged eXecute Never + +// #define pa2va(p) (((unsigned long)(p + PHYS_OFFSET))) +// #define va2pa(p) (((unsigned long)(p - PHYS_OFFSET))) + +static inline void *pa2va(unsigned long p) +{ + return (void *)(p + PHYS_OFFSET); +} + +static inline unsigned long va2pa(void *p) +{ + return (unsigned long)p - PHYS_OFFSET; +} + +#define IDENTITY_TT_L0 ((pd_t *)0x1000L) +#define IDENTITY_TT_L1 ((pd_t *)0x2000L) +#define IDENTITY_TT_L0_VA ((pd_t *)pa2va(0x1000L)) +#define IDENTITY_TT_L1_VA ((pd_t *)pa2va(0x2000L)) + +void setup_identity_mapping(); +void setup_kernel_space_mapping(); +void map_page(pd_t *table, unsigned long va, unsigned long pa, unsigned long flags); +void *alloc_stack(pd_t *table, unsigned long size); +void *alloc_prog(pd_t *table, unsigned long size, const char *file_content); +void setup_peripheral_identity(pd_t *table); +unsigned long get_pte(unsigned long va); +unsigned long el0_va2pa(unsigned long va); +void free_page_table(pd_t *table); +void replace_page_table(); + +#endif diff --git a/lab6/include/peripheral/base.h b/lab6/include/peripheral/base.h new file mode 100644 index 000000000..d9c9422a5 --- /dev/null +++ b/lab6/include/peripheral/base.h @@ -0,0 +1,9 @@ +#ifndef _PERIPHERAL_BASE_H +#define _PERIPHERAL_BASE_H + +#include "mmu.h" + +#define MMIO_BASE PHYS_OFFSET + 0x3F000000 +#define MAILBOX_BASE MMIO_BASE + 0xb880 + +#endif \ No newline at end of file diff --git a/lab6/include/peripheral/gpio.h b/lab6/include/peripheral/gpio.h new file mode 100644 index 000000000..8246c40ae --- /dev/null +++ b/lab6/include/peripheral/gpio.h @@ -0,0 +1,12 @@ +#ifndef _PERIPHERAL_GPIO_H +#define _PERIPHERAL_GPIO_H + +#include "peripheral/base.h" + +#define GPFSEL1 ((volatile unsigned int *)(MMIO_BASE+0x00200004)) +#define GPSET0 ((volatile unsigned int *)(MMIO_BASE+0x0020001C)) +#define GPCLR0 ((volatile unsigned int *)(MMIO_BASE+0x00200028)) +#define GPPUD ((volatile unsigned int *)(MMIO_BASE+0x00200094)) +#define GPPUDCLK0 ((volatile unsigned int *)(MMIO_BASE+0x00200098)) + +#endif \ No newline at end of file diff --git a/lab6/include/peripheral/mailbox.h b/lab6/include/peripheral/mailbox.h new file mode 100644 index 000000000..fc26769a9 --- /dev/null +++ b/lab6/include/peripheral/mailbox.h @@ -0,0 +1,36 @@ +#ifndef _MAILBOX_H +#define _MAILBOX_H + +#include "peripheral/base.h" + +#define MAILBOX_READ ((volatile unsigned int *)(MAILBOX_BASE)) +#define MAILBOX_STATUS ((volatile unsigned int *)(MAILBOX_BASE + 0x18)) +#define MAILBOX_WRITE ((volatile unsigned int *)(MAILBOX_BASE + 0x20)) + +#define MAILBOX_EMPTY 0x40000000 +#define MAILBOX_FULL 0x80000000 +#define MAILBOX_RESPONSE 0x80000000 +#define ARM_MEMORY 0x00010005 + +#define GET_BOARD_REVISION 0x00010002 +#define REQUEST_CODE 0x00000000 +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +#define MAILBOX_CH_POWER 0 +#define MAILBOX_CH_FB 1 +#define MAILBOX_CH_VUART 2 +#define MAILBOX_CH_VCHIQ 3 +#define MAILBOX_CH_LEDS 4 +#define MAILBOX_CH_BTNS 5 +#define MAILBOX_CH_TOUCH 6 +#define MAILBOX_CH_COUNT 7 +#define MAILBOX_CH_PROP 8 + +unsigned int mailbox_call(unsigned char channel, unsigned int *_mailbox); +unsigned int get_board_revision(); +void get_arm_memory(); + +#endif \ No newline at end of file diff --git a/lab6/include/peripheral/mini_uart.h b/lab6/include/peripheral/mini_uart.h new file mode 100644 index 000000000..0ac714e1c --- /dev/null +++ b/lab6/include/peripheral/mini_uart.h @@ -0,0 +1,30 @@ +#ifndef _PERIPHERAL_MINI_UART_H +#define _PERIPHERAL_MINI_UART_H + +#include "peripheral/base.h" + +#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)) + + + +#define ARM_IRQ_REG_BASE ((volatile unsigned int*)(MMIO_BASE + 0x0000b000)) +#define IRQ_PENDING_1 ((volatile unsigned int*)(MMIO_BASE + 0x0000b204)) +#define ENB_IRQS1 ((volatile unsigned int*)(MMIO_BASE + 0x0000b210)) +#define DISABLE_IRQS1 ((volatile unsigned int*)(MMIO_BASE + 0x0000b21c)) +#define AUX_IRQ (1 << 29) + + + + +#endif \ No newline at end of file diff --git a/lab6/include/sche.h b/lab6/include/sche.h new file mode 100644 index 000000000..740fdc955 --- /dev/null +++ b/lab6/include/sche.h @@ -0,0 +1,64 @@ +#ifndef __SCHE_H +#define __SCHE_H +#include "list.h" +#include "signal.h" +#include "mmu.h" + +typedef unsigned long pid_t; +typedef enum +{ + TASK_RUNNING, + TASK_WAITING, + TASK_STOPPED, + TASK_INIT, +} state_t; + +struct cpu_context +{ + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + unsigned long fp; + unsigned long sp; + unsigned long lr; +}; + +struct task +{ + struct cpu_context cpu_context; + char *kernel_stack; + char *user_stack; + char *user_prog; + size_t user_prog_size; + state_t state; + pid_t pid; + unsigned need_resched; + int exitcode; + unsigned long timeout; + list list; + struct signal *signal; + struct signal_context *sig_context; + pd_t *ttbr0; +}; + +extern list running_queue, waiting_queue, stopped_queue; +void add_task(struct task *t); +void kill_task(struct task *_task, int status); +void restart_task(struct task *_task); +void pause_task(struct task *_task); +void sleep_task(size_t ms); +void free_task(struct task *victim); +struct task *create_task(); +void switch_task(struct task *next); +struct task *pick_next_task(); +int get_the_cur_count(); +struct task *get_task(pid_t target); +extern pid_t task_count; +#endif \ No newline at end of file diff --git a/lab6/include/shell.h b/lab6/include/shell.h new file mode 100644 index 000000000..08f251990 --- /dev/null +++ b/lab6/include/shell.h @@ -0,0 +1,7 @@ +#ifndef _SHELL_H +#define _SHELL_H + +void shell(); +void read_command(char *str); +void parse_command(char *str); +#endif \ No newline at end of file diff --git a/lab6/include/signal.h b/lab6/include/signal.h new file mode 100644 index 000000000..768e13b87 --- /dev/null +++ b/lab6/include/signal.h @@ -0,0 +1,27 @@ +#ifndef __SIGNAL_H +#define __SIGNAL_H + +#define SIGKILL 9 + +#include "list.h" +#include "trap_frame.h" +#define SIG_NUM (sizeof(signal_table) / sizeof(signal_table[0])) +typedef void (*signal_handler)(int); + +struct signal +{ + unsigned int sig_num; + signal_handler handler; + struct list list; +}; +struct signal_context +{ + TrapFrame *trapframe; + char *user_stack; +}; + +extern signal_handler signal_table[]; + +void sig_context_update(TrapFrame *_regs, void (*handler)()); +void sig_context_restore(TrapFrame *_regs); +#endif diff --git a/lab6/include/sprintf.h b/lab6/include/sprintf.h new file mode 100644 index 000000000..a7c47f848 --- /dev/null +++ b/lab6/include/sprintf.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +#ifndef __SPRINT_H +#define __SPRINT_H + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); + +#endif \ No newline at end of file diff --git a/lab6/include/syscall.h b/lab6/include/syscall.h new file mode 100644 index 000000000..f556cf61f --- /dev/null +++ b/lab6/include/syscall.h @@ -0,0 +1,29 @@ +#ifndef __SYSCALL_H +#define __SYSCALL_H + +#include "trap_frame.h" + +#define _STR(x) #x +#define STR(s) _STR(s) + +typedef void (*syscall)(TrapFrame *); + +enum { + SYS_GETPID, //0 + SYS_UART_RECV, + SYS_UART_WRITE, + SYS_EXEC, + SYS_FORK, + SYS_EXIT, //5 + SYS_MBOX, + SYS_KILL_PID, + SYS_SIGNAL, + SYS_SIGKILL, + SYS_SIGRETURN, //10 + NUM_syscalls +}; + +extern syscall syscall_table[]; +void syscall_handler(TrapFrame *regs); + +#endif \ No newline at end of file diff --git a/lab6/include/thread.h b/lab6/include/thread.h new file mode 100644 index 000000000..59d238278 --- /dev/null +++ b/lab6/include/thread.h @@ -0,0 +1,13 @@ +#ifndef _THREAD_H +#define _THREAD_H +#include "list.h" +#include "utils_s.h" +#include "sche.h" +#define STACK_SIZE 0x4000 + +void thread_kill_zombies(); +void thread_schedule(size_t _); +void thread_init(); +struct task *thread_create(void *func); +void test_thread(); +#endif diff --git a/lab6/include/timer.h b/lab6/include/timer.h new file mode 100644 index 000000000..cd987ec6d --- /dev/null +++ b/lab6/include/timer.h @@ -0,0 +1,39 @@ +#ifndef __TIMER_H +#define __TIMER_H +#include "stddef.h" +#include "mmu.h" +#define CORE0_TIMER_IRQ_CTRL ((volatile unsigned int *)(PHYS_OFFSET + 0x40000040)) +#define CORE0_INTERRUPT_SOURCE ((volatile unsigned int *)(PHYS_OFFSET + 0x40000060)) +#define DEFAULT_TIMEOUT 30LL +#define SCHE_CYCLE 30LL +#define SYSTEM_TIMER_MSG "system_timeout" +#define S(n) (n * 1000LL) +#define MS(n) (n * 1LL) +#define GET_S(n) (n / 1000LL) +#define GET_MS(n) (n % 1000LL) + +typedef void (*timer_callback)(size_t); + +void core_timer_enable(); +void core_timer_disable(); +void set_expired_time(unsigned long duration); +unsigned long get_current_time(); +void core_timer_handler(); +void set_timeout(char *message, unsigned long time); +void print_message(char *msg); +void add_timer(void (*cb)(size_t), size_t arg, unsigned long duraction); +void timeout_event_init(); +void timer_handler(); + +typedef struct timeout_event +{ + unsigned long register_time; + unsigned long duration; + timer_callback callback; + size_t arg; + struct timeout_event *prev, *next; +} timeout_event; + +extern timeout_event *timeout_queue_head, *timeout_queue_tail; + +#endif diff --git a/lab6/include/trap_frame.h b/lab6/include/trap_frame.h new file mode 100644 index 000000000..593c45d50 --- /dev/null +++ b/lab6/include/trap_frame.h @@ -0,0 +1,12 @@ +#ifndef __TRAP_FRAME_H +#define __TRAP_FRAME_H + +typedef struct +{ + unsigned long regs[31]; // general purpose regs x0~x30 + unsigned long sp; // sp_el0 + unsigned long pc; // elr_el1 + unsigned long pstate; // spsr_el1 +}TrapFrame; + +#endif \ No newline at end of file diff --git a/lab6/include/utils_c.h b/lab6/include/utils_c.h new file mode 100644 index 000000000..16e3f9d24 --- /dev/null +++ b/lab6/include/utils_c.h @@ -0,0 +1,33 @@ +#ifndef _UTILS_C_H +#define _UTILS_C_H +#include +#include +#include "mmu.h" +#define PM_PASSWORD (PHYS_OFFSET + 0x5a000000) +#define PM_RSTC (PHYS_OFFSET + 0x3F10001c) +#define PM_WDOG (PHYS_OFFSET + 0x3F100024) + + +/* string */ +int utils_str_compare(const char *a, const char *b); +int utils_strncmp(const char *a, const char *b, size_t n); +void utils_newline2end(char *str); +char utils_int2char(int a); +void utils_int2str_dec(int a, char *str); +void utils_uint2str_dec(unsigned int num, char *str); +unsigned int utils_str2uint_dec(const char *str); +void align(void *size, size_t s); // aligned to 4 byte +size_t utils_strlen(const char *s); +uint32_t align_up(uint32_t size, int alignment); + +/* reboot */ +void set(long addr, unsigned long value); +void reset(int tick); +void cancel_reset(); + +/* others */ +void delay(unsigned int clock); +void memcpy(void *dst, const void *src, size_t n); +void *memset(void *s, int c, size_t n); + +#endif diff --git a/lab6/include/utils_s.h b/lab6/include/utils_s.h new file mode 100644 index 000000000..6f5a01825 --- /dev/null +++ b/lab6/include/utils_s.h @@ -0,0 +1,41 @@ +#ifndef __UTILS_S_H +#define __UTILS_S_H + +#define read_sysreg(r) ({ \ + unsigned long __val; \ + asm volatile("mrs %0, " #r \ + : "=r"(__val)); \ + __val; \ +}) + +#define write_sysreg(r, __val) ({ \ + asm volatile("msr " #r ", %0" ::"r"(__val)); \ +}) + +#define read_gpreg(r) ({ \ + unsigned long __val; \ + asm volatile("mov %0, " #r \ + : "=r"(__val)); \ + __val; \ +}) + +#define write_gpreg(r, __val) ({ \ + asm volatile("mov " #r ", %0" ::"r"(__val)); \ +}) + + +// EC,bits[31:26] +#define ESR_ELx_EC(esr) ((esr & 0xFC000000) >> 26) +// ISS,bits[24:0] +#define ESR_ELx_ISS(esr) (esr & 0x03FFFFFF) + +#define ESR_ELx_EC_SVC64 0b010101 +#define ESR_ELx_EC_DABT_LOW 0b100100 +#define ESR_ELx_EC_IABT_LOW 0b100000 + + +void branchAddr(void *addr); +int get_el(); +void switch_to(void *, void *); + +#endif diff --git a/lab6/kernel/exception_c.c b/lab6/kernel/exception_c.c new file mode 100644 index 000000000..5d5472def --- /dev/null +++ b/lab6/kernel/exception_c.c @@ -0,0 +1,109 @@ +#include "utils_s.h" +#include "mini_uart.h" +#include "timer.h" +#include "peripheral/mini_uart.h" +#include "exception_c.h" +#include "current.h" +#include "thread.h" +#include "syscall.h" +#define AUX_IRQ (1 << 29) + +void enable_interrupt() { asm volatile("msr DAIFClr, 0xf"); } +void disable_interrupt() { asm volatile("msr DAIFSet, 0xf"); } +unsigned long disable_irq() +{ + unsigned long flag = read_sysreg(DAIF); + disable_interrupt(); + return flag; +} +void irq_restore(unsigned long flag) +{ + write_sysreg(DAIF, flag); +} + +void default_handler() +{ + unsigned long spsr = read_sysreg(spsr_el1); + unsigned long elr = read_sysreg(elr_el1); + unsigned long esr = read_sysreg(esr_el1); + uart_printf("spsr_el1: %x\n", spsr); + uart_printf("elr_el1: %x\n", elr); + uart_printf("esr_el1: %x\n\n", esr); +} + +void lower_irq_handler() +{ + unsigned long current_time = get_current_time(); + uart_printf("After booting: %d seconds\n\n", current_time); + set_expired_time(2); +} + +int data_abort = 0; +int ins_abort = 0; +void lower_sync_handler(TrapFrame *_regs) +{ + unsigned long esr = read_sysreg(esr_el1); // cause of that exception + unsigned int ec = ESR_ELx_EC(esr); + switch (ec) + { + case ESR_ELx_EC_SVC64: + enable_interrupt(); + syscall_handler(_regs); + disable_interrupt(); + break; + case ESR_ELx_EC_DABT_LOW: + if (!data_abort) + { + data_abort = 1; + uart_send_string("in Data Abort\n"); + } + break; + case ESR_ELx_EC_IABT_LOW: + if (!ins_abort) + { + ins_abort = 1; + uart_send_string("in Instruction Abort\n"); + } + break; + default: + return; + } +} + +void irq_handler() +{ + unsigned int irq_is_pending = (*IRQ_PENDING_1 & AUX_IRQ); + unsigned int uart = (*AUX_MU_IIR_REG & 0x1) == 0; + unsigned int core_timer = (*CORE0_INTERRUPT_SOURCE & 0x2); + if (irq_is_pending && uart) + { + uart_handler(); + } + else if (core_timer) + { + timer_handler(); + } +} + +int a = 0; +void curr_sync_handler() +{ + if (!a) + { + uart_send_string("!!! in current sync handler !!!\n"); + a = 1; + } + return; +} + +void curr_fiq_handler() +{ + uart_send_string("!!! in current fiq handler !!!\n"); + return; +} + +void curr_serr_handler() +{ + uart_send_string("!!! in current serr handler !!!\n"); + return; +} diff --git a/lab6/kernel/exception_s.S b/lab6/kernel/exception_s.S new file mode 100644 index 000000000..d9b5fbecf --- /dev/null +++ b/lab6/kernel/exception_s.S @@ -0,0 +1,214 @@ +// save general registers to stack +.macro save_gp_reg + 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_gp_reg + 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 + + +// save all gp_regs and exc_regs +.macro kernel_entry el + sub sp, sp, 17 * 16 + stp x0, x1, [sp ,16 * 0] + stp x2, x3, [sp ,16 * 1] + stp x4, x5, [sp ,16 * 2] + stp x6, x7, [sp ,16 * 3] + stp x8, x9, [sp ,16 * 4] + stp x10, x11, [sp ,16 * 5] + stp x12, x13, [sp ,16 * 6] + stp x14, x15, [sp ,16 * 7] + stp x16, x17, [sp ,16 * 8] + stp x18, x19, [sp ,16 * 9] + stp x20, x21, [sp ,16 * 10] + stp x22, x23, [sp ,16 * 11] + stp x24, x25, [sp ,16 * 12] + stp x26, x27, [sp ,16 * 13] + stp x28, x29, [sp ,16 * 14] + + .if \el == 0 + mrs x0, sp_el0 + stp x30, x0, [sp, 16 * 15] + .else + str x30, [sp, 16 * 15] + .endif + + mrs x0, elr_el1 + mrs x1, spsr_el1 + stp x0, x1, [sp, 16 * 16] + + mov x0, sp +.endm + + +// load all gp_regs and exc_regs +.macro kernel_exit el + ldp x0, x1, [sp, 16 * 16] + msr elr_el1, x0 + msr spsr_el1, x1 + + .if \el ==0 + ldp x30, x0, [sp, 16 * 15] + msr sp_el0, x0 + .else + ldr x30, [sp, 16 * 15] + .endif + + ldp x28, x29, [sp ,16 * 14] + ldp x26, x27, [sp ,16 * 13] + ldp x24, x25, [sp ,16 * 12] + ldp x22, x23, [sp ,16 * 11] + ldp x20, x21, [sp ,16 * 10] + ldp x18, x19, [sp ,16 * 9] + ldp x16, x17, [sp ,16 * 8] + ldp x14, x15, [sp ,16 * 7] + ldp x12, x13, [sp ,16 * 6] + ldp x10, x11, [sp ,16 * 5] + ldp x8, x9, [sp ,16 * 4] + ldp x6, x7, [sp ,16 * 3] + ldp x4, x5, [sp ,16 * 2] + ldp x2, x3, [sp ,16 * 1] + ldp x0, x1, [sp ,16 * 0] + add sp, sp, 17 * 16 + + eret +.endm + +.global restore_regs_eret +restore_regs_eret: + bl replace_page_table + ldp x0, x1, [sp, 16 * 16] + msr elr_el1, x0 + msr spsr_el1, x1 + + ldp x30, x0, [sp, 16 * 15] + msr sp_el0, x0 + + ldp x28, x29, [sp ,16 * 14] + ldp x26, x27, [sp ,16 * 13] + ldp x24, x25, [sp ,16 * 12] + ldp x22, x23, [sp ,16 * 11] + ldp x20, x21, [sp ,16 * 10] + ldp x18, x19, [sp ,16 * 9] + ldp x16, x17, [sp ,16 * 8] + ldp x14, x15, [sp ,16 * 7] + ldp x12, x13, [sp ,16 * 6] + ldp x10, x11, [sp ,16 * 5] + ldp x8, x9, [sp ,16 * 4] + ldp x6, x7, [sp ,16 * 3] + ldp x4, x5, [sp ,16 * 2] + ldp x2, x3, [sp ,16 * 1] + ldp x0, x1, [sp ,16 * 0] + add sp, sp, 17 * 16 + + eret + + + +.macro exception_entry label + .align 7 + b \label // branch to a handler function. + +.endm + + +.global el1_vector_base + +.align 11 +el1_vector_base: + exception_entry exception_handler + exception_entry exception_handler + exception_entry exception_handler + exception_entry exception_handler + + + exception_entry _el1_curr_el_spx_sync + exception_entry _el1_curr_el_spx_irq + exception_entry _el1_curr_el_spx_fiq + exception_entry _el1_curr_el_spx_serr + + + exception_entry _el1_lower_el_aarch64_sync + exception_entry _el1_lower_el_aarch64_irq + exception_entry exception_handler + exception_entry exception_handler + + + exception_entry exception_handler + exception_entry exception_handler + exception_entry exception_handler + exception_entry exception_handler + + +_el1_lower_el_aarch64_sync: + kernel_entry 0 + bl lower_sync_handler + kernel_exit 0 + +_el1_lower_el_aarch64_irq: + kernel_entry 0 + bl irq_handler + kernel_exit 0 + +_el1_curr_el_spx_sync: + save_gp_reg + bl curr_sync_handler + load_gp_reg + eret + +_el1_curr_el_spx_irq: + kernel_entry 1 + bl irq_handler + kernel_exit 1 + +_el1_curr_el_spx_fiq: + save_gp_reg + bl curr_fiq_handler + load_gp_reg + eret + +_el1_curr_el_spx_serr: + save_gp_reg + bl curr_serr_handler + load_gp_reg + eret + +exception_handler: + save_gp_reg + bl default_handler + load_gp_reg + eret diff --git a/lab6/kernel/linker.ld b/lab6/kernel/linker.ld new file mode 100644 index 000000000..e78847942 --- /dev/null +++ b/lab6/kernel/linker.ld @@ -0,0 +1,34 @@ +_skernel = 0xffff000000080000; +_ekernel = 0xffff000000400000; +/* _skernel = 0x80000; +_ekernel = 0x400000; */ + + +ENTRY(_start) +SECTIONS +{ + . = _skernel; + + _stext = .; + .text : { + *(.text.kernel) + *(.text) + *(.rodata) + } + . = ALIGN(0x1000); + _etext = .; + + _sdata = .; + .data : { *(.data) } + . = ALIGN(0x1000); + _edata = .; + + + _sbss = .; + .bss : { *(.bss*) } + . = ALIGN(0x1000); + _ebss = .; + + . = _ekernel; + +} \ No newline at end of file diff --git a/lab6/kernel/main.c b/lab6/kernel/main.c new file mode 100644 index 000000000..fdead5d8b --- /dev/null +++ b/lab6/kernel/main.c @@ -0,0 +1,36 @@ +#include "mini_uart.h" +#include "dtb.h" +#include "exception_c.h" +#include "utils_s.h" +#include "shell.h" +#include "mm.h" +#include "timer.h" +#include "thread.h" +#include "sche.h" +#include "exec.h" +#include "mmu.h" + +static void idle(void) +{ + while (1) + { + thread_kill_zombies(); + thread_schedule(0); + } +} + +void kernel_main(void *_dtb_ptr) +{ + dtb_start=(uintptr_t)_dtb_ptr; + uart_send_string("Hello, world!\n"); + mm_init(); + + setup_kernel_space_mapping(); + thread_init(); + // thread_create(&shell); + exe_new_prog("vm.img"); + timeout_event_init(); + add_timer((timer_callback)thread_schedule, (size_t)0, MS(SCHE_CYCLE)); + enable_interrupt(); + idle(); +} \ No newline at end of file diff --git a/lab6/kernel/start.S b/lab6/kernel/start.S new file mode 100644 index 000000000..1388af994 --- /dev/null +++ b/lab6/kernel/start.S @@ -0,0 +1,62 @@ +.section ".text.kernel" +.globl _start + +#define PA(p) (p - 0xffff000000000000) + +_start: + ldr x9, =PA(_ekernel) + mov sp, x9 + + /* store dtb pointer */ + sub sp, sp, #0x10 + str x0, [sp] + + mov x9, sp + msr sp_el1, x9 + + /* cpu id pass */ + mrs x20, mpidr_el1 + and x20, x20,#0xFF // Check processor id + cbz x20, master // Hang for all non-primary CPU + +hang: + b hang + +master: + ldr x20, =PA(_sbss) + ldr x21, =PA(_ebss) + sub x21, x21, x20 + bl memzero + + /* setup interrupt vector base */ + ldr x0, =el1_vector_base + msr vbar_el1, x0 + bl from_el2_to_el1 + + bl setup_identity_mapping + + mov x1, #0 + movk x1, #0xffff, lsl 48 // set 0xffff to x1 and shift left 48 bit --> set x1 hight 16 bit + // kernel space start address + mov x0, sp + orr x0, x0, x1 + mov sp, x0 + + mov x0, fp + orr fp, x0, x1 + + ldr x0, [sp] + orr x0, x0, x1 + + ldr x2, =_dtb_ptr + str x0, [x2] + + ldr x9, =kernel_main + br x9 + +hang2: + b hang2 + +.global _dtb_ptr +.section .data +_dtb_ptr: .dc.a 0x0 \ No newline at end of file diff --git a/lab6/loadImg/loadImg.py b/lab6/loadImg/loadImg.py new file mode 100644 index 000000000..6fb3542ce --- /dev/null +++ b/lab6/loadImg/loadImg.py @@ -0,0 +1,30 @@ +#! /usr/bin/python3 + +import os +from socket import timeout +import time +import sys +import serial +from time import sleep + +BAUD_RATE = 115200 + +def send_img(ser,kernel): + print("Please sent the kernel image size:") + kernel_size=os.stat(kernel).st_size + ser.write((str(kernel_size)+"\n").encode()) + print(ser.read_until(b"Start to load the kernel image... \r\n").decode(), end="") + + with open(kernel, "rb") as image: + while kernel_size > 0: + kernel_size -= ser.write(image.read(1)) + ser.read_until(b".") + print(ser.read_until(b"$ ").decode(), end="") + return + +if __name__ == "__main__": + ser = serial.Serial("/dev/ttyUSB0", BAUD_RATE, timeout=5) + send_img(ser,"../build/kernel8.img") + + + diff --git a/lab6/loadImg/loadImg.sh b/lab6/loadImg/loadImg.sh new file mode 100644 index 000000000..171507561 --- /dev/null +++ b/lab6/loadImg/loadImg.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +sudo chmod 666 /dev/ttyUSB0 +source ../.env/bin/activate +python3 ./loadImg.py \ No newline at end of file diff --git a/lab6/requirements.txt b/lab6/requirements.txt new file mode 100644 index 000000000..4d1aaa2b8 --- /dev/null +++ b/lab6/requirements.txt @@ -0,0 +1 @@ +pyserial==3.5 \ No newline at end of file diff --git a/lab6/src/_cpio.c b/lab6/src/_cpio.c new file mode 100644 index 000000000..95d5721ed --- /dev/null +++ b/lab6/src/_cpio.c @@ -0,0 +1,117 @@ +#include "_cpio.h" +#include "utils_c.h" +#include "dtb.h" +#include "mini_uart.h" +#include "timer.h" +#include "mm.h" +#include "mmu.h" + +unsigned int hex2dec(char *s) +{ + unsigned int r = 0; + for (int i = 0; i < 8; ++i) + { + if (s[i] >= '0' && s[i] <= '9') + { + r = r * 16 + s[i] - '0'; + } + else + { + r = r * 16 + s[i] - 'A' + 10; + } + } + return r; +} + +char *findFile(const char *name) +{ + char *addr = initramfs_start; + while (utils_str_compare((char *)(addr + sizeof(cpio_header)), "TRAILER!!!") != 0) + { + if ((utils_str_compare((char *)(addr + sizeof(cpio_header)), name) == 0)) + { + return addr; + } + cpio_header *header = (cpio_header *)addr; + unsigned int pathname_size = hex2dec(header->c_namesize); + unsigned int file_size = hex2dec(header->c_filesize); + unsigned int headerPathname_size = sizeof(cpio_header) + pathname_size; + + align(&headerPathname_size, 4); + align(&file_size, 4); + addr += (headerPathname_size + file_size); + } + return 0; +} +void cpio_ls() +{ + char *addr = initramfs_start; + while (utils_str_compare((char *)(addr + sizeof(cpio_header)), "TRAILER!!!") != 0) + { + cpio_header *header = (cpio_header *)addr; + unsigned int pathname_size = hex2dec(header->c_namesize); + unsigned int file_size = hex2dec(header->c_filesize); + unsigned int headerPathname_size = sizeof(cpio_header) + pathname_size; + + align(&headerPathname_size, 4); + align(&file_size, 4); + + uart_send_string(addr + sizeof(cpio_header)); // print the file name + uart_send_string("\n"); + + addr += (headerPathname_size + file_size); + } +} + +void cpio_cat(const char *filename) +{ + char *target = findFile(filename); + if (target) + { + cpio_header *header = (cpio_header *)target; + unsigned int pathname_size = hex2dec(header->c_namesize); + unsigned int file_size = hex2dec(header->c_filesize); + unsigned int headerPathname_size = sizeof(cpio_header) + pathname_size; + + align(&headerPathname_size, 4); + align(&file_size, 4); + + char *file_content = target + headerPathname_size; + for (unsigned int i = 0; i < file_size; i++) + { + uart_send(file_content[i]); // print the file content + } + uart_send_string("\n"); + } + else + { + uart_send_string("Not found the file\n"); + } +} + +size_t cpio_load_program(const char *filename, void **target_addr, pd_t *table) +{ + char *prog_addr = findFile(filename); + if (prog_addr) + { + cpio_header *header = (cpio_header *)prog_addr; + unsigned int pathname_size = hex2dec(header->c_namesize); + unsigned int file_size = hex2dec(header->c_filesize); + unsigned int headerPathname_size = sizeof(cpio_header) + pathname_size; + + align(&headerPathname_size, 4); + align(&file_size, 4); + + uart_printf("load the %s\n", prog_addr + sizeof(cpio_header)); + + char *file_content = prog_addr + headerPathname_size; + *target_addr = alloc_prog(table, file_size, file_content); + + return file_size; + } + else + { + uart_send_string("Not found the program\n"); + return -1; + } +} diff --git a/lab6/src/dtb.c b/lab6/src/dtb.c new file mode 100644 index 000000000..6c6d0528c --- /dev/null +++ b/lab6/src/dtb.c @@ -0,0 +1,143 @@ +#include "dtb.h" +#include "_cpio.h" +#include "mini_uart.h" +#include "utils_c.h" +/* + It consists of + a small header + + the memory reservation block + space(aligned) + + the structure block + space(aligned) + + the strings block + space(aligned) +*/ +int space = 0; +char *initramfs_start, *initramfs_end; + +uint32_t get_le2be_uint(const void *p) +{ + // transfer little endian to big endian + const unsigned char *bytes = p; + uint32_t res = bytes[3]; + res |= bytes[2] << 8; + res |= bytes[1] << 16; + res |= bytes[0] << 24; + return res; +} + +void send_sapce(int n) +{ + while (n--) + uart_send_string(" "); +} + +int parse_struct(fdt_callback cb, uintptr_t cur_ptr, uintptr_t strings_ptr, uint32_t totalsize) +{ + uintptr_t end_ptr = cur_ptr + totalsize; + + while (cur_ptr < end_ptr) + { + uint32_t token = get_le2be_uint((char *)cur_ptr); + cur_ptr += 4; + switch (token) + { + case FDT_BEGIN_NODE: + // uart_send_string("In FDT_BEGIN_NODE\n"); + cb(token, (char *)cur_ptr, NULL, 0); + cur_ptr += align_up(utils_strlen((char *)cur_ptr), 4); + break; + case FDT_END_NODE: + // uart_send_string("In FDT_END_NODE\n"); + cb(token, NULL, NULL, 0); + break; + case FDT_PROP: + { + // uart_send_string("In FDT_PROP\n"); + uint32_t len = get_le2be_uint((char *)cur_ptr); + cur_ptr += 4; + uint32_t nameoff = get_le2be_uint((char *)cur_ptr); + cur_ptr += 4; + cb(token, (char *)(strings_ptr + nameoff), (void *)cur_ptr, len); + cur_ptr += align_up(len, 4); + ; + break; + } + case FDT_NOP: + // uart_send_string("In FDT_NOP\n"); + cb(token, NULL, NULL, 0); + break; + case FDT_END: + // uart_send_string("In FDT_END\n"); + cb(token, NULL, NULL, 0); + return 0; + default:; + return -1; + } + } + return 0; +} + +void print_dtb(int type, const char *name, const void *data, uint32_t size) +{ + switch (type) + { + case FDT_BEGIN_NODE: + uart_send_string("\n"); + send_sapce(space); + uart_send_string(name); + uart_send_string("{\n "); + space++; + break; + + case FDT_END_NODE: + uart_send_string("\n"); + space--; + if (space > 0) + send_sapce(space); + + uart_send_string("}\n"); + break; + + case FDT_NOP: + break; + + case FDT_PROP: + send_sapce(space); + uart_send_string(name); + break; + + case FDT_END: + break; + } +} + +void get_initramfs_addr(int type, const char *name, const void *data, uint32_t size) +{ + if (type == FDT_PROP && !utils_str_compare(name, "linux,initrd-start")) + { + initramfs_start = (char *)pa2va((uintptr_t)get_le2be_uint(data)); + } + else if (type == FDT_PROP && !utils_str_compare(name, "linux,initrd-end")) + { + initramfs_end = (char *)pa2va((uintptr_t)get_le2be_uint(data)); + } +} + +uintptr_t dtb_end,dtb_start; + +int fdt_traverse(fdt_callback cb) +{ + // uart_printf("\ndtb loading at:%x\n",dtb_start); + fdt_header *header = (fdt_header *)dtb_start; + + if (get_le2be_uint(&(header->magic)) != 0xd00dfeed) + { + uart_printf("header magic ==%x != 0xd00dfeed\n",get_le2be_uint(&(header->magic))); + return -1; + } + uint32_t totalsize = get_le2be_uint(&(header->totalsize)); + uintptr_t struct_ptr = dtb_start + get_le2be_uint(&(header->off_dt_struct)); + uintptr_t strings_ptr = dtb_start + get_le2be_uint(&(header->off_dt_strings)); + parse_struct(cb, struct_ptr, strings_ptr, totalsize); + + dtb_end = dtb_start + get_le2be_uint(&(header->totalsize)); + return 0; +} diff --git a/lab6/src/exec.c b/lab6/src/exec.c new file mode 100644 index 000000000..ff6ee53f1 --- /dev/null +++ b/lab6/src/exec.c @@ -0,0 +1,98 @@ +#include "exec.h" +#include "_cpio.h" +#include "sche.h" +#include "mm.h" +#include "trap_frame.h" +#include "utils_c.h" +#include "current.h" +#include "thread.h" +#include "mini_uart.h" +#include "mmu.h" + +static void replace_user_context(void *prog, size_t data_size, pd_t *ttbr0) +{ + struct task *_task = current; + + kfree(_task->user_stack); + free_page_table(_task->ttbr0); + kfree(_task->user_prog); + + _task->user_stack = alloc_stack(ttbr0, STACK_SIZE); + + _task->user_prog = prog; + _task->user_prog_size = data_size; + + _task->ttbr0 = ttbr0; + replace_page_table(); + + TrapFrame *trapframe = (TrapFrame *)((char *)_task->kernel_stack + STACK_SIZE - sizeof(TrapFrame)); + memset(trapframe, 0, sizeof(TrapFrame)); +} + +void jump_user_prog(void *target_addr, char *kernel_sp, char *user_sp) +{ + asm volatile("mov x0, 0 \n"); + asm volatile("msr spsr_el1, x0 \n"); // daif=0 + asm volatile("msr elr_el1, %0 \n" ::"r"(target_addr)); + asm volatile("msr sp_el0, %0 \n" ::"r"(user_sp)); + if (kernel_sp) + { + asm volatile("mov sp, %0 \n" ::"r"(kernel_sp)); + } + asm volatile("eret \n"); +} + +static void init_user_prog() +{ + jump_user_prog((char *)UPROG_VA, 0, (char *)USTACK_VA + (STACK_SIZE - 0x10)); +} + +int do_exec(const char *path, const char *argv[]) +{ + void *target_addr; + pd_t *ttbr0 = kcalloc(PAGE_SIZE); + size_t data_size = cpio_load_program(path, &target_addr, ttbr0); + if (data_size == -1) + { + uart_send_string("!! do_exec fail !!\n"); + return -1; + } + + setup_peripheral_identity(ttbr0); + replace_user_context(target_addr, data_size, ttbr0); + jump_user_prog((char *)UPROG_VA, current->kernel_stack + STACK_SIZE - sizeof(TrapFrame), (char *)USTACK_VA + (STACK_SIZE - 0x10)); + return 0; +} + +void exe_new_prog(char *filename) +{ + pd_t *ttbr0 = kcalloc(PAGE_SIZE); + setup_peripheral_identity(ttbr0); + + void *target_addr; + size_t data_size = cpio_load_program(filename, &target_addr, ttbr0); + if (data_size == -1) + { + uart_send_string("!! exe_new_prog fail !!\n"); + return; + } + + struct task *prog = thread_create(init_user_prog); + + prog->user_stack = alloc_stack(ttbr0, STACK_SIZE); + + prog->user_prog = target_addr; + prog->user_prog_size = data_size; + + prog->ttbr0 = ttbr0; + + asm( + "dsb ish\n" // ensure write has completed + "msr ttbr0_el1, %0\n" // switch translation based address. + "tlbi vmalle1is\n" // invalidate all TLB entries + "dsb ish\n" // ensure completion of TLB invalidatation + "isb\n" // clear pipeline + ::"r"(ttbr0)); + + return; +} diff --git a/lab6/src/fork.c b/lab6/src/fork.c new file mode 100644 index 000000000..19751756e --- /dev/null +++ b/lab6/src/fork.c @@ -0,0 +1,47 @@ +#include "fork.h" +#include "stddef.h" +#include "sche.h" +#include "thread.h" +#include "exception_c.h" +#include "exception_s.h" +#include "utils_c.h" +#include "current.h" +#include "mm.h" + +static struct task *fork_context(TrapFrame *_regs) +{ + struct task *child = kmalloc(sizeof(struct task)); + + unsigned long flags = disable_irq(); + *child = *current; // copy the current to child entirely + child->pid = task_count++; + irq_restore(flags); + + child->need_resched = 0; + + child->ttbr0 = kcalloc(PAGE_SIZE); + child->user_stack = alloc_stack(child->ttbr0, STACK_SIZE); + memcpy(child->user_stack, current->user_stack, STACK_SIZE); + + child->kernel_stack = kcalloc(STACK_SIZE); + TrapFrame *child_trapframe = (TrapFrame *)((unsigned long)child->kernel_stack + STACK_SIZE - sizeof(TrapFrame)); + memcpy(child_trapframe, _regs, sizeof(TrapFrame)); + + child->user_prog = alloc_prog(child->ttbr0, current->user_prog_size, current->user_prog); + + setup_peripheral_identity(child->ttbr0); + + child_trapframe->regs[0] = 0; // child process : return 0 + + child->cpu_context.sp = (unsigned long)child_trapframe; + child->cpu_context.lr = (unsigned long)restore_regs_eret; + + return child; +} + +size_t do_fork(TrapFrame *_regs) +{ + struct task *child = fork_context(_regs); + add_task(child); + return child->pid; +} diff --git a/lab6/src/list.c b/lab6/src/list.c new file mode 100644 index 000000000..9d3ab1fe3 --- /dev/null +++ b/lab6/src/list.c @@ -0,0 +1,47 @@ +#include "list.h" + +void list_init(list *node) { + node->next = node; + node->prev = node; +} + +void insert_head(list *head, list *v) { + v->next = head->next; + v->prev = head; + head->next->prev = v; + head->next = v; +} + +void insert_tail(list *head, list *v) { + v->next = head; + v->prev = head->prev; + head->prev->next = v; + head->prev = v; +} + +list *remove_head(list *head) { + list *ptr; + ptr = head->next; + head->next = head->next->next; + head->next->prev = head; + + return ptr; +} + +list *remove_tail(list *head) { + list *ptr; + ptr = head->prev; + head->prev = head->prev->prev; + head->prev->next = head; + + return ptr; +} + +void unlink(list *node) { + list *next, *prev; + next = node->next; + prev = node->prev; + + next->prev = prev; + prev->next = next; +} \ No newline at end of file diff --git a/lab6/src/mailbox.c b/lab6/src/mailbox.c new file mode 100644 index 000000000..501f42f3f --- /dev/null +++ b/lab6/src/mailbox.c @@ -0,0 +1,64 @@ +#include "peripheral/mailbox.h" +#include "utils_c.h" +#include "mini_uart.h" + +unsigned int __attribute__((aligned(16))) mailbox[8]; + +unsigned int mailbox_call(unsigned char channel, unsigned int *_mailbox) +{ + unsigned int readChannel = (((unsigned int)((unsigned long)_mailbox) & ~0xF) | (channel & 0xF)); + while (*MAILBOX_STATUS & MAILBOX_FULL) + { + } + *MAILBOX_WRITE = readChannel; + while (1) + { + while (*MAILBOX_STATUS & MAILBOX_EMPTY) + { + } + if (readChannel == *MAILBOX_READ) + { + return _mailbox[1] == MAILBOX_RESPONSE; + } + } + return 0; +} + +unsigned int get_board_revision() +{ + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = END_TAG; + mailbox_call(MAILBOX_CH_PROP, mailbox); // message passing procedure call, you should implement it following the 6 steps provided above. + // printf("0x%x\n", mailbox[5]); // it should be 0xa020d3 for rpi3 b+ + uart_hex(mailbox[5]); + uart_send_string("\n"); + return mailbox[5]; +} + +void get_arm_memory() +{ + mailbox[0] = 8 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = ARM_MEMORY; // tag identifier + mailbox[3] = 8; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + mailbox[6] = 0; // value buffer + // tags end + mailbox[7] = END_TAG; + mailbox_call(MAILBOX_CH_PROP, mailbox); // message passing procedure call, you should implement it following the 6 steps provided above. + uart_send_string("Arm base address: "); + uart_hex(mailbox[5]); + uart_send_string("\n"); + uart_send_string("Arm memory size: "); + uart_hex(mailbox[6]); + uart_send_string("\n"); +} diff --git a/lab6/src/memzero.S b/lab6/src/memzero.S new file mode 100644 index 000000000..91c1c4f0f --- /dev/null +++ b/lab6/src/memzero.S @@ -0,0 +1,7 @@ +.global memzero +memzero: + str xzr, [x20], #8 + subs x21, x21, #8 + b.gt memzero + ret + \ No newline at end of file diff --git a/lab6/src/mini_uart.c b/lab6/src/mini_uart.c new file mode 100644 index 000000000..0d0d73605 --- /dev/null +++ b/lab6/src/mini_uart.c @@ -0,0 +1,258 @@ +#include "peripheral/mini_uart.h" +#include "peripheral/gpio.h" +#include "sprintf.h" +#include "utils_c.h" +#include +#include +#include "mini_uart.h" + +#define ENABLE_RECEIVE_INTERRUPTS_BIT (1 << 0) +#define ENABLE_TRANSMIT_INTERRUPTS_BIT (1 << 1) +#define AUX_INT_BIT (1 << 29) + +#define BUFFER_MAX_SIZE 256u + +char read_buf[BUFFER_MAX_SIZE]; +char write_buf[BUFFER_MAX_SIZE]; +int read_buf_start, read_buf_end; +int write_buf_start, write_buf_end; + + +void enable_uart_interrupt() { *ENB_IRQS1 = AUX_IRQ; } + +void disable_uart_interrupt() { *DISABLE_IRQS1 = AUX_IRQ; } + +void set_transmit_interrupt() { *AUX_MU_IER_REG |= 0x2; } + +void clear_transmit_interrupt() { *AUX_MU_IER_REG &= ~(0x2); } + +void uart_init() +{ + unsigned int selector; + + selector = *GPFSEL1; + selector &= ~(7u << 12); // clean gpio14 + selector |= 2u << 12; // set alt5 for gpio14 + selector &= ~(7u << 15); // clean gpio15 + selector |= 2u << 15; // set alt5 for gpio 15 + *GPFSEL1 = selector; + + *GPPUD = 0; // set the required control signal (i.e. Pull-up or Pull-Down ) + delay(150u); // provides the required set-up time for the control signal + *GPPUDCLK0 = (1u << 14) | (1u << 15); + delay(150u); + *GPPUDCLK0 = 0u; + *AUX_ENABLE = 1u; // Enable mini uart (this also enables access to its registers) + *AUX_MU_CNTL_REG = 0u; // Disable auto flow control and disable receiver and transmitter (for now) + *AUX_MU_IER_REG = 1u; // Enable receive + *AUX_MU_LCR_REG = 3u; // Enable 8 bit mode + *AUX_MU_MCR_REG = 0u; // Set RTS line to be always high + *AUX_MU_BAUD_REG = 270u; // Set baud rate to 115200 + *AUX_MU_IIR_REG = 6; + + *AUX_MU_CNTL_REG = 3; // Finally, enable transmitter and receiver + + read_buf_start = read_buf_end = 0; + write_buf_start = write_buf_end = 0; + // enable_uart_interrupt(); +} + +void uart_send(const char c) +{ + /* + bit_5 == 1 -> writable + 0x20 = 0000 0000 0010 0000 + ref BCM2837-ARM-Peripherals p5 + */ + if (c == '\n') + { + uart_send('\r'); + } + while (!(*(AUX_MU_LSR_REG)&0x20)) + { + } + *AUX_MU_IO_REG = c; +} +char uart_recv() +{ + /* + bit_0 == 1 -> readable + 0x01 = 0000 0000 0000 0001 + ref BCM2837-ARM-Peripherals p5 + */ + while (!(*(AUX_MU_LSR_REG)&0x01)) + { + } + char temp = *(AUX_MU_IO_REG)&0xFF; + return temp == '\r' ? '\n' : temp; +} + +char uart_recv_raw() +{ + /* + bit_0 == 1 -> readable + 0x01 = 0000 0000 0000 0001 + ref BCM2837-ARM-Peripherals p5 + */ + while (!(*(AUX_MU_LSR_REG)&0x01)) + { + } + char temp = *(AUX_MU_IO_REG)&0xFF; + return temp; +} + +void uart_send_string(const char *str) +{ + while (*str) + { + uart_send(*str++); + } +} + +void uart_send_uint(unsigned int num, int newline) +{ + char str[256]; + utils_uint2str_dec(num, str); + uart_send_string(str); + if (newline) + { + uart_send_string("\n"); + } +} + +void uart_hex(unsigned int d) +{ + unsigned int n; + int c; + uart_send_string("0x"); + for (c = 28; c >= 0; c -= 4) + { + n = (d >> c) & 0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n += n > 9 ? 0x57 : 0x30; + uart_send(n); + } +} +void uart_dec(unsigned int num) +{ + if (num == 0) + uart_send('0'); + else + { + if (num >= 10) + uart_dec(num / 10); + uart_send(num % 10 + '0'); + } +} + +unsigned int uart_printf(char *fmt, ...) +{ + char dst[100]; + // __builtin_va_start(args, fmt): "..." is pointed by args + // __builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + unsigned int ret = vsprintf(dst, fmt, args); + uart_send_string(dst); + return ret; +} + +/* + async part +*/ + +void uart_handler() +{ + disable_uart_interrupt(); + int RX = (*AUX_MU_IIR_REG & 0x4); + int TX = (*AUX_MU_IIR_REG & 0x2); + if (RX) + { + char c = (char)(*AUX_MU_IO_REG); + read_buf[read_buf_end++] = c; + if (read_buf_end == BUFFER_MAX_SIZE) + read_buf_end = 0; + } + else if (TX) + { + while (*AUX_MU_LSR_REG & 0x20) + { + if (write_buf_start == write_buf_end) + { + clear_transmit_interrupt(); + break; + } + char c = write_buf[write_buf_start++]; + *AUX_MU_IO_REG = c; + if (write_buf_start == BUFFER_MAX_SIZE) + write_buf_start = 0; + } + } + enable_uart_interrupt(); +} + +char uart_async_recv() +{ + // wait until there are new data + while (read_buf_start == read_buf_end) + { + asm volatile("nop"); + } + char c = read_buf[read_buf_start++]; + if (read_buf_start == BUFFER_MAX_SIZE) + read_buf_start = 0; + return c == '\r' ? '\n' : c; +} + +void uart_async_send_string(char *str) +{ + + for (int i = 0; str[i]; i++) + { + if (str[i] == '\n') + { + write_buf[write_buf_end++] = '\r'; + write_buf[write_buf_end++] = '\n'; + continue; + } + write_buf[write_buf_end++] = str[i]; + if (write_buf_end == BUFFER_MAX_SIZE) + write_buf_end = 0; + } + set_transmit_interrupt(); +} + +void uart_async_send(char c) +{ + if (c == '\n') + { + write_buf[write_buf_end++] = '\r'; + write_buf[write_buf_end++] = '\n'; + set_transmit_interrupt(); + return; + } + write_buf[write_buf_end++] = c; + if (write_buf_end == BUFFER_MAX_SIZE) + write_buf_end = 0; + set_transmit_interrupt(); +} + +void test_uart_async() +{ + enable_uart_interrupt(); + delay(15000); + char buffer[BUFFER_MAX_SIZE]; + size_t index = 0; + while (1) + { + buffer[index] = uart_async_recv(); + if (buffer[index] == '\n') + { + break; + } + index++; + } + buffer[index + 1] = '\0'; + uart_async_send_string(buffer); + disable_uart_interrupt(); +} diff --git a/lab6/src/mm.c b/lab6/src/mm.c new file mode 100644 index 000000000..af17b086f --- /dev/null +++ b/lab6/src/mm.c @@ -0,0 +1,460 @@ +#include "mm.h" +#include "mini_uart.h" +#include "list.h" +#include "utils_c.h" +#include "_cpio.h" +#include "dtb.h" +#include "exception_c.h" +#include "mmu.h" + +// #define DEBUG + +#define FRAME_BASE ((uintptr_t)PHYS_OFFSET + 0x0) +// get from mailbox's arm memory +#define FRAME_END ((uintptr_t)PHYS_OFFSET + 0x3b400000) + +#define PAGE_SIZE 0x1000 // 4KB +#define FRAME_BINS_SIZE 12 +#define MAX_ORDER (FRAME_BINS_SIZE - 1) +#define FRAME_MAX_SIZE ORDER2SIZE(MAX_ORDER) +#define ORDER2SIZE(order) (PAGE_SIZE * (1 << (order))) + +#define FRAME_ARRAY_SIZE ((FRAME_END - FRAME_BASE) / PAGE_SIZE) + +#define CHUNK_MIN_SIZE 32 +#define CHUNK_BINS 7 +#define CHUNK_MAX_ORDER (CHUNK_BINS - 1) + +#define FRAME_FREE 0x8 +#define FRAME_INUSE 0x4 +#define FRAME_MEM_CHUNK 0x2 +#define IS_INUSE(frames) (frames.flag & FRAME_INUSE) +#define IS_MEM_CHUNK(frames) (frames.flag & FRAME_MEM_CHUNK) + +// for mm_int +extern char _skernel, _ekernel; +extern void *_dtb_ptr; + +FrameFlag *frames; +list frame_bins[FRAME_BINS_SIZE]; +Chunk *chunk_bins[CHUNK_BINS]; + +unsigned long *smalloc_cur = (unsigned long *)STARTUP_MEM_START; + +//////////////////////////////////////////////////////////////////////////////////////////////// +// utils // +//////////////////////////////////////////////////////////////////////////////////////////////// +static unsigned align_up_exp(unsigned n) +{ + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n++; + return n; +} +static int addr2idx(void *addr) +{ + return (((uintptr_t)addr & -PAGE_SIZE) - FRAME_BASE) / PAGE_SIZE; +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// startUp // +//////////////////////////////////////////////////////////////////////////////////////////////// + +void *smalloc(size_t size) +{ + align(&size, 4); // allocated the memory size is mutiple of 4 byte; + unsigned long *smalloc_ret = smalloc_cur; + if ((uint64_t)smalloc_cur + size > (uint64_t)STARTUP_MEM_END) + { + uart_printf("[!] No enough space!\r\n"); + return NULL; + } + smalloc_cur += (unsigned int)size; + return smalloc_ret; +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// others // +//////////////////////////////////////////////////////////////////////////////////////////////// + +void mm_init() +{ + init_buddy(); + memory_reserve((uintptr_t)pa2va(0), (uintptr_t)pa2va(0x1000)); // Spin tables for multicore boot + + memory_reserve((uintptr_t)IDENTITY_TT_L0_VA, (uintptr_t)IDENTITY_TT_L0_VA + PAGE_SIZE); // PGD's page frame + memory_reserve((uintptr_t)IDENTITY_TT_L1_VA, (uintptr_t)IDENTITY_TT_L1_VA + PAGE_SIZE); // PUD's page frame + + memory_reserve((uintptr_t)&_skernel, (uintptr_t)&_ekernel); // Kernel image + + fdt_traverse(get_initramfs_addr); + memory_reserve((uintptr_t)initramfs_start, (uintptr_t)initramfs_end); // Initramfs + + memory_reserve((uintptr_t)STARTUP_MEM_START, (uintptr_t)STARTUP_MEM_END); // Simple allocator + + memory_reserve((uintptr_t)dtb_start, (uintptr_t)dtb_end); // Devicetree + + merge_useful_pages(); +} + +void memory_reserve(uintptr_t start, uintptr_t end) +{ + + start = start & ~(PAGE_SIZE - 1); + end = align_up(end - PHYS_OFFSET, PAGE_SIZE) + PHYS_OFFSET; + for (uintptr_t i = start; i < end; i += PAGE_SIZE) + { + int idx = addr2idx((void *)i); + frames[idx].flag |= FRAME_INUSE; + frames[idx].order = 0; + } +#ifdef DEBUG + uart_printf("reserve addr from %x ~ %x\n", (unsigned long)start, (unsigned long)end); +#endif +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// buddy system // +//////////////////////////////////////////////////////////////////////////////////////////////// + +static int pages_to_frame_order(unsigned pages) +{ + pages = align_up_exp(pages); + return __builtin_ctz(pages); +} + +void init_buddy() +{ + frames = (FrameFlag *)smalloc(sizeof(FrameFlag) * FRAME_ARRAY_SIZE); + for (int i = 0; i < FRAME_BINS_SIZE; i++) + { + list_init(&frame_bins[i]); + } + for (int i = 0; i < FRAME_ARRAY_SIZE; i++) + { + frames[i].flag = 0; + frames[i].order = 0; + } +} + +void merge_useful_pages() +{ + int page_idx = 0; + list *page_addr = (list *)(FRAME_BASE); + { // only insert the 4KB page to frame_bins + while (1) + { + if (!IS_INUSE(frames[page_idx])) + { + insert_tail(&frame_bins[0], page_addr); + } + page_idx++; + if (page_idx >= FRAME_ARRAY_SIZE) + { + break; + } + page_addr = (void *)(FRAME_BASE + page_idx * PAGE_SIZE); + } + } + + for (int order = 0; order < MAX_ORDER; order++) + { // merging the pages by left page + page_idx = 0; + page_addr = (list *)(FRAME_BASE); + int buddy_page_idx = 0; + list *buddy_addr = (list *)(FRAME_BASE); + while (1) + { + buddy_page_idx = page_idx ^ (1 << order); + buddy_addr = (void *)(FRAME_BASE + buddy_page_idx * PAGE_SIZE); + + if (!IS_INUSE(frames[page_idx]) && + frames[page_idx].order == order && + buddy_page_idx < FRAME_ARRAY_SIZE && + !IS_INUSE(frames[buddy_page_idx]) && + frames[buddy_page_idx].order == order) + { + unlink((list *)page_addr); + unlink((list *)buddy_addr); + insert_tail(&frame_bins[order + 1], page_addr); + frames[page_idx].order = order + 1; + } + page_idx += (1 << (order + 1)); + if (page_idx >= FRAME_ARRAY_SIZE) + { + break; + } + page_addr = (void *)(FRAME_BASE + page_idx * PAGE_SIZE); + } + } +} + +static void *split_frames(int order, int target_order) +{ + list *ptr = remove_head(&frame_bins[order]); + +#ifdef DEBUG + uart_printf("split frame: %x\n", (unsigned long)ptr); +#endif + + for (int i = order; i > target_order; i--) + { /* insert splitted frame to bin list */ + list *half_right = (list *)((char *)ptr + ORDER2SIZE(i - 1)); + + insert_head(&frame_bins[i - 1], half_right); + frames[((uintptr_t)half_right - FRAME_BASE) / PAGE_SIZE].order = i - 1; + +#ifdef DEBUG + uart_printf("insert frame at %x\n", (unsigned long)half_right); +#endif + } + int idx = addr2idx(ptr); + frames[idx].order = target_order; + frames[idx].flag |= FRAME_INUSE; + return ptr; +} + +void *alloc_pages(unsigned int pages) +{ + int target_order = pages_to_frame_order(pages); + if (frame_bins[target_order].next != &frame_bins[target_order]) + { + list *ptr = remove_head(&frame_bins[target_order]); +#ifdef DEBUG + uart_printf("return page at: %x\n", (unsigned long)ptr); +#endif + int idx = addr2idx(ptr); + frames[idx].order = target_order; + frames[idx].flag |= FRAME_INUSE; + return ptr; + } + else + { + for (int i = target_order; i < FRAME_BINS_SIZE; i++) + { + if (frame_bins[i].next != &frame_bins[i]) + { + return split_frames(i, target_order); + } + } + } + + uart_send_string("alloc page return NULL"); + return NULL; +} + +void free_pages(void *victim) +{ + int page_idx = ((uintptr_t)victim - FRAME_BASE) / PAGE_SIZE; + if (!IS_INUSE(frames[page_idx])) + { + uart_printf("Error! double free the memory at %x\n", (uintptr_t)victim); + return; + } + unsigned int order = frames[page_idx].order; + int buddy_page_idx = page_idx ^ (1 << order); + frames[page_idx].flag &= ~FRAME_INUSE; + + while (order <= MAX_ORDER && + !IS_INUSE(frames[buddy_page_idx]) && + order == frames[buddy_page_idx].order) + { + void *buddy_victim = (void *)(FRAME_BASE + buddy_page_idx * PAGE_SIZE); + unlink((list *)buddy_victim); + +#ifdef DEBUG + uart_printf("merge buddy frame: %x \n", (unsigned long)buddy_victim); +#endif + order += 1; + victim = page_idx < buddy_page_idx ? victim : buddy_victim; + page_idx = page_idx < buddy_page_idx ? page_idx : buddy_page_idx; + buddy_page_idx = page_idx ^ (1 << order); + } + + insert_head(&frame_bins[order], victim); + frames[page_idx].order = order; + +#ifdef DEBUG + uart_printf("attach frame: %x \n\n", (unsigned long)victim); +#endif +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// chunks // +//////////////////////////////////////////////////////////////////////////////////////////////// + +static int size_to_chunk_order(unsigned int size) +{ + size = align_up_exp(size); + size /= CHUNK_MIN_SIZE; + return __builtin_ctz(size); +} + +static void *get_chunk(uint32_t size) +{ + int order = size_to_chunk_order(size); + + void *ptr = chunk_bins[order]; + if (ptr) + { + chunk_bins[order] = chunk_bins[order]->next; + int idx = addr2idx(ptr); + frames[idx].ref_count += 1; + +#ifdef DEBUG + uart_printf("detach chunk at %x\n", (unsigned long)ptr); +#endif + } + + return ptr; +} + +static void alloc_chunk(void *mem, int size) +{ + int count = PAGE_SIZE / size; + int idx = addr2idx(mem); + int order = size_to_chunk_order(size); + frames[idx].flag |= FRAME_MEM_CHUNK; + frames[idx].ref_count = 0; + frames[idx].chunk_order = order; + for (int i = 0; i < count; i++) + { + Chunk *ptr = (Chunk *)((uintptr_t)mem + i * size); + ptr->next = chunk_bins[order]; + chunk_bins[order] = ptr; + +#ifdef DEBUG + uart_printf("insert chunk at %x\n", (unsigned long)ptr); +#endif + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// dynamic memory simple_allocator // +//////////////////////////////////////////////////////////////////////////////////////////////// + +void *kmalloc(unsigned int size) +{ + unsigned int aligned_page_size = align_up(size, PAGE_SIZE); + if (aligned_page_size > FRAME_MAX_SIZE) + { + return NULL; + } + + size = size < CHUNK_MIN_SIZE ? CHUNK_MIN_SIZE : size; + + size_t flag = disable_irq(); + + void *ptr; + if (align_up_exp(size) < PAGE_SIZE) // just allocate a small chunk + { + size = align_up_exp(size); + ptr = get_chunk(size); + + if (!ptr) + { + void *mem = alloc_pages(1); + alloc_chunk(mem, size); + ptr = get_chunk(size); + } + } + else + { + unsigned int pages = aligned_page_size / PAGE_SIZE; + ptr = alloc_pages(pages); + } + irq_restore(flag); + return ptr; +} +void *kcalloc(unsigned int size) +{ + void *p = kmalloc(size); + if (!p) + { + return NULL; + } + if (size < PAGE_SIZE) + { + size = align_up_exp(size); + } + else + { + size = align_up(size, PAGE_SIZE); + } + memset(p, 0, size); + + return p; +} + +void kfree(void *ptr) +{ + int idx = addr2idx(ptr); + if (idx >= FRAME_ARRAY_SIZE) + { + uart_send_string("Error! kfree wrong address\n"); + return; + } + size_t flag = disable_irq(); + if (IS_MEM_CHUNK(frames[idx])) + { + int order = frames[idx].chunk_order; + ((Chunk *)ptr)->next = chunk_bins[order]; + chunk_bins[order] = ptr; + frames[idx].ref_count -= 1; + +#ifdef DEBUG + uart_printf("free chunk at %x\n", (unsigned long)ptr); +#endif + } + else + { + free_pages(ptr); + } + irq_restore(flag); +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// test // +//////////////////////////////////////////////////////////////////////////////////////////////// + +void test_buddy() +{ + int test_size = 5; + void *a[test_size]; + uart_send_string("\n\n----- Malloc -----\n"); + for (int i = 0; i < test_size; i++) + { + a[i] = alloc_pages(test_size); + } + uart_send_string("\n\n----- Free -----\n"); + for (int i = 0; i < test_size; i++) + { + free_pages(a[i]); + } +} + +struct test_b +{ + double b1, b2, b3, b4, b5, b6; +}; + +void test_dynamic_alloc() +{ + uart_send_string("allocate a1\n"); + int *a1 = kmalloc(sizeof(int)); + uart_send_string("allocate a2\n"); + int *a2 = kmalloc(sizeof(int)); + uart_send_string("allocate b\n"); + struct test_b *b = kmalloc(sizeof(struct test_b)); + + uart_send_string("free a1\n"); + kfree(a1); + uart_send_string("free b\n"); + kfree(b); + uart_send_string("free a2\n"); + kfree(a2); +} diff --git a/lab6/src/mmu.c b/lab6/src/mmu.c new file mode 100644 index 000000000..432e64d5b --- /dev/null +++ b/lab6/src/mmu.c @@ -0,0 +1,174 @@ +#include "mmu.h" +#include "utils_s.h" +#include "utils_c.h" +#include "mini_uart.h" +#include "mm.h" +#include "current.h" + +#define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16)) +#define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30)) +#define TCR_CONFIG_DEFAULT (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB) + +#define MAIR_DEVICE_nGnRnE 0b00000000 +#define MAIR_NORMAL_NOCACHE 0b01000100 +#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_NORMAL_NOCACHE 1 + +#define BOOT_PGD_ATTR PD_TABLE // 01 +#define BOOT_PUD_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK) +#define MMU_ENABLE 1 +#define PAGE_SIZE 0x1000 + +#define PERIPHERAL_START 0x3c000000 +#define PERIPHERAL_END 0x3f000000 + +void setup_identity_mapping() +{ + write_sysreg(tcr_el1, TCR_CONFIG_DEFAULT); + size_t mair_attr_01 = + (MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | + (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8)); + write_sysreg(mair_el1, mair_attr_01); + + memset(IDENTITY_TT_L0, 0, 0x1000); // IDENTITY_TT_L0 is the address of the PGD + memset(IDENTITY_TT_L1, 0, 0x1000); // IDENTITY_TT_L1 is the address of the PUD + + // set the entry of the PGD + IDENTITY_TT_L0[0] = (pd_t)IDENTITY_TT_L1 | BOOT_PGD_ATTR; + // set the two entry of the PUD + IDENTITY_TT_L1[0] = 0x00000000 | BOOT_PUD_ATTR; + IDENTITY_TT_L1[1] = 0x40000000 | BOOT_PUD_ATTR; + + write_sysreg(ttbr0_el1, IDENTITY_TT_L0); + write_sysreg(ttbr1_el1, IDENTITY_TT_L0); // also load PGD to the upper translation based register. + unsigned long sctlr = read_sysreg(sctlr_el1); // sctlr_el1 --> System Control Register, EL1 + write_sysreg(sctlr_el1, sctlr | MMU_ENABLE); // Enable the MMU by set the bit 1 of the sctlr_el1 +} + +void setup_kernel_space_mapping() +{ + /* three-level 2MB block mapping */ + + /* 0x00000000 ~ 0x3F000000 for normal mem */ + pd_t *p0 = kcalloc(PAGE_SIZE); + for (int i = 0; i < 504; i++) + { + p0[i] = (i << 21) | PD_ACCESS | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_BLOCK; + } + /* 0x3F000000 ~ 0x40000000 for device mem */ + for (int i = 504; i < 512; i++) + { + p0[i] = (i << 21) | PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK; + } + + /* 0x40000000 ~ 0x80000000 for device mem */ + pd_t *p1 = kcalloc(PAGE_SIZE); + for (int i = 0; i < 512; i++) + { + p1[i] = 0x40000000 | (i << 21) | PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK; + } + + asm volatile("dsb ish\n\t"); + + IDENTITY_TT_L1_VA[0] = (pd_t)va2pa(p0) | PD_TABLE; + IDENTITY_TT_L1_VA[1] = (pd_t)va2pa(p1) | PD_TABLE; +} + +void map_page(pd_t *table, unsigned long va, unsigned long pa, unsigned long flags) +{ + for (int level = 0; level < 4; level++) + { + unsigned idx = (va >> (39 - 9 * level)) & 0b111111111; + if (!table[idx]) + { + if (level == 3) + { + table[idx] = pa; + table[idx] |= PD_PXN | PD_ACCESS | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_PAGE | flags; + return; + } + else + { + table[idx] = (pd_t)va2pa(kcalloc(PAGE_SIZE)); + table[idx] |= PD_ACCESS | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_TABLE; + } + } + + if ((table[idx] & 0b11) == PD_TABLE) + { + table = (pd_t *)pa2va(table[idx] & 0xfffffffff000L); + } + } +} + +void *alloc_stack(pd_t *table, unsigned long size) +{ + void *stack = kcalloc(size); + unsigned long pages = align_up(size, PAGE_SIZE) / PAGE_SIZE; + for (int i = 0; i < pages; i++) + { + map_page(table, USTACK_VA + i * PAGE_SIZE, va2pa(stack + i * PAGE_SIZE), PD_USER_RW | PD_UXN); + } + + return stack; +} + +void *alloc_prog(pd_t *table, unsigned long size, const char *file_content) +{ + void *prog = kcalloc(size); + unsigned long pages = align_up(size, PAGE_SIZE) / PAGE_SIZE; + for (int i = 0; i < pages; i++) + { + map_page(table, UPROG_VA + i * PAGE_SIZE, va2pa(prog + i * PAGE_SIZE), PD_USER_RW); + } + memcpy(prog, file_content, size); + + return prog; +} + +void setup_peripheral_identity(pd_t *table) +{ + unsigned long pages = align_up(PERIPHERAL_END - PERIPHERAL_START, PAGE_SIZE) / PAGE_SIZE; + for (int i = 0; i < pages; i++) + { + map_page(table, PERIPHERAL_START + i * PAGE_SIZE, PERIPHERAL_START + i * PAGE_SIZE, PD_USER_RW); + } +} + +unsigned long get_pte(unsigned long va) +{ + unsigned long flags = disable_irq(); + + asm("at s1e0r, %0\n\t" ::"r"(va)); + unsigned long pte = read_sysreg(par_el1); + + irq_restore(flags); + return pte; +} + +unsigned long el0_va2pa(unsigned long va) +{ + unsigned long entry = get_pte(va); + if (entry & 1) + { + uart_printf("Failed map virtual addr at 0x%x\n", va); + } + unsigned long offset = va & 0xfff; + return (unsigned long)(pa2va((entry & 0xfffffffff000L) | offset)); +} +void free_page_table(pd_t *table) +{ + // free the page table created by translating from map_page() + /* TODO */ +} + +void replace_page_table() +{ + asm( + "dsb ish\n" // ensure write has completed + "msr ttbr0_el1, %0\n" // switch translation based address. + "tlbi vmalle1is\n" // invalidate all TLB entries + "dsb ish\n" // ensure completion of TLB invalidatation + "isb\n" // clear pipeline + ::"r"(current->ttbr0)); +} \ No newline at end of file diff --git a/lab6/src/sche.c b/lab6/src/sche.c new file mode 100644 index 000000000..49f3e4ad2 --- /dev/null +++ b/lab6/src/sche.c @@ -0,0 +1,153 @@ +#include "sche.h" +#include "current.h" +#include "timer.h" +#include "exception_c.h" +#include "mini_uart.h" +#include "mm.h" + +pid_t task_count = 0; + +list running_queue = LIST_HEAD_INIT(running_queue); +list waiting_queue = LIST_HEAD_INIT(waiting_queue); +list stopped_queue = LIST_HEAD_INIT(stopped_queue); + +int get_the_cur_count() +{ + int count = 0; + list *head = &running_queue; + while (head->next != &running_queue) + { + count++; + head = head->next; + } + return count; +} + +void add_task(struct task *t) +{ + size_t flags = disable_irq(); + insert_tail(&running_queue, &t->list); + irq_restore(flags); +} + +void kill_task(struct task *_task, int status) +{ + size_t flags = disable_irq(); + + _task->state = TASK_STOPPED; + _task->need_resched = 1; + unlink(&_task->list); + _task->exitcode = status; + insert_head(&stopped_queue, &_task->list); + + irq_restore(flags); + thread_schedule(0); +} + +void restart_task(struct task *_task) +{ + size_t flags = disable_irq(); + + if (_task->state != TASK_WAITING) + { + uart_send_string("---- task state inconsistent ----\n"); + return; + } + _task->state = TASK_RUNNING; + unlink(&_task->list); + insert_tail(&running_queue, &_task->list); + + irq_restore(flags); +} + +void pause_task(struct task *_task) +{ + size_t flags = disable_irq(); + + if (_task->state != TASK_RUNNING) + { + uart_send_string("---- task state inconsistent ----\n"); + return; + } + _task->state = TASK_WAITING; + _task->need_resched = 1; + unlink(&_task->list); + insert_head(&waiting_queue, &_task->list); + + irq_restore(flags); +} + +void sleep_task(size_t ms) +{ + size_t flags = disable_irq(); + + add_timer((timer_callback)restart_task, (size_t)current, ms); + pause_task(current); + irq_restore(flags); + + thread_schedule(0); +} + +void free_task(struct task *victim) +{ + if (victim->kernel_stack) + kfree(victim->kernel_stack); + kfree(victim); +} + +struct task *create_task() +{ + struct task *new_task = kmalloc(sizeof(struct task)); + new_task->cpu_context.lr = new_task->cpu_context.sp = new_task->cpu_context.fp = 0; + new_task->kernel_stack = NULL; + new_task->user_stack = NULL; + new_task->user_prog = NULL; + new_task->user_prog_size = 0; + new_task->state = TASK_INIT; + new_task->pid = task_count++; + new_task->need_resched = 0; + new_task->exitcode = 0; + new_task->timeout = get_current_time() + DEFAULT_TIMEOUT; + new_task->signal = NULL; + new_task->sig_context = NULL; + new_task->ttbr0 = NULL; + return new_task; +} + +struct task *pick_next_task() +{ + if (list_empty(&running_queue)) + { + while (1) + { + }; + } + struct task *next_task = list_first_entry(&running_queue, struct task, list); + unlink(&next_task->list); + insert_tail(&running_queue, &next_task->list); + + return next_task; +} + +void switch_task(struct task *next) +{ + if (current == next) + { + return; + } + switch_to(¤t->cpu_context, &next->cpu_context); + replace_page_table(); +} + +struct task *get_task(pid_t target) +{ + struct task *_task; + list_for_each_entry(_task, &running_queue, list) + { + if (_task->pid == target) + { + return _task; + } + } + return NULL; +} \ No newline at end of file diff --git a/lab6/src/shell.c b/lab6/src/shell.c new file mode 100644 index 000000000..e4394aeb4 --- /dev/null +++ b/lab6/src/shell.c @@ -0,0 +1,226 @@ +#include "shell.h" +#include "mini_uart.h" +#include "utils_c.h" +#include "utils_s.h" +#include "peripheral/mailbox.h" +#include "_cpio.h" +#include "exception_c.h" +#include "timer.h" +#include "dtb.h" +#include "mm.h" +#include "exec.h" +#include "thread.h" +#include +#define BUFFER_MAX_SIZE 256u +#define COMMNAD_LENGTH_MAX 20u + +extern void *_dtb_ptr; + +int split(const char *buf, char *outbuf[], int n) +{ + const char *ps, *pe; + int idx = 0; + ps = pe = buf; + + while (idx < n) + { + while (*pe && *pe != ' ') + { + pe++; + } + + int size = pe - ps; + if (size) + { + outbuf[idx] = kmalloc(size + 1); + memcpy(outbuf[idx], ps, size); + outbuf[idx][size] = '\0'; + idx++; + } + + if (*pe) + { + while (*pe == ' ') + pe++; + ps = pe; + } + else + { + break; + } + } + + return idx; +} + +void read_command(char *buffer) +{ + size_t index = 0; + while (1) + { + buffer[index] = uart_recv(); + uart_send(buffer[index]); + if (buffer[index] == '\n') + { + break; + } + index++; + } + buffer[index + 1] = '\0'; + utils_newline2end(buffer); + uart_send('\r'); +} + +void parse_arg(char *buffer, int *argi) +{ + int i = 0; + int argi_index = 0; + argi[argi_index] = i; + while (buffer[i] != '\0') + { + if (buffer[i] == ' ') + { + buffer[i] = '\0'; + argi[++argi_index] = ++i; + continue; + } + i++; + } +} + +void help() +{ + uart_send_string("help :"); + uart_send_string("print this help menu\n"); + uart_send_string("hello :"); + uart_send_string("print Hello World!\n"); + uart_send_string("reboot : "); + uart_send_string("reboot the device\n"); + uart_send_string("info : "); + uart_send_string("the mailbox hardware info\n"); + uart_send_string("ls : "); + uart_send_string("list the all file\n"); + uart_send_string("cat : "); + uart_send_string("print the file content\n"); + uart_send_string("dtb : "); + uart_send_string("print the device name tree \n"); + uart_send_string("async : "); + uart_send_string("test uart async send and recv\n"); + uart_send_string("set : "); + uart_send_string("set the timeout (set message second)\n"); + uart_send_string("buddy : "); + uart_send_string("test the page allocate and free\n"); + uart_send_string("dynamic : "); + uart_send_string("test the dynamic memory simple_allocator\n"); +} + +void hello() +{ + uart_send_string("Hello World!\n"); +} + +void info() +{ + get_board_revision(); + // get_arm_memory(); +} + +void parse_command(char *buffer) +{ + // int argi[BUFFER_MAX_SIZE]; + if (utils_str_compare(buffer, "") == 0) + { + return; + } + else if (utils_str_compare(buffer, "help") == 0) + { + help(); + } + else if (utils_str_compare(buffer, "hello") == 0) + { + hello(); + } + else if (utils_str_compare(buffer, "ls") == 0) + { + cpio_ls(); + } + else if (utils_str_compare(buffer, "cat") == 0) + { + uart_send_string("Filename: "); + char buffer[BUFFER_MAX_SIZE]; + read_command(buffer); + cpio_cat(buffer); + } + else if (utils_str_compare(buffer, "exe") == 0) + { + exe_new_prog("user2.img"); + } + else if (utils_str_compare(buffer, "wtf") == 0) + { + uart_printf("Current task count :%d\n",get_the_cur_count()); + } + else if (utils_str_compare(buffer, "thread") == 0) + { + test_thread(); + uart_async_send_string("exit the test_thread\n"); + } + else if (utils_str_compare(buffer, "reboot") == 0) + { + uart_send_string("rebooting...\n"); + reset(1000); + } + else if (utils_str_compare(buffer, "info") == 0) + { + info(); + } + else if (utils_str_compare(buffer, "dtb") == 0) + { + fdt_traverse(print_dtb); + } + + else if (utils_str_compare(buffer, "async") == 0) + { + test_uart_async(); + } + else if (utils_strncmp(buffer, "set", 3) == 0) + { + char *args[3]; + split(buffer, args, 3); + unsigned long time = (unsigned long)utils_str2uint_dec(args[2]); + set_timeout(args[1], S(time)); + } + else if (utils_str_compare(buffer, "buddy") == 0) + { + test_buddy(); + } + else if (utils_str_compare(buffer, "dynamic") == 0) + { + test_dynamic_alloc(); + } + else + { + uart_send_string("commnad '"); + uart_send_string(buffer); + uart_send_string("' not found\n"); + } +} + +void clear_buffer(char *buf) +{ + for (int i = 0; i < BUFFER_MAX_SIZE; i++) + { + buf[i] = '\0'; + } +} + +void shell() +{ + while (1) + { + char buffer[BUFFER_MAX_SIZE]; + clear_buffer(buffer); + uart_send_string("$ "); + read_command(buffer); + parse_command(buffer); + } +} \ No newline at end of file diff --git a/lab6/src/signal.c b/lab6/src/signal.c new file mode 100644 index 000000000..1b46aa58b --- /dev/null +++ b/lab6/src/signal.c @@ -0,0 +1,63 @@ +#include "signal.h" +#include "sche.h" +#include "current.h" +#include "mm.h" +#include "trap_frame.h" +#include "mini_uart.h" +#include "utils_c.h" + +static void sig_ignore(int _) +{ + return; +} +void sigkill_handler(int target) +{ + if (current->pid == target) + { + kill_task(current, target); + return; + } + struct task *victim = get_task(target); + if (victim) + { + kill_task(victim, 0); + } +} +void sig_return(void) +{ + asm volatile( + "mov x8, 10\n" + "svc 0\n"); +} + +void sig_context_update(TrapFrame *_regs, void (*handler)()) +{ + struct signal_context *sig_context = kmalloc(sizeof(struct signal_context)); + sig_context->trapframe = kmalloc(sizeof(TrapFrame)); + sig_context->user_stack = kmalloc(STACK_SIZE); + memcpy(sig_context->trapframe, _regs, sizeof(TrapFrame)); + + current->sig_context = sig_context; + + _regs->regs[30] = (unsigned long)&sig_return; + _regs->pc = (unsigned long)handler; + _regs->sp = (unsigned long)sig_context->user_stack + STACK_SIZE - 0x10; +} + +void sig_context_restore(TrapFrame *_regs) +{ + memcpy(_regs, current->sig_context->trapframe, sizeof(TrapFrame)); +} + +signal_handler signal_table[] = { + [0] = &sig_ignore, + [1] = &sig_ignore, + [2] = &sig_ignore, + [3] = &sig_ignore, + [4] = &sig_ignore, + [5] = &sig_ignore, + [6] = &sig_ignore, + [7] = &sig_ignore, + [8] = &sig_ignore, + [SIGKILL] = &sigkill_handler, +}; \ No newline at end of file diff --git a/lab6/src/sprintf.c b/lab6/src/sprintf.c new file mode 100644 index 000000000..246748b62 --- /dev/null +++ b/lab6/src/sprintf.c @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +/** + * minimal sprintf implementation + */ +#include "../include/sprintf.h" + +unsigned int vsprintf(char *dst, char* fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig=dst, tmpstr[19]; + + // failsafes + if(dst==(void*)0 || fmt==(void*)0) { + return 0; + } + + // main loop + arg = 0; + while(*fmt) { + // argument access + if(*fmt=='%') { + fmt++; + // literal % + if(*fmt=='%') { + goto put; + } + len=0; + // size modifier + while(*fmt>='0' && *fmt<='9') { + len *= 10; + len += *fmt-'0'; + fmt++; + } + // skip long modifier + if(*fmt=='l') { + fmt++; + } + // character + if(*fmt=='c') { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } else + // decimal number + if(*fmt=='d') { + arg = __builtin_va_arg(args, int); + // check input + sign=0; + if((int)arg<0) { + arg*=-1; + sign++; + } + if(arg>99999999999999999L) { + arg=99999999999999999L; + } + // convert to string + i=18; + tmpstr[i]=0; + do { + tmpstr[--i]='0'+(arg%10); + arg/=10; + } while(arg!=0 && i>0); + if(sign) { + tmpstr[--i]='-'; + } + // padding, only space + if(len>0 && len<18) { + while(i>18-len) { + tmpstr[--i]=' '; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // hex number + if(*fmt=='x') { + arg = __builtin_va_arg(args, long int); + // convert to string + i=16; + tmpstr[i]=0; + do { + char n=arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i]=n+(n>9?0x37:0x30); + arg>>=4; + } while(arg!=0 && i>0); + // padding, only leading zeros + if(len>0 && len<=16) { + while(i>16-len) { + tmpstr[--i]='0'; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // string + if(*fmt=='s') { + p = __builtin_va_arg(args, char*); +copystring: if(p==(void*)0) { + p="(null)"; + } + while(*p) { + *dst++ = *p++; + } + } + } else { +put: *dst++ = *fmt; + } + fmt++; + } + *dst=0; + // number of bytes written + return dst-orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char* fmt, ...) +{ + //__builtin_va_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst,fmt,args); +} \ No newline at end of file diff --git a/lab6/src/syscall.c b/lab6/src/syscall.c new file mode 100644 index 000000000..fd77772e5 --- /dev/null +++ b/lab6/src/syscall.c @@ -0,0 +1,151 @@ +#include "syscall.h" +#include "stddef.h" +#include "trap_frame.h" +#include "current.h" +#include "peripheral/mailbox.h" +#include "mini_uart.h" +#include "signal.h" +#include "exec.h" +#include "exception_c.h" +#include "mm.h" +#include "fork.h" + +void sys_getpid(TrapFrame *_regs) +{ + _regs->regs[0] = current->pid; +} +void sys_uartrecv(TrapFrame *_regs) +{ + char *buf = (char *)_regs->regs[0]; + int count = _regs->regs[1]; + for (int i = 0; i < count; i++) + { + buf[i] = uart_recv(); + } + _regs->regs[0] = count; +} +void sys_uartwrite(TrapFrame *_regs) +{ + char *buf = (char *)_regs->regs[0]; + int count = _regs->regs[1]; + for (int i = 0; i < count; i++) + { + uart_send(buf[i]); + } + _regs->regs[0] = count; +} +void sys_exec(TrapFrame *_regs) +{ + const char *path = (char *)_regs->regs[0]; + const char **args = (const char **)_regs->regs[1]; + _regs->regs[0] = do_exec(path, args); +} +void sys_fork(TrapFrame *_regs) +{ + _regs->regs[0] = do_fork(_regs); +} +void sys_exit(TrapFrame *_regs) +{ + kill_task(current, _regs->regs[0]); +} +void sys_mbox_call(TrapFrame *_regs) +{ + unsigned int channel = _regs->regs[0]; + unsigned int *mailbox_va = (unsigned int *)_regs->regs[1]; + + void *mailbox_pa = (unsigned int *)el0_va2pa((unsigned long)mailbox_va); + mailbox_call(channel, mailbox_pa); +} +void sys_kill_pid(TrapFrame *_regs) +{ + pid_t target = _regs->regs[0]; + if (current->pid == target) + { + kill_task(current, target); + return; + } + struct task *victim = get_task(target); + if (victim) + { + kill_task(victim, 0); + } +} +void sys_signal(TrapFrame *_regs) +{ + int sig_num = _regs->regs[0]; + signal_handler _hand = (signal_handler)_regs->regs[1]; + + struct signal *new_signal = kmalloc(sizeof(struct signal)); + new_signal->sig_num = sig_num; + new_signal->handler = _hand; + new_signal->list.next = new_signal->list.prev = &new_signal->list; + + if (!current->signal) + { + current->signal = new_signal; + } + else + { + insert_tail(¤t->signal->list, &new_signal->list); + } +} + +void sys_sigkill(TrapFrame *_regs) +{ + int target = _regs->regs[0]; + int SIGNAL = _regs->regs[1]; + int is_find = 0; + if (current->signal) + { + struct signal *cur = current->signal; + do + { + if (cur->sig_num == SIGNAL) + { + is_find = 1; + sig_context_update(_regs, cur->handler); + break; + } + cur = list_entry(cur->list.next, struct signal, list); + } while (cur != current->signal); + } + else if (!current->signal && !is_find) + { + (signal_table[SIGNAL])(target); + } +} +void sys_sigreturn(TrapFrame *_regs) +{ + sig_context_restore(_regs); + + disable_interrupt(); + kfree(current->sig_context->trapframe); + kfree(current->sig_context->user_stack); + kfree(current->sig_context); + current->sig_context = NULL; + enable_interrupt(); +} +syscall syscall_table[NUM_syscalls] = { + [SYS_GETPID] = &sys_getpid, + [SYS_UART_RECV] = &sys_uartrecv, + [SYS_UART_WRITE] = &sys_uartwrite, + [SYS_EXEC] = &sys_exec, + [SYS_FORK] = &sys_fork, + [SYS_EXIT] = &sys_exit, + [SYS_MBOX] = &sys_mbox_call, + [SYS_KILL_PID] = &sys_kill_pid, + [SYS_SIGNAL] = &sys_signal, + [SYS_SIGKILL] = &sys_sigkill, + [SYS_SIGRETURN] = &sys_sigreturn, +}; + +void syscall_handler(TrapFrame *_regs) +{ + unsigned int sys_index = _regs->regs[8]; + if (sys_index >= NUM_syscalls) + { + uart_send_string("!!! Invalid system call !!!\n"); + return; + } + (syscall_table[sys_index])(_regs); +} diff --git a/lab6/src/thread.c b/lab6/src/thread.c new file mode 100644 index 000000000..b647e65c0 --- /dev/null +++ b/lab6/src/thread.c @@ -0,0 +1,76 @@ +#include "thread.h" +#include "mini_uart.h" +#include "timer.h" +#include "sche.h" +#include "list.h" +#include "mm.h" +#include "exception_c.h" +#include "current.h" +#include "trap_frame.h" + +void thread_kill_zombies() +{ + unsigned long flags = disable_irq(); + while (!list_empty(&stopped_queue)) + { + struct task *victim = list_first_entry(&stopped_queue, struct task, list); + unlink(&victim->list); + free_task(victim); + } + irq_restore(flags); +} + +void thread_schedule(size_t _) +{ + if (!current->need_resched) + { + return; + } + + unsigned long flags = disable_irq(); + struct task *next = pick_next_task(); + next->need_resched = 0; + irq_restore(flags); + + switch_task(next); +} + +void thread_init() +{ + struct task *init = create_task(); + set_thread_ds(init); // init the thread structure +} + +static void foo() +{ + for (int i = 0; i < 5; ++i) + { + uart_printf("Thread id: %d i=%d\n", current->pid, i); + // sleep_task(500); + delay(1000000); + } + kill_task(current, 0); + thread_schedule(0); +} + +struct task *thread_create(void *func) +{ + struct task *new_thread = create_task(); + new_thread->kernel_stack = kmalloc(STACK_SIZE); + new_thread->state = TASK_RUNNING; + new_thread->cpu_context.lr = (unsigned long)func; + new_thread->cpu_context.sp = (unsigned long)new_thread->kernel_stack + STACK_SIZE - sizeof(TrapFrame); + + add_task(new_thread); + + return new_thread; +} + +void test_thread() +{ + for (int i = 0; i < 3; ++i) + { + thread_create(&foo); + } + uart_printf("end of test_thread\n"); +} diff --git a/lab6/src/timer.c b/lab6/src/timer.c new file mode 100644 index 000000000..a17bc0ccd --- /dev/null +++ b/lab6/src/timer.c @@ -0,0 +1,155 @@ +#include "timer.h" +#include "utils_s.h" +#include "mm.h" +#include "mini_uart.h" +#include "utils_c.h" +#include "thread.h" +#include "exception_c.h" +#include "current.h" + +timeout_event *timeout_queue_head = 0, *timeout_queue_tail = 0; +void core_timer_enable() +{ + /* + cntpct_el0 >= cntp_cval_el0 -> interrupt + cntp_tval_el0 = cntpct_el0 - cntp_cval_el0 + */ + write_sysreg(cntp_ctl_el0, 1); // enable + unsigned long frq = read_sysreg(cntfrq_el0) / 1000; + write_sysreg(cntp_tval_el0, frq * MS(SCHE_CYCLE)); // set expired time + *CORE0_TIMER_IRQ_CTRL = 2; // unmask timer interrupt +} + +void core_timer_disable() +{ + write_sysreg(cntp_ctl_el0, 0); // disable + *CORE0_TIMER_IRQ_CTRL = 0; // mask timer interrupt +} + +void set_expired_time(unsigned long duration) +{ + unsigned long frq = read_sysreg(cntfrq_el0) / 1000; + write_sysreg(cntp_tval_el0, frq * MS(duration)); // ms +} + +unsigned long get_current_time() +{ + // cntpct_el0: The timer’s current count. + unsigned long frq = read_sysreg(cntfrq_el0) / 1000; + unsigned long current_count = read_sysreg(cntpct_el0); + return (unsigned long)(current_count / frq); +} + +void set_timeout(char *message, unsigned long time) +{ + add_timer((timer_callback)print_message, (size_t)message, time); +} + +void print_message(char *msg) +{ + unsigned long current_time = get_current_time(); + uart_printf("\ncurrent time : %d.%ds\n", GET_S(current_time), GET_MS(current_time)); +} + +void timeout_event_init() +{ + timeout_queue_head = 0; + timeout_queue_tail = 0; + unsigned long cntkctl_el1; + cntkctl_el1 = read_sysreg(CNTKCTL_EL1); + cntkctl_el1 |= 1; + write_sysreg(CNTKCTL_EL1, cntkctl_el1); +} + +void add_timer(void (*cb)(size_t), size_t arg, unsigned long duration) +{ + timeout_event *new_event = (timeout_event *)kmalloc(sizeof(timeout_event)); + new_event->register_time = get_current_time(); + new_event->duration = duration; + new_event->callback = cb; + new_event->arg = arg; + new_event->next = 0; + new_event->prev = 0; + + size_t flag = disable_irq(); + if (timeout_queue_head == 0) + { + timeout_queue_head = new_event; + timeout_queue_tail = new_event; + core_timer_enable(); + set_expired_time(duration); + } + else + { + unsigned long timeout = new_event->register_time + new_event->duration; + timeout_event *cur = timeout_queue_head; + while (cur) + { + if ((cur->register_time + cur->duration) > timeout) + break; + cur = cur->next; + } + + if (cur == 0) + { // cur at end + new_event->prev = timeout_queue_tail; + timeout_queue_tail->next = new_event; + timeout_queue_tail = new_event; + } + else if (cur->prev == 0) + { // cur at head + new_event->next = cur; + (timeout_queue_head)->prev = new_event; + timeout_queue_head = new_event; + set_expired_time(duration); + } + else + { // cur at middle + new_event->next = cur; + new_event->prev = cur->prev; + (cur->prev)->next = new_event; + cur->prev = new_event; + } + } + irq_restore(flag); +} + +static inline void set_resched(unsigned long current_time) +{ + if (current_time >= current->timeout) + { + current->need_resched = 1; + } +} + +void timer_handler() +{ + unsigned long current_time = get_current_time(); + timeout_event *cur_event = timeout_queue_head; + timeout_event *next_event = cur_event->next; + if (next_event) + { + next_event->prev = 0; + timeout_queue_head = next_event; + set_expired_time(next_event->register_time + next_event->duration - current_time); + } + else + { + timeout_queue_head = timeout_queue_tail = 0; + core_timer_disable(); + } + + if (cur_event->callback == (timer_callback)&thread_schedule) + { + set_resched(current_time); + add_timer((timer_callback)thread_schedule, (size_t)0, MS(SCHE_CYCLE)); + enable_interrupt(); + thread_schedule(0); + disable_interrupt(); + } + else if (cur_event->callback) + { + cur_event->callback(cur_event->arg); + } + kfree(cur_event); +} \ No newline at end of file diff --git a/lab6/src/trans_el.S b/lab6/src/trans_el.S new file mode 100644 index 000000000..066bc1c7a --- /dev/null +++ b/lab6/src/trans_el.S @@ -0,0 +1,9 @@ +.globl from_el2_to_el1 +from_el2_to_el1: + mov x0, (1 << 31) // EL1 uses aarch64 + msr hcr_el2, x0 + mov x0, 0x3c5 // EL1h (SPSel = 1) with interrupt disabled + msr spsr_el2, x0 + msr elr_el2, lr + eret // return to EL1 + \ No newline at end of file diff --git a/lab6/src/utils_c.c b/lab6/src/utils_c.c new file mode 100644 index 000000000..2608a7c5d --- /dev/null +++ b/lab6/src/utils_c.c @@ -0,0 +1,176 @@ +#include "utils_c.h" +#include "mini_uart.h" +#include + +/* + string part +*/ + +int utils_str_compare(const char *a, const char *b) +{ + char aa, bb; + do + { + aa = (char)*a++; + bb = (char)*b++; + if (aa == '\0' || bb == '\0') + { + return aa - bb; + } + } while (aa == bb); + return aa - bb; +} + +int utils_strncmp(const char *a, const char *b, size_t n) +{ + size_t i = 0; + while (i < n - 1 && a[i] == b[i] && a[i] != '\0' && b[i] != '\0') + i++; + return a[i] - b[i]; +} +void utils_newline2end(char *str) +{ + while (*str != '\0') + { + if (*str == '\n') + { + *str = '\0'; + return; + } + ++str; + } +} + +void utils_int2str_dec(int num, char *str) +{ + // num=7114 digit=4 + int digit = -1, temp = num; + while (temp > 0) + { + temp /= 10; + digit++; + } + for (int i = digit; i >= 0; i--) + { + int t = 1; + for (int j = 0; j < i; j++) + { + t *= 10; + } + *str = '0' + num / t; + num = num % t; + str++; + } + *str = '\0'; +} + +void utils_uint2str_dec(unsigned int num, char *str) +{ + // num=7114 digit=4 + unsigned int temp = num; + int digit = -1; + while (temp > 0) + { + temp /= 10; + digit++; + } + for (int i = digit; i >= 0; i--) + { + int t = 1; + for (int j = 0; j < i; j++) + { + t *= 10; + } + *str = '0' + num / t; + num = num % t; + str++; + } + *str = '\0'; +} + +unsigned int utils_str2uint_dec(const char *str) +{ + unsigned int value = 0u; + + while (*str) + { + value = value * 10u + (*str - '0'); + ++str; + } + return value; +} + +size_t utils_strlen(const char *s) +{ + size_t i = 0; + while (s[i]) + i++; + return i + 1; +} + +/* + reboot part +*/ + +void set(long addr, unsigned long value) +{ + volatile unsigned int *point = (unsigned int *)addr; + *point = value; +} + +void reset(int tick) +{ // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick +} + +void cancel_reset() +{ + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} + +/* + others +*/ + +void align(void *size, size_t s) +{ + unsigned int *x = (unsigned int *)size; + if ((*x) & (s - 1)) + { + (*x) += s - ((*x) & (s - 1)); + } +} + +uint32_t align_up(uint32_t size, int alignment) +{ + return (size + alignment - 1) & -alignment; +} + +void delay(unsigned int clock) +{ + while (clock--) + { + asm volatile("nop"); + } +} + +void memcpy(void *dst, const void *src, size_t n) +{ + char *_dst = dst; + const char *_src = src; + + while (n--) + { + *_dst++ = *_src++; + } +} + +void *memset(void *s, int c, size_t n) { + char *p = s; + for (size_t i = 0; i < n; i++) { + p[i] = c; + } + return s; +} \ No newline at end of file diff --git a/lab6/src/utils_s.S b/lab6/src/utils_s.S new file mode 100644 index 000000000..2db1bb5ab --- /dev/null +++ b/lab6/src/utils_s.S @@ -0,0 +1,34 @@ +.global branchAddr +branchAddr: + br x0 + + +.globl get_el +get_el: + mrs x0, CurrentEl + lsr x0, x0, #2 + ret + +.global switch_to +switch_to: + + mov x9, sp + stp x19, x20, [x0, #0x0] + stp x21, x22, [x0, #0x10] + stp x23, x24, [x0, #0x20] + stp x25, x26, [x0, #0x30] + stp x27, x28, [x0, #0x40] + stp fp, x9, [x0, #0x50] + str lr, [x0, #0x60] + + ldp x19, x20, [x1, #0x0] + ldp x21, x22, [x1, #0x10] + ldp x23, x24, [x1, #0x20] + ldp x25, x26, [x1, #0x30] + ldp x27, x28, [x1, #0x40] + ldp fp, x9, [x1, #0x50] + ldr lr, [x1, #0x60] + mov sp, x9 + msr tpidr_el1, x1 + ret + diff --git a/lab6/users/user1/linker.ld b/lab6/users/user1/linker.ld new file mode 100644 index 000000000..bac8da058 --- /dev/null +++ b/lab6/users/user1/linker.ld @@ -0,0 +1,26 @@ +SECTIONS +{ + .start : { + *(.start) + } + + _stext = .; + .text : { + *(.text) + *(.rodata) + } + . = ALIGN(0x1000); + _etext = .; + + _sdata = .; + .data : { *(.data) } + . = ALIGN(0x1000); + _edata = .; + + + _sbss = .; + .bss : { *(.bss*) } + . = ALIGN(0x1000); + _ebss = .; + +} \ No newline at end of file diff --git a/lab6/users/user1/main.c b/lab6/users/user1/main.c new file mode 100644 index 000000000..4a8ceeea0 --- /dev/null +++ b/lab6/users/user1/main.c @@ -0,0 +1,286 @@ +#include +#include + +#define SYS_GETPID 0 +#define SYS_UART_RECV 1 +#define SYS_UART_WRITE 2 +#define SYS_EXEC 3 +#define SYS_FORK 4 +#define SYS_EXIT 5 +#define SYS_MBOX_CALL 6 +#define SYS_KILL_PID 7 + +int start(void) __attribute__((section(".start"))); + +unsigned long syscall(unsigned long syscall_num, + void *x0, + void *x1, + void *x2, + void *x3, + void *x4, + void *x5) +{ + unsigned long result; + + asm volatile( + "ldr x8, %0\n" + "ldr x0, %1\n" + "ldr x1, %2\n" + "ldr x2, %3\n" + "ldr x3, %4\n" + "ldr x4, %5\n" + "ldr x5, %6\n" + "svc 0\n" ::"m"(syscall_num), + "m"(x0), "m"(x1), + "m"(x2), "m"(x3), "m"(x4), "m"(x5)); + + asm volatile( + "str x0, %0\n" + : "=m"(result)); + + return result; +} +/* system call */ +int getpid() +{ + return (int)syscall(SYS_GETPID, 0, 0, 0, 0, 0, 0); +} + +void uart_recv(const char buf[], size_t size) +{ + syscall(SYS_UART_RECV, (void *)buf, (void *)size, 0, 0, 0, 0); +} + +void uart_write(const char buf[], size_t size) +{ + syscall(SYS_UART_WRITE, (void *)buf, (void *)size, 0, 0, 0, 0); +} + +void exit(void) +{ + syscall(SYS_EXIT, 0, 0, 0, 0, 0, 0); +} +void kill_pid(unsigned long pid) +{ + syscall(SYS_KILL_PID, (void *)pid, 0, 0, 0, 0, 0); +} +void mailbox_call(unsigned char ch, unsigned int *mbox) +{ + syscall(SYS_MBOX_CALL, (void *)(unsigned long)ch, mbox, 0, 0, 0, 0); +} +void exec(const char *name, char *const argv[]) +{ + syscall(SYS_EXEC, (void *)name, (void *)argv, 0, 0, 0, 0); +} + +/* normal function */ + +static void uart_send(char c) +{ + uart_write(&c, 1); +} + +void uart_send_string(const char *str) +{ + while (*str) + { + uart_send(*str++); + } +} + +unsigned int vsprintf(char *dst, char *fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig = dst, tmpstr[19]; + + // failsafes + if (dst == (void *)0 || fmt == (void *)0) + { + return 0; + } + + // main loop + arg = 0; + while (*fmt) + { + // argument access + if (*fmt == '%') + { + fmt++; + // literal % + if (*fmt == '%') + { + goto put; + } + len = 0; + // size modifier + while (*fmt >= '0' && *fmt <= '9') + { + len *= 10; + len += *fmt - '0'; + fmt++; + } + // skip long modifier + if (*fmt == 'l') + { + fmt++; + } + // character + if (*fmt == 'c') + { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } + else + // decimal number + if (*fmt == 'd') + { + arg = __builtin_va_arg(args, int); + // check input + sign = 0; + if ((int)arg < 0) + { + arg *= -1; + sign++; + } + if (arg > 99999999999999999L) + { + arg = 99999999999999999L; + } + // convert to string + i = 18; + tmpstr[i] = 0; + do + { + tmpstr[--i] = '0' + (arg % 10); + arg /= 10; + } while (arg != 0 && i > 0); + if (sign) + { + tmpstr[--i] = '-'; + } + // padding, only space + if (len > 0 && len < 18) + { + while (i > 18 - len) + { + tmpstr[--i] = ' '; + } + } + p = &tmpstr[i]; + goto copystring; + } + else + // hex number + if (*fmt == 'x') + { + arg = __builtin_va_arg(args, long int); + // convert to string + i = 16; + tmpstr[i] = 0; + do + { + char n = arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i] = n + (n > 9 ? 0x37 : 0x30); + arg >>= 4; + } while (arg != 0 && i > 0); + // padding, only leading zeros + if (len > 0 && len <= 16) + { + while (i > 16 - len) + { + tmpstr[--i] = '0'; + } + } + p = &tmpstr[i]; + goto copystring; + } + else + // string + if (*fmt == 's') + { + p = __builtin_va_arg(args, char *); + copystring: + if (p == (void *)0) + { + p = "(null)"; + } + while (*p) + { + *dst++ = *p++; + } + } + } + else + { + put: + *dst++ = *fmt; + } + fmt++; + } + *dst = 0; + // number of bytes written + return dst - orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char *fmt, ...) +{ + //__builtin_va_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst, fmt, args); +} +unsigned int uart_printf(char *fmt, ...) +{ + char dst[100]; + // __builtin_va_start(args, fmt): "..." is pointed by args + // __builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + unsigned int ret = vsprintf(dst, fmt, args); + uart_send_string(dst); + return ret; +} + +#define MAILBOX_CH_PROP 8 +#define REQUEST_CODE 0x00000000 +#define GET_BOARD_REVISION 0x00010002 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + + +unsigned int __attribute__((aligned(16))) mailbox[8]; + + +unsigned int get_board_revision() +{ + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = END_TAG; + + mailbox_call(MAILBOX_CH_PROP, mailbox); // message passing procedure call, you should implement it following the 6 steps provided above. + return mailbox[5]; +} + +int start(void) +{ + int pid = getpid(); + uart_printf("[User1] pid:%d\n", pid); + + exit(); + return 0; +} diff --git a/lab6/users/user2/linker.ld b/lab6/users/user2/linker.ld new file mode 100644 index 000000000..bac8da058 --- /dev/null +++ b/lab6/users/user2/linker.ld @@ -0,0 +1,26 @@ +SECTIONS +{ + .start : { + *(.start) + } + + _stext = .; + .text : { + *(.text) + *(.rodata) + } + . = ALIGN(0x1000); + _etext = .; + + _sdata = .; + .data : { *(.data) } + . = ALIGN(0x1000); + _edata = .; + + + _sbss = .; + .bss : { *(.bss*) } + . = ALIGN(0x1000); + _ebss = .; + +} \ No newline at end of file diff --git a/lab6/users/user2/main.c b/lab6/users/user2/main.c new file mode 100644 index 000000000..f685335a3 --- /dev/null +++ b/lab6/users/user2/main.c @@ -0,0 +1,305 @@ +#include +#include + +#define SYS_GETPID 0 +#define SYS_UART_RECV 1 +#define SYS_UART_WRITE 2 +#define SYS_EXEC 3 +#define SYS_FORK 4 +#define SYS_EXIT 5 +#define SYS_MBOX_CALL 6 +#define SYS_KILL_PID 7 + +int start(void) __attribute__((section(".start"))); + +unsigned long syscall(unsigned long syscall_num, + void *x0, + void *x1, + void *x2, + void *x3, + void *x4, + void *x5) +{ + unsigned long result; + + asm volatile( + "ldr x8, %0\n" + "ldr x0, %1\n" + "ldr x1, %2\n" + "ldr x2, %3\n" + "ldr x3, %4\n" + "ldr x4, %5\n" + "ldr x5, %6\n" + "svc 0\n" ::"m"(syscall_num), + "m"(x0), "m"(x1), + "m"(x2), "m"(x3), "m"(x4), "m"(x5)); + + asm volatile( + "str x0, %0\n" + : "=m"(result)); + + return result; +} +/* system call */ +int getpid() +{ + return (int)syscall(SYS_GETPID, 0, 0, 0, 0, 0, 0); +} + +void uart_recv(const char buf[], size_t size) +{ + syscall(SYS_UART_RECV, (void *)buf, (void *)size, 0, 0, 0, 0); +} + +void uart_write(const char buf[], size_t size) +{ + syscall(SYS_UART_WRITE, (void *)buf, (void *)size, 0, 0, 0, 0); +} + +void exit(void) +{ + syscall(SYS_EXIT, 0, 0, 0, 0, 0, 0); +} +void kill_pid(unsigned long pid) +{ + syscall(SYS_KILL_PID, (void *)pid, 0, 0, 0, 0, 0); +} +void mailbox_call(unsigned char ch, unsigned int *mbox) +{ + syscall(SYS_MBOX_CALL, (void *)(unsigned long)ch, mbox, 0, 0, 0, 0); +} +void exec(const char *name, char *const argv[]) +{ + syscall(SYS_EXEC, (void *)name, (void *)argv, 0, 0, 0, 0); +} +int fork(void) +{ + return (int)syscall(SYS_FORK, 0, 0, 0, 0, 0, 0); +} +/* normal function */ + +static void uart_send(char c) +{ + uart_write(&c, 1); +} + +void uart_send_string(const char *str) +{ + while (*str) + { + uart_send(*str++); + } +} + +unsigned int vsprintf(char *dst, char *fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig = dst, tmpstr[19]; + + // failsafes + if (dst == (void *)0 || fmt == (void *)0) + { + return 0; + } + + // main loop + arg = 0; + while (*fmt) + { + // argument access + if (*fmt == '%') + { + fmt++; + // literal % + if (*fmt == '%') + { + goto put; + } + len = 0; + // size modifier + while (*fmt >= '0' && *fmt <= '9') + { + len *= 10; + len += *fmt - '0'; + fmt++; + } + // skip long modifier + if (*fmt == 'l') + { + fmt++; + } + // character + if (*fmt == 'c') + { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } + else + // decimal number + if (*fmt == 'd') + { + arg = __builtin_va_arg(args, int); + // check input + sign = 0; + if ((int)arg < 0) + { + arg *= -1; + sign++; + } + if (arg > 99999999999999999L) + { + arg = 99999999999999999L; + } + // convert to string + i = 18; + tmpstr[i] = 0; + do + { + tmpstr[--i] = '0' + (arg % 10); + arg /= 10; + } while (arg != 0 && i > 0); + if (sign) + { + tmpstr[--i] = '-'; + } + // padding, only space + if (len > 0 && len < 18) + { + while (i > 18 - len) + { + tmpstr[--i] = ' '; + } + } + p = &tmpstr[i]; + goto copystring; + } + else + // hex number + if (*fmt == 'x') + { + arg = __builtin_va_arg(args, long int); + // convert to string + i = 16; + tmpstr[i] = 0; + do + { + char n = arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i] = n + (n > 9 ? 0x37 : 0x30); + arg >>= 4; + } while (arg != 0 && i > 0); + // padding, only leading zeros + if (len > 0 && len <= 16) + { + while (i > 16 - len) + { + tmpstr[--i] = '0'; + } + } + p = &tmpstr[i]; + goto copystring; + } + else + // string + if (*fmt == 's') + { + p = __builtin_va_arg(args, char *); + copystring: + if (p == (void *)0) + { + p = "(null)"; + } + while (*p) + { + *dst++ = *p++; + } + } + } + else + { + put: + *dst++ = *fmt; + } + fmt++; + } + *dst = 0; + // number of bytes written + return dst - orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char *fmt, ...) +{ + //__builtin_va_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst, fmt, args); +} +unsigned int uart_printf(char *fmt, ...) +{ + char dst[100]; + // __builtin_va_start(args, fmt): "..." is pointed by args + // __builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + unsigned int ret = vsprintf(dst, fmt, args); + uart_send_string(dst); + return ret; +} + +#define MAILBOX_CH_PROP 8 +#define REQUEST_CODE 0x00000000 +#define GET_BOARD_REVISION 0x00010002 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +// unsigned int __attribute__((aligned(16))) mailbox[8]; +unsigned int get_board_revision() +{ + unsigned int __attribute__((aligned(16))) mailbox[8]; + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = END_TAG; + mailbox_call(MAILBOX_CH_PROP, &mailbox[0]); // message passing procedure call, you should implement it following the 6 steps provided above. + return mailbox[5]; +} + +int start(void) +{ + // char buf1[0x10] = {0}; + uart_printf("[User2] Into start\n"); + int pid = getpid(); + + uart_printf("[User2] pid:%d\n", pid); + + unsigned int revision = get_board_revision(); + uart_printf("[User2] Revision: %x\n", revision); + + pid = fork(); + + if (pid == 0) + { + uart_printf("[User2] child: exec user1.img\r\n"); + exec("user1.img", NULL); + } + else + { + uart_printf("[User2] parent: child pid: %d\n", pid); + } + uart_printf("[User2 ] exit\n"); + + exit(); + return 0; +} diff --git a/lab7/Makefile b/lab7/Makefile new file mode 100644 index 000000000..785c198a1 --- /dev/null +++ b/lab7/Makefile @@ -0,0 +1,106 @@ +CFLAG = -Iinclude -Wall -ffreestanding -fno-stack-protector -nostdlib -nostartfiles -mgeneral-regs-only +K8=kernel8 +BL=bootloader +LINKER=linker.ld +START=start +CPIO:=archive/initramfs.cpio +TA_CPIO:=archive/TA/initramfs.cpio +TA_IMG:=archive/TA/vfs1.img + +DTB:=archive/bcm2710-rpi-3-b-plus.dtb +USER_DIR:=users/user +USER1:=user1 +USER2:=user2 +BUILD:=build/ + +BUILD_ELF:=$(shell find build/ -name '*.elf') +BUILD_IMG:=$(shell find build/ -name '*.img') +ARC_ROOTFS_IMG:=$(shell find archive/rootfs -name '*.img') + +SRC_C:=$(shell find src/ -name '*.c') +SRC_S:=$(shell find src/ -name '*.S') + +KER_C:=$(shell find kernel/ -name '*.c') +KER_S:=$(shell find kernel/ -name '*.S') + +BL_C:=$(shell find bootloader/ -name '*.c') +BL_S:=$(shell find bootloader/ -name '*.S') + +USER1_C:=$(shell find users/user1/ -name '*.c') +USER1_OBJS:= $(USER1_C:%.c=%.o) + +USER2_C:=$(shell find users/user2/ -name '*.c') +USER2_OBJS:= $(USER2_C:%.c=%.o) + +OBJS:= $(SRC_C:%.c=%.o) \ + $(SRC_S:%.S=%.o) \ + + +KERNEL_OBJS:=$(KER_C:%.c=%.o) \ + $(KER_S:%.S=%.o) + + + +BL_OBJS:=$(BL_C:%.c=%.o) \ + $(BL_S:%.S=%.o) \ + src/mini_uart.o src/utils_c.o src/utils_s.o src/memzero.o src/sprintf.o + + + + +all: $(BUILD)$(USER1).img\ + $(BUILD)$(USER2).img \ + $(BUILD)$(K8).img \ + $(BUILD)$(BL).img \ + rd.o + + + +rd.o:$(CPIO) + aarch64-linux-gnu-ld -r -b binary -o rd.o $(CPIO) + + +%.o: %.S + aarch64-linux-gnu-gcc -g -o $@ -c $< + +%.o: %.c + aarch64-linux-gnu-gcc -g -o $@ $(CFLAG) -c $< + + +$(BUILD)$(K8).img: $(OBJS) $(KERNEL_OBJS) + aarch64-linux-gnu-ld -T kernel/$(LINKER) -o $(BUILD)$(K8).elf $^ + aarch64-linux-gnu-objcopy -O binary $(BUILD)$(K8).elf $@ + +$(BUILD)$(BL).img: $(BL_OBJS) + aarch64-linux-gnu-ld -T bootloader/$(LINKER) -o $(BUILD)$(BL).elf $^ + aarch64-linux-gnu-objcopy -O binary $(BUILD)$(BL).elf $@ + +$(BUILD)$(USER1).img:$(USER1_OBJS) + aarch64-linux-gnu-ld -T $(USER_DIR)1/$(LINKER) -o $(BUILD)$(USER1).elf $< + aarch64-linux-gnu-objcopy -O binary $(BUILD)$(USER1).elf $@ + cp $@ archive/rootfs/ + +$(BUILD)$(USER2).img:$(USER2_OBJS) + aarch64-linux-gnu-ld -T $(USER_DIR)2/$(LINKER) -o $(BUILD)$(USER2).elf $< + aarch64-linux-gnu-objcopy -O binary $(BUILD)$(USER2).elf $@ + cp $@ archive/rootfs/ + +$(CPIO): + cp $(TA_IMG) archive/rootfs + cd archive/rootfs&&find . | cpio -o -H newc > ../initramfs.cpio + +on: + sudo screen /dev/ttyUSB0 115200 +qe: $(BUILD)$(K8).img + qemu-system-aarch64 -M raspi3 -kernel $< \ + -display none \ + -serial null -serial stdio -s \ + -initrd $(CPIO) \ + -dtb $(DTB) \ + +clean: + $(RM) $(BUILD_ELF) $(CPIO) \ + $(OBJS) $(KERNEL_OBJS) $(BL_OBJS) $(USER1_OBJS) $(USER2_OBJS)\ + $(ARC_ROOTFS_IMG) \ + $(BUILD_IMG) \ + \ No newline at end of file diff --git a/lab7/ReadMe.md b/lab7/ReadMe.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/lab7/ReadMe.md @@ -0,0 +1 @@ + diff --git a/lab7/archive/TA/initramfs.cpio b/lab7/archive/TA/initramfs.cpio new file mode 100644 index 000000000..0676fb158 Binary files /dev/null and b/lab7/archive/TA/initramfs.cpio differ diff --git a/lab7/archive/TA/vfs1.img b/lab7/archive/TA/vfs1.img new file mode 100644 index 000000000..2c41bd71a Binary files /dev/null and b/lab7/archive/TA/vfs1.img differ diff --git a/lab7/archive/TA/vm.img b/lab7/archive/TA/vm.img new file mode 100644 index 000000000..8ba674e6c Binary files /dev/null and b/lab7/archive/TA/vm.img differ diff --git a/lab7/archive/bcm2710-rpi-3-b-plus.dtb b/lab7/archive/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..3934b3a26 Binary files /dev/null and b/lab7/archive/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab7/archive/rootfs/one b/lab7/archive/rootfs/one new file mode 100644 index 000000000..50ecbb596 --- /dev/null +++ b/lab7/archive/rootfs/one @@ -0,0 +1,3 @@ +1 2 3 +4 5 6 +7 8 9 diff --git a/lab7/archive/rootfs/two b/lab7/archive/rootfs/two new file mode 100644 index 000000000..599c97676 --- /dev/null +++ b/lab7/archive/rootfs/two @@ -0,0 +1,3 @@ +hello + world + !!!!! diff --git a/lab7/bootloader/linker.ld b/lab7/bootloader/linker.ld new file mode 100644 index 000000000..2efc319db --- /dev/null +++ b/lab7/bootloader/linker.ld @@ -0,0 +1,28 @@ +ENTRY(_start) +SECTIONS +{ + . = 0x60000; + _stext = .; + .text : { + *(.text.relo) + _bl_entry = .; + *(.text.boot) + *(.text) + *(.rodata) + } + . = ALIGN(0x1000); + _etext = .; + + _sdata = .; + .data : { *(.data) } + . = ALIGN(0x1000); + _edata = .; + + + _sbss = .; + .bss : { *(.bss*) } + . = ALIGN(0x1000); + _ebss = .; + + _blsize = _ebss - _stext; +} diff --git a/lab7/bootloader/main.c b/lab7/bootloader/main.c new file mode 100644 index 000000000..a18076e82 --- /dev/null +++ b/lab7/bootloader/main.c @@ -0,0 +1,48 @@ +#include "mini_uart.h" +#include "utils_c.h" +#include "utils_s.h" +#include +#define BUFFER_MAX_SIZE 256u + +extern char *_dtb; +void load_img() +{ + char * kernel_addr = (char *)0x80000; + uart_send_string("Please sent the kernel image size:"); + char buffer[BUFFER_MAX_SIZE]; + // read_command(buffer); + size_t index = 0; + while (1) + { + buffer[index] = uart_recv(); + uart_send(buffer[index]); + if (buffer[index] == '\n') + { + break; + } + index++; + } + buffer[index + 1] = '\0'; + utils_newline2end(buffer); + uart_send('\r'); + unsigned int img_size = utils_str2uint_dec(buffer); + uart_send_string("Start to load the kernel image... \n"); + + unsigned char *current = (unsigned char *)kernel_addr; + while (img_size--) + { + *current = uart_recv_raw(); + current++; + uart_send('.'); + } + uart_send_string("loading...\n"); + // branchAddr(kernel_addr); + ((void (*)(char *))kernel_addr)(_dtb); +} + +void bootloader_main(void) +{ + uart_init(); + uart_send_string("In bootloader_main!\n"); + load_img(); +} \ No newline at end of file diff --git a/lab7/bootloader/start.S b/lab7/bootloader/start.S new file mode 100644 index 000000000..549ee4109 --- /dev/null +++ b/lab7/bootloader/start.S @@ -0,0 +1,46 @@ +.section ".text.relo" +.globl _start + +# need to relocate the bootloader from 0x80000 to 0x60000 +_start: + adr x10, . //x10=0x80000 + ldr x11, =_blsize + add x11, x11, x10 + ldr x12, =_stext // x12=0x60000 + +moving_relo: + cmp x10, x11 //without bootloader + b.eq end_relo + ldr x13, [x10] + str x13, [x12] //move 0x80000 data to 0x60000 + add x12, x12, #8 + add x10, x10, #8 + b moving_relo +end_relo: + ldr x14, =_bl_entry //jump to boot part + br x14 + + +.section ".text.boot" +.globl _start_bl + ldr x20, =_dtb + str x0, [x20] + mrs x20, mpidr_el1 + and x20, x20,#0xFF // Check processor id + cbz x20, master // Hang for all non-primary CPU + +hang: + b hang + +master: + adr x20, _sbss + adr x21, _ebss + sub x21, x21, x20 + bl memzero + + mov sp, #0x400000 // 4MB + bl bootloader_main + +.global _dtb +.section .data +_dtb: .dc.a 0x0 diff --git a/lab7/include/_cpio.h b/lab7/include/_cpio.h new file mode 100644 index 000000000..52e4fd260 --- /dev/null +++ b/lab7/include/_cpio.h @@ -0,0 +1,33 @@ +#ifndef __CPIO_H +#define __CPIO_H +#include +#include "mmu.h" + +/* + cpio archive comprises a header record with basic numeric metadata followed by + the full pathname of the entry and the file data. +*/ +typedef struct 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. +} cpio_header; + +void cpio_ls(); +void cpio_cat(const char *filename); +char *findFile(const char *name); +size_t cpio_load_program(const char *filename, void **put_addr, pd_t *table); +#endif \ No newline at end of file diff --git a/lab7/include/current.h b/lab7/include/current.h new file mode 100644 index 000000000..9cc1e993a --- /dev/null +++ b/lab7/include/current.h @@ -0,0 +1,16 @@ +#ifndef _CURRENT_H +#define _CURRENT_H + +#include "thread.h" + +static inline struct task *get_thread_ds() +{ + return (struct task *)read_sysreg(tpidr_el1); +} +static inline void set_thread_ds(struct task *cur) +{ + write_sysreg(tpidr_el1, cur); +} +#define current get_thread_ds() + +#endif diff --git a/lab7/include/dtb.h b/lab7/include/dtb.h new file mode 100644 index 000000000..461f32cbe --- /dev/null +++ b/lab7/include/dtb.h @@ -0,0 +1,39 @@ +#ifndef _DTB_H +#define _DTB_H +#include +#include +/* + structure block: located at a 4-byte aligned offset from the beginning of the devicetree blob + token is a big-endian 32-bit integer, alligned on 32bit(padding 0) + +*/ + +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + +typedef struct fdt_header +{ + uint32_t magic; // contain the value 0xd00dfeed (big-endian). + uint32_t totalsize; // in byte + uint32_t off_dt_struct; // the offset in bytes of the structure block from the beginning of the header + 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; // the length in bytes of the strings block section + uint32_t size_dt_struct; +} fdt_header; + +typedef void (*fdt_callback)(int type, const char *name, const void *data, uint32_t size); +void print_dtb(int type, const char *name, const void *data, uint32_t size); +void get_initramfs_addr(int type, const char *name, const void *data, uint32_t size); +int fdt_traverse(fdt_callback cb); + +extern uintptr_t dtb_end, dtb_start; +extern char *initramfs_start, *initramfs_end; + +#endif \ No newline at end of file diff --git a/lab7/include/exception_c.h b/lab7/include/exception_c.h new file mode 100644 index 000000000..c47caa49c --- /dev/null +++ b/lab7/include/exception_c.h @@ -0,0 +1,17 @@ +#ifndef _EXCEPTION_C_H +#define _EXCEPTION_C_H +#include +#include "trap_frame.h" +typedef void (*task_callback)(void *); + +void enable_interrupt(); +void disable_interrupt(); +unsigned long disable_irq(); +void irq_restore(unsigned long flag); + +void default_handler(); +void lower_sync_handler(TrapFrame *_regs); +void irq_handler(); +void curr_sync_handler(); + +#endif diff --git a/lab7/include/exception_s.h b/lab7/include/exception_s.h new file mode 100644 index 000000000..fd2409595 --- /dev/null +++ b/lab7/include/exception_s.h @@ -0,0 +1,6 @@ +#ifndef _EXCEPTION_S_H +#define _EXCEPTION_S_H + +void restore_regs_eret(); + +#endif diff --git a/lab7/include/exec.h b/lab7/include/exec.h new file mode 100644 index 000000000..2676c33ae --- /dev/null +++ b/lab7/include/exec.h @@ -0,0 +1,7 @@ +#ifndef __EXEC_H_ +#define __EXEC_H_ + +void exe_new_prog(char *filename); +int do_exec(const char *path, const char *argv[]); + +#endif \ No newline at end of file diff --git a/lab7/include/fork.h b/lab7/include/fork.h new file mode 100644 index 000000000..3fa7d5d3b --- /dev/null +++ b/lab7/include/fork.h @@ -0,0 +1,8 @@ +#ifndef __FORK_H_ +#define __FORK_H_ +#include +#include "trap_frame.h" + +size_t do_fork(TrapFrame *regs); + +#endif \ No newline at end of file diff --git a/lab7/include/initramfs.h b/lab7/include/initramfs.h new file mode 100644 index 000000000..85a29fee2 --- /dev/null +++ b/lab7/include/initramfs.h @@ -0,0 +1,10 @@ +#ifndef __INITRAM_FS_H +#define __INITRAM_FS_H + +struct filesystem *initramfs_create(); +struct vnode* vnode_create(const char *name, unsigned int flags); + +extern struct file_operations initramfs_f_ops; +extern struct vnode_operations initramfs_v_ops; + +#endif diff --git a/lab7/include/list.h b/lab7/include/list.h new file mode 100644 index 000000000..0f886e233 --- /dev/null +++ b/lab7/include/list.h @@ -0,0 +1,45 @@ +#ifndef __LIST_H +#define __LIST_H +#include +#include + +typedef struct list +{ + struct list *next, *prev; +} list; + +#define container_of(ptr, type, member) ({ \ + void *__mptr = (void *)(ptr); \ + ((type *)(__mptr - offsetof(type, member))); }) + +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +#define list_for_each_entry(entry, head, member) \ + for (entry = list_entry((head)->next, __typeof__(*entry), member); \ + &entry->member != (head); \ + entry = list_entry(entry->member.next, __typeof__(*entry), member)) + +#define LIST_HEAD_INIT(name) \ + { \ + &(name), &(name) \ + } + +static inline int list_empty(const list *head) +{ + return head->next == head; +} + +void list_init(list *node); +void insert_head(list *head, list *v); +void insert_tail(list *head, list *v); +list *remove_head(list *head); +list *remove_tail(list *head); +void unlink(list *node); +#endif diff --git a/lab7/include/mini_uart.h b/lab7/include/mini_uart.h new file mode 100644 index 000000000..2c17055b3 --- /dev/null +++ b/lab7/include/mini_uart.h @@ -0,0 +1,22 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + + +void delay(unsigned int clock); +void enable_uart_interrupt(); +void disable_uart_interrupt(); +void uart_init(); +void uart_send_string(const char* str); +void uart_send(const char c); +char uart_recv(); +char uart_recv_raw(); +void uart_hex(unsigned int d); +void uart_dec(unsigned int num); +void uart_handler(); +void test_uart_async(); +char uart_async_recv(); +void uart_async_send_string(char *str); +void uart_async_send(char c); + +unsigned int uart_printf(char* fmt, ...); +#endif \ No newline at end of file diff --git a/lab7/include/mm.h b/lab7/include/mm.h new file mode 100644 index 000000000..0294a50af --- /dev/null +++ b/lab7/include/mm.h @@ -0,0 +1,47 @@ +#ifndef _MM_H +#define _MM_H + +#include +#include + +#define STARTUP_MEM_START (PHYS_OFFSET + 0x07000000) +#define STARTUP_MEM_END (PHYS_OFFSET + 0x07ffffff) + +typedef struct FrameFlag +{ + unsigned char flag; + unsigned char order; + unsigned short ref_count; + unsigned char chunk_order; +} FrameFlag; + +typedef struct Chunk +{ + struct Chunk *next; +} Chunk; + +// buddy system +void init_buddy(); +void *alloc_pages(unsigned int pages); +void free_pages(void *victim); + +// dynamic mem allocate +void *kmalloc(unsigned int size); +void *kcalloc(unsigned int size); +void kfree(void *ptr); + +// test +void test_buddy(); +void test_dynamic_alloc(); + +// others +void memory_reserve(uintptr_t start, uintptr_t end); +void mm_init(); +void merge_useful_pages(); + +// start up allocation +void *smalloc(size_t size); + + +#endif + diff --git a/lab7/include/mmu.h b/lab7/include/mmu.h new file mode 100644 index 000000000..02159b620 --- /dev/null +++ b/lab7/include/mmu.h @@ -0,0 +1,53 @@ +#ifndef __MMU_H_ +#define __MMU_H_ + +#include "exception_c.h" +typedef unsigned long pd_t; + +#define PHYS_OFFSET 0xffff000000000000 +#define PAR_PA_MASK 0xffffffff000L + +#define PAGE_SIZE 0x1000 +#define USTACK_VA 0xffffffffb000 +#define STACK_SIZE 0x4000 +#define UPROG_VA 0x0 + +#define PD_TABLE 0b11 +#define PD_BLOCK 0b01 +#define PD_PAGE 0b11 +#define PD_ACCESS (1 << 10) +#define PD_USER_RW (0b01 << 6) +#define PD_USER_R (0b11 << 6) +#define PD_UXN (1L << 54) +#define PD_PXN (1L << 53) + +// #define pa2va(p) (((unsigned long)(p + PHYS_OFFSET))) +// #define va2pa(p) (((unsigned long)(p - PHYS_OFFSET))) + +static inline void *pa2va(unsigned long p) +{ + return (void *)(p + PHYS_OFFSET); +} + +static inline unsigned long va2pa(void *p) +{ + return (unsigned long)p - PHYS_OFFSET; +} + +#define IDENTITY_TT_L0 ((pd_t *)0x1000L) +#define IDENTITY_TT_L1 ((pd_t *)0x2000L) +#define IDENTITY_TT_L0_VA ((pd_t *)pa2va(0x1000L)) +#define IDENTITY_TT_L1_VA ((pd_t *)pa2va(0x2000L)) + +void setup_identity_mapping(); +void setup_kernel_space_mapping(); +void map_page(pd_t *table, unsigned long va, unsigned long pa, unsigned long flags); +void *alloc_stack(pd_t *table, unsigned long size); +void *alloc_prog(pd_t *table, unsigned long size, const char *file_content); +void setup_peripheral_identity(pd_t *table); +unsigned long get_pte(unsigned long va); +unsigned long el0_va2pa(unsigned long va); +void free_page_table(pd_t *table); +void replace_page_table(); + +#endif diff --git a/lab7/include/peripheral/base.h b/lab7/include/peripheral/base.h new file mode 100644 index 000000000..d9c9422a5 --- /dev/null +++ b/lab7/include/peripheral/base.h @@ -0,0 +1,9 @@ +#ifndef _PERIPHERAL_BASE_H +#define _PERIPHERAL_BASE_H + +#include "mmu.h" + +#define MMIO_BASE PHYS_OFFSET + 0x3F000000 +#define MAILBOX_BASE MMIO_BASE + 0xb880 + +#endif \ No newline at end of file diff --git a/lab7/include/peripheral/gpio.h b/lab7/include/peripheral/gpio.h new file mode 100644 index 000000000..8246c40ae --- /dev/null +++ b/lab7/include/peripheral/gpio.h @@ -0,0 +1,12 @@ +#ifndef _PERIPHERAL_GPIO_H +#define _PERIPHERAL_GPIO_H + +#include "peripheral/base.h" + +#define GPFSEL1 ((volatile unsigned int *)(MMIO_BASE+0x00200004)) +#define GPSET0 ((volatile unsigned int *)(MMIO_BASE+0x0020001C)) +#define GPCLR0 ((volatile unsigned int *)(MMIO_BASE+0x00200028)) +#define GPPUD ((volatile unsigned int *)(MMIO_BASE+0x00200094)) +#define GPPUDCLK0 ((volatile unsigned int *)(MMIO_BASE+0x00200098)) + +#endif \ No newline at end of file diff --git a/lab7/include/peripheral/mailbox.h b/lab7/include/peripheral/mailbox.h new file mode 100644 index 000000000..fc26769a9 --- /dev/null +++ b/lab7/include/peripheral/mailbox.h @@ -0,0 +1,36 @@ +#ifndef _MAILBOX_H +#define _MAILBOX_H + +#include "peripheral/base.h" + +#define MAILBOX_READ ((volatile unsigned int *)(MAILBOX_BASE)) +#define MAILBOX_STATUS ((volatile unsigned int *)(MAILBOX_BASE + 0x18)) +#define MAILBOX_WRITE ((volatile unsigned int *)(MAILBOX_BASE + 0x20)) + +#define MAILBOX_EMPTY 0x40000000 +#define MAILBOX_FULL 0x80000000 +#define MAILBOX_RESPONSE 0x80000000 +#define ARM_MEMORY 0x00010005 + +#define GET_BOARD_REVISION 0x00010002 +#define REQUEST_CODE 0x00000000 +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +#define MAILBOX_CH_POWER 0 +#define MAILBOX_CH_FB 1 +#define MAILBOX_CH_VUART 2 +#define MAILBOX_CH_VCHIQ 3 +#define MAILBOX_CH_LEDS 4 +#define MAILBOX_CH_BTNS 5 +#define MAILBOX_CH_TOUCH 6 +#define MAILBOX_CH_COUNT 7 +#define MAILBOX_CH_PROP 8 + +unsigned int mailbox_call(unsigned char channel, unsigned int *_mailbox); +unsigned int get_board_revision(); +void get_arm_memory(); + +#endif \ No newline at end of file diff --git a/lab7/include/peripheral/mini_uart.h b/lab7/include/peripheral/mini_uart.h new file mode 100644 index 000000000..0ac714e1c --- /dev/null +++ b/lab7/include/peripheral/mini_uart.h @@ -0,0 +1,30 @@ +#ifndef _PERIPHERAL_MINI_UART_H +#define _PERIPHERAL_MINI_UART_H + +#include "peripheral/base.h" + +#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)) + + + +#define ARM_IRQ_REG_BASE ((volatile unsigned int*)(MMIO_BASE + 0x0000b000)) +#define IRQ_PENDING_1 ((volatile unsigned int*)(MMIO_BASE + 0x0000b204)) +#define ENB_IRQS1 ((volatile unsigned int*)(MMIO_BASE + 0x0000b210)) +#define DISABLE_IRQS1 ((volatile unsigned int*)(MMIO_BASE + 0x0000b21c)) +#define AUX_IRQ (1 << 29) + + + + +#endif \ No newline at end of file diff --git a/lab7/include/sche.h b/lab7/include/sche.h new file mode 100644 index 000000000..e3cb851d7 --- /dev/null +++ b/lab7/include/sche.h @@ -0,0 +1,67 @@ +#ifndef __SCHE_H +#define __SCHE_H +#include "list.h" +#include "signal.h" +#include "mmu.h" +#include "vfs.h" + +typedef unsigned long pid_t; +typedef enum +{ + TASK_RUNNING, + TASK_WAITING, + TASK_STOPPED, + TASK_INIT, +} state_t; + +struct cpu_context +{ + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + unsigned long fp; + unsigned long sp; + unsigned long lr; +}; + +struct task +{ + struct cpu_context cpu_context; + char *kernel_stack; + char *user_stack; + char *user_prog; + size_t user_prog_size; + state_t state; + pid_t pid; + unsigned need_resched; + int exitcode; + unsigned long timeout; + list list; + struct signal *signal; + struct signal_context *sig_context; + pd_t *ttbr0; + struct vnode *pwd; + struct file *fd_table[FD_TABLE_SIZE]; +}; + +extern list running_queue, waiting_queue, stopped_queue; +void add_task(struct task *t); +void kill_task(struct task *_task, int status); +void restart_task(struct task *_task); +void pause_task(struct task *_task); +void sleep_task(size_t ms); +void free_task(struct task *victim); +struct task *create_task(); +void switch_task(struct task *next); +struct task *pick_next_task(); +int get_the_cur_count(); +struct task *get_task(pid_t target); +extern pid_t task_count; +#endif \ No newline at end of file diff --git a/lab7/include/shell.h b/lab7/include/shell.h new file mode 100644 index 000000000..08f251990 --- /dev/null +++ b/lab7/include/shell.h @@ -0,0 +1,7 @@ +#ifndef _SHELL_H +#define _SHELL_H + +void shell(); +void read_command(char *str); +void parse_command(char *str); +#endif \ No newline at end of file diff --git a/lab7/include/signal.h b/lab7/include/signal.h new file mode 100644 index 000000000..768e13b87 --- /dev/null +++ b/lab7/include/signal.h @@ -0,0 +1,27 @@ +#ifndef __SIGNAL_H +#define __SIGNAL_H + +#define SIGKILL 9 + +#include "list.h" +#include "trap_frame.h" +#define SIG_NUM (sizeof(signal_table) / sizeof(signal_table[0])) +typedef void (*signal_handler)(int); + +struct signal +{ + unsigned int sig_num; + signal_handler handler; + struct list list; +}; +struct signal_context +{ + TrapFrame *trapframe; + char *user_stack; +}; + +extern signal_handler signal_table[]; + +void sig_context_update(TrapFrame *_regs, void (*handler)()); +void sig_context_restore(TrapFrame *_regs); +#endif diff --git a/lab7/include/sprintf.h b/lab7/include/sprintf.h new file mode 100644 index 000000000..a7c47f848 --- /dev/null +++ b/lab7/include/sprintf.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +#ifndef __SPRINT_H +#define __SPRINT_H + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); + +#endif \ No newline at end of file diff --git a/lab7/include/stat.h b/lab7/include/stat.h new file mode 100644 index 000000000..c910dd761 --- /dev/null +++ b/lab7/include/stat.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __STAT_H +#define __STAT_H + +#define S_IFMT 00170000 +#define S_IFSOCK 0140000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFBLK 0060000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFIFO 0010000 +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define S_ISVTX 0001000 + +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) + +#define S_IRWXU 00700 +#define S_IRUSR 00400 +#define S_IWUSR 00200 +#define S_IXUSR 00100 + +#define S_IRWXG 00070 +#define S_IRGRP 00040 +#define S_IWGRP 00020 +#define S_IXGRP 00010 + +#define S_IRWXO 00007 +#define S_IROTH 00004 +#define S_IWOTH 00002 +#define S_IXOTH 00001 + +#endif \ No newline at end of file diff --git a/lab7/include/syscall.h b/lab7/include/syscall.h new file mode 100644 index 000000000..8b43f759e --- /dev/null +++ b/lab7/include/syscall.h @@ -0,0 +1,36 @@ +#ifndef __SYSCALL_H +#define __SYSCALL_H + +#include "trap_frame.h" + +#define _STR(x) #x +#define STR(s) _STR(s) + +typedef void (*syscall)(TrapFrame *); + +enum { + SYS_GETPID, //0 + SYS_UART_RECV, + SYS_UART_WRITE, + SYS_EXEC, + SYS_FORK, + SYS_EXIT, //5 + SYS_MBOX, + SYS_KILL_PID, + SYS_SIGNAL, + SYS_SIGKILL, + SYS_SIGRETURN, //10 + SYS_OPEN, + SYS_CLOSE, + SYS_WRITE, + SYS_READ, + SYS_MKDIR, //15 + SYS_MOUNT, + SYS_CHDIR, + NUM_syscalls +}; + +extern syscall syscall_table[]; +void syscall_handler(TrapFrame *regs); + +#endif \ No newline at end of file diff --git a/lab7/include/thread.h b/lab7/include/thread.h new file mode 100644 index 000000000..59d238278 --- /dev/null +++ b/lab7/include/thread.h @@ -0,0 +1,13 @@ +#ifndef _THREAD_H +#define _THREAD_H +#include "list.h" +#include "utils_s.h" +#include "sche.h" +#define STACK_SIZE 0x4000 + +void thread_kill_zombies(); +void thread_schedule(size_t _); +void thread_init(); +struct task *thread_create(void *func); +void test_thread(); +#endif diff --git a/lab7/include/timer.h b/lab7/include/timer.h new file mode 100644 index 000000000..cd987ec6d --- /dev/null +++ b/lab7/include/timer.h @@ -0,0 +1,39 @@ +#ifndef __TIMER_H +#define __TIMER_H +#include "stddef.h" +#include "mmu.h" +#define CORE0_TIMER_IRQ_CTRL ((volatile unsigned int *)(PHYS_OFFSET + 0x40000040)) +#define CORE0_INTERRUPT_SOURCE ((volatile unsigned int *)(PHYS_OFFSET + 0x40000060)) +#define DEFAULT_TIMEOUT 30LL +#define SCHE_CYCLE 30LL +#define SYSTEM_TIMER_MSG "system_timeout" +#define S(n) (n * 1000LL) +#define MS(n) (n * 1LL) +#define GET_S(n) (n / 1000LL) +#define GET_MS(n) (n % 1000LL) + +typedef void (*timer_callback)(size_t); + +void core_timer_enable(); +void core_timer_disable(); +void set_expired_time(unsigned long duration); +unsigned long get_current_time(); +void core_timer_handler(); +void set_timeout(char *message, unsigned long time); +void print_message(char *msg); +void add_timer(void (*cb)(size_t), size_t arg, unsigned long duraction); +void timeout_event_init(); +void timer_handler(); + +typedef struct timeout_event +{ + unsigned long register_time; + unsigned long duration; + timer_callback callback; + size_t arg; + struct timeout_event *prev, *next; +} timeout_event; + +extern timeout_event *timeout_queue_head, *timeout_queue_tail; + +#endif diff --git a/lab7/include/tmpfs.h b/lab7/include/tmpfs.h new file mode 100644 index 000000000..71b66766a --- /dev/null +++ b/lab7/include/tmpfs.h @@ -0,0 +1,10 @@ +#ifndef __TMPFS_H_ +#define __TMPFS_H_ + +#define COMPONENT_SIZE 16 +struct filesystem *tmpfs_create(); +struct vnode* vnode_create(const char *name, unsigned int flags); + +extern struct file_operations tmpfs_f_ops; +extern struct vnode_operations tmpfs_v_ops; +#endif \ No newline at end of file diff --git a/lab7/include/trap_frame.h b/lab7/include/trap_frame.h new file mode 100644 index 000000000..593c45d50 --- /dev/null +++ b/lab7/include/trap_frame.h @@ -0,0 +1,12 @@ +#ifndef __TRAP_FRAME_H +#define __TRAP_FRAME_H + +typedef struct +{ + unsigned long regs[31]; // general purpose regs x0~x30 + unsigned long sp; // sp_el0 + unsigned long pc; // elr_el1 + unsigned long pstate; // spsr_el1 +}TrapFrame; + +#endif \ No newline at end of file diff --git a/lab7/include/utils_c.h b/lab7/include/utils_c.h new file mode 100644 index 000000000..16e3f9d24 --- /dev/null +++ b/lab7/include/utils_c.h @@ -0,0 +1,33 @@ +#ifndef _UTILS_C_H +#define _UTILS_C_H +#include +#include +#include "mmu.h" +#define PM_PASSWORD (PHYS_OFFSET + 0x5a000000) +#define PM_RSTC (PHYS_OFFSET + 0x3F10001c) +#define PM_WDOG (PHYS_OFFSET + 0x3F100024) + + +/* string */ +int utils_str_compare(const char *a, const char *b); +int utils_strncmp(const char *a, const char *b, size_t n); +void utils_newline2end(char *str); +char utils_int2char(int a); +void utils_int2str_dec(int a, char *str); +void utils_uint2str_dec(unsigned int num, char *str); +unsigned int utils_str2uint_dec(const char *str); +void align(void *size, size_t s); // aligned to 4 byte +size_t utils_strlen(const char *s); +uint32_t align_up(uint32_t size, int alignment); + +/* reboot */ +void set(long addr, unsigned long value); +void reset(int tick); +void cancel_reset(); + +/* others */ +void delay(unsigned int clock); +void memcpy(void *dst, const void *src, size_t n); +void *memset(void *s, int c, size_t n); + +#endif diff --git a/lab7/include/utils_s.h b/lab7/include/utils_s.h new file mode 100644 index 000000000..6f5a01825 --- /dev/null +++ b/lab7/include/utils_s.h @@ -0,0 +1,41 @@ +#ifndef __UTILS_S_H +#define __UTILS_S_H + +#define read_sysreg(r) ({ \ + unsigned long __val; \ + asm volatile("mrs %0, " #r \ + : "=r"(__val)); \ + __val; \ +}) + +#define write_sysreg(r, __val) ({ \ + asm volatile("msr " #r ", %0" ::"r"(__val)); \ +}) + +#define read_gpreg(r) ({ \ + unsigned long __val; \ + asm volatile("mov %0, " #r \ + : "=r"(__val)); \ + __val; \ +}) + +#define write_gpreg(r, __val) ({ \ + asm volatile("mov " #r ", %0" ::"r"(__val)); \ +}) + + +// EC,bits[31:26] +#define ESR_ELx_EC(esr) ((esr & 0xFC000000) >> 26) +// ISS,bits[24:0] +#define ESR_ELx_ISS(esr) (esr & 0x03FFFFFF) + +#define ESR_ELx_EC_SVC64 0b010101 +#define ESR_ELx_EC_DABT_LOW 0b100100 +#define ESR_ELx_EC_IABT_LOW 0b100000 + + +void branchAddr(void *addr); +int get_el(); +void switch_to(void *, void *); + +#endif diff --git a/lab7/include/vfs.h b/lab7/include/vfs.h new file mode 100644 index 000000000..aaaa5c6b5 --- /dev/null +++ b/lab7/include/vfs.h @@ -0,0 +1,87 @@ +#ifndef __VFS_H_ +#define __VFS_H_ + +#include "stat.h" +#include "list.h" + +// #define FS_DEBUG +#define FD_TABLE_SIZE 16 +#define O_CREAT 00000100 +struct vnode +{ + struct mount *mount; + struct vnode_operations *v_ops; + struct file_operations *f_ops; + + // internal + list childs; + size_t child_num; + list self; + struct vnode *parent; + char *name; + unsigned int f_mode; + + void *content; + size_t content_size; +}; + +// file handle +struct file +{ + struct vnode *vnode; + size_t f_pos; // RW position of this file handle + struct file_operations *f_ops; + int flags; +}; + +struct mount +{ + struct vnode *root; + struct filesystem *fs; +}; + +struct filesystem +{ + const char *name; + int (*setup_mount)(struct filesystem *fs, struct mount *mount); + list list; +}; + +struct file_operations +{ + int (*write)(struct file *file, const void *buf, size_t len); + int (*read)(struct file *file, void *buf, size_t len); + int (*open)(struct vnode *file_node, struct file **target); + int (*close)(struct file *file); + long (*lseek64)(struct file *file, long offset, int whence); +}; + +struct vnode_operations +{ + int (*lookup)(struct vnode *dir_node, struct vnode **target, + const char *component_name); + int (*create)(struct vnode *dir_node, struct vnode **target, + const char *component_name); + int (*mkdir)(struct vnode *dir_node, struct vnode **target, + const char *component_name); +}; + +void fs_init(); + +int fs_register(struct filesystem *fs); +struct filesystem *fs_get(const char *name); + +int vfs_open(const char *pathname, int flags, struct file **target); +int vfs_close(struct file *file); +int vfs_write(struct file *file, const void *buf, size_t len); +int vfs_read(struct file *file, void *buf, size_t len); +int vfs_mkdir(const char *pathname); +int vfs_mount(const char *target, const char *filesystem); +int vfs_lookup(const char *pathname, struct vnode **target); +int vfs_chdir(const char *pathname); +struct vnode *vnode_create(const char *name, unsigned int flags); +void vfs_test(); + + +extern struct mount *rootfs, *initramfs; +#endif \ No newline at end of file diff --git a/lab7/kernel/exception_c.c b/lab7/kernel/exception_c.c new file mode 100644 index 000000000..5d5472def --- /dev/null +++ b/lab7/kernel/exception_c.c @@ -0,0 +1,109 @@ +#include "utils_s.h" +#include "mini_uart.h" +#include "timer.h" +#include "peripheral/mini_uart.h" +#include "exception_c.h" +#include "current.h" +#include "thread.h" +#include "syscall.h" +#define AUX_IRQ (1 << 29) + +void enable_interrupt() { asm volatile("msr DAIFClr, 0xf"); } +void disable_interrupt() { asm volatile("msr DAIFSet, 0xf"); } +unsigned long disable_irq() +{ + unsigned long flag = read_sysreg(DAIF); + disable_interrupt(); + return flag; +} +void irq_restore(unsigned long flag) +{ + write_sysreg(DAIF, flag); +} + +void default_handler() +{ + unsigned long spsr = read_sysreg(spsr_el1); + unsigned long elr = read_sysreg(elr_el1); + unsigned long esr = read_sysreg(esr_el1); + uart_printf("spsr_el1: %x\n", spsr); + uart_printf("elr_el1: %x\n", elr); + uart_printf("esr_el1: %x\n\n", esr); +} + +void lower_irq_handler() +{ + unsigned long current_time = get_current_time(); + uart_printf("After booting: %d seconds\n\n", current_time); + set_expired_time(2); +} + +int data_abort = 0; +int ins_abort = 0; +void lower_sync_handler(TrapFrame *_regs) +{ + unsigned long esr = read_sysreg(esr_el1); // cause of that exception + unsigned int ec = ESR_ELx_EC(esr); + switch (ec) + { + case ESR_ELx_EC_SVC64: + enable_interrupt(); + syscall_handler(_regs); + disable_interrupt(); + break; + case ESR_ELx_EC_DABT_LOW: + if (!data_abort) + { + data_abort = 1; + uart_send_string("in Data Abort\n"); + } + break; + case ESR_ELx_EC_IABT_LOW: + if (!ins_abort) + { + ins_abort = 1; + uart_send_string("in Instruction Abort\n"); + } + break; + default: + return; + } +} + +void irq_handler() +{ + unsigned int irq_is_pending = (*IRQ_PENDING_1 & AUX_IRQ); + unsigned int uart = (*AUX_MU_IIR_REG & 0x1) == 0; + unsigned int core_timer = (*CORE0_INTERRUPT_SOURCE & 0x2); + if (irq_is_pending && uart) + { + uart_handler(); + } + else if (core_timer) + { + timer_handler(); + } +} + +int a = 0; +void curr_sync_handler() +{ + if (!a) + { + uart_send_string("!!! in current sync handler !!!\n"); + a = 1; + } + return; +} + +void curr_fiq_handler() +{ + uart_send_string("!!! in current fiq handler !!!\n"); + return; +} + +void curr_serr_handler() +{ + uart_send_string("!!! in current serr handler !!!\n"); + return; +} diff --git a/lab7/kernel/exception_s.S b/lab7/kernel/exception_s.S new file mode 100644 index 000000000..d9b5fbecf --- /dev/null +++ b/lab7/kernel/exception_s.S @@ -0,0 +1,214 @@ +// save general registers to stack +.macro save_gp_reg + 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_gp_reg + 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 + + +// save all gp_regs and exc_regs +.macro kernel_entry el + sub sp, sp, 17 * 16 + stp x0, x1, [sp ,16 * 0] + stp x2, x3, [sp ,16 * 1] + stp x4, x5, [sp ,16 * 2] + stp x6, x7, [sp ,16 * 3] + stp x8, x9, [sp ,16 * 4] + stp x10, x11, [sp ,16 * 5] + stp x12, x13, [sp ,16 * 6] + stp x14, x15, [sp ,16 * 7] + stp x16, x17, [sp ,16 * 8] + stp x18, x19, [sp ,16 * 9] + stp x20, x21, [sp ,16 * 10] + stp x22, x23, [sp ,16 * 11] + stp x24, x25, [sp ,16 * 12] + stp x26, x27, [sp ,16 * 13] + stp x28, x29, [sp ,16 * 14] + + .if \el == 0 + mrs x0, sp_el0 + stp x30, x0, [sp, 16 * 15] + .else + str x30, [sp, 16 * 15] + .endif + + mrs x0, elr_el1 + mrs x1, spsr_el1 + stp x0, x1, [sp, 16 * 16] + + mov x0, sp +.endm + + +// load all gp_regs and exc_regs +.macro kernel_exit el + ldp x0, x1, [sp, 16 * 16] + msr elr_el1, x0 + msr spsr_el1, x1 + + .if \el ==0 + ldp x30, x0, [sp, 16 * 15] + msr sp_el0, x0 + .else + ldr x30, [sp, 16 * 15] + .endif + + ldp x28, x29, [sp ,16 * 14] + ldp x26, x27, [sp ,16 * 13] + ldp x24, x25, [sp ,16 * 12] + ldp x22, x23, [sp ,16 * 11] + ldp x20, x21, [sp ,16 * 10] + ldp x18, x19, [sp ,16 * 9] + ldp x16, x17, [sp ,16 * 8] + ldp x14, x15, [sp ,16 * 7] + ldp x12, x13, [sp ,16 * 6] + ldp x10, x11, [sp ,16 * 5] + ldp x8, x9, [sp ,16 * 4] + ldp x6, x7, [sp ,16 * 3] + ldp x4, x5, [sp ,16 * 2] + ldp x2, x3, [sp ,16 * 1] + ldp x0, x1, [sp ,16 * 0] + add sp, sp, 17 * 16 + + eret +.endm + +.global restore_regs_eret +restore_regs_eret: + bl replace_page_table + ldp x0, x1, [sp, 16 * 16] + msr elr_el1, x0 + msr spsr_el1, x1 + + ldp x30, x0, [sp, 16 * 15] + msr sp_el0, x0 + + ldp x28, x29, [sp ,16 * 14] + ldp x26, x27, [sp ,16 * 13] + ldp x24, x25, [sp ,16 * 12] + ldp x22, x23, [sp ,16 * 11] + ldp x20, x21, [sp ,16 * 10] + ldp x18, x19, [sp ,16 * 9] + ldp x16, x17, [sp ,16 * 8] + ldp x14, x15, [sp ,16 * 7] + ldp x12, x13, [sp ,16 * 6] + ldp x10, x11, [sp ,16 * 5] + ldp x8, x9, [sp ,16 * 4] + ldp x6, x7, [sp ,16 * 3] + ldp x4, x5, [sp ,16 * 2] + ldp x2, x3, [sp ,16 * 1] + ldp x0, x1, [sp ,16 * 0] + add sp, sp, 17 * 16 + + eret + + + +.macro exception_entry label + .align 7 + b \label // branch to a handler function. + +.endm + + +.global el1_vector_base + +.align 11 +el1_vector_base: + exception_entry exception_handler + exception_entry exception_handler + exception_entry exception_handler + exception_entry exception_handler + + + exception_entry _el1_curr_el_spx_sync + exception_entry _el1_curr_el_spx_irq + exception_entry _el1_curr_el_spx_fiq + exception_entry _el1_curr_el_spx_serr + + + exception_entry _el1_lower_el_aarch64_sync + exception_entry _el1_lower_el_aarch64_irq + exception_entry exception_handler + exception_entry exception_handler + + + exception_entry exception_handler + exception_entry exception_handler + exception_entry exception_handler + exception_entry exception_handler + + +_el1_lower_el_aarch64_sync: + kernel_entry 0 + bl lower_sync_handler + kernel_exit 0 + +_el1_lower_el_aarch64_irq: + kernel_entry 0 + bl irq_handler + kernel_exit 0 + +_el1_curr_el_spx_sync: + save_gp_reg + bl curr_sync_handler + load_gp_reg + eret + +_el1_curr_el_spx_irq: + kernel_entry 1 + bl irq_handler + kernel_exit 1 + +_el1_curr_el_spx_fiq: + save_gp_reg + bl curr_fiq_handler + load_gp_reg + eret + +_el1_curr_el_spx_serr: + save_gp_reg + bl curr_serr_handler + load_gp_reg + eret + +exception_handler: + save_gp_reg + bl default_handler + load_gp_reg + eret diff --git a/lab7/kernel/linker.ld b/lab7/kernel/linker.ld new file mode 100644 index 000000000..e78847942 --- /dev/null +++ b/lab7/kernel/linker.ld @@ -0,0 +1,34 @@ +_skernel = 0xffff000000080000; +_ekernel = 0xffff000000400000; +/* _skernel = 0x80000; +_ekernel = 0x400000; */ + + +ENTRY(_start) +SECTIONS +{ + . = _skernel; + + _stext = .; + .text : { + *(.text.kernel) + *(.text) + *(.rodata) + } + . = ALIGN(0x1000); + _etext = .; + + _sdata = .; + .data : { *(.data) } + . = ALIGN(0x1000); + _edata = .; + + + _sbss = .; + .bss : { *(.bss*) } + . = ALIGN(0x1000); + _ebss = .; + + . = _ekernel; + +} \ No newline at end of file diff --git a/lab7/kernel/main.c b/lab7/kernel/main.c new file mode 100644 index 000000000..a43e66b1f --- /dev/null +++ b/lab7/kernel/main.c @@ -0,0 +1,39 @@ +#include "mini_uart.h" +#include "dtb.h" +#include "exception_c.h" +#include "utils_s.h" +#include "shell.h" +#include "mm.h" +#include "timer.h" +#include "thread.h" +#include "sche.h" +#include "exec.h" +#include "mmu.h" +#include "vfs.h" + +static void idle(void) +{ + while (1) + { + thread_kill_zombies(); + thread_schedule(0); + } +} + +void kernel_main(void *_dtb_ptr) +{ + dtb_start=(uintptr_t)_dtb_ptr; + uart_send_string("Hello, world!\n"); + mm_init(); + + setup_kernel_space_mapping(); + fs_init(); + + thread_init(); + // thread_create(&shell); + exe_new_prog("/initramfs/vfs1.img"); + timeout_event_init(); + add_timer((timer_callback)thread_schedule, (size_t)0, MS(SCHE_CYCLE)); + enable_interrupt(); + idle(); +} \ No newline at end of file diff --git a/lab7/kernel/start.S b/lab7/kernel/start.S new file mode 100644 index 000000000..71473982f --- /dev/null +++ b/lab7/kernel/start.S @@ -0,0 +1,62 @@ +.section ".text.kernel" +.globl _start + +#define PA(p) (p - 0xffff000000000000) + +_start: + ldr x9, =PA(_ekernel) + mov sp, x9 + + /* store dtb pointer */ + sub sp, sp, #0x10 + str x0, [sp] + + mov x9, sp + msr sp_el1, x9 + + /* cpu id pass */ + mrs x20, mpidr_el1 + and x20, x20,#0xFF // Check processor id + cbz x20, master // Hang for all non-primary CPU + +hang: + b hang + +master: + ldr x20, =PA(_sbss) + ldr x21, =PA(_ebss) + sub x21, x21, x20 + bl memzero + + /* setup interrupt vector base */ + ldr x0, =el1_vector_base + msr vbar_el1, x0 + bl from_el2_to_el1 + + bl setup_identity_mapping + + mov x1, #0 + movk x1, #0xffff, lsl 48 + + mov x0, sp + orr x0, x0, x1 + mov sp, x0 + + mov x0, fp + orr fp, x0, x1 + + ldr x0, [sp] + orr x0, x0, x1 + + ldr x2, =_dtb_ptr + str x0, [x2] + + ldr x9, =kernel_main + br x9 + +hang2: + b hang2 + +.global _dtb_ptr +.section .data +_dtb_ptr: .dc.a 0x0 \ No newline at end of file diff --git a/lab7/loadImg/loadImg.py b/lab7/loadImg/loadImg.py new file mode 100644 index 000000000..6fb3542ce --- /dev/null +++ b/lab7/loadImg/loadImg.py @@ -0,0 +1,30 @@ +#! /usr/bin/python3 + +import os +from socket import timeout +import time +import sys +import serial +from time import sleep + +BAUD_RATE = 115200 + +def send_img(ser,kernel): + print("Please sent the kernel image size:") + kernel_size=os.stat(kernel).st_size + ser.write((str(kernel_size)+"\n").encode()) + print(ser.read_until(b"Start to load the kernel image... \r\n").decode(), end="") + + with open(kernel, "rb") as image: + while kernel_size > 0: + kernel_size -= ser.write(image.read(1)) + ser.read_until(b".") + print(ser.read_until(b"$ ").decode(), end="") + return + +if __name__ == "__main__": + ser = serial.Serial("/dev/ttyUSB0", BAUD_RATE, timeout=5) + send_img(ser,"../build/kernel8.img") + + + diff --git a/lab7/loadImg/loadImg.sh b/lab7/loadImg/loadImg.sh new file mode 100644 index 000000000..171507561 --- /dev/null +++ b/lab7/loadImg/loadImg.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +sudo chmod 666 /dev/ttyUSB0 +source ../.env/bin/activate +python3 ./loadImg.py \ No newline at end of file diff --git a/lab7/requirements.txt b/lab7/requirements.txt new file mode 100644 index 000000000..4d1aaa2b8 --- /dev/null +++ b/lab7/requirements.txt @@ -0,0 +1 @@ +pyserial==3.5 \ No newline at end of file diff --git a/lab7/src/_cpio.c b/lab7/src/_cpio.c new file mode 100644 index 000000000..6c91469c2 --- /dev/null +++ b/lab7/src/_cpio.c @@ -0,0 +1,117 @@ +#include "_cpio.h" +#include "utils_c.h" +#include "dtb.h" +#include "mini_uart.h" +#include "timer.h" +#include "mm.h" +#include "mmu.h" + +static unsigned int hex2dec(char *s) +{ + unsigned int r = 0; + for (int i = 0; i < 8; ++i) + { + if (s[i] >= '0' && s[i] <= '9') + { + r = r * 16 + s[i] - '0'; + } + else + { + r = r * 16 + s[i] - 'A' + 10; + } + } + return r; +} + +char *findFile(const char *name) +{ + char *addr = initramfs_start; + while (utils_str_compare((char *)(addr + sizeof(cpio_header)), "TRAILER!!!") != 0) + { + if ((utils_str_compare((char *)(addr + sizeof(cpio_header)), name) == 0)) + { + return addr; + } + cpio_header *header = (cpio_header *)addr; + unsigned int pathname_size = hex2dec(header->c_namesize); + unsigned int file_size = hex2dec(header->c_filesize); + unsigned int headerPathname_size = sizeof(cpio_header) + pathname_size; + + align(&headerPathname_size, 4); + align(&file_size, 4); + addr += (headerPathname_size + file_size); + } + return 0; +} +void cpio_ls() +{ + char *addr = initramfs_start; + while (utils_str_compare((char *)(addr + sizeof(cpio_header)), "TRAILER!!!") != 0) + { + cpio_header *header = (cpio_header *)addr; + unsigned int pathname_size = hex2dec(header->c_namesize); + unsigned int file_size = hex2dec(header->c_filesize); + unsigned int headerPathname_size = sizeof(cpio_header) + pathname_size; + + align(&headerPathname_size, 4); + align(&file_size, 4); + + uart_send_string(addr + sizeof(cpio_header)); // print the file name + uart_send_string("\n"); + + addr += (headerPathname_size + file_size); + } +} + +void cpio_cat(const char *filename) +{ + char *target = findFile(filename); + if (target) + { + cpio_header *header = (cpio_header *)target; + unsigned int pathname_size = hex2dec(header->c_namesize); + unsigned int file_size = hex2dec(header->c_filesize); + unsigned int headerPathname_size = sizeof(cpio_header) + pathname_size; + + align(&headerPathname_size, 4); + align(&file_size, 4); + + char *file_content = target + headerPathname_size; + for (unsigned int i = 0; i < file_size; i++) + { + uart_send(file_content[i]); // print the file content + } + uart_send_string("\n"); + } + else + { + uart_send_string("Not found the file\n"); + } +} + +size_t cpio_load_program(const char *filename, void **target_addr, pd_t *table) +{ + char *prog_addr = findFile(filename); + if (prog_addr) + { + cpio_header *header = (cpio_header *)prog_addr; + unsigned int pathname_size = hex2dec(header->c_namesize); + unsigned int file_size = hex2dec(header->c_filesize); + unsigned int headerPathname_size = sizeof(cpio_header) + pathname_size; + + align(&headerPathname_size, 4); + align(&file_size, 4); + + uart_printf("load the %s\n", prog_addr + sizeof(cpio_header)); + + char *file_content = prog_addr + headerPathname_size; + *target_addr = alloc_prog(table, file_size, file_content); + + return file_size; + } + else + { + uart_send_string("Not found the program\n"); + return -1; + } +} diff --git a/lab7/src/dtb.c b/lab7/src/dtb.c new file mode 100644 index 000000000..6c6d0528c --- /dev/null +++ b/lab7/src/dtb.c @@ -0,0 +1,143 @@ +#include "dtb.h" +#include "_cpio.h" +#include "mini_uart.h" +#include "utils_c.h" +/* + It consists of + a small header + + the memory reservation block + space(aligned) + + the structure block + space(aligned) + + the strings block + space(aligned) +*/ +int space = 0; +char *initramfs_start, *initramfs_end; + +uint32_t get_le2be_uint(const void *p) +{ + // transfer little endian to big endian + const unsigned char *bytes = p; + uint32_t res = bytes[3]; + res |= bytes[2] << 8; + res |= bytes[1] << 16; + res |= bytes[0] << 24; + return res; +} + +void send_sapce(int n) +{ + while (n--) + uart_send_string(" "); +} + +int parse_struct(fdt_callback cb, uintptr_t cur_ptr, uintptr_t strings_ptr, uint32_t totalsize) +{ + uintptr_t end_ptr = cur_ptr + totalsize; + + while (cur_ptr < end_ptr) + { + uint32_t token = get_le2be_uint((char *)cur_ptr); + cur_ptr += 4; + switch (token) + { + case FDT_BEGIN_NODE: + // uart_send_string("In FDT_BEGIN_NODE\n"); + cb(token, (char *)cur_ptr, NULL, 0); + cur_ptr += align_up(utils_strlen((char *)cur_ptr), 4); + break; + case FDT_END_NODE: + // uart_send_string("In FDT_END_NODE\n"); + cb(token, NULL, NULL, 0); + break; + case FDT_PROP: + { + // uart_send_string("In FDT_PROP\n"); + uint32_t len = get_le2be_uint((char *)cur_ptr); + cur_ptr += 4; + uint32_t nameoff = get_le2be_uint((char *)cur_ptr); + cur_ptr += 4; + cb(token, (char *)(strings_ptr + nameoff), (void *)cur_ptr, len); + cur_ptr += align_up(len, 4); + ; + break; + } + case FDT_NOP: + // uart_send_string("In FDT_NOP\n"); + cb(token, NULL, NULL, 0); + break; + case FDT_END: + // uart_send_string("In FDT_END\n"); + cb(token, NULL, NULL, 0); + return 0; + default:; + return -1; + } + } + return 0; +} + +void print_dtb(int type, const char *name, const void *data, uint32_t size) +{ + switch (type) + { + case FDT_BEGIN_NODE: + uart_send_string("\n"); + send_sapce(space); + uart_send_string(name); + uart_send_string("{\n "); + space++; + break; + + case FDT_END_NODE: + uart_send_string("\n"); + space--; + if (space > 0) + send_sapce(space); + + uart_send_string("}\n"); + break; + + case FDT_NOP: + break; + + case FDT_PROP: + send_sapce(space); + uart_send_string(name); + break; + + case FDT_END: + break; + } +} + +void get_initramfs_addr(int type, const char *name, const void *data, uint32_t size) +{ + if (type == FDT_PROP && !utils_str_compare(name, "linux,initrd-start")) + { + initramfs_start = (char *)pa2va((uintptr_t)get_le2be_uint(data)); + } + else if (type == FDT_PROP && !utils_str_compare(name, "linux,initrd-end")) + { + initramfs_end = (char *)pa2va((uintptr_t)get_le2be_uint(data)); + } +} + +uintptr_t dtb_end,dtb_start; + +int fdt_traverse(fdt_callback cb) +{ + // uart_printf("\ndtb loading at:%x\n",dtb_start); + fdt_header *header = (fdt_header *)dtb_start; + + if (get_le2be_uint(&(header->magic)) != 0xd00dfeed) + { + uart_printf("header magic ==%x != 0xd00dfeed\n",get_le2be_uint(&(header->magic))); + return -1; + } + uint32_t totalsize = get_le2be_uint(&(header->totalsize)); + uintptr_t struct_ptr = dtb_start + get_le2be_uint(&(header->off_dt_struct)); + uintptr_t strings_ptr = dtb_start + get_le2be_uint(&(header->off_dt_strings)); + parse_struct(cb, struct_ptr, strings_ptr, totalsize); + + dtb_end = dtb_start + get_le2be_uint(&(header->totalsize)); + return 0; +} diff --git a/lab7/src/exec.c b/lab7/src/exec.c new file mode 100644 index 000000000..6f91c6548 --- /dev/null +++ b/lab7/src/exec.c @@ -0,0 +1,109 @@ +#include "exec.h" +#include "_cpio.h" +#include "sche.h" +#include "mm.h" +#include "trap_frame.h" +#include "utils_c.h" +#include "current.h" +#include "thread.h" +#include "mini_uart.h" +#include "vfs.h" +#include "mmu.h" + +static void replace_user_context(void *prog, size_t data_size, pd_t *ttbr0) +{ + struct task *_task = current; + + kfree(_task->user_stack); + free_page_table(_task->ttbr0); + kfree(_task->user_prog); + + _task->user_stack = alloc_stack(ttbr0, STACK_SIZE); + + _task->user_prog = prog; + _task->user_prog_size = data_size; + + _task->ttbr0 = ttbr0; + replace_page_table(); + + TrapFrame *trapframe = (TrapFrame *)((char *)_task->kernel_stack + STACK_SIZE - sizeof(TrapFrame)); + memset(trapframe, 0, sizeof(TrapFrame)); +} + +void jump_user_prog(void *target_addr, char *kernel_sp, char *user_sp) +{ + asm volatile("mov x0, 0 \n"); + asm volatile("msr spsr_el1, x0 \n"); // daif=0 + asm volatile("msr elr_el1, %0 \n" ::"r"(target_addr)); + asm volatile("msr sp_el0, %0 \n" ::"r"(user_sp)); + if (kernel_sp) + { + asm volatile("mov sp, %0 \n" ::"r"(kernel_sp)); + } + asm volatile("eret \n"); +} + +static void init_user_prog() +{ + jump_user_prog((char *)UPROG_VA, 0, (char *)USTACK_VA + (STACK_SIZE - 0x10)); +} + +int do_exec(const char *path, const char *argv[]) +{ + pd_t *ttbr0 = kcalloc(PAGE_SIZE); + struct file *file; + if (vfs_open(path, 0, &file)) + { + uart_send_string("[do_exec] fail to lookup\n"); + } + size_t data_size = file->vnode->content_size; + if (data_size == -1) + { + uart_send_string("!! do_exec fail !!\n"); + return -1; + } + void *target_addr = alloc_prog(ttbr0, data_size, file->vnode->content); + + setup_peripheral_identity(ttbr0); + replace_user_context(target_addr, data_size, ttbr0); + jump_user_prog((char *)UPROG_VA, current->kernel_stack + STACK_SIZE - sizeof(TrapFrame), (char *)USTACK_VA + (STACK_SIZE - 0x10)); + return 0; +} + +void exe_new_prog(char *path) +{ + pd_t *ttbr0 = kcalloc(PAGE_SIZE); + setup_peripheral_identity(ttbr0); + + struct file *file; + if (vfs_open(path, 0, &file)) + { + uart_send_string("[exe_new_prog] fail to lookup\n"); + } + size_t data_size = file->vnode->content_size; + if (data_size == -1) + { + uart_send_string("[exe_new_prog] data_size==-1\n"); + return ; + } + void *target_addr = alloc_prog(ttbr0, data_size, file->vnode->content); + + struct task *prog = thread_create(init_user_prog); + + prog->user_stack = alloc_stack(ttbr0, STACK_SIZE); + + prog->user_prog = target_addr; + prog->user_prog_size = data_size; + + prog->ttbr0 = ttbr0; + + asm( + "dsb ish\n" // ensure write has completed + "msr ttbr0_el1, %0\n" // switch translation based address. + "tlbi vmalle1is\n" // invalidate all TLB entries + "dsb ish\n" // ensure completion of TLB invalidatation + "isb\n" // clear pipeline + ::"r"(ttbr0)); + + return; +} diff --git a/lab7/src/fork.c b/lab7/src/fork.c new file mode 100644 index 000000000..19751756e --- /dev/null +++ b/lab7/src/fork.c @@ -0,0 +1,47 @@ +#include "fork.h" +#include "stddef.h" +#include "sche.h" +#include "thread.h" +#include "exception_c.h" +#include "exception_s.h" +#include "utils_c.h" +#include "current.h" +#include "mm.h" + +static struct task *fork_context(TrapFrame *_regs) +{ + struct task *child = kmalloc(sizeof(struct task)); + + unsigned long flags = disable_irq(); + *child = *current; // copy the current to child entirely + child->pid = task_count++; + irq_restore(flags); + + child->need_resched = 0; + + child->ttbr0 = kcalloc(PAGE_SIZE); + child->user_stack = alloc_stack(child->ttbr0, STACK_SIZE); + memcpy(child->user_stack, current->user_stack, STACK_SIZE); + + child->kernel_stack = kcalloc(STACK_SIZE); + TrapFrame *child_trapframe = (TrapFrame *)((unsigned long)child->kernel_stack + STACK_SIZE - sizeof(TrapFrame)); + memcpy(child_trapframe, _regs, sizeof(TrapFrame)); + + child->user_prog = alloc_prog(child->ttbr0, current->user_prog_size, current->user_prog); + + setup_peripheral_identity(child->ttbr0); + + child_trapframe->regs[0] = 0; // child process : return 0 + + child->cpu_context.sp = (unsigned long)child_trapframe; + child->cpu_context.lr = (unsigned long)restore_regs_eret; + + return child; +} + +size_t do_fork(TrapFrame *_regs) +{ + struct task *child = fork_context(_regs); + add_task(child); + return child->pid; +} diff --git a/lab7/src/initramfs.c b/lab7/src/initramfs.c new file mode 100644 index 000000000..6037bfde9 --- /dev/null +++ b/lab7/src/initramfs.c @@ -0,0 +1,185 @@ +#include "initramfs.h" +#include "vfs.h" +#include "utils_c.h" +#include "mm.h" +#include "stat.h" +#include "mini_uart.h" +#include "_cpio.h" +#include "dtb.h" + +static int lookup(struct vnode *dir_node, struct vnode **target, const char *component_name); +static int create(struct vnode *dir_node, struct vnode **target, const char *component_name); +static int mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name); +struct vnode_operations initramfs_v_ops = { + lookup, + create, + mkdir, +}; + +static int write(struct file *file, const void *buf, size_t len); +static int read(struct file *file, void *buf, size_t len); +static int open(struct vnode *file_node, struct file **target); +static int close(struct file *file); +static long lseek64(struct file *file, long offset, int whence); +struct file_operations initramfs_f_ops = { + write, + read, + open, + close, + lseek64, +}; + +static unsigned int hex2dec(char *s) +{ + unsigned int r = 0; + for (int i = 0; i < 8; ++i) + { + if (s[i] >= '0' && s[i] <= '9') + { + r = r * 16 + s[i] - '0'; + } + else + { + r = r * 16 + s[i] - 'A' + 10; + } + } + return r; +} + +static int create_init(struct vnode *dir_node, struct vnode **target, const char *component_name) +{ + if (!lookup(dir_node, target, component_name)) + { + uart_printf("[create] the %s file is already exist\n", component_name); + return -1; + } + +#ifdef FS_DEBUG + uart_printf("[fs] create file:%s, parent:%s\n", component_name, dir_node->name); +#endif + + struct vnode *new_vnode = vnode_create(component_name, S_IFREG); + new_vnode->mount = dir_node->mount; + new_vnode->v_ops = dir_node->v_ops; + new_vnode->f_ops = dir_node->f_ops; + new_vnode->parent = dir_node; + + insert_tail(&dir_node->childs, &new_vnode->self); + dir_node->child_num += 1; + + *target = new_vnode; + return 0; +} + +static void init_cpio_files() +{ + struct vnode *dir = NULL; + struct vnode *target = NULL; + if (vfs_lookup("/initramfs", &dir)) + { + uart_printf("[init_cpio_files] fail to lookup dir\n"); + } + + char *addr = initramfs_start; + while (utils_str_compare((char *)(addr + sizeof(cpio_header)), "TRAILER!!!") != 0) + { + cpio_header *header = (cpio_header *)addr; + unsigned int pathname_size = hex2dec(header->c_namesize); + unsigned int file_size = hex2dec(header->c_filesize); + unsigned int headerPathname_size = sizeof(cpio_header) + pathname_size; + + align(&headerPathname_size, 4); + align(&file_size, 4); + + create_init(dir, &target, (char *)(addr + sizeof(cpio_header))); + target->content = addr + headerPathname_size; + target->content_size = file_size; + + addr += (headerPathname_size + file_size); + } +} + +static int setup_mount(struct filesystem *fs, struct mount *mount) +{ + // should set mount->root as a obj before call setup_mount + mount->root->mount = mount; + mount->root->f_ops = &initramfs_f_ops; + mount->root->v_ops = &initramfs_v_ops; + mount->fs = fs; + + // clear the internal content + list_init(&mount->root->childs); + mount->root->child_num = 0; + mount->root->content = NULL; + mount->root->content_size = 0; + init_cpio_files(); + return 0; +} + +static int lookup(struct vnode *dir_node, struct vnode **target, const char *component_name) +{ + struct vnode *vnode = NULL; + list_for_each_entry(vnode, &dir_node->childs, self) + { + if (!(utils_str_compare(vnode->name, component_name))) + { + *target = vnode; + return 0; + } + } + return -1; +} +static int create(struct vnode *dir_node, struct vnode **target, const char *component_name) +{ + return -1; +} +static int mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name) +{ + return -1; +} + +static int write(struct file *file, const void *buf, size_t len) +{ + return -1; +} +static int read(struct file *file, void *buf, size_t len) +{ + struct vnode *vnode = file->vnode; + if (!S_ISREG(vnode->f_mode)) + { + uart_send_string("[write] not a regular file\n"); + return -1; + } + int min = (len > vnode->content_size - file->f_pos - 1) ? vnode->content_size - file->f_pos - 1 : len; // -1 for EOF; + if (min == 0) + { + return -1; // f_pos at EOF or len==0; + } + memcpy(buf, vnode->content + file->f_pos, min); + file->f_pos += min; + return min; +} +static int open(struct vnode *file_node, struct file **target) +{ + // TODO + return 0; +} +static int close(struct file *file) +{ + kfree(file); + return 0; +} +static long lseek64(struct file *file, long offset, int whence) +{ + // TODO + return 0; +} + +struct filesystem *initramfs_create() +{ + struct filesystem *fs = kmalloc(sizeof(struct filesystem)); + fs->name = "initramfs"; + fs->setup_mount = &setup_mount; + list_init(&fs->list); + return fs; +} diff --git a/lab7/src/list.c b/lab7/src/list.c new file mode 100644 index 000000000..fd4033e51 --- /dev/null +++ b/lab7/src/list.c @@ -0,0 +1,53 @@ +#include "list.h" + +void list_init(list *node) +{ + node->next = node; + node->prev = node; +} + +void insert_head(list *head, list *v) +{ + v->next = head->next; + v->prev = head; + head->next->prev = v; + head->next = v; +} + +void insert_tail(list *head, list *v) +{ + v->next = head; + v->prev = head->prev; + head->prev->next = v; + head->prev = v; +} + +list *remove_head(list *head) +{ + list *ptr; + ptr = head->next; + head->next = head->next->next; + head->next->prev = head; + + return ptr; +} + +list *remove_tail(list *head) +{ + list *ptr; + ptr = head->prev; + head->prev = head->prev->prev; + head->prev->next = head; + + return ptr; +} + +void unlink(list *node) +{ + list *next, *prev; + next = node->next; + prev = node->prev; + + next->prev = prev; + prev->next = next; +} \ No newline at end of file diff --git a/lab7/src/mailbox.c b/lab7/src/mailbox.c new file mode 100644 index 000000000..501f42f3f --- /dev/null +++ b/lab7/src/mailbox.c @@ -0,0 +1,64 @@ +#include "peripheral/mailbox.h" +#include "utils_c.h" +#include "mini_uart.h" + +unsigned int __attribute__((aligned(16))) mailbox[8]; + +unsigned int mailbox_call(unsigned char channel, unsigned int *_mailbox) +{ + unsigned int readChannel = (((unsigned int)((unsigned long)_mailbox) & ~0xF) | (channel & 0xF)); + while (*MAILBOX_STATUS & MAILBOX_FULL) + { + } + *MAILBOX_WRITE = readChannel; + while (1) + { + while (*MAILBOX_STATUS & MAILBOX_EMPTY) + { + } + if (readChannel == *MAILBOX_READ) + { + return _mailbox[1] == MAILBOX_RESPONSE; + } + } + return 0; +} + +unsigned int get_board_revision() +{ + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = END_TAG; + mailbox_call(MAILBOX_CH_PROP, mailbox); // message passing procedure call, you should implement it following the 6 steps provided above. + // printf("0x%x\n", mailbox[5]); // it should be 0xa020d3 for rpi3 b+ + uart_hex(mailbox[5]); + uart_send_string("\n"); + return mailbox[5]; +} + +void get_arm_memory() +{ + mailbox[0] = 8 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = ARM_MEMORY; // tag identifier + mailbox[3] = 8; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + mailbox[6] = 0; // value buffer + // tags end + mailbox[7] = END_TAG; + mailbox_call(MAILBOX_CH_PROP, mailbox); // message passing procedure call, you should implement it following the 6 steps provided above. + uart_send_string("Arm base address: "); + uart_hex(mailbox[5]); + uart_send_string("\n"); + uart_send_string("Arm memory size: "); + uart_hex(mailbox[6]); + uart_send_string("\n"); +} diff --git a/lab7/src/memzero.S b/lab7/src/memzero.S new file mode 100644 index 000000000..91c1c4f0f --- /dev/null +++ b/lab7/src/memzero.S @@ -0,0 +1,7 @@ +.global memzero +memzero: + str xzr, [x20], #8 + subs x21, x21, #8 + b.gt memzero + ret + \ No newline at end of file diff --git a/lab7/src/mini_uart.c b/lab7/src/mini_uart.c new file mode 100644 index 000000000..0d0d73605 --- /dev/null +++ b/lab7/src/mini_uart.c @@ -0,0 +1,258 @@ +#include "peripheral/mini_uart.h" +#include "peripheral/gpio.h" +#include "sprintf.h" +#include "utils_c.h" +#include +#include +#include "mini_uart.h" + +#define ENABLE_RECEIVE_INTERRUPTS_BIT (1 << 0) +#define ENABLE_TRANSMIT_INTERRUPTS_BIT (1 << 1) +#define AUX_INT_BIT (1 << 29) + +#define BUFFER_MAX_SIZE 256u + +char read_buf[BUFFER_MAX_SIZE]; +char write_buf[BUFFER_MAX_SIZE]; +int read_buf_start, read_buf_end; +int write_buf_start, write_buf_end; + + +void enable_uart_interrupt() { *ENB_IRQS1 = AUX_IRQ; } + +void disable_uart_interrupt() { *DISABLE_IRQS1 = AUX_IRQ; } + +void set_transmit_interrupt() { *AUX_MU_IER_REG |= 0x2; } + +void clear_transmit_interrupt() { *AUX_MU_IER_REG &= ~(0x2); } + +void uart_init() +{ + unsigned int selector; + + selector = *GPFSEL1; + selector &= ~(7u << 12); // clean gpio14 + selector |= 2u << 12; // set alt5 for gpio14 + selector &= ~(7u << 15); // clean gpio15 + selector |= 2u << 15; // set alt5 for gpio 15 + *GPFSEL1 = selector; + + *GPPUD = 0; // set the required control signal (i.e. Pull-up or Pull-Down ) + delay(150u); // provides the required set-up time for the control signal + *GPPUDCLK0 = (1u << 14) | (1u << 15); + delay(150u); + *GPPUDCLK0 = 0u; + *AUX_ENABLE = 1u; // Enable mini uart (this also enables access to its registers) + *AUX_MU_CNTL_REG = 0u; // Disable auto flow control and disable receiver and transmitter (for now) + *AUX_MU_IER_REG = 1u; // Enable receive + *AUX_MU_LCR_REG = 3u; // Enable 8 bit mode + *AUX_MU_MCR_REG = 0u; // Set RTS line to be always high + *AUX_MU_BAUD_REG = 270u; // Set baud rate to 115200 + *AUX_MU_IIR_REG = 6; + + *AUX_MU_CNTL_REG = 3; // Finally, enable transmitter and receiver + + read_buf_start = read_buf_end = 0; + write_buf_start = write_buf_end = 0; + // enable_uart_interrupt(); +} + +void uart_send(const char c) +{ + /* + bit_5 == 1 -> writable + 0x20 = 0000 0000 0010 0000 + ref BCM2837-ARM-Peripherals p5 + */ + if (c == '\n') + { + uart_send('\r'); + } + while (!(*(AUX_MU_LSR_REG)&0x20)) + { + } + *AUX_MU_IO_REG = c; +} +char uart_recv() +{ + /* + bit_0 == 1 -> readable + 0x01 = 0000 0000 0000 0001 + ref BCM2837-ARM-Peripherals p5 + */ + while (!(*(AUX_MU_LSR_REG)&0x01)) + { + } + char temp = *(AUX_MU_IO_REG)&0xFF; + return temp == '\r' ? '\n' : temp; +} + +char uart_recv_raw() +{ + /* + bit_0 == 1 -> readable + 0x01 = 0000 0000 0000 0001 + ref BCM2837-ARM-Peripherals p5 + */ + while (!(*(AUX_MU_LSR_REG)&0x01)) + { + } + char temp = *(AUX_MU_IO_REG)&0xFF; + return temp; +} + +void uart_send_string(const char *str) +{ + while (*str) + { + uart_send(*str++); + } +} + +void uart_send_uint(unsigned int num, int newline) +{ + char str[256]; + utils_uint2str_dec(num, str); + uart_send_string(str); + if (newline) + { + uart_send_string("\n"); + } +} + +void uart_hex(unsigned int d) +{ + unsigned int n; + int c; + uart_send_string("0x"); + for (c = 28; c >= 0; c -= 4) + { + n = (d >> c) & 0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n += n > 9 ? 0x57 : 0x30; + uart_send(n); + } +} +void uart_dec(unsigned int num) +{ + if (num == 0) + uart_send('0'); + else + { + if (num >= 10) + uart_dec(num / 10); + uart_send(num % 10 + '0'); + } +} + +unsigned int uart_printf(char *fmt, ...) +{ + char dst[100]; + // __builtin_va_start(args, fmt): "..." is pointed by args + // __builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + unsigned int ret = vsprintf(dst, fmt, args); + uart_send_string(dst); + return ret; +} + +/* + async part +*/ + +void uart_handler() +{ + disable_uart_interrupt(); + int RX = (*AUX_MU_IIR_REG & 0x4); + int TX = (*AUX_MU_IIR_REG & 0x2); + if (RX) + { + char c = (char)(*AUX_MU_IO_REG); + read_buf[read_buf_end++] = c; + if (read_buf_end == BUFFER_MAX_SIZE) + read_buf_end = 0; + } + else if (TX) + { + while (*AUX_MU_LSR_REG & 0x20) + { + if (write_buf_start == write_buf_end) + { + clear_transmit_interrupt(); + break; + } + char c = write_buf[write_buf_start++]; + *AUX_MU_IO_REG = c; + if (write_buf_start == BUFFER_MAX_SIZE) + write_buf_start = 0; + } + } + enable_uart_interrupt(); +} + +char uart_async_recv() +{ + // wait until there are new data + while (read_buf_start == read_buf_end) + { + asm volatile("nop"); + } + char c = read_buf[read_buf_start++]; + if (read_buf_start == BUFFER_MAX_SIZE) + read_buf_start = 0; + return c == '\r' ? '\n' : c; +} + +void uart_async_send_string(char *str) +{ + + for (int i = 0; str[i]; i++) + { + if (str[i] == '\n') + { + write_buf[write_buf_end++] = '\r'; + write_buf[write_buf_end++] = '\n'; + continue; + } + write_buf[write_buf_end++] = str[i]; + if (write_buf_end == BUFFER_MAX_SIZE) + write_buf_end = 0; + } + set_transmit_interrupt(); +} + +void uart_async_send(char c) +{ + if (c == '\n') + { + write_buf[write_buf_end++] = '\r'; + write_buf[write_buf_end++] = '\n'; + set_transmit_interrupt(); + return; + } + write_buf[write_buf_end++] = c; + if (write_buf_end == BUFFER_MAX_SIZE) + write_buf_end = 0; + set_transmit_interrupt(); +} + +void test_uart_async() +{ + enable_uart_interrupt(); + delay(15000); + char buffer[BUFFER_MAX_SIZE]; + size_t index = 0; + while (1) + { + buffer[index] = uart_async_recv(); + if (buffer[index] == '\n') + { + break; + } + index++; + } + buffer[index + 1] = '\0'; + uart_async_send_string(buffer); + disable_uart_interrupt(); +} diff --git a/lab7/src/mm.c b/lab7/src/mm.c new file mode 100644 index 000000000..af17b086f --- /dev/null +++ b/lab7/src/mm.c @@ -0,0 +1,460 @@ +#include "mm.h" +#include "mini_uart.h" +#include "list.h" +#include "utils_c.h" +#include "_cpio.h" +#include "dtb.h" +#include "exception_c.h" +#include "mmu.h" + +// #define DEBUG + +#define FRAME_BASE ((uintptr_t)PHYS_OFFSET + 0x0) +// get from mailbox's arm memory +#define FRAME_END ((uintptr_t)PHYS_OFFSET + 0x3b400000) + +#define PAGE_SIZE 0x1000 // 4KB +#define FRAME_BINS_SIZE 12 +#define MAX_ORDER (FRAME_BINS_SIZE - 1) +#define FRAME_MAX_SIZE ORDER2SIZE(MAX_ORDER) +#define ORDER2SIZE(order) (PAGE_SIZE * (1 << (order))) + +#define FRAME_ARRAY_SIZE ((FRAME_END - FRAME_BASE) / PAGE_SIZE) + +#define CHUNK_MIN_SIZE 32 +#define CHUNK_BINS 7 +#define CHUNK_MAX_ORDER (CHUNK_BINS - 1) + +#define FRAME_FREE 0x8 +#define FRAME_INUSE 0x4 +#define FRAME_MEM_CHUNK 0x2 +#define IS_INUSE(frames) (frames.flag & FRAME_INUSE) +#define IS_MEM_CHUNK(frames) (frames.flag & FRAME_MEM_CHUNK) + +// for mm_int +extern char _skernel, _ekernel; +extern void *_dtb_ptr; + +FrameFlag *frames; +list frame_bins[FRAME_BINS_SIZE]; +Chunk *chunk_bins[CHUNK_BINS]; + +unsigned long *smalloc_cur = (unsigned long *)STARTUP_MEM_START; + +//////////////////////////////////////////////////////////////////////////////////////////////// +// utils // +//////////////////////////////////////////////////////////////////////////////////////////////// +static unsigned align_up_exp(unsigned n) +{ + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n++; + return n; +} +static int addr2idx(void *addr) +{ + return (((uintptr_t)addr & -PAGE_SIZE) - FRAME_BASE) / PAGE_SIZE; +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// startUp // +//////////////////////////////////////////////////////////////////////////////////////////////// + +void *smalloc(size_t size) +{ + align(&size, 4); // allocated the memory size is mutiple of 4 byte; + unsigned long *smalloc_ret = smalloc_cur; + if ((uint64_t)smalloc_cur + size > (uint64_t)STARTUP_MEM_END) + { + uart_printf("[!] No enough space!\r\n"); + return NULL; + } + smalloc_cur += (unsigned int)size; + return smalloc_ret; +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// others // +//////////////////////////////////////////////////////////////////////////////////////////////// + +void mm_init() +{ + init_buddy(); + memory_reserve((uintptr_t)pa2va(0), (uintptr_t)pa2va(0x1000)); // Spin tables for multicore boot + + memory_reserve((uintptr_t)IDENTITY_TT_L0_VA, (uintptr_t)IDENTITY_TT_L0_VA + PAGE_SIZE); // PGD's page frame + memory_reserve((uintptr_t)IDENTITY_TT_L1_VA, (uintptr_t)IDENTITY_TT_L1_VA + PAGE_SIZE); // PUD's page frame + + memory_reserve((uintptr_t)&_skernel, (uintptr_t)&_ekernel); // Kernel image + + fdt_traverse(get_initramfs_addr); + memory_reserve((uintptr_t)initramfs_start, (uintptr_t)initramfs_end); // Initramfs + + memory_reserve((uintptr_t)STARTUP_MEM_START, (uintptr_t)STARTUP_MEM_END); // Simple allocator + + memory_reserve((uintptr_t)dtb_start, (uintptr_t)dtb_end); // Devicetree + + merge_useful_pages(); +} + +void memory_reserve(uintptr_t start, uintptr_t end) +{ + + start = start & ~(PAGE_SIZE - 1); + end = align_up(end - PHYS_OFFSET, PAGE_SIZE) + PHYS_OFFSET; + for (uintptr_t i = start; i < end; i += PAGE_SIZE) + { + int idx = addr2idx((void *)i); + frames[idx].flag |= FRAME_INUSE; + frames[idx].order = 0; + } +#ifdef DEBUG + uart_printf("reserve addr from %x ~ %x\n", (unsigned long)start, (unsigned long)end); +#endif +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// buddy system // +//////////////////////////////////////////////////////////////////////////////////////////////// + +static int pages_to_frame_order(unsigned pages) +{ + pages = align_up_exp(pages); + return __builtin_ctz(pages); +} + +void init_buddy() +{ + frames = (FrameFlag *)smalloc(sizeof(FrameFlag) * FRAME_ARRAY_SIZE); + for (int i = 0; i < FRAME_BINS_SIZE; i++) + { + list_init(&frame_bins[i]); + } + for (int i = 0; i < FRAME_ARRAY_SIZE; i++) + { + frames[i].flag = 0; + frames[i].order = 0; + } +} + +void merge_useful_pages() +{ + int page_idx = 0; + list *page_addr = (list *)(FRAME_BASE); + { // only insert the 4KB page to frame_bins + while (1) + { + if (!IS_INUSE(frames[page_idx])) + { + insert_tail(&frame_bins[0], page_addr); + } + page_idx++; + if (page_idx >= FRAME_ARRAY_SIZE) + { + break; + } + page_addr = (void *)(FRAME_BASE + page_idx * PAGE_SIZE); + } + } + + for (int order = 0; order < MAX_ORDER; order++) + { // merging the pages by left page + page_idx = 0; + page_addr = (list *)(FRAME_BASE); + int buddy_page_idx = 0; + list *buddy_addr = (list *)(FRAME_BASE); + while (1) + { + buddy_page_idx = page_idx ^ (1 << order); + buddy_addr = (void *)(FRAME_BASE + buddy_page_idx * PAGE_SIZE); + + if (!IS_INUSE(frames[page_idx]) && + frames[page_idx].order == order && + buddy_page_idx < FRAME_ARRAY_SIZE && + !IS_INUSE(frames[buddy_page_idx]) && + frames[buddy_page_idx].order == order) + { + unlink((list *)page_addr); + unlink((list *)buddy_addr); + insert_tail(&frame_bins[order + 1], page_addr); + frames[page_idx].order = order + 1; + } + page_idx += (1 << (order + 1)); + if (page_idx >= FRAME_ARRAY_SIZE) + { + break; + } + page_addr = (void *)(FRAME_BASE + page_idx * PAGE_SIZE); + } + } +} + +static void *split_frames(int order, int target_order) +{ + list *ptr = remove_head(&frame_bins[order]); + +#ifdef DEBUG + uart_printf("split frame: %x\n", (unsigned long)ptr); +#endif + + for (int i = order; i > target_order; i--) + { /* insert splitted frame to bin list */ + list *half_right = (list *)((char *)ptr + ORDER2SIZE(i - 1)); + + insert_head(&frame_bins[i - 1], half_right); + frames[((uintptr_t)half_right - FRAME_BASE) / PAGE_SIZE].order = i - 1; + +#ifdef DEBUG + uart_printf("insert frame at %x\n", (unsigned long)half_right); +#endif + } + int idx = addr2idx(ptr); + frames[idx].order = target_order; + frames[idx].flag |= FRAME_INUSE; + return ptr; +} + +void *alloc_pages(unsigned int pages) +{ + int target_order = pages_to_frame_order(pages); + if (frame_bins[target_order].next != &frame_bins[target_order]) + { + list *ptr = remove_head(&frame_bins[target_order]); +#ifdef DEBUG + uart_printf("return page at: %x\n", (unsigned long)ptr); +#endif + int idx = addr2idx(ptr); + frames[idx].order = target_order; + frames[idx].flag |= FRAME_INUSE; + return ptr; + } + else + { + for (int i = target_order; i < FRAME_BINS_SIZE; i++) + { + if (frame_bins[i].next != &frame_bins[i]) + { + return split_frames(i, target_order); + } + } + } + + uart_send_string("alloc page return NULL"); + return NULL; +} + +void free_pages(void *victim) +{ + int page_idx = ((uintptr_t)victim - FRAME_BASE) / PAGE_SIZE; + if (!IS_INUSE(frames[page_idx])) + { + uart_printf("Error! double free the memory at %x\n", (uintptr_t)victim); + return; + } + unsigned int order = frames[page_idx].order; + int buddy_page_idx = page_idx ^ (1 << order); + frames[page_idx].flag &= ~FRAME_INUSE; + + while (order <= MAX_ORDER && + !IS_INUSE(frames[buddy_page_idx]) && + order == frames[buddy_page_idx].order) + { + void *buddy_victim = (void *)(FRAME_BASE + buddy_page_idx * PAGE_SIZE); + unlink((list *)buddy_victim); + +#ifdef DEBUG + uart_printf("merge buddy frame: %x \n", (unsigned long)buddy_victim); +#endif + order += 1; + victim = page_idx < buddy_page_idx ? victim : buddy_victim; + page_idx = page_idx < buddy_page_idx ? page_idx : buddy_page_idx; + buddy_page_idx = page_idx ^ (1 << order); + } + + insert_head(&frame_bins[order], victim); + frames[page_idx].order = order; + +#ifdef DEBUG + uart_printf("attach frame: %x \n\n", (unsigned long)victim); +#endif +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// chunks // +//////////////////////////////////////////////////////////////////////////////////////////////// + +static int size_to_chunk_order(unsigned int size) +{ + size = align_up_exp(size); + size /= CHUNK_MIN_SIZE; + return __builtin_ctz(size); +} + +static void *get_chunk(uint32_t size) +{ + int order = size_to_chunk_order(size); + + void *ptr = chunk_bins[order]; + if (ptr) + { + chunk_bins[order] = chunk_bins[order]->next; + int idx = addr2idx(ptr); + frames[idx].ref_count += 1; + +#ifdef DEBUG + uart_printf("detach chunk at %x\n", (unsigned long)ptr); +#endif + } + + return ptr; +} + +static void alloc_chunk(void *mem, int size) +{ + int count = PAGE_SIZE / size; + int idx = addr2idx(mem); + int order = size_to_chunk_order(size); + frames[idx].flag |= FRAME_MEM_CHUNK; + frames[idx].ref_count = 0; + frames[idx].chunk_order = order; + for (int i = 0; i < count; i++) + { + Chunk *ptr = (Chunk *)((uintptr_t)mem + i * size); + ptr->next = chunk_bins[order]; + chunk_bins[order] = ptr; + +#ifdef DEBUG + uart_printf("insert chunk at %x\n", (unsigned long)ptr); +#endif + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// dynamic memory simple_allocator // +//////////////////////////////////////////////////////////////////////////////////////////////// + +void *kmalloc(unsigned int size) +{ + unsigned int aligned_page_size = align_up(size, PAGE_SIZE); + if (aligned_page_size > FRAME_MAX_SIZE) + { + return NULL; + } + + size = size < CHUNK_MIN_SIZE ? CHUNK_MIN_SIZE : size; + + size_t flag = disable_irq(); + + void *ptr; + if (align_up_exp(size) < PAGE_SIZE) // just allocate a small chunk + { + size = align_up_exp(size); + ptr = get_chunk(size); + + if (!ptr) + { + void *mem = alloc_pages(1); + alloc_chunk(mem, size); + ptr = get_chunk(size); + } + } + else + { + unsigned int pages = aligned_page_size / PAGE_SIZE; + ptr = alloc_pages(pages); + } + irq_restore(flag); + return ptr; +} +void *kcalloc(unsigned int size) +{ + void *p = kmalloc(size); + if (!p) + { + return NULL; + } + if (size < PAGE_SIZE) + { + size = align_up_exp(size); + } + else + { + size = align_up(size, PAGE_SIZE); + } + memset(p, 0, size); + + return p; +} + +void kfree(void *ptr) +{ + int idx = addr2idx(ptr); + if (idx >= FRAME_ARRAY_SIZE) + { + uart_send_string("Error! kfree wrong address\n"); + return; + } + size_t flag = disable_irq(); + if (IS_MEM_CHUNK(frames[idx])) + { + int order = frames[idx].chunk_order; + ((Chunk *)ptr)->next = chunk_bins[order]; + chunk_bins[order] = ptr; + frames[idx].ref_count -= 1; + +#ifdef DEBUG + uart_printf("free chunk at %x\n", (unsigned long)ptr); +#endif + } + else + { + free_pages(ptr); + } + irq_restore(flag); +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// test // +//////////////////////////////////////////////////////////////////////////////////////////////// + +void test_buddy() +{ + int test_size = 5; + void *a[test_size]; + uart_send_string("\n\n----- Malloc -----\n"); + for (int i = 0; i < test_size; i++) + { + a[i] = alloc_pages(test_size); + } + uart_send_string("\n\n----- Free -----\n"); + for (int i = 0; i < test_size; i++) + { + free_pages(a[i]); + } +} + +struct test_b +{ + double b1, b2, b3, b4, b5, b6; +}; + +void test_dynamic_alloc() +{ + uart_send_string("allocate a1\n"); + int *a1 = kmalloc(sizeof(int)); + uart_send_string("allocate a2\n"); + int *a2 = kmalloc(sizeof(int)); + uart_send_string("allocate b\n"); + struct test_b *b = kmalloc(sizeof(struct test_b)); + + uart_send_string("free a1\n"); + kfree(a1); + uart_send_string("free b\n"); + kfree(b); + uart_send_string("free a2\n"); + kfree(a2); +} diff --git a/lab7/src/mmu.c b/lab7/src/mmu.c new file mode 100644 index 000000000..9f4dbcd93 --- /dev/null +++ b/lab7/src/mmu.c @@ -0,0 +1,172 @@ +#include "mmu.h" +#include "utils_s.h" +#include "utils_c.h" +#include "mini_uart.h" +#include "mm.h" +#include "current.h" + +#define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16)) +#define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30)) +#define TCR_CONFIG_DEFAULT (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB) + +#define MAIR_DEVICE_nGnRnE 0b00000000 +#define MAIR_NORMAL_NOCACHE 0b01000100 +#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_NORMAL_NOCACHE 1 + +#define BOOT_PGD_ATTR PD_TABLE +#define BOOT_PUD_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK) +#define MMU_ENABLE 1 +#define PAGE_SIZE 0x1000 + +#define PERIPHERAL_START 0x3c000000 +#define PERIPHERAL_END 0x3f000000 + +void setup_identity_mapping() +{ + write_sysreg(tcr_el1, TCR_CONFIG_DEFAULT); + size_t mair_attr_01 = + (MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | + (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8)); + write_sysreg(mair_el1, mair_attr_01); + + memset(IDENTITY_TT_L0, 0, 0x1000); + memset(IDENTITY_TT_L1, 0, 0x1000); + + IDENTITY_TT_L0[0] = (pd_t)IDENTITY_TT_L1 | BOOT_PGD_ATTR; + IDENTITY_TT_L1[0] = 0x00000000 | BOOT_PUD_ATTR; + IDENTITY_TT_L1[1] = 0x40000000 | BOOT_PUD_ATTR; + + write_sysreg(ttbr0_el1, IDENTITY_TT_L0); + write_sysreg(ttbr1_el1, IDENTITY_TT_L0); // also load PGD to the upper translation based register. + unsigned long sctlr = read_sysreg(sctlr_el1); + write_sysreg(sctlr_el1, sctlr | MMU_ENABLE); +} + +void setup_kernel_space_mapping() +{ + /* three-level 2MB block mapping */ + + /* 0x00000000 ~ 0x3F000000 for normal mem */ + pd_t *p0 = kcalloc(PAGE_SIZE); + for (int i = 0; i < 504; i++) + { + p0[i] = (i << 21) | PD_ACCESS | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_BLOCK; + } + /* 0x3F000000 ~ 0x40000000 for device mem */ + for (int i = 504; i < 512; i++) + { + p0[i] = (i << 21) | PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK; + } + + /* 0x40000000 ~ 0x80000000 for device mem */ + pd_t *p1 = kcalloc(PAGE_SIZE); + for (int i = 0; i < 512; i++) + { + p1[i] = 0x40000000 | (i << 21) | PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK; + } + + asm volatile("dsb ish\n\t"); + + IDENTITY_TT_L1_VA[0] = (pd_t)va2pa(p0) | PD_TABLE; + IDENTITY_TT_L1_VA[1] = (pd_t)va2pa(p1) | PD_TABLE; +} + +void map_page(pd_t *table, unsigned long va, unsigned long pa, unsigned long flags) +{ + for (int level = 0; level < 4; level++) + { + unsigned idx = (va >> (39 - 9 * level)) & 0b111111111; + if (!table[idx]) + { + if (level == 3) + { + table[idx] = pa; + table[idx] |= PD_PXN | PD_ACCESS | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_PAGE | flags; + return; + } + else + { + table[idx] = (pd_t)va2pa(kcalloc(PAGE_SIZE)); + table[idx] |= PD_ACCESS | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_TABLE; + } + } + + if ((table[idx] & 0b11) == PD_TABLE) + { + table = (pd_t *)pa2va(table[idx] & 0xfffffffff000L); + } + } +} + +void *alloc_stack(pd_t *table, unsigned long size) +{ + void *stack = kcalloc(size); + unsigned long pages = align_up(size, PAGE_SIZE) / PAGE_SIZE; + for (int i = 0; i < pages; i++) + { + map_page(table, USTACK_VA + i * PAGE_SIZE, va2pa(stack + i * PAGE_SIZE), PD_USER_RW | PD_UXN); + } + + return stack; +} + +void *alloc_prog(pd_t *table, unsigned long size, const char *file_content) +{ + void *prog = kcalloc(size); + unsigned long pages = align_up(size, PAGE_SIZE) / PAGE_SIZE; + for (int i = 0; i < pages; i++) + { + map_page(table, UPROG_VA + i * PAGE_SIZE, va2pa(prog + i * PAGE_SIZE), PD_USER_RW); + } + memcpy(prog, file_content, size); + + return prog; +} + +void setup_peripheral_identity(pd_t *table) +{ + unsigned long pages = align_up(PERIPHERAL_END - PERIPHERAL_START, PAGE_SIZE) / PAGE_SIZE; + for (int i = 0; i < pages; i++) + { + map_page(table, PERIPHERAL_START + i * PAGE_SIZE, PERIPHERAL_START + i * PAGE_SIZE, PD_USER_RW); + } +} + +unsigned long get_pte(unsigned long va) +{ + unsigned long flags = disable_irq(); + + asm("at s1e0r, %0\n\t" ::"r"(va)); + unsigned long pte = read_sysreg(par_el1); + + irq_restore(flags); + return pte; +} + +unsigned long el0_va2pa(unsigned long va) +{ + unsigned long entry = get_pte(va); + if (entry & 1) + { + uart_printf("Failed map virtual addr at 0x%x\n", va); + } + unsigned long offset = va & 0xfff; + return (unsigned long)(pa2va((entry & 0xfffffffff000L) | offset)); +} +void free_page_table(pd_t *table) +{ + // free the page table created by translating from map_page() + /* TODO */ +} + +void replace_page_table() +{ + asm( + "dsb ish\n" // ensure write has completed + "msr ttbr0_el1, %0\n" // switch translation based address. + "tlbi vmalle1is\n" // invalidate all TLB entries + "dsb ish\n" // ensure completion of TLB invalidatation + "isb\n" // clear pipeline + ::"r"(current->ttbr0)); +} \ No newline at end of file diff --git a/lab7/src/sche.c b/lab7/src/sche.c new file mode 100644 index 000000000..50424ae2c --- /dev/null +++ b/lab7/src/sche.c @@ -0,0 +1,158 @@ +#include "sche.h" +#include "current.h" +#include "timer.h" +#include "exception_c.h" +#include "mini_uart.h" +#include "mm.h" + +pid_t task_count = 0; + +list running_queue = LIST_HEAD_INIT(running_queue); +list waiting_queue = LIST_HEAD_INIT(waiting_queue); +list stopped_queue = LIST_HEAD_INIT(stopped_queue); + +int get_the_cur_count() +{ + int count = 0; + list *head = &running_queue; + while (head->next != &running_queue) + { + count++; + head = head->next; + } + return count; +} + +void add_task(struct task *t) +{ + size_t flags = disable_irq(); + insert_tail(&running_queue, &t->list); + irq_restore(flags); +} + +void kill_task(struct task *_task, int status) +{ + size_t flags = disable_irq(); + + _task->state = TASK_STOPPED; + _task->need_resched = 1; + unlink(&_task->list); + _task->exitcode = status; + insert_head(&stopped_queue, &_task->list); + + irq_restore(flags); + thread_schedule(0); +} + +void restart_task(struct task *_task) +{ + size_t flags = disable_irq(); + + if (_task->state != TASK_WAITING) + { + uart_send_string("---- task state inconsistent ----\n"); + return; + } + _task->state = TASK_RUNNING; + unlink(&_task->list); + insert_tail(&running_queue, &_task->list); + + irq_restore(flags); +} + +void pause_task(struct task *_task) +{ + size_t flags = disable_irq(); + + if (_task->state != TASK_RUNNING) + { + uart_send_string("---- task state inconsistent ----\n"); + return; + } + _task->state = TASK_WAITING; + _task->need_resched = 1; + unlink(&_task->list); + insert_head(&waiting_queue, &_task->list); + + irq_restore(flags); +} + +void sleep_task(size_t ms) +{ + size_t flags = disable_irq(); + + add_timer((timer_callback)restart_task, (size_t)current, ms); + pause_task(current); + irq_restore(flags); + + thread_schedule(0); +} + +void free_task(struct task *victim) +{ + if (victim->kernel_stack) + kfree(victim->kernel_stack); + kfree(victim); +} + +struct task *create_task() +{ + struct task *new_task = kmalloc(sizeof(struct task)); + new_task->cpu_context.lr = new_task->cpu_context.sp = new_task->cpu_context.fp = 0; + new_task->kernel_stack = NULL; + new_task->user_stack = NULL; + new_task->user_prog = NULL; + new_task->user_prog_size = 0; + new_task->state = TASK_INIT; + new_task->pid = task_count++; + new_task->need_resched = 0; + new_task->exitcode = 0; + new_task->timeout = get_current_time() + DEFAULT_TIMEOUT; + new_task->signal = NULL; + new_task->sig_context = NULL; + new_task->ttbr0 = NULL; + new_task->pwd = rootfs->root; + for (int i = 0; i < FD_TABLE_SIZE; i++) + { + new_task->fd_table[i] = NULL; // file descriptor table, max 16 + } + return new_task; +} + +struct task *pick_next_task() +{ + if (list_empty(&running_queue)) + { + while (1) + { + }; + } + struct task *next_task = list_first_entry(&running_queue, struct task, list); + unlink(&next_task->list); + insert_tail(&running_queue, &next_task->list); + + return next_task; +} + +void switch_task(struct task *next) +{ + if (current == next) + { + return; + } + switch_to(¤t->cpu_context, &next->cpu_context); + replace_page_table(); +} + +struct task *get_task(pid_t target) +{ + struct task *_task; + list_for_each_entry(_task, &running_queue, list) + { + if (_task->pid == target) + { + return _task; + } + } + return NULL; +} \ No newline at end of file diff --git a/lab7/src/shell.c b/lab7/src/shell.c new file mode 100644 index 000000000..f49661779 --- /dev/null +++ b/lab7/src/shell.c @@ -0,0 +1,230 @@ +#include "shell.h" +#include "mini_uart.h" +#include "utils_c.h" +#include "utils_s.h" +#include "peripheral/mailbox.h" +#include "_cpio.h" +#include "exception_c.h" +#include "timer.h" +#include "dtb.h" +#include "mm.h" +#include "exec.h" +#include "thread.h" +#include +#include "vfs.h" +#define BUFFER_MAX_SIZE 256u +#define COMMNAD_LENGTH_MAX 20u + +extern void *_dtb_ptr; + +int split(const char *buf, char *outbuf[], int n) +{ + const char *ps, *pe; + int idx = 0; + ps = pe = buf; + + while (idx < n) + { + while (*pe && *pe != ' ') + { + pe++; + } + + int size = pe - ps; + if (size) + { + outbuf[idx] = kmalloc(size + 1); + memcpy(outbuf[idx], ps, size); + outbuf[idx][size] = '\0'; + idx++; + } + + if (*pe) + { + while (*pe == ' ') + pe++; + ps = pe; + } + else + { + break; + } + } + + return idx; +} + +void read_command(char *buffer) +{ + size_t index = 0; + while (1) + { + buffer[index] = uart_recv(); + uart_send(buffer[index]); + if (buffer[index] == '\n') + { + break; + } + index++; + } + buffer[index + 1] = '\0'; + utils_newline2end(buffer); + uart_send('\r'); +} + +void parse_arg(char *buffer, int *argi) +{ + int i = 0; + int argi_index = 0; + argi[argi_index] = i; + while (buffer[i] != '\0') + { + if (buffer[i] == ' ') + { + buffer[i] = '\0'; + argi[++argi_index] = ++i; + continue; + } + i++; + } +} + +void help() +{ + uart_send_string("help :"); + uart_send_string("print this help menu\n"); + uart_send_string("hello :"); + uart_send_string("print Hello World!\n"); + uart_send_string("reboot : "); + uart_send_string("reboot the device\n"); + uart_send_string("info : "); + uart_send_string("the mailbox hardware info\n"); + uart_send_string("ls : "); + uart_send_string("list the all file\n"); + uart_send_string("cat : "); + uart_send_string("print the file content\n"); + uart_send_string("dtb : "); + uart_send_string("print the device name tree \n"); + uart_send_string("async : "); + uart_send_string("test uart async send and recv\n"); + uart_send_string("set : "); + uart_send_string("set the timeout (set message second)\n"); + uart_send_string("buddy : "); + uart_send_string("test the page allocate and free\n"); + uart_send_string("dynamic : "); + uart_send_string("test the dynamic memory simple_allocator\n"); +} + +void hello() +{ + uart_send_string("Hello World!\n"); +} + +void info() +{ + get_board_revision(); + // get_arm_memory(); +} + +void parse_command(char *buffer) +{ + // int argi[BUFFER_MAX_SIZE]; + if (utils_str_compare(buffer, "") == 0) + { + return; + } + else if (utils_str_compare(buffer, "help") == 0) + { + help(); + } + else if (utils_str_compare(buffer, "hello") == 0) + { + hello(); + } + else if (utils_str_compare(buffer, "ls") == 0) + { + cpio_ls(); + } + else if (utils_str_compare(buffer, "cat") == 0) + { + uart_send_string("Filename: "); + char buffer[BUFFER_MAX_SIZE]; + read_command(buffer); + cpio_cat(buffer); + } + else if (utils_str_compare(buffer, "exe") == 0) + { + exe_new_prog("/initramfs/user2.img"); + } + else if (utils_str_compare(buffer, "wtf") == 0) + { + uart_printf("Current task count :%d\n",get_the_cur_count()); + } + else if (utils_str_compare(buffer, "thread") == 0) + { + test_thread(); + uart_async_send_string("exit the test_thread\n"); + } + else if (utils_str_compare(buffer, "reboot") == 0) + { + uart_send_string("rebooting...\n"); + reset(1000); + } + else if (utils_str_compare(buffer, "info") == 0) + { + info(); + } + else if (utils_str_compare(buffer, "dtb") == 0) + { + fdt_traverse(print_dtb); + } + else if (utils_str_compare(buffer, "fs") == 0) + { + vfs_test(); + } + else if (utils_str_compare(buffer, "async") == 0) + { + test_uart_async(); + } + else if (utils_strncmp(buffer, "set", 3) == 0) + { + char *args[3]; + split(buffer, args, 3); + unsigned long time = (unsigned long)utils_str2uint_dec(args[2]); + set_timeout(args[1], S(time)); + } + else if (utils_str_compare(buffer, "buddy") == 0) + { + test_buddy(); + } + else if (utils_str_compare(buffer, "dynamic") == 0) + { + test_dynamic_alloc(); + } + else + { + uart_send_string("commnad '"); + uart_send_string(buffer); + uart_send_string("' not found\n"); + } +} + +void clear_buffer(char *buf) +{ + for (int i = 0; i < BUFFER_MAX_SIZE; i++) + { + buf[i] = '\0'; + } +} + +void shell() +{ + while (1) + { + char buffer[BUFFER_MAX_SIZE]; + clear_buffer(buffer); + uart_send_string("$ "); + read_command(buffer); + parse_command(buffer); + } +} \ No newline at end of file diff --git a/lab7/src/signal.c b/lab7/src/signal.c new file mode 100644 index 000000000..1b46aa58b --- /dev/null +++ b/lab7/src/signal.c @@ -0,0 +1,63 @@ +#include "signal.h" +#include "sche.h" +#include "current.h" +#include "mm.h" +#include "trap_frame.h" +#include "mini_uart.h" +#include "utils_c.h" + +static void sig_ignore(int _) +{ + return; +} +void sigkill_handler(int target) +{ + if (current->pid == target) + { + kill_task(current, target); + return; + } + struct task *victim = get_task(target); + if (victim) + { + kill_task(victim, 0); + } +} +void sig_return(void) +{ + asm volatile( + "mov x8, 10\n" + "svc 0\n"); +} + +void sig_context_update(TrapFrame *_regs, void (*handler)()) +{ + struct signal_context *sig_context = kmalloc(sizeof(struct signal_context)); + sig_context->trapframe = kmalloc(sizeof(TrapFrame)); + sig_context->user_stack = kmalloc(STACK_SIZE); + memcpy(sig_context->trapframe, _regs, sizeof(TrapFrame)); + + current->sig_context = sig_context; + + _regs->regs[30] = (unsigned long)&sig_return; + _regs->pc = (unsigned long)handler; + _regs->sp = (unsigned long)sig_context->user_stack + STACK_SIZE - 0x10; +} + +void sig_context_restore(TrapFrame *_regs) +{ + memcpy(_regs, current->sig_context->trapframe, sizeof(TrapFrame)); +} + +signal_handler signal_table[] = { + [0] = &sig_ignore, + [1] = &sig_ignore, + [2] = &sig_ignore, + [3] = &sig_ignore, + [4] = &sig_ignore, + [5] = &sig_ignore, + [6] = &sig_ignore, + [7] = &sig_ignore, + [8] = &sig_ignore, + [SIGKILL] = &sigkill_handler, +}; \ No newline at end of file diff --git a/lab7/src/sprintf.c b/lab7/src/sprintf.c new file mode 100644 index 000000000..246748b62 --- /dev/null +++ b/lab7/src/sprintf.c @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +/** + * minimal sprintf implementation + */ +#include "../include/sprintf.h" + +unsigned int vsprintf(char *dst, char* fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig=dst, tmpstr[19]; + + // failsafes + if(dst==(void*)0 || fmt==(void*)0) { + return 0; + } + + // main loop + arg = 0; + while(*fmt) { + // argument access + if(*fmt=='%') { + fmt++; + // literal % + if(*fmt=='%') { + goto put; + } + len=0; + // size modifier + while(*fmt>='0' && *fmt<='9') { + len *= 10; + len += *fmt-'0'; + fmt++; + } + // skip long modifier + if(*fmt=='l') { + fmt++; + } + // character + if(*fmt=='c') { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } else + // decimal number + if(*fmt=='d') { + arg = __builtin_va_arg(args, int); + // check input + sign=0; + if((int)arg<0) { + arg*=-1; + sign++; + } + if(arg>99999999999999999L) { + arg=99999999999999999L; + } + // convert to string + i=18; + tmpstr[i]=0; + do { + tmpstr[--i]='0'+(arg%10); + arg/=10; + } while(arg!=0 && i>0); + if(sign) { + tmpstr[--i]='-'; + } + // padding, only space + if(len>0 && len<18) { + while(i>18-len) { + tmpstr[--i]=' '; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // hex number + if(*fmt=='x') { + arg = __builtin_va_arg(args, long int); + // convert to string + i=16; + tmpstr[i]=0; + do { + char n=arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i]=n+(n>9?0x37:0x30); + arg>>=4; + } while(arg!=0 && i>0); + // padding, only leading zeros + if(len>0 && len<=16) { + while(i>16-len) { + tmpstr[--i]='0'; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // string + if(*fmt=='s') { + p = __builtin_va_arg(args, char*); +copystring: if(p==(void*)0) { + p="(null)"; + } + while(*p) { + *dst++ = *p++; + } + } + } else { +put: *dst++ = *fmt; + } + fmt++; + } + *dst=0; + // number of bytes written + return dst-orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char* fmt, ...) +{ + //__builtin_va_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst,fmt,args); +} \ No newline at end of file diff --git a/lab7/src/syscall.c b/lab7/src/syscall.c new file mode 100644 index 000000000..15235a26a --- /dev/null +++ b/lab7/src/syscall.c @@ -0,0 +1,248 @@ +#include "syscall.h" +#include "stddef.h" +#include "trap_frame.h" +#include "current.h" +#include "peripheral/mailbox.h" +#include "mini_uart.h" +#include "signal.h" +#include "exec.h" +#include "exception_c.h" +#include "mm.h" +#include "fork.h" + +void sys_getpid(TrapFrame *_regs) +{ + _regs->regs[0] = current->pid; +} +void sys_uartrecv(TrapFrame *_regs) +{ + char *buf = (char *)_regs->regs[0]; + int count = _regs->regs[1]; + for (int i = 0; i < count; i++) + { + buf[i] = uart_recv(); + } + _regs->regs[0] = count; +} +void sys_uartwrite(TrapFrame *_regs) +{ + char *buf = (char *)_regs->regs[0]; + int count = _regs->regs[1]; + for (int i = 0; i < count; i++) + { + uart_send(buf[i]); + } + _regs->regs[0] = count; +} +void sys_exec(TrapFrame *_regs) +{ + const char *path = (char *)_regs->regs[0]; + const char **args = (const char **)_regs->regs[1]; + _regs->regs[0] = do_exec(path, args); +} +void sys_fork(TrapFrame *_regs) +{ + _regs->regs[0] = do_fork(_regs); +} +void sys_exit(TrapFrame *_regs) +{ + kill_task(current, _regs->regs[0]); +} +void sys_mbox_call(TrapFrame *_regs) +{ + unsigned int channel = _regs->regs[0]; + unsigned int *mailbox_va = (unsigned int *)_regs->regs[1]; + + void *mailbox_pa = (unsigned int *)el0_va2pa((unsigned long)mailbox_va); + mailbox_call(channel, mailbox_pa); +} +void sys_kill_pid(TrapFrame *_regs) +{ + pid_t target = _regs->regs[0]; + if (current->pid == target) + { + kill_task(current, target); + return; + } + struct task *victim = get_task(target); + if (victim) + { + kill_task(victim, 0); + } +} +void sys_signal(TrapFrame *_regs) +{ + int sig_num = _regs->regs[0]; + signal_handler _hand = (signal_handler)_regs->regs[1]; + + struct signal *new_signal = kmalloc(sizeof(struct signal)); + new_signal->sig_num = sig_num; + new_signal->handler = _hand; + new_signal->list.next = new_signal->list.prev = &new_signal->list; + + if (!current->signal) + { + current->signal = new_signal; + } + else + { + insert_tail(¤t->signal->list, &new_signal->list); + } +} + +void sys_sigkill(TrapFrame *_regs) +{ + int target = _regs->regs[0]; + int SIGNAL = _regs->regs[1]; + int is_find = 0; + if (current->signal) + { + struct signal *cur = current->signal; + do + { + if (cur->sig_num == SIGNAL) + { + is_find = 1; + sig_context_update(_regs, cur->handler); + break; + } + cur = list_entry(cur->list.next, struct signal, list); + } while (cur != current->signal); + } + else if (!current->signal && !is_find) + { + (signal_table[SIGNAL])(target); + } +} +void sys_sigreturn(TrapFrame *_regs) +{ + sig_context_restore(_regs); + + disable_interrupt(); + kfree(current->sig_context->trapframe); + kfree(current->sig_context->user_stack); + kfree(current->sig_context); + current->sig_context = NULL; + enable_interrupt(); +} +void sys_open(TrapFrame *_regs) +{ + const char *pathname = (char *)_regs->regs[0]; + int flags = _regs->regs[1]; + for (int i = 0; i < FD_TABLE_SIZE; i++) + { + if (!current->fd_table[i] && !vfs_open(pathname, flags, &(current->fd_table[i]))) + { + _regs->regs[0] = i; + return; + } + } + return; +} +void sys_close(TrapFrame *_regs) +{ + int fd = _regs->regs[0]; + + if (fd < 0 || fd >= FD_TABLE_SIZE) + { + _regs->regs[0] = -1; + return; + } + + if (current->fd_table[fd] && !vfs_close(current->fd_table[fd])) + { + current->fd_table[fd] = NULL; + _regs->regs[0] = 0; + } + + return; +} +void sys_write(TrapFrame *_regs) +{ + int fd = _regs->regs[0]; + const void *buf = (void *)_regs->regs[1]; + unsigned long count = _regs->regs[2]; + + if (fd < 0 || fd >= FD_TABLE_SIZE) + { + _regs->regs[0] = -1; + return; + } + if (current->fd_table[fd]) + { + _regs->regs[0] = vfs_write(current->fd_table[fd], buf, count); + } + + return; +} +void sys_read(TrapFrame *_regs) +{ + int fd = _regs->regs[0]; + void *buf = (void *)_regs->regs[1]; + unsigned long count = _regs->regs[2]; + + if (fd < 0 || fd >= FD_TABLE_SIZE) + { + _regs->regs[0] = -1; + return; + } + if (current->fd_table[fd]) + { + _regs->regs[0] = vfs_read(current->fd_table[fd], buf, count); + } + + return; +} +void sys_mkdir(TrapFrame *_regs) +{ + const char *pathname = (char *)_regs->regs[0]; + + _regs->regs[0] = vfs_mkdir(pathname); + return; +} +void sys_mount(TrapFrame *_regs) +{ + const char *target = (char *)_regs->regs[1]; + const char *filesystem = (char *)_regs->regs[2]; + + _regs->regs[0] = vfs_mount(target, filesystem); + return; +} +void sys_chdir(TrapFrame *_regs) +{ + const char *path = (char *)_regs->regs[0]; + + _regs->regs[0] = vfs_chdir(path); + return; +} +syscall syscall_table[NUM_syscalls] = { + [SYS_GETPID] = &sys_getpid, + [SYS_UART_RECV] = &sys_uartrecv, + [SYS_UART_WRITE] = &sys_uartwrite, + [SYS_EXEC] = &sys_exec, + [SYS_FORK] = &sys_fork, + [SYS_EXIT] = &sys_exit, + [SYS_MBOX] = &sys_mbox_call, + [SYS_KILL_PID] = &sys_kill_pid, + [SYS_SIGNAL] = &sys_signal, + [SYS_SIGKILL] = &sys_sigkill, + [SYS_SIGRETURN] = &sys_sigreturn, + [SYS_OPEN] = &sys_open, + [SYS_CLOSE] = &sys_close, + [SYS_WRITE] = &sys_write, + [SYS_READ] = &sys_read, + [SYS_MKDIR] = &sys_mkdir, + [SYS_MOUNT] = &sys_mount, + [SYS_CHDIR] = &sys_chdir, +}; + +void syscall_handler(TrapFrame *_regs) +{ + unsigned int sys_index = _regs->regs[8]; + if (sys_index >= NUM_syscalls) + { + uart_send_string("!!! Invalid system call !!!\n"); + return; + } + (syscall_table[sys_index])(_regs); +} diff --git a/lab7/src/thread.c b/lab7/src/thread.c new file mode 100644 index 000000000..b647e65c0 --- /dev/null +++ b/lab7/src/thread.c @@ -0,0 +1,76 @@ +#include "thread.h" +#include "mini_uart.h" +#include "timer.h" +#include "sche.h" +#include "list.h" +#include "mm.h" +#include "exception_c.h" +#include "current.h" +#include "trap_frame.h" + +void thread_kill_zombies() +{ + unsigned long flags = disable_irq(); + while (!list_empty(&stopped_queue)) + { + struct task *victim = list_first_entry(&stopped_queue, struct task, list); + unlink(&victim->list); + free_task(victim); + } + irq_restore(flags); +} + +void thread_schedule(size_t _) +{ + if (!current->need_resched) + { + return; + } + + unsigned long flags = disable_irq(); + struct task *next = pick_next_task(); + next->need_resched = 0; + irq_restore(flags); + + switch_task(next); +} + +void thread_init() +{ + struct task *init = create_task(); + set_thread_ds(init); // init the thread structure +} + +static void foo() +{ + for (int i = 0; i < 5; ++i) + { + uart_printf("Thread id: %d i=%d\n", current->pid, i); + // sleep_task(500); + delay(1000000); + } + kill_task(current, 0); + thread_schedule(0); +} + +struct task *thread_create(void *func) +{ + struct task *new_thread = create_task(); + new_thread->kernel_stack = kmalloc(STACK_SIZE); + new_thread->state = TASK_RUNNING; + new_thread->cpu_context.lr = (unsigned long)func; + new_thread->cpu_context.sp = (unsigned long)new_thread->kernel_stack + STACK_SIZE - sizeof(TrapFrame); + + add_task(new_thread); + + return new_thread; +} + +void test_thread() +{ + for (int i = 0; i < 3; ++i) + { + thread_create(&foo); + } + uart_printf("end of test_thread\n"); +} diff --git a/lab7/src/timer.c b/lab7/src/timer.c new file mode 100644 index 000000000..a17bc0ccd --- /dev/null +++ b/lab7/src/timer.c @@ -0,0 +1,155 @@ +#include "timer.h" +#include "utils_s.h" +#include "mm.h" +#include "mini_uart.h" +#include "utils_c.h" +#include "thread.h" +#include "exception_c.h" +#include "current.h" + +timeout_event *timeout_queue_head = 0, *timeout_queue_tail = 0; +void core_timer_enable() +{ + /* + cntpct_el0 >= cntp_cval_el0 -> interrupt + cntp_tval_el0 = cntpct_el0 - cntp_cval_el0 + */ + write_sysreg(cntp_ctl_el0, 1); // enable + unsigned long frq = read_sysreg(cntfrq_el0) / 1000; + write_sysreg(cntp_tval_el0, frq * MS(SCHE_CYCLE)); // set expired time + *CORE0_TIMER_IRQ_CTRL = 2; // unmask timer interrupt +} + +void core_timer_disable() +{ + write_sysreg(cntp_ctl_el0, 0); // disable + *CORE0_TIMER_IRQ_CTRL = 0; // mask timer interrupt +} + +void set_expired_time(unsigned long duration) +{ + unsigned long frq = read_sysreg(cntfrq_el0) / 1000; + write_sysreg(cntp_tval_el0, frq * MS(duration)); // ms +} + +unsigned long get_current_time() +{ + // cntpct_el0: The timer’s current count. + unsigned long frq = read_sysreg(cntfrq_el0) / 1000; + unsigned long current_count = read_sysreg(cntpct_el0); + return (unsigned long)(current_count / frq); +} + +void set_timeout(char *message, unsigned long time) +{ + add_timer((timer_callback)print_message, (size_t)message, time); +} + +void print_message(char *msg) +{ + unsigned long current_time = get_current_time(); + uart_printf("\ncurrent time : %d.%ds\n", GET_S(current_time), GET_MS(current_time)); +} + +void timeout_event_init() +{ + timeout_queue_head = 0; + timeout_queue_tail = 0; + unsigned long cntkctl_el1; + cntkctl_el1 = read_sysreg(CNTKCTL_EL1); + cntkctl_el1 |= 1; + write_sysreg(CNTKCTL_EL1, cntkctl_el1); +} + +void add_timer(void (*cb)(size_t), size_t arg, unsigned long duration) +{ + timeout_event *new_event = (timeout_event *)kmalloc(sizeof(timeout_event)); + new_event->register_time = get_current_time(); + new_event->duration = duration; + new_event->callback = cb; + new_event->arg = arg; + new_event->next = 0; + new_event->prev = 0; + + size_t flag = disable_irq(); + if (timeout_queue_head == 0) + { + timeout_queue_head = new_event; + timeout_queue_tail = new_event; + core_timer_enable(); + set_expired_time(duration); + } + else + { + unsigned long timeout = new_event->register_time + new_event->duration; + timeout_event *cur = timeout_queue_head; + while (cur) + { + if ((cur->register_time + cur->duration) > timeout) + break; + cur = cur->next; + } + + if (cur == 0) + { // cur at end + new_event->prev = timeout_queue_tail; + timeout_queue_tail->next = new_event; + timeout_queue_tail = new_event; + } + else if (cur->prev == 0) + { // cur at head + new_event->next = cur; + (timeout_queue_head)->prev = new_event; + timeout_queue_head = new_event; + set_expired_time(duration); + } + else + { // cur at middle + new_event->next = cur; + new_event->prev = cur->prev; + (cur->prev)->next = new_event; + cur->prev = new_event; + } + } + irq_restore(flag); +} + +static inline void set_resched(unsigned long current_time) +{ + if (current_time >= current->timeout) + { + current->need_resched = 1; + } +} + +void timer_handler() +{ + unsigned long current_time = get_current_time(); + timeout_event *cur_event = timeout_queue_head; + timeout_event *next_event = cur_event->next; + if (next_event) + { + next_event->prev = 0; + timeout_queue_head = next_event; + set_expired_time(next_event->register_time + next_event->duration - current_time); + } + else + { + timeout_queue_head = timeout_queue_tail = 0; + core_timer_disable(); + } + + if (cur_event->callback == (timer_callback)&thread_schedule) + { + set_resched(current_time); + add_timer((timer_callback)thread_schedule, (size_t)0, MS(SCHE_CYCLE)); + enable_interrupt(); + thread_schedule(0); + disable_interrupt(); + } + else if (cur_event->callback) + { + cur_event->callback(cur_event->arg); + } + kfree(cur_event); +} \ No newline at end of file diff --git a/lab7/src/tmpfs.c b/lab7/src/tmpfs.c new file mode 100644 index 000000000..6233927a1 --- /dev/null +++ b/lab7/src/tmpfs.c @@ -0,0 +1,176 @@ +#include "tmpfs.h" +#include "vfs.h" +#include "utils_c.h" +#include "mm.h" +#include "stat.h" +#include "mini_uart.h" + +static int lookup(struct vnode *dir_node, struct vnode **target, const char *component_name); +static int create(struct vnode *dir_node, struct vnode **target, const char *component_name); +static int mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name); +struct vnode_operations tmpfs_v_ops = { + lookup, + create, + mkdir, +}; + +static int write(struct file *file, const void *buf, size_t len); +static int read(struct file *file, void *buf, size_t len); +static int open(struct vnode *file_node, struct file **target); +static int close(struct file *file); +static long lseek64(struct file *file, long offset, int whence); +struct file_operations tmpfs_f_ops = { + write, + read, + open, + close, + lseek64, +}; + +static int setup_mount(struct filesystem *fs, struct mount *mount) +{ + // should set mount->root as a obj before call setup_mount + mount->root->mount = mount; + mount->root->f_ops = &tmpfs_f_ops; + mount->root->v_ops = &tmpfs_v_ops; + mount->fs = fs; + + // clear the internal content + list_init(&mount->root->childs); + mount->root->child_num = 0; + mount->root->content = NULL; + mount->root->content_size = 0; + + return 0; +} + +static int lookup(struct vnode *dir_node, struct vnode **target, const char *component_name) +{ + struct vnode *vnode = NULL; + list_for_each_entry(vnode, &dir_node->childs, self) + { + if (!(utils_str_compare(vnode->name, component_name))) + { + *target = vnode; + return 0; + + } + } + return -1; +} +static int create(struct vnode *dir_node, struct vnode **target, const char *component_name) +{ + if (!lookup(dir_node, target, component_name)) + { + uart_printf("[create] the %s file is already exist\n", component_name); + return -1; + } + +#ifdef FS_DEBUG + uart_printf("[fs] create file:%s, parent:%s\n", component_name, dir_node->name); +#endif + + struct vnode *new_vnode = vnode_create(component_name, S_IFREG); + new_vnode->mount = dir_node->mount; + new_vnode->v_ops = dir_node->v_ops; + new_vnode->f_ops = dir_node->f_ops; + new_vnode->parent = dir_node; + + insert_tail(&dir_node->childs, &new_vnode->self); + dir_node->child_num += 1; + + *target = new_vnode; + return 0; +} +static int mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name) +{ + if (!lookup(dir_node, target, component_name)) + { + uart_printf("[mkdir] the %s directory is already exist\n", component_name); + return -1; + } + +#ifdef FS_DEBUG + uart_printf("[fs] mkdir:%s, parent:%s\n", component_name, dir_node->name); +#endif + + struct vnode *new_vnode = vnode_create(component_name, S_IFDIR); + new_vnode->mount = dir_node->mount; + new_vnode->v_ops = dir_node->v_ops; + new_vnode->f_ops = dir_node->f_ops; + new_vnode->parent = dir_node; + + insert_tail(&dir_node->childs, &new_vnode->self); + dir_node->child_num += 1; + + *target = new_vnode; + return 0; +} + +static int write(struct file *file, const void *buf, size_t len) +{ + struct vnode *vnode = file->vnode; + if (!S_ISREG(vnode->f_mode)) + { + uart_send_string("[write] not a regular file\n"); + return -1; + } + if (vnode->content_size <= file->f_pos + len) + { // enlarge content, +1 for EOF + void *new_content = kcalloc(sizeof(file->f_ops + len + 1)); + memcpy(new_content, vnode->content, vnode->content_size); // origin data; + if (vnode->content) + { // avoid the free the 0 in beginning + kfree(vnode->content); + } + + vnode->content = new_content; + vnode->content_size = file->f_pos + len + 1; // pos=22 len=8 30 + } + + memcpy(vnode->content + file->f_pos, buf, len); + file->f_pos += len; + + return len; +} +static int read(struct file *file, void *buf, size_t len) +{ + struct vnode *vnode = file->vnode; + if (!S_ISREG(vnode->f_mode)) + { + uart_send_string("[write] not a regular file\n"); + return -1; + } + int min = (len > vnode->content_size - file->f_pos - 1) ? vnode->content_size - file->f_pos - 1 : len; // -1 for EOF; + if (min == 0) + { + return -1; // f_pos at EOF or len==0; + } + memcpy(buf, vnode->content + file->f_pos, min); + file->f_pos += min; + return min; +} +static int open(struct vnode *file_node, struct file **target) +{ + // TODO + return 0; +} +static int close(struct file *file) +{ + kfree(file); + return 0; +} +static long lseek64(struct file *file, long offset, int whence) +{ + // TODO + return 0; +} + +struct filesystem *tmpfs_create() +{ + struct filesystem *fs = kmalloc(sizeof(struct filesystem)); + fs->name = "tmpfs"; + fs->setup_mount = &setup_mount; + list_init(&fs->list); + return fs; +} diff --git a/lab7/src/trans_el.S b/lab7/src/trans_el.S new file mode 100644 index 000000000..066bc1c7a --- /dev/null +++ b/lab7/src/trans_el.S @@ -0,0 +1,9 @@ +.globl from_el2_to_el1 +from_el2_to_el1: + mov x0, (1 << 31) // EL1 uses aarch64 + msr hcr_el2, x0 + mov x0, 0x3c5 // EL1h (SPSel = 1) with interrupt disabled + msr spsr_el2, x0 + msr elr_el2, lr + eret // return to EL1 + \ No newline at end of file diff --git a/lab7/src/utils_c.c b/lab7/src/utils_c.c new file mode 100644 index 000000000..e3d874f46 --- /dev/null +++ b/lab7/src/utils_c.c @@ -0,0 +1,185 @@ +#include "utils_c.h" +#include "mini_uart.h" +#include + +/* + string part +*/ + +int utils_str_compare(const char *a, const char *b) +{ + char aa, bb; + do + { + aa = (char)*a++; + bb = (char)*b++; + if (aa == '\0' || bb == '\0') + { + return aa - bb; + } + } while (aa == bb); + return aa - bb; +} + +int utils_strncmp(const char *a, const char *b, size_t n) +{ + size_t i = 0; + while (i < n - 1 && a[i] == b[i] && a[i] != '\0' && b[i] != '\0') + i++; + return a[i] - b[i]; +} + +int utils_str_delim(const char *str, const char *delim) +{ + // TODO + return 0; +} + +void utils_newline2end(char *str) +{ + while (*str != '\0') + { + if (*str == '\n') + { + *str = '\0'; + return; + } + ++str; + } +} + +void utils_int2str_dec(int num, char *str) +{ + // num=7114 digit=4 + int digit = -1, temp = num; + while (temp > 0) + { + temp /= 10; + digit++; + } + for (int i = digit; i >= 0; i--) + { + int t = 1; + for (int j = 0; j < i; j++) + { + t *= 10; + } + *str = '0' + num / t; + num = num % t; + str++; + } + *str = '\0'; +} + +void utils_uint2str_dec(unsigned int num, char *str) +{ + // num=7114 digit=4 + unsigned int temp = num; + int digit = -1; + while (temp > 0) + { + temp /= 10; + digit++; + } + for (int i = digit; i >= 0; i--) + { + int t = 1; + for (int j = 0; j < i; j++) + { + t *= 10; + } + *str = '0' + num / t; + num = num % t; + str++; + } + *str = '\0'; +} + +unsigned int utils_str2uint_dec(const char *str) +{ + unsigned int value = 0u; + + while (*str) + { + value = value * 10u + (*str - '0'); + ++str; + } + return value; +} + +size_t utils_strlen(const char *s) +{ + size_t i = 0; + while (s[i]) + i++; + return i + 1; +} + +/* + reboot part +*/ + +void set(long addr, unsigned long value) +{ + volatile unsigned int *point = (unsigned int *)addr; + *point = value; +} + +void reset(int tick) +{ // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick +} + +void cancel_reset() +{ + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} + +/* + others +*/ + +void align(void *size, size_t s) +{ + unsigned int *x = (unsigned int *)size; + if ((*x) & (s - 1)) + { + (*x) += s - ((*x) & (s - 1)); + } +} + +uint32_t align_up(uint32_t size, int alignment) +{ + return (size + alignment - 1) & -alignment; +} + +void delay(unsigned int clock) +{ + while (clock--) + { + asm volatile("nop"); + } +} + +void memcpy(void *dst, const void *src, size_t n) +{ + char *_dst = dst; + const char *_src = src; + + while (n--) + { + *_dst++ = *_src++; + } +} + +void *memset(void *s, int c, size_t n) +{ + char *p = s; + for (size_t i = 0; i < n; i++) + { + p[i] = c; + } + return s; +} diff --git a/lab7/src/utils_s.S b/lab7/src/utils_s.S new file mode 100644 index 000000000..2db1bb5ab --- /dev/null +++ b/lab7/src/utils_s.S @@ -0,0 +1,34 @@ +.global branchAddr +branchAddr: + br x0 + + +.globl get_el +get_el: + mrs x0, CurrentEl + lsr x0, x0, #2 + ret + +.global switch_to +switch_to: + + mov x9, sp + stp x19, x20, [x0, #0x0] + stp x21, x22, [x0, #0x10] + stp x23, x24, [x0, #0x20] + stp x25, x26, [x0, #0x30] + stp x27, x28, [x0, #0x40] + stp fp, x9, [x0, #0x50] + str lr, [x0, #0x60] + + ldp x19, x20, [x1, #0x0] + ldp x21, x22, [x1, #0x10] + ldp x23, x24, [x1, #0x20] + ldp x25, x26, [x1, #0x30] + ldp x27, x28, [x1, #0x40] + ldp fp, x9, [x1, #0x50] + ldr lr, [x1, #0x60] + mov sp, x9 + msr tpidr_el1, x1 + ret + diff --git a/lab7/src/vfs.c b/lab7/src/vfs.c new file mode 100644 index 000000000..dac00f62c --- /dev/null +++ b/lab7/src/vfs.c @@ -0,0 +1,505 @@ +#include "vfs.h" +#include "utils_c.h" +#include "mm.h" +#include "tmpfs.h" +#include "initramfs.h" +#include "mini_uart.h" +#include "current.h" + +list fs_list = LIST_HEAD_INIT(fs_list); +struct mount *rootfs, *initramfs; + +static const char *next_lvl_path(const char *src, char *dst, int size) +{ + for (int i = 0; i < size; ++i) + { + if (src[i] == 0) + { + dst[i] = 0; + return 0; + } + else if (src[i] == '/') + { + dst[i] = 0; + return src + i + 1; + } + else + dst[i] = src[i]; + } + return 0; +} + +char *get_path(struct vnode **node) +{ + /* return a absolute path for node*/ + int count = 0; + struct vnode *itr = *node; + char *compenent[128]; // brute force =_= + for (int i = 0; i < 128; i++) + { + compenent[i] = NULL; + } + while (itr->parent != itr) + { + int strlen = utils_strlen(itr->name); + compenent[count] = kcalloc(sizeof(char) * strlen); + memcpy(compenent[count], itr->name, strlen); + count++; + itr = itr->parent; + } + count -= 1; + + char *ret = kcalloc((count + 1) * COMPONENT_SIZE * sizeof(char)); // +1 for slash + int index = 1; + + ret[0] = '/'; + + for (int i = count - 1; i >= 0; i--) + { + for (int j = 0; j < utils_strlen(compenent[i]) - 1; j++) + { + ret[index++] = compenent[i][j]; + } + ret[index++] = '/'; + } + ret[index - 1] = '\0'; + for (int i = count - 1; i >= 0; i--) + { + kfree(compenent[i]); + } + + return ret; +} + +const char *path_to_abs(const char *pathname) +{ + struct vnode *target_node = NULL; + const char *_pathname = pathname; + + if (pathname[0] == '/') + { + return pathname; + } + else if (pathname[0] == '.') + { + if (pathname[1] == '.') + { // parent + target_node = current->pwd->parent; + _pathname = &pathname[3]; + } + else + { // cur + target_node = current->pwd; + _pathname = &pathname[2]; + } + } + else + { + target_node = current->pwd; + _pathname = pathname; + } + + char *prefix = get_path(&target_node); + int prefix_len = utils_strlen(prefix) - 1; + int _pathname_len = utils_strlen(_pathname); + + char *ret = kcalloc((prefix_len + _pathname_len) * sizeof(char)); + memcpy(ret, prefix, prefix_len); + ret[prefix_len] = '/'; + memcpy(ret + prefix_len + 1, _pathname, _pathname_len); + ret[prefix_len + _pathname_len] = '\0'; + + return ret; +} + +int set_itr_node(const char *pathname, struct vnode **vnode) +{ + /*set the beginning of traversing and return the index of _pathname start*/ + struct vnode *target_node = NULL; + int index = 0; + + if (pathname[0] == '/') // root file + { + *vnode = rootfs->root; + index = 1; + return index; + } + else if (pathname[0] == '.') + { + if (pathname[1] == '.') // ../ + { + target_node = current->pwd->parent; + index = 3; + } + else // ./ + { + target_node = current->pwd; + index = 2; + } + } + else + { + target_node = current->pwd; + } + + *vnode = target_node; + return index; +} + +int set_couple_node(struct vnode **parent, struct vnode **child, const char *pathname, char *prefix) +{ + /* if the pathname='/dir1/dir2/text' -> parent=dir2 child=text */ + struct vnode *target_node = NULL; + + struct vnode *itr = NULL; + int index = set_itr_node(pathname, &itr); + const char *_pathname = &pathname[index]; // pathname=../dir2/file _pathname=dir2/file; + + /* if pathname='/' -> _pathname='' */ + if (!_pathname[0]) + { + *parent = rootfs->root; + *child = rootfs->root; + next_lvl_path(_pathname, prefix, COMPONENT_SIZE); // update prefix + return 0; + } + + /* The itr will be a directory (root is the toppest) */ + while (1) + { + _pathname = next_lvl_path(_pathname, prefix, COMPONENT_SIZE); + + if (itr->v_ops->lookup(itr, &target_node, prefix) == -1) + { + *parent = itr; + *child = NULL; + return -1; + } + else + { + if (S_ISDIR(target_node->f_mode)) // S_ISDIR --> is directory + { + if (!_pathname) + { + /* encounter the last component */ + *child = target_node; + *parent = target_node->parent; + return 0; + } + itr = target_node; + } + else if (S_ISREG(target_node->f_mode)) // S_ISREG --> is normal file + { + *child = target_node; + *parent = target_node->parent; + return 0; + } + } + } + + return 0; +} + +struct vnode *vnode_create(const char *name, unsigned int flags) +{ + struct vnode *vnode = kcalloc(sizeof(struct vnode)); + + list_init(&vnode->childs); + list_init(&vnode->self); + vnode->child_num = 0; + vnode->parent = NULL; + + size_t name_len = utils_strlen(name); + vnode->name = kcalloc(sizeof(name_len)); + memcpy(vnode->name, name, name_len); + + vnode->f_mode = flags; + + vnode->content = NULL; + vnode->content_size = 0; + + return vnode; +} + +void init_rootfs() +{ + if (fs_register(tmpfs_create())) + { + uart_send_string("[fs] Error! fail to register tmpfs\n"); + } + rootfs = kcalloc(sizeof(struct mount)); + struct filesystem *fs = fs_get("tmpfs"); + if (!fs) + { + uart_send_string("[fs] Error! fail to get tmpfs\n"); + return; + } + rootfs->fs = fs; + rootfs->root = vnode_create("", S_IFDIR); // tag --> is directory + rootfs->fs->setup_mount(rootfs->fs, rootfs); +#ifdef FS_DEBUG + uart_send_string("[fs] init rootfs success\n"); +#endif +} +void init_initramfs() +{ + struct vnode *initramfs_root = NULL; + if (vfs_lookup("/initramfs", &initramfs_root)) + { + uart_send_string("[init_initramfs] fail to lookup /initramfs\n"); + } + if (fs_register(initramfs_create())) + { + uart_send_string("[fs] Error! fail to register tmpfs\n"); + } + initramfs = kcalloc(sizeof(struct mount)); + struct filesystem *fs = fs_get("initramfs"); + if (!fs) + { + uart_send_string("[fs] Error! fail to get initramfs\n"); + return; + } + initramfs->fs = fs; + initramfs->root = initramfs_root; + initramfs->fs->setup_mount(initramfs->fs, initramfs); +#ifdef FS_DEBUG + uart_send_string("[fs] init rootfs success\n"); +#endif +} + +void fs_init() +{ + init_rootfs(); + vfs_mkdir("/initramfs"); + init_initramfs(); +} + +int fs_register(struct filesystem *fs) +{ + if (!fs_get(fs->name)) + { + insert_tail(&fs_list, &fs->list); + return 0; + } + return -1; +} + +struct filesystem *fs_get(const char *name) +{ + struct filesystem *fs; + list_for_each_entry(fs, &fs_list, list) + { + if (!utils_str_compare(fs->name, name)) + { + return fs; + } + } + return NULL; +} + +int vfs_open(const char *pathname, int flags, struct file **target) +{ + int res = 0; + struct vnode *target_node = NULL; + res = vfs_lookup(pathname, &target_node); // find child return 0, can't find child retrun -1 + + // can't find file(vnode) and don't need creat file + if (res == -1 && !(flags & O_CREAT)) + { + /* can't lookup and without O_CREAT flag */ + uart_printf("[vfs_open] fail to open the %s\n", pathname); + return -1; + } + + // creat file handle + *target = kcalloc(sizeof(struct file)); + (*target)->flags = flags; + (*target)->f_ops = target_node->f_ops; + (*target)->f_pos = 0; + + if (!res) // find file(vnode) + { + (*target)->vnode = target_node; +#ifdef FS_DEBUG + uart_printf("[vfs_open] find it by lookup\n"); +#endif + return 0; + } + + // can't find file(vnode) --> creat vnode + struct vnode *parent = NULL, *child = NULL; + char child_name[COMPONENT_SIZE]; + + set_couple_node(&parent, &child, pathname, child_name); + if (!child) + { + parent->v_ops->create(parent, &child, child_name); + (*target)->vnode = child; // file handle connect vnode + return 0; + } + + return -1; +} + +int vfs_close(struct file *file) +{ + return file->vnode->f_ops->close(file); +} + +int vfs_write(struct file *file, const void *buf, size_t len) +{ + return file->vnode->f_ops->write(file, buf, len); +} + +int vfs_read(struct file *file, void *buf, size_t len) +{ + return file->vnode->f_ops->read(file, buf, len); +} + +int vfs_mkdir(const char *pathname) +{ + struct vnode *parent = NULL, *child = NULL; + char child_name[COMPONENT_SIZE]; + + set_couple_node(&parent, &child, pathname, child_name); + + if (child) + { + uart_printf("[vfs_mkdir] the %s is already exist\n", pathname); + return -1; + } + parent->v_ops->mkdir(parent, &child, child_name); + return 0; +} +int vfs_mount(const char *target, const char *filesystem) +{ + struct filesystem *fs = fs_get(filesystem); + if (!fs) + { + uart_send_string("[vfs_mount] Error! fail to get fs\n"); + return -1; + } + + struct vnode *vnode; + if (vfs_lookup(target, &vnode) == -1) + { + uart_send_string("[vfs_mount] Error! fail to lookup\n"); + return -1; + } + + if (!S_ISDIR(vnode->f_mode)) + { + uart_send_string("[vfs_mount] Error! the target is not a directory\n"); + return -1; + } + + struct mount *new_mount = kcalloc(sizeof(struct mount)); + new_mount->fs = fs; + new_mount->root = vnode; + new_mount->fs->setup_mount(new_mount->fs, new_mount); + + return 0; +} + +// find child return 0, can't find child retrun -1 +int vfs_lookup(const char *pathname, struct vnode **target) +{ + struct vnode *parent = NULL, *child = NULL; + char child_name[COMPONENT_SIZE]; + set_couple_node(&parent, &child, pathname, child_name); + if (child) + { + *target = child; + return 0; + } + return -1; +} + +// change directory +int vfs_chdir(const char *pathname) +{ + struct vnode *node = NULL; + + if (vfs_lookup(pathname, &node) == -1) + { + uart_printf("[vfs_chdir] fail to loopup the dir:%s\n", pathname); + return -1; + } + current->pwd = node; + return 0; +} + +void vfs_test() +{ + struct file *f1; + /* + // absolute path + vfs_mkdir("/dir1"); + vfs_mkdir("/dir4"); + vfs_mkdir("/dir1/dir3"); + vfs_mkdir("/dir1/dir2"); + + if (!vfs_open("/dir1/dir3/text", O_CREAT, &f1)) + { + uart_send_string("[v] open the /dir1/dir3/text \n"); + } + char buf1[10] = "012345678\n"; + char buf2[10] = {0}; + vfs_write(f1, buf1, 8); + vfs_close(f1); + + vfs_open("/dir1/dir3/text", 0, &f1); + vfs_read(f1, buf2, 8); + uart_printf("read buf2 :%s\n", buf2); + vfs_close(f1); + + if (vfs_mkdir("/dir1/dir2/dir5")) + { + uart_send_string("[v] vfs_mkdir /dir1/dir2/dir5 fail \n"); + } + if (!vfs_mount("/dir1/dir2/dir5", "tmpfs")) + { + uart_send_string("[v] vfs_mount /dir1/dir2/dir5 success \n"); + } + + vfs_open("/dir4/t2", O_CREAT, &f1); + vfs_close(f1); + + vfs_mkdir("/dir1/dir1"); + vfs_open("/dir1/dir1/t3", O_CREAT, &f1); + vfs_close(f1); + + vfs_chdir("/dir1"); + */ + + // relative path + if (vfs_mkdir("/dir1") == -1) + { + uart_printf("fail to mkdir /dir1\n"); + } + vfs_chdir("/dir1"); + if (vfs_mkdir("../dir4") == -1) + { + uart_printf("fail to mkdir ../dir4\n"); + } + vfs_mkdir("dir2"); + vfs_mkdir("./dir3"); + vfs_open("../dir4/t2", O_CREAT, &f1); + + char buf1[10] = "012345678\n"; + char buf2[10] = {0}; + vfs_write(f1, buf1, 8); + vfs_close(f1); + vfs_open("../dir4/t2", 0, &f1); + vfs_read(f1, buf2, 8); + uart_printf("read buf2 :%s\n", buf2); + vfs_close(f1); + if (vfs_mkdir("./dir2/dir5")) + { + uart_send_string("[v] vfs_mkdir ./dir2/dir5 fail \n"); + } + if (!vfs_mount("dir2/dir5", "tmpfs")) + { + uart_send_string("[v] vfs_mount dir2/dir5 success \n"); + } +} \ No newline at end of file diff --git a/lab7/users/user1/linker.ld b/lab7/users/user1/linker.ld new file mode 100644 index 000000000..bac8da058 --- /dev/null +++ b/lab7/users/user1/linker.ld @@ -0,0 +1,26 @@ +SECTIONS +{ + .start : { + *(.start) + } + + _stext = .; + .text : { + *(.text) + *(.rodata) + } + . = ALIGN(0x1000); + _etext = .; + + _sdata = .; + .data : { *(.data) } + . = ALIGN(0x1000); + _edata = .; + + + _sbss = .; + .bss : { *(.bss*) } + . = ALIGN(0x1000); + _ebss = .; + +} \ No newline at end of file diff --git a/lab7/users/user1/main.c b/lab7/users/user1/main.c new file mode 100644 index 000000000..4a8ceeea0 --- /dev/null +++ b/lab7/users/user1/main.c @@ -0,0 +1,286 @@ +#include +#include + +#define SYS_GETPID 0 +#define SYS_UART_RECV 1 +#define SYS_UART_WRITE 2 +#define SYS_EXEC 3 +#define SYS_FORK 4 +#define SYS_EXIT 5 +#define SYS_MBOX_CALL 6 +#define SYS_KILL_PID 7 + +int start(void) __attribute__((section(".start"))); + +unsigned long syscall(unsigned long syscall_num, + void *x0, + void *x1, + void *x2, + void *x3, + void *x4, + void *x5) +{ + unsigned long result; + + asm volatile( + "ldr x8, %0\n" + "ldr x0, %1\n" + "ldr x1, %2\n" + "ldr x2, %3\n" + "ldr x3, %4\n" + "ldr x4, %5\n" + "ldr x5, %6\n" + "svc 0\n" ::"m"(syscall_num), + "m"(x0), "m"(x1), + "m"(x2), "m"(x3), "m"(x4), "m"(x5)); + + asm volatile( + "str x0, %0\n" + : "=m"(result)); + + return result; +} +/* system call */ +int getpid() +{ + return (int)syscall(SYS_GETPID, 0, 0, 0, 0, 0, 0); +} + +void uart_recv(const char buf[], size_t size) +{ + syscall(SYS_UART_RECV, (void *)buf, (void *)size, 0, 0, 0, 0); +} + +void uart_write(const char buf[], size_t size) +{ + syscall(SYS_UART_WRITE, (void *)buf, (void *)size, 0, 0, 0, 0); +} + +void exit(void) +{ + syscall(SYS_EXIT, 0, 0, 0, 0, 0, 0); +} +void kill_pid(unsigned long pid) +{ + syscall(SYS_KILL_PID, (void *)pid, 0, 0, 0, 0, 0); +} +void mailbox_call(unsigned char ch, unsigned int *mbox) +{ + syscall(SYS_MBOX_CALL, (void *)(unsigned long)ch, mbox, 0, 0, 0, 0); +} +void exec(const char *name, char *const argv[]) +{ + syscall(SYS_EXEC, (void *)name, (void *)argv, 0, 0, 0, 0); +} + +/* normal function */ + +static void uart_send(char c) +{ + uart_write(&c, 1); +} + +void uart_send_string(const char *str) +{ + while (*str) + { + uart_send(*str++); + } +} + +unsigned int vsprintf(char *dst, char *fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig = dst, tmpstr[19]; + + // failsafes + if (dst == (void *)0 || fmt == (void *)0) + { + return 0; + } + + // main loop + arg = 0; + while (*fmt) + { + // argument access + if (*fmt == '%') + { + fmt++; + // literal % + if (*fmt == '%') + { + goto put; + } + len = 0; + // size modifier + while (*fmt >= '0' && *fmt <= '9') + { + len *= 10; + len += *fmt - '0'; + fmt++; + } + // skip long modifier + if (*fmt == 'l') + { + fmt++; + } + // character + if (*fmt == 'c') + { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } + else + // decimal number + if (*fmt == 'd') + { + arg = __builtin_va_arg(args, int); + // check input + sign = 0; + if ((int)arg < 0) + { + arg *= -1; + sign++; + } + if (arg > 99999999999999999L) + { + arg = 99999999999999999L; + } + // convert to string + i = 18; + tmpstr[i] = 0; + do + { + tmpstr[--i] = '0' + (arg % 10); + arg /= 10; + } while (arg != 0 && i > 0); + if (sign) + { + tmpstr[--i] = '-'; + } + // padding, only space + if (len > 0 && len < 18) + { + while (i > 18 - len) + { + tmpstr[--i] = ' '; + } + } + p = &tmpstr[i]; + goto copystring; + } + else + // hex number + if (*fmt == 'x') + { + arg = __builtin_va_arg(args, long int); + // convert to string + i = 16; + tmpstr[i] = 0; + do + { + char n = arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i] = n + (n > 9 ? 0x37 : 0x30); + arg >>= 4; + } while (arg != 0 && i > 0); + // padding, only leading zeros + if (len > 0 && len <= 16) + { + while (i > 16 - len) + { + tmpstr[--i] = '0'; + } + } + p = &tmpstr[i]; + goto copystring; + } + else + // string + if (*fmt == 's') + { + p = __builtin_va_arg(args, char *); + copystring: + if (p == (void *)0) + { + p = "(null)"; + } + while (*p) + { + *dst++ = *p++; + } + } + } + else + { + put: + *dst++ = *fmt; + } + fmt++; + } + *dst = 0; + // number of bytes written + return dst - orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char *fmt, ...) +{ + //__builtin_va_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst, fmt, args); +} +unsigned int uart_printf(char *fmt, ...) +{ + char dst[100]; + // __builtin_va_start(args, fmt): "..." is pointed by args + // __builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + unsigned int ret = vsprintf(dst, fmt, args); + uart_send_string(dst); + return ret; +} + +#define MAILBOX_CH_PROP 8 +#define REQUEST_CODE 0x00000000 +#define GET_BOARD_REVISION 0x00010002 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + + +unsigned int __attribute__((aligned(16))) mailbox[8]; + + +unsigned int get_board_revision() +{ + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = END_TAG; + + mailbox_call(MAILBOX_CH_PROP, mailbox); // message passing procedure call, you should implement it following the 6 steps provided above. + return mailbox[5]; +} + +int start(void) +{ + int pid = getpid(); + uart_printf("[User1] pid:%d\n", pid); + + exit(); + return 0; +} diff --git a/lab7/users/user2/linker.ld b/lab7/users/user2/linker.ld new file mode 100644 index 000000000..bac8da058 --- /dev/null +++ b/lab7/users/user2/linker.ld @@ -0,0 +1,26 @@ +SECTIONS +{ + .start : { + *(.start) + } + + _stext = .; + .text : { + *(.text) + *(.rodata) + } + . = ALIGN(0x1000); + _etext = .; + + _sdata = .; + .data : { *(.data) } + . = ALIGN(0x1000); + _edata = .; + + + _sbss = .; + .bss : { *(.bss*) } + . = ALIGN(0x1000); + _ebss = .; + +} \ No newline at end of file diff --git a/lab7/users/user2/main.c b/lab7/users/user2/main.c new file mode 100644 index 000000000..e4f23e9f3 --- /dev/null +++ b/lab7/users/user2/main.c @@ -0,0 +1,305 @@ +#include +#include + +#define SYS_GETPID 0 +#define SYS_UART_RECV 1 +#define SYS_UART_WRITE 2 +#define SYS_EXEC 3 +#define SYS_FORK 4 +#define SYS_EXIT 5 +#define SYS_MBOX_CALL 6 +#define SYS_KILL_PID 7 + +int start(void) __attribute__((section(".start"))); + +unsigned long syscall(unsigned long syscall_num, + void *x0, + void *x1, + void *x2, + void *x3, + void *x4, + void *x5) +{ + unsigned long result; + + asm volatile( + "ldr x8, %0\n" + "ldr x0, %1\n" + "ldr x1, %2\n" + "ldr x2, %3\n" + "ldr x3, %4\n" + "ldr x4, %5\n" + "ldr x5, %6\n" + "svc 0\n" ::"m"(syscall_num), + "m"(x0), "m"(x1), + "m"(x2), "m"(x3), "m"(x4), "m"(x5)); + + asm volatile( + "str x0, %0\n" + : "=m"(result)); + + return result; +} +/* system call */ +int getpid() +{ + return (int)syscall(SYS_GETPID, 0, 0, 0, 0, 0, 0); +} + +void uart_recv(const char buf[], size_t size) +{ + syscall(SYS_UART_RECV, (void *)buf, (void *)size, 0, 0, 0, 0); +} + +void uart_write(const char buf[], size_t size) +{ + syscall(SYS_UART_WRITE, (void *)buf, (void *)size, 0, 0, 0, 0); +} + +void exit(void) +{ + syscall(SYS_EXIT, 0, 0, 0, 0, 0, 0); +} +void kill_pid(unsigned long pid) +{ + syscall(SYS_KILL_PID, (void *)pid, 0, 0, 0, 0, 0); +} +void mailbox_call(unsigned char ch, unsigned int *mbox) +{ + syscall(SYS_MBOX_CALL, (void *)(unsigned long)ch, mbox, 0, 0, 0, 0); +} +void exec(const char *name, char *const argv[]) +{ + syscall(SYS_EXEC, (void *)name, (void *)argv, 0, 0, 0, 0); +} +int fork(void) +{ + return (int)syscall(SYS_FORK, 0, 0, 0, 0, 0, 0); +} +/* normal function */ + +static void uart_send(char c) +{ + uart_write(&c, 1); +} + +void uart_send_string(const char *str) +{ + while (*str) + { + uart_send(*str++); + } +} + +unsigned int vsprintf(char *dst, char *fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig = dst, tmpstr[19]; + + // failsafes + if (dst == (void *)0 || fmt == (void *)0) + { + return 0; + } + + // main loop + arg = 0; + while (*fmt) + { + // argument access + if (*fmt == '%') + { + fmt++; + // literal % + if (*fmt == '%') + { + goto put; + } + len = 0; + // size modifier + while (*fmt >= '0' && *fmt <= '9') + { + len *= 10; + len += *fmt - '0'; + fmt++; + } + // skip long modifier + if (*fmt == 'l') + { + fmt++; + } + // character + if (*fmt == 'c') + { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } + else + // decimal number + if (*fmt == 'd') + { + arg = __builtin_va_arg(args, int); + // check input + sign = 0; + if ((int)arg < 0) + { + arg *= -1; + sign++; + } + if (arg > 99999999999999999L) + { + arg = 99999999999999999L; + } + // convert to string + i = 18; + tmpstr[i] = 0; + do + { + tmpstr[--i] = '0' + (arg % 10); + arg /= 10; + } while (arg != 0 && i > 0); + if (sign) + { + tmpstr[--i] = '-'; + } + // padding, only space + if (len > 0 && len < 18) + { + while (i > 18 - len) + { + tmpstr[--i] = ' '; + } + } + p = &tmpstr[i]; + goto copystring; + } + else + // hex number + if (*fmt == 'x') + { + arg = __builtin_va_arg(args, long int); + // convert to string + i = 16; + tmpstr[i] = 0; + do + { + char n = arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i] = n + (n > 9 ? 0x37 : 0x30); + arg >>= 4; + } while (arg != 0 && i > 0); + // padding, only leading zeros + if (len > 0 && len <= 16) + { + while (i > 16 - len) + { + tmpstr[--i] = '0'; + } + } + p = &tmpstr[i]; + goto copystring; + } + else + // string + if (*fmt == 's') + { + p = __builtin_va_arg(args, char *); + copystring: + if (p == (void *)0) + { + p = "(null)"; + } + while (*p) + { + *dst++ = *p++; + } + } + } + else + { + put: + *dst++ = *fmt; + } + fmt++; + } + *dst = 0; + // number of bytes written + return dst - orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char *fmt, ...) +{ + //__builtin_va_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst, fmt, args); +} +unsigned int uart_printf(char *fmt, ...) +{ + char dst[100]; + // __builtin_va_start(args, fmt): "..." is pointed by args + // __builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + unsigned int ret = vsprintf(dst, fmt, args); + uart_send_string(dst); + return ret; +} + +#define MAILBOX_CH_PROP 8 +#define REQUEST_CODE 0x00000000 +#define GET_BOARD_REVISION 0x00010002 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +// unsigned int __attribute__((aligned(16))) mailbox[8]; +unsigned int get_board_revision() +{ + unsigned int __attribute__((aligned(16))) mailbox[8]; + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = END_TAG; + mailbox_call(MAILBOX_CH_PROP, &mailbox[0]); // message passing procedure call, you should implement it following the 6 steps provided above. + return mailbox[5]; +} + +int start(void) +{ + // char buf1[0x10] = {0}; + uart_printf("[User2] Into start\n"); + int pid = getpid(); + + uart_printf("[User2] pid:%d\n", pid); + + unsigned int revision = get_board_revision(); + uart_printf("[User2] Revision: %x\n", revision); + + pid = fork(); + + if (pid == 0) + { + uart_printf("[User2] child: exec /initramfs/user1.img\r\n"); + exec("/initramfs/user1.img", NULL); + } + else + { + uart_printf("[User2] parent: child pid: %d\n", pid); + } + uart_printf("[User2 ] exit\n"); + + exit(); + return 0; +} diff --git a/lab8/ReadMe.md b/lab8/ReadMe.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/lab8/ReadMe.md @@ -0,0 +1 @@ + diff --git a/lab8/img/FAT_R.txt b/lab8/img/FAT_R.txt new file mode 100644 index 000000000..5d2252cd1 --- /dev/null +++ b/lab8/img/FAT_R.txt @@ -0,0 +1 @@ +fat_r test \ No newline at end of file diff --git a/lab8/img/bcm2710-rpi-3-b-plus.dtb b/lab8/img/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..3934b3a26 Binary files /dev/null and b/lab8/img/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab8/img/bootcode.bin b/lab8/img/bootcode.bin new file mode 100644 index 000000000..944263a65 Binary files /dev/null and b/lab8/img/bootcode.bin differ diff --git a/lab8/img/config.txt b/lab8/img/config.txt new file mode 100644 index 000000000..e82fa85fa --- /dev/null +++ b/lab8/img/config.txt @@ -0,0 +1,3 @@ +kernel=bootloader.img +arm_64bit=1 +initramfs initramfs.cpio 0x8000000 \ No newline at end of file diff --git a/lab8/img/fixup.dat b/lab8/img/fixup.dat new file mode 100644 index 000000000..e928ee3fc Binary files /dev/null and b/lab8/img/fixup.dat differ diff --git a/lab8/img/start.elf b/lab8/img/start.elf new file mode 100644 index 000000000..2f1fc7d33 Binary files /dev/null and b/lab8/img/start.elf differ diff --git a/lab8/include/bootloader/BCM2837.h b/lab8/include/bootloader/BCM2837.h new file mode 100644 index 000000000..a38cc74e7 --- /dev/null +++ b/lab8/include/bootloader/BCM2837.h @@ -0,0 +1,54 @@ +#ifndef _BCM2837_H +#define _BCM2837_H +// Ref: https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf + +#define PERIPHERALS_BASE 0x3f000000 +#define BUS_BASE 0x7e000000 + +#define BUS_TO_PERIPHERALS(addr) (addr - BUS_BASE + PERIPHERALS_BASE) + +// Auxiliaries: UART1 & SPI1, SPI2 +#define AUX_IRQ BUS_TO_PERIPHERALS(0x7E215000) +#define AUX_ENABLES BUS_TO_PERIPHERALS(0x7E215004) +#define AUX_MU_IO_REG BUS_TO_PERIPHERALS(0x7E215040) +#define AUX_MU_IER_REG BUS_TO_PERIPHERALS(0x7E215044) +#define AUX_MU_IIR_REG BUS_TO_PERIPHERALS(0x7E215048) +#define AUX_MU_LCR_REG BUS_TO_PERIPHERALS(0x7E21504c) +#define AUX_MU_MCR_REG BUS_TO_PERIPHERALS(0x7E215050) +#define AUX_MU_LSR_REG BUS_TO_PERIPHERALS(0x7E215054) +#define AUX_MU_MSR_REG BUS_TO_PERIPHERALS(0x7E215058) +#define AUX_MU_SCRATCH BUS_TO_PERIPHERALS(0x7E21505c) +#define AUX_MU_CNTL_REG BUS_TO_PERIPHERALS(0x7E215060) +#define AUX_MU_STAT_REG BUS_TO_PERIPHERALS(0x7E215064) +#define AUX_MU_BAUD_REG BUS_TO_PERIPHERALS(0x7E215068) +#define AUX_SPI0_CNTL0_REG BUS_TO_PERIPHERALS(0x7E215080) +#define AUX_SPI0_CNTL1_REG BUS_TO_PERIPHERALS(0x7E215084) +#define AUX_SPI0_STAT_REG BUS_TO_PERIPHERALS(0x7E215088) +#define AUX_SPI0_IO_REG BUS_TO_PERIPHERALS(0x7E215090) +#define AUX_SPI0_PEEK_REG BUS_TO_PERIPHERALS(0x7E215094) +#define AUX_SPI1_CNTL0_REG BUS_TO_PERIPHERALS(0x7E2150c0) +#define AUX_SPI1_CNTL1_REG BUS_TO_PERIPHERALS(0x7E2150c4) +#define AUX_SPI1_STAT_REG BUS_TO_PERIPHERALS(0x7E2150c8) +#define AUX_SPI1_IO_REG BUS_TO_PERIPHERALS(0x7E2150d0) +#define AUX_SPI1_PEEK_REG BUS_TO_PERIPHERALS(0x7E2150d4) + +// GPIO +#define GPFSEL0 BUS_TO_PERIPHERALS(0x7E200000) +#define GPFSEL1 BUS_TO_PERIPHERALS(0x7E200004) +#define GPFSEL2 BUS_TO_PERIPHERALS(0x7E200008) +#define GPFSEL3 BUS_TO_PERIPHERALS(0x7E20000c) +#define GPFSEL4 BUS_TO_PERIPHERALS(0x7E200010) +#define GPFSEL5 BUS_TO_PERIPHERALS(0x7E200014) + +#define GPPUD BUS_TO_PERIPHERALS(0x7E200094) +#define GPPUDCLK0 BUS_TO_PERIPHERALS(0x7E200098) +#define GPPUDCLK1 BUS_TO_PERIPHERALS(0x7E20009c) + +// Interrupt +#define IRQ_ENABLE_1_REG BUS_TO_PERIPHERALS(0x7E00B210) + +void BCM2837_reset(int tick); +void BCM2837_cancel_reset(); + + +#endif /* _BCM2837_H */ \ No newline at end of file diff --git a/lab8/include/bootloader/mini_uart.h b/lab8/include/bootloader/mini_uart.h new file mode 100644 index 000000000..6fb5e637f --- /dev/null +++ b/lab8/include/bootloader/mini_uart.h @@ -0,0 +1,14 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + +#include + +uint32 uart_recvline(char *buff, int maxlen); +void uart_init(void); +char uart_recv(void); +uint32 uart_recv_uint(void); +void uart_send(char c); +void uart_sendn(char *str, int n); +void uart_printf(char *fmt, ...); + +#endif /* _MINI_UART_H */ \ No newline at end of file diff --git a/lab8/include/bootloader/rpi3.h b/lab8/include/bootloader/rpi3.h new file mode 100644 index 000000000..90d9ab894 --- /dev/null +++ b/lab8/include/bootloader/rpi3.h @@ -0,0 +1,13 @@ +#ifndef _RPI3_H +#define _RPI3_H + +struct arm_memory_info { + unsigned int baseaddr; + unsigned int size; +}; + +void mailbox_call(unsigned char channel, unsigned int *mb); +unsigned int get_board_revision(void); +void get_arm_memory(struct arm_memory_info *); + +#endif \ No newline at end of file diff --git a/lab8/include/kernel/BCM2837.h b/lab8/include/kernel/BCM2837.h new file mode 100644 index 000000000..a38cc74e7 --- /dev/null +++ b/lab8/include/kernel/BCM2837.h @@ -0,0 +1,54 @@ +#ifndef _BCM2837_H +#define _BCM2837_H +// Ref: https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf + +#define PERIPHERALS_BASE 0x3f000000 +#define BUS_BASE 0x7e000000 + +#define BUS_TO_PERIPHERALS(addr) (addr - BUS_BASE + PERIPHERALS_BASE) + +// Auxiliaries: UART1 & SPI1, SPI2 +#define AUX_IRQ BUS_TO_PERIPHERALS(0x7E215000) +#define AUX_ENABLES BUS_TO_PERIPHERALS(0x7E215004) +#define AUX_MU_IO_REG BUS_TO_PERIPHERALS(0x7E215040) +#define AUX_MU_IER_REG BUS_TO_PERIPHERALS(0x7E215044) +#define AUX_MU_IIR_REG BUS_TO_PERIPHERALS(0x7E215048) +#define AUX_MU_LCR_REG BUS_TO_PERIPHERALS(0x7E21504c) +#define AUX_MU_MCR_REG BUS_TO_PERIPHERALS(0x7E215050) +#define AUX_MU_LSR_REG BUS_TO_PERIPHERALS(0x7E215054) +#define AUX_MU_MSR_REG BUS_TO_PERIPHERALS(0x7E215058) +#define AUX_MU_SCRATCH BUS_TO_PERIPHERALS(0x7E21505c) +#define AUX_MU_CNTL_REG BUS_TO_PERIPHERALS(0x7E215060) +#define AUX_MU_STAT_REG BUS_TO_PERIPHERALS(0x7E215064) +#define AUX_MU_BAUD_REG BUS_TO_PERIPHERALS(0x7E215068) +#define AUX_SPI0_CNTL0_REG BUS_TO_PERIPHERALS(0x7E215080) +#define AUX_SPI0_CNTL1_REG BUS_TO_PERIPHERALS(0x7E215084) +#define AUX_SPI0_STAT_REG BUS_TO_PERIPHERALS(0x7E215088) +#define AUX_SPI0_IO_REG BUS_TO_PERIPHERALS(0x7E215090) +#define AUX_SPI0_PEEK_REG BUS_TO_PERIPHERALS(0x7E215094) +#define AUX_SPI1_CNTL0_REG BUS_TO_PERIPHERALS(0x7E2150c0) +#define AUX_SPI1_CNTL1_REG BUS_TO_PERIPHERALS(0x7E2150c4) +#define AUX_SPI1_STAT_REG BUS_TO_PERIPHERALS(0x7E2150c8) +#define AUX_SPI1_IO_REG BUS_TO_PERIPHERALS(0x7E2150d0) +#define AUX_SPI1_PEEK_REG BUS_TO_PERIPHERALS(0x7E2150d4) + +// GPIO +#define GPFSEL0 BUS_TO_PERIPHERALS(0x7E200000) +#define GPFSEL1 BUS_TO_PERIPHERALS(0x7E200004) +#define GPFSEL2 BUS_TO_PERIPHERALS(0x7E200008) +#define GPFSEL3 BUS_TO_PERIPHERALS(0x7E20000c) +#define GPFSEL4 BUS_TO_PERIPHERALS(0x7E200010) +#define GPFSEL5 BUS_TO_PERIPHERALS(0x7E200014) + +#define GPPUD BUS_TO_PERIPHERALS(0x7E200094) +#define GPPUDCLK0 BUS_TO_PERIPHERALS(0x7E200098) +#define GPPUDCLK1 BUS_TO_PERIPHERALS(0x7E20009c) + +// Interrupt +#define IRQ_ENABLE_1_REG BUS_TO_PERIPHERALS(0x7E00B210) + +void BCM2837_reset(int tick); +void BCM2837_cancel_reset(); + + +#endif /* _BCM2837_H */ \ No newline at end of file diff --git a/lab8/include/kernel/arm.h b/lab8/include/kernel/arm.h new file mode 100644 index 000000000..c0e282c21 --- /dev/null +++ b/lab8/include/kernel/arm.h @@ -0,0 +1,28 @@ +#ifndef _ARM_H +#define _ARM_H + +/* ==== PAR_EL1 related ==== */ +#define PAR_FAILED(par) (par & 1) +#define PAR_PA(par) (par & 0x0000fffffffff000) + +/* ==== ESR_EL1 related ==== */ +#define EC_SVC_64 0x15 +#define EC_IA_LE 0x20 +#define EC_DA_LE 0x24 + +#define ISS_FSC(esr) (esr->iss & 0x3f) + +#define FSC_TF_L0 0b000100 +#define FSC_TF_L1 0b000101 +#define FSC_TF_L2 0b000110 +#define FSC_TF_L3 0b000111 + +#define ISS_WnR(esr) (esr->iss & 0x40) + +typedef struct { + unsigned int iss:25, // Instruction specific syndrome + il:1, // Instruction length bit + ec:6; // Exception class +} esr_el1_t; + +#endif /* _ARM_H */ \ No newline at end of file diff --git a/lab8/include/kernel/cpio.h b/lab8/include/kernel/cpio.h new file mode 100644 index 000000000..10ecf6d48 --- /dev/null +++ b/lab8/include/kernel/cpio.h @@ -0,0 +1,11 @@ +#ifndef _CPIO_H +#define _CPIO_H + +#include + +extern void *initramfs_base; +extern void *initramfs_end; + +void initramfs_init(void); + +#endif /* _CPIO_H */ \ No newline at end of file diff --git a/lab8/include/kernel/current.h b/lab8/include/kernel/current.h new file mode 100644 index 000000000..c98baf989 --- /dev/null +++ b/lab8/include/kernel/current.h @@ -0,0 +1,20 @@ +#ifndef _CURRENT_H +#define _CURRENT_H + +#include + +struct _task_struct; + +static inline struct _task_struct *get_current(void) +{ + return (struct _task_struct *)read_sysreg(tpidr_el1); +} + +static inline void set_current(struct _task_struct *task) +{ + write_sysreg(tpidr_el1, task); +} + +#define current get_current() + +#endif /* _CURRENT_H */ \ No newline at end of file diff --git a/lab8/include/kernel/entry.h b/lab8/include/kernel/entry.h new file mode 100644 index 000000000..0f7d560f9 --- /dev/null +++ b/lab8/include/kernel/entry.h @@ -0,0 +1,9 @@ +#ifndef _ENTRY_H +#define _ENTRY_H + +#include +#include + +void el0_sync_handler(trapframe *regs, uint32 syn); + +#endif /* _ENTRY_H */ \ No newline at end of file diff --git a/lab8/include/kernel/exec.h b/lab8/include/kernel/exec.h new file mode 100644 index 000000000..c3f48b435 --- /dev/null +++ b/lab8/include/kernel/exec.h @@ -0,0 +1,11 @@ +#ifndef _EXEC_H +#define _EXEC_H + +// TODO: Add argv & envp +void sched_new_user_prog(char *filename); + +void exit_user_prog(void); + +void exec_user_prog(void *entry, char *user_sp, char *kernel_sp); + +#endif /* _EXEC_H */ \ No newline at end of file diff --git a/lab8/include/kernel/fdt.h b/lab8/include/kernel/fdt.h new file mode 100644 index 000000000..83cffc016 --- /dev/null +++ b/lab8/include/kernel/fdt.h @@ -0,0 +1,110 @@ +// Ref: https://elixir.bootlin.com/linux/v5.16.14/source/scripts/dtc/libfdt/fdt.h +#ifndef _FDT_H +#define _FDT_H + +#include + +struct fdt_header; +struct fdt_node_header; +struct fdt_property; + +typedef int (*fdt_parser)(int level, char *cur, char *dt_strings); + +extern char *fdt_base; + +void fdt_traversal(char *dtb); +void parse_dtb(char *dtb, fdt_parser parser); + +typedef uint32 fdt32_t; +typedef uint64 fdt64_t; + +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * Copyright 2012 Kim Phillips, Freescale Semiconductor. + */ + +#ifndef __ASSEMBLY__ + +struct fdt_header { + fdt32_t magic; /* magic word FDT_MAGIC */ + fdt32_t totalsize; /* total size of DT block */ + fdt32_t off_dt_struct; /* offset to structure */ + fdt32_t off_dt_strings; /* offset to strings */ + fdt32_t off_mem_rsvmap; /* offset to memory reserve map */ + fdt32_t version; /* format version */ + fdt32_t last_comp_version; /* last compatible version */ + + /* version 2 fields below */ + fdt32_t boot_cpuid_phys; /* Which physical CPU id we're + booting on */ + /* version 3 fields below */ + fdt32_t size_dt_strings; /* size of the strings block */ + + /* version 17 fields below */ + fdt32_t size_dt_struct; /* size of the structure block */ +}; + +struct fdt_node_header { + fdt32_t tag; + char name[0]; +}; + +struct fdt_property { + fdt32_t tag; + fdt32_t len; + fdt32_t nameoff; + char data[0]; +}; + +#endif /* !__ASSEMBLY */ + +#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ +#define FDT_TAGSIZE sizeof(fdt32_t) + +#define FDT_BEGIN_NODE 0x1 /* Start node: full name */ +#define FDT_END_NODE 0x2 /* End node */ +#define FDT_PROP 0x3 /* Property: name off, size, content */ +#define FDT_NOP 0x4 /* nop */ +#define FDT_END 0x9 + +#define FDT_V1_SIZE (7*sizeof(fdt32_t)) +#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t)) +#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t)) +#define FDT_V16_SIZE FDT_V3_SIZE +#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t)) + +// Ref: https://elixir.bootlin.com/linux/v5.16.14/source/scripts/dtc/libfdt/libfdt.h#L249 +#define fdt_get_header(fdt, field) \ + (fdt32_ld(&((const struct fdt_header *)(fdt))->field)) +#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) +#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) +#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) +#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) +#define fdt_version(fdt) (fdt_get_header(fdt, version)) +#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) +#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) +#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) + +#define fdtn_get_header(fdtn, field) \ + (fdt32_ld(&((const struct fdt_node_header *)(fdtn))->field)) +#define fdtn_tag(fdtn) (fdtn_get_header(fdtn, tag)) + +#define fdtp_get_header(fdtp, field) \ + (fdt32_ld(&((const struct fdt_property *)(fdtp))->field)) +#define fdtp_tag(fdtp) (fdtp_get_header(fdtp, tag)) +#define fdtp_len(fdtp) (fdtp_get_header(fdtp, len)) +#define fdtp_nameoff(fdtp) (fdtp_get_header(fdtp, nameoff)) + +// Load fdt32 (big-endian) +static inline uint32 fdt32_ld(const fdt32_t *p) +{ + const uint8 *bp = (const uint8 *)p; + + return ((uint32)bp[0] << 24) + | ((uint32)bp[1] << 16) + | ((uint32)bp[2] << 8) + | bp[3]; +} + +#endif /* _FDT_H */ \ No newline at end of file diff --git a/lab8/include/kernel/fs/cpiofs.h b/lab8/include/kernel/fs/cpiofs.h new file mode 100644 index 000000000..9a7fa0841 --- /dev/null +++ b/lab8/include/kernel/fs/cpiofs.h @@ -0,0 +1,8 @@ +#ifndef _CPIOFS_H +#define _CPIOFS_H + +#include + +struct filesystem *cpiofs_init(void); + +#endif /* _CPIOFS_H */ \ No newline at end of file diff --git a/lab8/include/kernel/fs/fat32fs.h b/lab8/include/kernel/fs/fat32fs.h new file mode 100644 index 000000000..c5872a8e9 --- /dev/null +++ b/lab8/include/kernel/fs/fat32fs.h @@ -0,0 +1,8 @@ +#ifndef _FAT32FS_H +#define _FAT32FS_H + +#include + +struct filesystem *fat32fs_init(void); + +#endif /* _FAT32FS_H */ \ No newline at end of file diff --git a/lab8/include/kernel/fs/framebufferfs.h b/lab8/include/kernel/fs/framebufferfs.h new file mode 100644 index 000000000..3e0310785 --- /dev/null +++ b/lab8/include/kernel/fs/framebufferfs.h @@ -0,0 +1,8 @@ +#ifndef _FRAMEBUFFERFS_H +#define _FRAMEBUFFERFS_H + +#include + +struct filesystem *framebufferfs_init(void); + +#endif /* _FRAMEBUFFERFS_H */ \ No newline at end of file diff --git a/lab8/include/kernel/fs/fsinit.h b/lab8/include/kernel/fs/fsinit.h new file mode 100644 index 000000000..1397a7b31 --- /dev/null +++ b/lab8/include/kernel/fs/fsinit.h @@ -0,0 +1,13 @@ +#ifndef _FSINIT_H +#define _FSINIT_H + +#include +#include +#include +#include +#include +#include + +void fs_init(void); + +#endif /* _FSINIT_H */ \ No newline at end of file diff --git a/lab8/include/kernel/fs/tmpfs.h b/lab8/include/kernel/fs/tmpfs.h new file mode 100644 index 000000000..348b09d8d --- /dev/null +++ b/lab8/include/kernel/fs/tmpfs.h @@ -0,0 +1,8 @@ +#ifndef _TMPFS_H +#define _TMPFS_H + +#include + +struct filesystem *tmpfs_init(void); + +#endif /* _TMPFS_H */ \ No newline at end of file diff --git a/lab8/include/kernel/fs/uartfs.h b/lab8/include/kernel/fs/uartfs.h new file mode 100644 index 000000000..0fd27263f --- /dev/null +++ b/lab8/include/kernel/fs/uartfs.h @@ -0,0 +1,8 @@ +#ifndef _UARTFS_H +#define _UARTFS_H + +#include + +struct filesystem *uartfs_init(void); + +#endif /* _UARTFS_H */ \ No newline at end of file diff --git a/lab8/include/kernel/fs/vfs.h b/lab8/include/kernel/fs/vfs.h new file mode 100644 index 000000000..11d6cfe71 --- /dev/null +++ b/lab8/include/kernel/fs/vfs.h @@ -0,0 +1,96 @@ +#ifndef _VFS_H +#define _VFS_H + +#include +#include +#include +#include + +#define O_CREAT 00000100 + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +/* File metadata */ +struct vnode { + struct mount *mount; + struct vnode_operations *v_ops; + struct file_operations *f_ops; + struct vnode *parent; + void *internal; +}; + +/* File handle */ +struct file { + struct vnode *vnode; + size_t f_pos; // RW position of this file handle + struct file_operations *f_ops; + int flags; +}; + +struct mount { + struct vnode *root; + struct filesystem *fs; +}; + +struct filesystem { + const char *name; + /* Link all filesystems */ + struct list_head fs_list; + int (*mount)(struct filesystem *fs, struct mount *mount); + int (*alloc_vnode)(struct filesystem *fs, struct vnode **target); + int (*sync)(struct filesystem *fs); +}; + +struct file_operations { + int (*write)(struct file *file, const void *buf, size_t len); + int (*read)(struct file *file, void *buf, size_t len); + int (*open)(struct vnode *file_node, struct file *target); + int (*close)(struct file *file); + long (*lseek64)(struct file *file, long offset, int whence); + int (*ioctl)(struct file *file, uint64 request, va_list args); +}; + +struct vnode_operations { + int (*lookup)(struct vnode *dir_node, struct vnode **target, + const char *component_name); + int (*create)(struct vnode *dir_node, struct vnode **target, + const char *component_name); + int (*mkdir)(struct vnode *dir_node, struct vnode **target, + const char *component_name); + int (*isdir)(struct vnode *dir_node); + int (*getname)(struct vnode *dir_node, const char **name); + int (*getsize)(struct vnode *dir_node); +}; + +extern struct mount *rootmount; + +void vfs_init(void); +void vfs_init_rootmount(struct filesystem *fs); + +int register_filesystem(struct filesystem *fs); +int vfs_open(const char *pathname, int flags, struct file *target); +int vfs_close(struct file *file); +int vfs_write(struct file *file, const void *buf, size_t len); +int vfs_read(struct file *file, void *buf, size_t len); +long vfs_lseek64(struct file *file, long offset, int whence); +int vfs_ioctl(struct file *file, uint64 request, va_list args); +int vfs_mkdir(const char *pathname); +int vfs_mount(const char *mountpath, const char *filesystem); +int vfs_lookup(const char *pathname, struct vnode **target); +int vfs_sync(struct filesystem *fs); + +void syscall_open(trapframe *frame, const char *pathname, int flags); +void syscall_close(trapframe *frame, int fd); +void syscall_write(trapframe *frame, int fd, const void *buf, uint64 count); +void syscall_read(trapframe *frame, int fd, void *buf, uint64 count); +void syscall_mkdir(trapframe *frame, const char *pathname, uint32 mode); +void syscall_mount(trapframe *frame, const char *src, const char *target, + const char *filesystem, uint64 flags, const void *data); +void syscall_chdir(trapframe *frame, const char *path); +void syscall_lseek64(trapframe *frame, int fd, int64 offset, int whence); +void syscall_ioctl(trapframe *frame, int fd, uint64 request, ...); +void syscall_sync(trapframe *frame); + +#endif /* _VFS_H */ \ No newline at end of file diff --git a/lab8/include/kernel/head.h b/lab8/include/kernel/head.h new file mode 100644 index 000000000..fc408f05e --- /dev/null +++ b/lab8/include/kernel/head.h @@ -0,0 +1,6 @@ +#ifndef _HEAD_H +#define _HEAD_H + +void _start(void); + +#endif /* _HEAD_H */ \ No newline at end of file diff --git a/lab8/include/kernel/irq.h b/lab8/include/kernel/irq.h new file mode 100644 index 000000000..3fd4b75e9 --- /dev/null +++ b/lab8/include/kernel/irq.h @@ -0,0 +1,20 @@ +#ifndef _IRQ_H +#define _IRQ_H + +#include + +void irq_init(); + +/* + * On success, 0 is returned + */ +int irq_run_task(void (*task)(void *), + void *args, + void (*fini)(void), + uint32 prio); + +void irq_handler(); +void exception_default_handler(uint32 n); +void irq1_enable(int bit); + +#endif /* _IRQ_H */ \ No newline at end of file diff --git a/lab8/include/kernel/kthread.h b/lab8/include/kernel/kthread.h new file mode 100644 index 000000000..ad0ae2e9b --- /dev/null +++ b/lab8/include/kernel/kthread.h @@ -0,0 +1,16 @@ +#ifndef _KTHREAD_H +#define _KTHREAD_H + +#include + +void kthread_early_init(void); +void kthread_init(void); + +void kthread_create(void (*start)(void)); +void kthread_fini(void); + +void kthread_add_wait_queue(task_struct *task); + +void kthread_kill_zombies(void); + +#endif /* _KTHREAD_H */ \ No newline at end of file diff --git a/lab8/include/kernel/mini_uart.h b/lab8/include/kernel/mini_uart.h new file mode 100644 index 000000000..5de196e03 --- /dev/null +++ b/lab8/include/kernel/mini_uart.h @@ -0,0 +1,24 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + +#include +#include + +uint32 uart_recvline(char *buff, int maxlen); +void uart_init(void); +char uart_recv(void); +void uart_recvn(char *buff, int n); +uint32 uart_recv_uint(void); +void uart_send(char c); +void uart_sendn(const char *str, int n); +void uart_printf(const char *fmt, ...); + +void uart_sync_printf(const char *fmt, ...); +void uart_sync_vprintf(const char *fmt, va_list args); + +int uart_irq_check(void); + +/* Switch asynchronous/synchronous mode for uart RW */ +int uart_switch_mode(void); + +#endif /* _MINI_UART_H */ \ No newline at end of file diff --git a/lab8/include/kernel/mm/early_alloc.h b/lab8/include/kernel/mm/early_alloc.h new file mode 100644 index 000000000..f214ad528 --- /dev/null +++ b/lab8/include/kernel/mm/early_alloc.h @@ -0,0 +1,15 @@ +#ifndef _MEM_H +#define _MEM_H + +#include + +/* From linker.ld */ +extern char _early_mem_base; +extern char _early_mem_end; + +#define EARLY_MEM_BASE (&_early_mem_base) +#define EARLY_MEM_END (&_early_mem_end) + +void* early_malloc(size_t size); + +#endif /* _MEM_H */ \ No newline at end of file diff --git a/lab8/include/kernel/mm/mm.h b/lab8/include/kernel/mm/mm.h new file mode 100644 index 000000000..47511a0b7 --- /dev/null +++ b/lab8/include/kernel/mm/mm.h @@ -0,0 +1,14 @@ +#ifndef _MM_H +#define _MM_H + +#include +#include +#include + +void mm_init(void); + +void *kmalloc(int size); + +void kfree(void *ptr); + +#endif /* _MM_H */ \ No newline at end of file diff --git a/lab8/include/kernel/mm/page_alloc.h b/lab8/include/kernel/mm/page_alloc.h new file mode 100644 index 000000000..c4b6ee05c --- /dev/null +++ b/lab8/include/kernel/mm/page_alloc.h @@ -0,0 +1,59 @@ +#ifndef _PAGE_ALLOC_H +#define _PAGE_ALLOC_H + +#include + +/* Initialize by page_allocator_early_init() */ +extern uint32 frame_ents_size; +extern uint64 buddy_base; +extern uint64 buddy_end; + +/* + * Convert frame idx to the frame address + */ +static inline void *idx2addr(int idx) +{ + return (void *)(buddy_base + idx * PAGE_SIZE); +} + +/* + * Convert frame address to the frame idx + */ +static inline int addr2idx(void *hdr) +{ + return ((uint64)hdr - buddy_base) / PAGE_SIZE; +} + +/* + * Initialize @start ~ @end memory for buddy system + * page_allocator_early_init() must be called before calling mem_reserve(). + */ +void page_allocator_early_init(void *start, void *end); + +/* + * Reserve @start ~ @end memory. + * mem_reserve() must be called before calling page_allocator_init(). + */ +void mem_reserve(void *start, void *end); + +void page_allocator_init(void); + +/* + * Allocate @num contiguous pages. + * Return NULL if failed. + */ +void *alloc_pages(int num); + +/* + * Allocate 1 page. + * Return NULL if failed. + */ +void *alloc_page(void); + +void free_page(void *page); + +#ifdef MM_DEBUG +void page_allocator_test(void); +#endif + +#endif /* _PAGE_ALLOC_H */ \ No newline at end of file diff --git a/lab8/include/kernel/mm/sc_alloc.h b/lab8/include/kernel/mm/sc_alloc.h new file mode 100644 index 000000000..991a98ca7 --- /dev/null +++ b/lab8/include/kernel/mm/sc_alloc.h @@ -0,0 +1,21 @@ +#ifndef _SC_ALLOC_H +#define _SC_ALLOC_H + +#include + +void sc_early_init(void); + +void sc_init(void); + +void *sc_alloc(int size); + +/* + * Return 0 if successful. + */ +int sc_free(void *sc); + +#ifdef MM_DEBUG +void sc_test(void); +#endif + +#endif /* _SC_ALLOC_H */ \ No newline at end of file diff --git a/lab8/include/kernel/mmu.h b/lab8/include/kernel/mmu.h new file mode 100644 index 000000000..90ef6bd08 --- /dev/null +++ b/lab8/include/kernel/mmu.h @@ -0,0 +1,81 @@ +#ifndef _MMU_H +#define _MMU_H + +#include +#include +#include +#include + +#define PAGE_TABLE_SIZE 0x1000 + +#define PT_R 0x0001 +#define PT_W 0x0002 +#define PT_X 0x0004 + +#define VMA_R PT_R +#define VMA_W PT_W +#define VMA_X PT_X +// PA +#define VMA_PA 0x0008 +// Kernel VA +#define VMA_KVA 0x0010 +// Anonymous +#define VMA_ANON 0x0020 + +typedef uint64 pd_t; + +/* TODO: The vm_area_t linked list is not sorted, making it an ordered list. */ +typedef struct _vm_area_t { + /* @list links to next vm_area_t */ + struct list_head list; + uint64 va_begin; + uint64 va_end; + uint64 flag; + /* @kva: Mapped kernel virtual address */ + uint64 kva; +} vm_area_t; + +typedef struct { + /* @vma links all vm_area_t */ + struct list_head vma; +} vm_area_meta_t; + +/* + * Set identity paging, enable MMU + */ +void mmu_init(void); + +pd_t *pt_create(void); +void pt_free(pd_t *pt); + +/* + * Create a @size mapping of @va -> @pa. + * @pt is PGD. + */ +void pt_map(pd_t *pt, void *va, uint64 size, void *pa, uint64 flag); + +vm_area_meta_t *vma_meta_create(void); +void vma_meta_free(vm_area_meta_t *vma_meta, pd_t *page_table); +void vma_meta_copy(vm_area_meta_t *to, vm_area_meta_t *from, pd_t *page_table); + +void vma_map(vm_area_meta_t *vma_meta, void *va, uint64 size, + uint64 flag, void *addr); + +void mem_abort(esr_el1_t *esr); + +/* syscalls */ +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 + +#define MAP_ANONYMOUS 0x0020 +#define MAP_POPULATE 0x8000 + +/* + * TODO: @fd, @file_offset are ignored currently. + */ +void syscall_mmap(trapframe *frame, void *addr, size_t len, int prot, + int flags, int fd, int file_offset); + +#endif /* _MMU_H */ \ No newline at end of file diff --git a/lab8/include/kernel/mode_switch.h b/lab8/include/kernel/mode_switch.h new file mode 100644 index 000000000..54edbf70c --- /dev/null +++ b/lab8/include/kernel/mode_switch.h @@ -0,0 +1,8 @@ +#ifndef _MODE_SWITCH_H +#define _MODE_SWITCH_H + +#include + +void exit_to_user_mode(trapframe regs); + +#endif /* _MODE_SWITCH_H */ \ No newline at end of file diff --git a/lab8/include/kernel/panic.h b/lab8/include/kernel/panic.h new file mode 100644 index 000000000..1c1978411 --- /dev/null +++ b/lab8/include/kernel/panic.h @@ -0,0 +1,6 @@ +#ifndef _PANIC_H +#define _PANIC_H + +void panic(const char *fmt, ...); + +#endif /* _PANIC_H */ \ No newline at end of file diff --git a/lab8/include/kernel/preempt.h b/lab8/include/kernel/preempt.h new file mode 100644 index 000000000..51f3d1920 --- /dev/null +++ b/lab8/include/kernel/preempt.h @@ -0,0 +1,7 @@ +#ifndef _PREEMPT_H +#define _PREEMPT_H + +void preempt_disable(void); +void preempt_enable(void); + +#endif /* _PREEMPT_H */ \ No newline at end of file diff --git a/lab8/include/kernel/rpi3.h b/lab8/include/kernel/rpi3.h new file mode 100644 index 000000000..b2888dd7a --- /dev/null +++ b/lab8/include/kernel/rpi3.h @@ -0,0 +1,29 @@ +#ifndef _RPI3_H +#define _RPI3_H + +/* Channels */ +#define MAILBOX_CH_POWER 0 +#define MAILBOX_CH_FB 1 +#define MAILBOX_CH_VUART 2 +#define MAILBOX_CH_VCHIQ 3 +#define MAILBOX_CH_LEDS 4 +#define MAILBOX_CH_BTNS 5 +#define MAILBOX_CH_TOUCH 6 +#define MAILBOX_CH_COUNT 7 +#define MAILBOX_CH_PROP 8 + +/* Others */ +#define MBOX_REQUEST_CODE 0x00000000 +#define MBOX_TAG_REQUEST 0x00000000 +#define MBOX_END_TAG 0x00000000 + +struct arm_memory_info { + unsigned int baseaddr; + unsigned int size; +}; + +void mailbox_call(unsigned char channel, unsigned int *mb); +unsigned int get_board_revision(void); +void get_arm_memory(struct arm_memory_info *); + +#endif \ No newline at end of file diff --git a/lab8/include/kernel/sched.h b/lab8/include/kernel/sched.h new file mode 100644 index 000000000..2cce0fb5d --- /dev/null +++ b/lab8/include/kernel/sched.h @@ -0,0 +1,18 @@ +#ifndef _SCHED_H +#define _SCHED_H + +#include + +void switch_to(task_struct *from, task_struct *to); + +void scheduler_init(void); + +void schedule(void); + +void schedule_tick(void); + +void sched_add_task(task_struct *task); + +void sched_del_task(task_struct *task); + +#endif /* _SCHED_H */ \ No newline at end of file diff --git a/lab8/include/kernel/sdhost.h b/lab8/include/kernel/sdhost.h new file mode 100644 index 000000000..afc7658f7 --- /dev/null +++ b/lab8/include/kernel/sdhost.h @@ -0,0 +1,11 @@ +#ifndef _SDHOST_H +#define _SDHOST_H + +#define BLOCK_SIZE 512 + +void sd_init(void); + +void sd_readblock(int block_idx, void *buf); +void sd_writeblock(int block_idx, const void *buf); + +#endif /* _SDHOST_H */ \ No newline at end of file diff --git a/lab8/include/kernel/signal.h b/lab8/include/kernel/signal.h new file mode 100644 index 000000000..69cf991f1 --- /dev/null +++ b/lab8/include/kernel/signal.h @@ -0,0 +1,89 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H + +#include +#include +#include + +// https://man7.org/linux/man-pages/man7/signal.7.html +// 0 means no signal +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL 29 +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGUNUSED 31 + +#define NSIG 32 + +struct signal_head_t { + /* Link signal_t */ + struct list_head list; +}; + +struct signal_t { + struct list_head list; + uint32 signum; +}; + +typedef void (*sighandler_t)(int); + +struct sigaction_t { + sighandler_t sighand; + + /* flags */ + uint32 kernel_hand; +}; + +struct sighand_t { + // 0-th sigaction_t is not used + struct sigaction_t sigactions[NSIG]; +}; + +struct signal_head_t *signal_head_create(void); +void signal_head_free(struct signal_head_t *head); +void signal_head_reset(struct signal_head_t *head); + +void handle_signal(trapframe *_); + +struct sighand_t *sighand_create(void); +void sighand_free(struct sighand_t *sighand); +void sighand_reset(struct sighand_t *sighand); + +/* Copy current signal handler to @sighand */ +void sighand_copy(struct sighand_t *sighand); + +/* syscalls */ +void syscall_signal(trapframe *_, uint32 signal, void (*handler)(int)); +void syscall_kill(trapframe *_, int pid, int signal); +void syscall_sigreturn(trapframe *_); + +#endif /* _SIGNAL_H */ \ No newline at end of file diff --git a/lab8/include/kernel/syscall.h b/lab8/include/kernel/syscall.h new file mode 100644 index 000000000..d7bc0f612 --- /dev/null +++ b/lab8/include/kernel/syscall.h @@ -0,0 +1,32 @@ +#ifndef _SYSCALL_H +#define _SYSCALL_H + +#include + +#define SCNUM_GETPID 0 +#define SCNUM_UART_READ 1 +#define SCNUM_UART_WRITE 2 +#define SCNUM_EXEC 3 +#define SCNUM_FORK 4 +#define SCNUM_EXIT 5 +#define SCNUM_MBOX_CALL 6 +#define SCNUM_KILL_PID 7 +#define SCNUM_SIGNAL 8 +#define SCNUM_KILL 9 +#define SCNUM_MMAP 10 +#define SCNUM_OPEN 11 +#define SCNUM_CLOSE 12 +#define SCNUM_WRITE 13 +#define SCNUM_READ 14 +#define SCNUM_MKDIR 15 +#define SCNUM_MOUNT 16 +#define SCNUM_CHDIR 17 +#define SCNUM_LSEEK64 18 +#define SCNUM_IOCTL 19 +#define SCNUM_SYNC 20 +#define SCNUM_SIGRETURN 21 +#define SCNUM_SHOW_INFO 22 + +void syscall_handler(trapframe *regs); + +#endif /* _SYSCALL_H */ \ No newline at end of file diff --git a/lab8/include/kernel/task.h b/lab8/include/kernel/task.h new file mode 100644 index 000000000..0b2cb3a1d --- /dev/null +++ b/lab8/include/kernel/task.h @@ -0,0 +1,92 @@ +#ifndef _TASK_H +#define _TASK_H + +#include +#include +#include +#include + +#define STACK_SIZE (4 * PAGE_SIZE) + +#define TASK_MAX_FD 0x10 + +/* Task status */ +#define TASK_NEW 0 +#define TASK_RUNNING 1 +#define TASK_DEAD 2 + +/* Define in include/kernel/signal.h */ +struct signal_head_t; +struct sighand_t; + +struct pt_regs { + void *x19; + void *x20; + void *x21; + void *x22; + void *x23; + void *x24; + void *x25; + void *x26; + void *x27; + void *x28; + void *fp; + void *lr; + void *sp; +}; + +typedef struct _task_struct { + struct pt_regs regs; + pd_t *page_table; + /* The order of the above elements cannot be changed */ + vm_area_meta_t *address_space; + void *kernel_stack; + /* @list is used by run_queue / wait_queue */ + struct list_head list; + /* @task_list links all tasks */ + struct list_head task_list; + uint16 status; + uint16 need_resched:1; + uint32 tid; + uint32 preempt; + /* Signal */ + struct signal_head_t *signal; + struct sighand_t *sighand; + /* Files */ + int maxfd; + struct file fds[TASK_MAX_FD]; + struct vnode *work_dir; +} task_struct; + +#define SAVE_REGS(task) \ + asm volatile ( \ + "stp x19, x20, [%x0, 16 * 0]\n" \ + "stp x21, x22, [%x0, 16 * 1]\n" \ + "stp x23, x24, [%x0, 16 * 2]\n" \ + "stp x25, x26, [%x0, 16 * 3]\n" \ + "stp x27, x28, [%x0, 16 * 4]\n" \ + "stp fp, lr, [%x0, 16 * 5]\n" \ + "mov x9, sp\n" \ + "str x9, [%x0, 16 * 6]\n" \ + : : "r" (&task->regs) \ + ); + +void task_init(void); + +task_struct *task_create(void); +void task_free(task_struct *task); + +task_struct *task_get_by_tid(uint32 tid); + +/* + * Create initial mapping for user program + * + * 0x00003c000000 ~ 0x00003f000000: rw-: Mailbox address + * 0x7f0000000000 ~ : r-x: Kernel functions exposed to users + * 0xffffffffb000 ~ : rw-: Stack + */ +void task_init_map(task_struct *task); + +void task_reset_mm(task_struct *task); + +#endif /* _TASK_H */ \ No newline at end of file diff --git a/lab8/include/kernel/text_user_shared.h b/lab8/include/kernel/text_user_shared.h new file mode 100644 index 000000000..3be42d0ed --- /dev/null +++ b/lab8/include/kernel/text_user_shared.h @@ -0,0 +1,25 @@ +#ifndef _TEXT_USER_SHARED_H +#define _TEXT_USER_SHARED_H + +/* + * See the comment of task_init_map in task.h: + * + * 0x7f0000000000 ~ : r-x: Kernel functions exposed to users + * + * The kernel functions with the SECTION_TUS attribute will be mapped into + * this user address space. + */ + +#define SECTION_TUS __attribute__ ((section (".text.user.shared"))) + +#define TUS2VA(x) ((((uint64)x) - TEXT_USER_SHARED_BASE) + 0x7f0000000000) + +/* From linker.ld */ +extern char _stext_user_shared; +extern char _etext_user_shared; + +#define TEXT_USER_SHARED_BASE (uint64)(&_stext_user_shared) +#define TEXT_USER_SHARED_END (uint64)(&_etext_user_shared) +#define TEXT_USER_SHARED_LEN (TEXT_USER_SHARED_END - TEXT_USER_SHARED_BASE) + +#endif /* _TEXT_USER_SHARED_H */ \ No newline at end of file diff --git a/lab8/include/kernel/timer.h b/lab8/include/kernel/timer.h new file mode 100644 index 000000000..8253f6ad0 --- /dev/null +++ b/lab8/include/kernel/timer.h @@ -0,0 +1,16 @@ +#ifndef _TIMER_H +#define _TIMER_H + +#include + +void timer_init(); +int timer_irq_check(); +void timer_switch_info(); + +/* Call @proc(@args) after @after seconds. */ +void timer_add_proc_after(void (*proc)(void *), void *args, uint32 after); + +/* Call @proc(@args) after 1/@freq second. */ +void timer_add_proc_freq(void (*proc)(void *), void *args, uint32 freq); + +#endif /* _TIMER_H */ \ No newline at end of file diff --git a/lab8/include/kernel/trapframe.h b/lab8/include/kernel/trapframe.h new file mode 100644 index 000000000..530467f54 --- /dev/null +++ b/lab8/include/kernel/trapframe.h @@ -0,0 +1,83 @@ +#ifndef _TRAPFRAME_H +#define _TRAPFRAME_H + +#include +#include + +typedef struct { + uint64 x0; + uint64 x1; + uint64 x2; + uint64 x3; + uint64 x4; + uint64 x5; + uint64 x6; + uint64 x7; + uint64 x8; + uint64 x9; + uint64 x10; + uint64 x11; + uint64 x12; + uint64 x13; + uint64 x14; + uint64 x15; + uint64 x16; + uint64 x17; + uint64 x18; + uint64 x19; + uint64 x20; + uint64 x21; + uint64 x22; + uint64 x23; + uint64 x24; + uint64 x25; + uint64 x26; + uint64 x27; + uint64 x28; + uint64 x29; + uint64 x30; + void *sp_el0; + void *elr_el1; + void *spsr_el1; +} trapframe; + +static inline void show_trapframe(trapframe *regs) +{ + uart_sync_printf("\r\n[*] Trapframe:\r\n"); + uart_sync_printf("\tx0: %llx\r\n", regs->x0); + uart_sync_printf("\tx1: %llx\r\n", regs->x1); + uart_sync_printf("\tx2: %llx\r\n", regs->x2); + uart_sync_printf("\tx3: %llx\r\n", regs->x3); + uart_sync_printf("\tx4: %llx\r\n", regs->x4); + uart_sync_printf("\tx5: %llx\r\n", regs->x5); + uart_sync_printf("\tx6: %llx\r\n", regs->x6); + uart_sync_printf("\tx7: %llx\r\n", regs->x7); + uart_sync_printf("\tx8: %llx\r\n", regs->x8); + uart_sync_printf("\tx9: %llx\r\n", regs->x9); + uart_sync_printf("\tx10: %llx\r\n", regs->x10); + uart_sync_printf("\tx11: %llx\r\n", regs->x11); + uart_sync_printf("\tx12: %llx\r\n", regs->x12); + uart_sync_printf("\tx13: %llx\r\n", regs->x13); + uart_sync_printf("\tx14: %llx\r\n", regs->x14); + uart_sync_printf("\tx15: %llx\r\n", regs->x15); + uart_sync_printf("\tx16: %llx\r\n", regs->x16); + uart_sync_printf("\tx17: %llx\r\n", regs->x17); + uart_sync_printf("\tx18: %llx\r\n", regs->x18); + uart_sync_printf("\tx19: %llx\r\n", regs->x19); + uart_sync_printf("\tx20: %llx\r\n", regs->x20); + uart_sync_printf("\tx21: %llx\r\n", regs->x21); + uart_sync_printf("\tx22: %llx\r\n", regs->x22); + uart_sync_printf("\tx23: %llx\r\n", regs->x23); + uart_sync_printf("\tx24: %llx\r\n", regs->x24); + uart_sync_printf("\tx25: %llx\r\n", regs->x25); + uart_sync_printf("\tx26: %llx\r\n", regs->x26); + uart_sync_printf("\tx27: %llx\r\n", regs->x27); + uart_sync_printf("\tx28: %llx\r\n", regs->x28); + uart_sync_printf("\tx29: %llx\r\n", regs->x29); + uart_sync_printf("\tx30: %llx\r\n", regs->x30); + uart_sync_printf("\tsp_el0 : %llx\r\n", regs->sp_el0); + uart_sync_printf("\telr_el1 : %llx\r\n", regs->elr_el1); + uart_sync_printf("\tspsr_el1: %llx\r\n", regs->spsr_el1); +} + +#endif /* _TRAPFRAME_H */ \ No newline at end of file diff --git a/lab8/include/kernel/waitqueue.h b/lab8/include/kernel/waitqueue.h new file mode 100644 index 000000000..8c31735b3 --- /dev/null +++ b/lab8/include/kernel/waitqueue.h @@ -0,0 +1,19 @@ +#ifndef _WAITQUEUE_H +#define _WAITQUEUE_H + +#include + +typedef struct { + struct list_head list; +} wait_queue_head; + +wait_queue_head *wq_create(void); + +int wq_empty(wait_queue_head *head); + +void wq_add_task(task_struct *task, wait_queue_head *head); +void wq_del_task(task_struct *task); + +task_struct *wq_get_first_task(wait_queue_head *head); + +#endif /* _WAITQUEUE_H */ \ No newline at end of file diff --git a/lab8/include/lib/bitops.h b/lab8/include/lib/bitops.h new file mode 100644 index 000000000..53ee638d9 --- /dev/null +++ b/lab8/include/lib/bitops.h @@ -0,0 +1,12 @@ +#ifndef _BITOPS_H +#define _BITOPS_H + +// Find First bit Set +#define ffs(x) __builtin_ffs(x) + +static inline int fls(unsigned int x) +{ + return x ? sizeof(x) * 8 - __builtin_clz(x) : 0; +} + +#endif \ No newline at end of file diff --git a/lab8/include/lib/list.h b/lab8/include/lib/list.h new file mode 100644 index 000000000..671158b9b --- /dev/null +++ b/lab8/include/lib/list.h @@ -0,0 +1,459 @@ +/* Linux-like doubly-linked list implementation */ +#ifndef _LIST_H +#define _LIST_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include + +/* "typeof" is a GNU extension. + * Reference: https://gcc.gnu.org/onlinedocs/gcc/Typeof.html + */ +#if defined(__GNUC__) +#define __LIST_HAVE_TYPEOF 1 +#endif /* defined(__GNUC__) */ + +/** + * struct list_head - Head and node of a doubly-linked list + * @prev: pointer to the previous node in the list + * @next: pointer to the next node in the list + * + * The simple doubly-linked list consists of a head and nodes attached to + * this head. Both node and head share the same struct type. The list_* + * functions and macros can be used to access and modify this data structure. + * + * The @prev pointer of the list head points to the last list node of the + * list and @next points to the first list node of the list. For an empty list, + * both member variables point to the head. + * + * The list nodes are usually embedded in a container structure which holds the + * actual data. Such an container object is called entry. The helper list_entry + * can be used to calculate the object address from the address of the node. + */ +struct list_head { + struct list_head *prev; + struct list_head *next; +}; + +/** + * container_of() - Calculate address of object that contains address ptr + * @ptr: pointer to member variable + * @type: type of the structure containing ptr + * @member: name of the member variable in struct @type + * + * Return: @type pointer of object containing ptr + */ +#ifndef container_of +#ifdef __LIST_HAVE_TYPEOF +#define container_of(ptr, type, member) \ + __extension__({ \ + const __typeof__(((type *) 0)->member) *__pmember = (ptr); \ + (type *) ((char *) __pmember - offsetof(type, member)); \ + }) +#else /* __LIST_HAVE_TYPEOF */ +#define container_of(ptr, type, member) \ + ((type *) ((char *) (ptr) -offsetof(type, member))) +#endif /* __LIST_HAVE_TYPEOF */ +#endif /* container_of */ + +/** + * LIST_HEAD - Declare list head and initialize it + * @head: name of the new object + */ +#define LIST_HEAD(head) struct list_head head = {&(head), &(head)} + +/** + * INIT_LIST_HEAD() - Initialize empty list head + * @head: pointer to list head + * + * This can also be used to initialize a unlinked list node. + * + * A node is usually linked inside a list, will be added to a list in + * the near future or the entry containing the node will be free'd soon. + * + * But an unlinked node may be given to a function which uses list_del(_init) + * before it ends up in a previously mentioned state. The list_del(_init) on an + * initialized node is well defined and safe. But the result of a + * list_del(_init) on an uninitialized node is undefined (unrelated memory is + * modified, crashes, ...). + */ +static inline void INIT_LIST_HEAD(struct list_head *head) +{ + head->next = head; + head->prev = head; +} + +/** + * list_add() - Add a list node to the beginning of the list + * @node: pointer to the new node + * @head: pointer to the head of the list + */ +static inline void list_add(struct list_head *node, struct list_head *head) +{ + struct list_head *next = head->next; + + next->prev = node; + node->next = next; + node->prev = head; + head->next = node; +} + +/** + * list_add_tail() - Add a list node to the end of the list + * @node: pointer to the new node + * @head: pointer to the head of the list + */ +static inline void list_add_tail(struct list_head *node, struct list_head *head) +{ + struct list_head *prev = head->prev; + + prev->next = node; + node->next = head; + node->prev = prev; + head->prev = node; +} + +/** + * list_del() - Remove a list node from the list + * @node: pointer to the node + * + * The node is only removed from the list. Neither the memory of the removed + * node nor the memory of the entry containing the node is free'd. The node + * has to be handled like an uninitialized node. Accessing the next or prev + * pointer of the node is not safe. + * + * Unlinked, initialized nodes are also uninitialized after list_del. + * + * LIST_POISONING can be enabled during build-time to provoke an invalid memory + * access when the memory behind the next/prev pointer is used after a list_del. + * This only works on systems which prohibit access to the predefined memory + * addresses. + */ +static inline void list_del(struct list_head *node) +{ + struct list_head *next = node->next; + struct list_head *prev = node->prev; + + next->prev = prev; + prev->next = next; + +#ifdef LIST_POISONING + node->prev = (struct list_head *) (0x00100100); + node->next = (struct list_head *) (0x00200200); +#endif /* LIST_POISONING */ +} + +/** + * list_del_init() - Remove a list node from the list and reinitialize it + * @node: pointer to the node + * + * The removed node will not end up in an uninitialized state like when using + * list_del. Instead the node is initialized again to the unlinked state. + */ +static inline void list_del_init(struct list_head *node) +{ + list_del(node); + INIT_LIST_HEAD(node); +} + +/** + * list_empty() - Check if list head has no nodes attached + * @head: pointer to the head of the list + * + * Return: 0 - list is not empty !0 - list is empty + */ +static inline int list_empty(const struct list_head *head) +{ + return (head->next == head); +} + +/** + * list_is_singular() - Check if list head has exactly one node attached + * @head: pointer to the head of the list + * + * Return: 0 - list is not singular !0 -list has exactly one entry + */ +static inline int list_is_singular(const struct list_head *head) +{ + return (!list_empty(head) && head->prev == head->next); +} + +/** + * list_splice() - Add list nodes from a list to beginning of another list + * @list: pointer to the head of the list with the node entries + * @head: pointer to the head of the list + * + * All nodes from @list are added to the beginning of the list of @head. + * It is similar to list_add but for multiple nodes. The @list head is not + * modified and has to be initialized to be used as a valid list head/node + * again. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + struct list_head *head_first = head->next; + struct list_head *list_first = list->next; + struct list_head *list_last = list->prev; + + if (list_empty(list)) + return; + + head->next = list_first; + list_first->prev = head; + + list_last->next = head_first; + head_first->prev = list_last; +} + +/** + * list_splice_tail() - Add list nodes from a list to end of another list + * @list: pointer to the head of the list with the node entries + * @head: pointer to the head of the list + * + * All nodes from @list are added to to the end of the list of @head. + * It is similar to list_add_tail but for multiple nodes. The @list head is not + * modified and has to be initialized to be used as a valid list head/node + * again. + */ +static inline void list_splice_tail(struct list_head *list, + struct list_head *head) +{ + struct list_head *head_last = head->prev; + struct list_head *list_first = list->next; + struct list_head *list_last = list->prev; + + if (list_empty(list)) + return; + + head->prev = list_last; + list_last->next = head; + + list_first->prev = head_last; + head_last->next = list_first; +} + +/** + * list_splice_init() - Move list nodes from a list to beginning of another list + * @list: pointer to the head of the list with the node entries + * @head: pointer to the head of the list + * + * All nodes from @list are added to to the beginning of the list of @head. + * It is similar to list_add but for multiple nodes. + * + * The @list head will not end up in an uninitialized state like when using + * list_splice. Instead the @list is initialized again to the an empty + * list/unlinked state. + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + list_splice(list, head); + INIT_LIST_HEAD(list); +} + +/** + * list_splice_tail_init() - Move list nodes from a list to end of another list + * @list: pointer to the head of the list with the node entries + * @head: pointer to the head of the list + * + * All nodes from @list are added to to the end of the list of @head. + * It is similar to list_add_tail but for multiple nodes. + * + * The @list head will not end up in an uninitialized state like when using + * list_splice. Instead the @list is initialized again to the an empty + * list/unlinked state. + */ +static inline void list_splice_tail_init(struct list_head *list, + struct list_head *head) +{ + list_splice_tail(list, head); + INIT_LIST_HEAD(list); +} + +/** + * list_cut_position() - Move beginning of a list to another list + * @head_to: pointer to the head of the list which receives nodes + * @head_from: pointer to the head of the list + * @node: pointer to the node in which defines the cutting point + * + * All entries from the beginning of the list @head_from to (including) the + * @node is moved to @head_to. + * + * @head_to is replaced when @head_from is not empty. @node must be a real + * list node from @head_from or the behavior is undefined. + */ +static inline void list_cut_position(struct list_head *head_to, + struct list_head *head_from, + struct list_head *node) +{ + struct list_head *head_from_first = head_from->next; + + if (list_empty(head_from)) + return; + + if (head_from == node) { + INIT_LIST_HEAD(head_to); + return; + } + + head_from->next = node->next; + head_from->next->prev = head_from; + + head_to->prev = node; + node->next = head_to; + head_to->next = head_from_first; + head_to->next->prev = head_to; +} + +/** + * list_move() - Move a list node to the beginning of the list + * @node: pointer to the node + * @head: pointer to the head of the list + * + * The @node is removed from its old position/node and add to the beginning of + * @head + */ +static inline void list_move(struct list_head *node, struct list_head *head) +{ + list_del(node); + list_add(node, head); +} + +/** + * list_move_tail() - Move a list node to the end of the list + * @node: pointer to the node + * @head: pointer to the head of the list + * + * The @node is removed from its old position/node and add to the end of @head + */ +static inline void list_move_tail(struct list_head *node, + struct list_head *head) +{ + list_del(node); + list_add_tail(node, head); +} + +/** + * list_entry() - Calculate address of entry that contains list node + * @node: pointer to list node + * @type: type of the entry containing the list node + * @member: name of the list_head member variable in struct @type + * + * Return: @type pointer of entry containing node + */ +#define list_entry(node, type, member) container_of(node, type, member) + +/** + * list_first_entry() - get first entry of the list + * @head: pointer to the head of the list + * @type: type of the entry containing the list node + * @member: name of the list_head member variable in struct @type + * + * Return: @type pointer of first entry in list + */ +#define list_first_entry(head, type, member) \ + list_entry((head)->next, type, member) + +/** + * list_last_entry() - get last entry of the list + * @head: pointer to the head of the list + * @type: type of the entry containing the list node + * @member: name of the list_head member variable in struct @type + * + * Return: @type pointer of last entry in list + */ +#define list_last_entry(head, type, member) \ + list_entry((head)->prev, type, member) + +/** + * list_for_each - iterate over list nodes + * @node: list_head pointer used as iterator + * @head: pointer to the head of the list + * + * The nodes and the head of the list must be kept unmodified while + * iterating through it. Any modifications to the the list will cause undefined + * behavior. + */ +#define list_for_each(node, head) \ + for (node = (head)->next; node != (head); node = node->next) + +/** + * list_for_each_entry - iterate over list entries + * @entry: pointer used as iterator + * @head: pointer to the head of the list + * @member: name of the list_head member variable in struct type of @entry + * + * The nodes and the head of the list must be kept unmodified while + * iterating through it. Any modifications to the the list will cause undefined + * behavior. + * + * FIXME: remove dependency of __typeof__ extension + */ +#ifdef __LIST_HAVE_TYPEOF +#define list_for_each_entry(entry, head, member) \ + for (entry = list_entry((head)->next, __typeof__(*entry), member); \ + &entry->member != (head); \ + entry = list_entry(entry->member.next, __typeof__(*entry), member)) +#endif /* __LIST_HAVE_TYPEOF */ + +/** + * iter_for_each_entry - iterate over list entries from @iter + * @entry: pointer used as iterator + * @iter: pointer to the start of this iteration + * @head: pointer to the head of the list + * @member: name of the list_head member variable in struct type of @entry + * + * FIXME: remove dependency of __typeof__ extension + */ +#ifdef __LIST_HAVE_TYPEOF +#define iter_for_each_entry(entry, iter, head, member) \ + for (entry = list_entry(iter, __typeof__(*entry), member); \ + &entry->member != (head); \ + entry = list_entry(entry->member.next, __typeof__(*entry), member)) +#endif /* __LIST_HAVE_TYPEOF */ + +/** + * list_for_each_safe - iterate over list nodes and allow deletes + * @node: list_head pointer used as iterator + * @safe: list_head pointer used to store info for next entry in list + * @head: pointer to the head of the list + * + * The current node (iterator) is allowed to be removed from the list. Any + * other modifications to the the list will cause undefined behavior. + */ +#define list_for_each_safe(node, safe, head) \ + for (node = (head)->next, safe = node->next; node != (head); \ + node = safe, safe = node->next) + +/** + * list_for_each_entry_safe - iterate over list entries and allow deletes + * @entry: pointer used as iterator + * @safe: @type pointer used to store info for next entry in list + * @head: pointer to the head of the list + * @member: name of the list_head member variable in struct type of @entry + * + * The current node (iterator) is allowed to be removed from the list. Any + * other modifications to the the list will cause undefined behavior. + * + * FIXME: remove dependency of __typeof__ extension + */ +#define list_for_each_entry_safe(entry, safe, head, member) \ + for (entry = list_entry((head)->next, __typeof__(*entry), member), \ + safe = list_entry(entry->member.next, __typeof__(*entry), member); \ + &entry->member != (head); entry = safe, \ + safe = list_entry(safe->member.next, __typeof__(*entry), member)) + +#define list_for_each_entry_safe_rev(entry, safe, head, member) \ + for (entry = list_entry((head)->prev, __typeof__(*entry), member), \ + safe = list_entry(entry->member.prev, __typeof__(*entry), member); \ + &entry->member != (head); entry = safe, \ + safe = list_entry(safe->member.prev, __typeof__(*entry), member)) + +#undef __LIST_HAVE_TYPEOF + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _LIST_H */ \ No newline at end of file diff --git a/lab8/include/lib/string.h b/lab8/include/lib/string.h new file mode 100644 index 000000000..3bcd75df4 --- /dev/null +++ b/lab8/include/lib/string.h @@ -0,0 +1,14 @@ +#ifndef _STRING_H +#define _STRING_H + +int strcmp(const char *str1, const char *str2); +int strncmp(const char *str1, const char *str2, int n); +int strcasecmp(const char *s1, const char *s2); +int strlen(const char *str); +int strcpy(char *dst, const char *src); +char *strcat(char *dest, const char *src); +char *strncat(char *dest, const char *src, int n); + +int atoi(const char *str); + +#endif /* _STRING_H */ \ No newline at end of file diff --git a/lab8/include/lib/types.h b/lab8/include/lib/types.h new file mode 100644 index 000000000..518cb85aa --- /dev/null +++ b/lab8/include/lib/types.h @@ -0,0 +1,18 @@ +#ifndef _TYPES_H +#define _TYPES_H + +#include + +typedef unsigned long long int uint64; +typedef unsigned int uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; + +typedef long long int int64; +typedef int int32; +typedef short int16; +typedef char int8; + +#define PAGE_SIZE 0x1000 + +#endif /* _TYPES_H */ \ No newline at end of file diff --git a/lab8/include/lib/utils.h b/lab8/include/lib/utils.h new file mode 100644 index 000000000..2ebd1fbce --- /dev/null +++ b/lab8/include/lib/utils.h @@ -0,0 +1,89 @@ +#ifndef _UTILS_H +#define _UTILS_H + +#include + +#ifndef __ASSEMBLER__ + +void delay(uint64 cnt); +void put32(uint64 addr, const uint32 val); +uint32 get32(uint64 addr); + +void memzero(char *src, uint64 n); +void memncpy(char *dst, const char *src, uint64 n); +void memset(void *ptr, uint8 value, uint64 num); + +#endif /* __ASSEMBLER__ */ + +// Reference from https://elixir.bootlin.com/linux/latest/source/tools/lib/perf/mmap.c#L299 +#define read_sysreg(r) ({ \ + uint64 __val; \ + asm volatile("mrs %0, " #r : "=r" (__val)); \ + __val; \ +}) + +// Reference from https://elixir.bootlin.com/linux/latest/source/arch/arm64/include/asm/sysreg.h#L1281 +#define write_sysreg(r, v) do { \ + uint64 __val = (uint64)(v); \ + asm volatile("msr " #r ", %x0" \ + : : "rZ" (__val)); \ +} while (0) + +#define enable_interrupt() do { \ + asm volatile("msr DAIFClr, 0xf"); \ +} while (0) + +#define disable_interrupt() do { \ + asm volatile("msr DAIFSet, 0xf"); \ +} while (0) + +#define set_page_table(page_table) do { \ + asm volatile( \ + "mov x9, %0\n" \ + "and x9, x9, #0x0000ffffffffffff\n" \ + "dsb ish\n" \ + "msr ttbr0_el1, x9\n" \ + "tlbi vmalle1is\n" \ + "dsb ish\n" \ + "isb\n" \ + :: "r" (page_table) \ + ); \ +} while (0) + +#define get_page_table() ({ \ + uint64 __val; \ + __val = PA2VA(read_sysreg(TTBR0_EL1)); \ + __val; \ +}) + +static inline uint32 save_and_disable_interrupt(void) +{ + uint32 daif; + + daif = read_sysreg(DAIF); + disable_interrupt(); + + return daif; +} + +static inline void restore_interrupt(uint32 daif) +{ + write_sysreg(DAIF, daif); +} + +#define get_elem_idx(elem, array) \ + (((char *)elem - (char *)array) / sizeof(array[0])) + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +#define ALIGN(num, base) ((num + base - 1) & ~(base - 1)) + +#define TO_CHAR_PTR(a) ((char *)(uint64)(a)) + +#define PA2VA(x) (((uint64)(x)) | 0xffff000000000000) +#define VA2PA(x) (((uint64)(x)) & 0x0000ffffffffffff) + +#define M2STR(macro) #macro +#define MC2STR(macro) M2STR(macro) + +#endif /* _UTILS_H */ \ No newline at end of file diff --git a/lab8/initramfs/Makefile b/lab8/initramfs/Makefile new file mode 100644 index 000000000..43e87bd49 --- /dev/null +++ b/lab8/initramfs/Makefile @@ -0,0 +1,33 @@ +CROSS_COMPILE ?= aarch64-linux-gnu- +CC := $(CROSS_COMPILE)gcc +LD := $(CROSS_COMPILE)ld + +CFLAGS := -Wall -nostdlib -nostartfiles -ffreestanding -mgeneral-regs-only + +all: userprog1 userprog2 + +userprog1: userprog1.elf + $(CROSS_COMPILE)objcopy -O binary $^ $@ + +userprog1.elf: linker.ld userprog1.o + $(LD) $(LDFLAGS) -T $< -o $@ userprog1.o + +userprog1.o: userprog1.s + $(CC) $(CFLAGS) -c $< -o $@ + +userprog2: userprog2.elf + $(CROSS_COMPILE)objcopy -O binary $^ $@ + +userprog2.elf: linker.ld userprog2.o + $(LD) $(LDFLAGS) -T $< -o $@ userprog2.o + +userprog2.o: userprog2.c + $(CC) $(CFLAGS) -c $< -o $@ + +.PHONY: clean +clean: + rm -f *.o *.elf + +.PHONY: clean-all +clean-all: clean + rm -f userprog1 userprog2 \ No newline at end of file diff --git a/lab8/initramfs/linker.ld b/lab8/initramfs/linker.ld new file mode 100644 index 000000000..ab050c29d --- /dev/null +++ b/lab8/initramfs/linker.ld @@ -0,0 +1,26 @@ +SECTIONS +{ + .start : { + *(.start) + } + + .text : { + *(.text) + } + + .rodata : { + *(.rodata) + } + + .data : { + *(.got) + *(.got.plt) + *(.data*) + } + + _sbss = .; + .bss : { + *(.bss*) + } + _ebss = .; +} \ No newline at end of file diff --git a/lab8/initramfs/syscall.img b/lab8/initramfs/syscall.img new file mode 100644 index 000000000..70d4a5539 Binary files /dev/null and b/lab8/initramfs/syscall.img differ diff --git a/lab8/initramfs/test.txt b/lab8/initramfs/test.txt new file mode 100644 index 000000000..ec5460c5a --- /dev/null +++ b/lab8/initramfs/test.txt @@ -0,0 +1 @@ +This is test.txt yo \ No newline at end of file diff --git a/lab8/initramfs/test2.txt b/lab8/initramfs/test2.txt new file mode 100644 index 000000000..300af8400 --- /dev/null +++ b/lab8/initramfs/test2.txt @@ -0,0 +1,3 @@ +This is start of test2.txt +hello, bye. +This is end of test2.txt \ No newline at end of file diff --git a/lab8/initramfs/userprog1 b/lab8/initramfs/userprog1 new file mode 100644 index 000000000..237765563 Binary files /dev/null and b/lab8/initramfs/userprog1 differ diff --git a/lab8/initramfs/userprog1.s b/lab8/initramfs/userprog1.s new file mode 100644 index 000000000..1e0ab6b7e --- /dev/null +++ b/lab8/initramfs/userprog1.s @@ -0,0 +1,19 @@ +.section ".text" +.global _start +_start: + mov x0, 0 +1: + add x0, x0, 1 + + // syscall_show_info + mov x8, 10 + svc 0 + + cmp x0, 5 + blt 1b +1: + // syscall_exit + mov x8, 5 + svc 0 + + b 1b diff --git a/lab8/initramfs/userprog2 b/lab8/initramfs/userprog2 new file mode 100644 index 000000000..6f524be75 Binary files /dev/null and b/lab8/initramfs/userprog2 differ diff --git a/lab8/initramfs/userprog2.c b/lab8/initramfs/userprog2.c new file mode 100644 index 000000000..80529d420 --- /dev/null +++ b/lab8/initramfs/userprog2.c @@ -0,0 +1,278 @@ +#include +#include + +#define SIGN 1 + +typedef unsigned long long int uint64; +typedef unsigned int uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; + +typedef long long int int64; +typedef int int32; +typedef short int16; +typedef char int8; + +#define SYS_GETPID 0 +#define SYS_UART_RECV 1 +#define SYS_UART_WRITE 2 +#define SYS_EXEC 3 +#define SYS_FORK 4 +#define SYS_EXIT 5 +#define SYS_MBOX_CALL 6 +#define SYS_KILL_PID 7 + +int start(void) __attribute__((section(".start"))); + +uint64 syscall(uint64 syscall_num, + void *x0, + void *x1, + void *x2, + void *x3, + void *x4, + void *x5) +{ + uint64 result; + + asm volatile ( + "ldr x8, %0\n" + "ldr x0, %1\n" + "ldr x1, %2\n" + "ldr x2, %3\n" + "ldr x3, %4\n" + "ldr x4, %5\n" + "ldr x5, %6\n" + "svc 0\n" + :: "m" (syscall_num), "m" (x0), "m" (x1), + "m" (x2), "m" (x3), "m" (x4), "m" (x5) + ); + + asm volatile ( + "str x0, %0\n" + : "=m" (result) + ); + + return result; +} + +int getpid() +{ + return (int)syscall(SYS_GETPID, 0, 0, 0, 0, 0, 0); +} + +void uart_recv(const char buf[], size_t size) +{ + syscall(SYS_UART_RECV, (void *)buf, (void *)size, 0, 0, 0, 0); +} + +void uart_write(const char buf[], size_t size) +{ + syscall(SYS_UART_WRITE, (void *)buf, (void *)size, 0, 0, 0, 0); +} + +static void uart_send_char(char c) +{ + uart_write(&c, 1); +} + +static void uart_send_string(const char *str) +{ + for (int i = 0; str[i] != '\0'; i++) { + uart_send_char(str[i]); + } +} + +static void uart_send_num(int64 num, int base, int type) +{ + static const char digits[16] = "0123456789ABCDEF"; + char tmp[66]; + int i; + + if (type | SIGN) { + if (num < 0) { + uart_send_char('-'); + } + } + + i = 0; + + if (num == 0) { + tmp[i++] = '0'; + } else { + while (num != 0) { + uint8 r = (uint32)num % base; + num = (uint32)num / base; + tmp[i++] = digits[r]; + } + } + + while (--i >= 0) { + uart_send_char(tmp[i]); + } +} + +static void _uart_printf(const char *fmt, va_list args) +{ + const char *s; + char c; + uint64 num; + char width; + + for (; *fmt; ++fmt) { + if (*fmt != '%') { + uart_send_char(*fmt); + continue; + } + + ++fmt; + + // Get width + width = 0; + if (fmt[0] == 'l' && fmt[1] == 'l') { + width = 1; + fmt += 2; + } + + switch (*fmt) { + case 'c': + c = va_arg(args, uint32) & 0xff; + uart_send_char(c); + continue; + case 'd': + if (width) { + num = va_arg(args, int64); + } else { + num = va_arg(args, int32); + } + uart_send_num(num, 10, SIGN); + continue; + case 's': + s = va_arg(args, char *); + uart_send_string(s); + continue; + case 'x': + if (width) { + num = va_arg(args, uint64); + } else { + num = va_arg(args, uint32); + } + uart_send_num(num, 16, 0); + continue; + } + } +} + +void uart_printf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + _uart_printf(fmt, args); + + va_end(args); +} + +void exec(const char *name, char *const argv[]) +{ + syscall(SYS_EXEC, (void *)name, (void *)argv, 0, 0, 0, 0); +} + +int fork(void) +{ + return (int)syscall(SYS_FORK, 0, 0, 0, 0, 0, 0); +} + +void exit(void) +{ + syscall(SYS_EXIT, 0, 0, 0, 0, 0, 0); +} + +void mbox_call(unsigned char ch, unsigned int *mbox) +{ + syscall(SYS_MBOX_CALL, (void *)(uint64)ch, mbox, 0, 0, 0, 0); +} + +void kill_pid(int pid) +{ + syscall(SYS_KILL_PID, (void *)(uint64)pid, 0, 0, 0, 0, 0); +} + +/* Channels */ +#define MAILBOX_CH_PROP 8 + +/* Tags */ +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +/* Tag identifier */ +#define GET_BOARD_REVISION 0x00010002 + +/* Others */ +#define REQUEST_CODE 0x00000000 + +static unsigned int __attribute__((aligned(0x10))) mailbox[16]; + +// It should be 0xa020d3 for rpi3 b+ +unsigned int get_board_revision(void) +{ + mailbox[0] = 7 * 4; // Buffer size in bytes + mailbox[1] = REQUEST_CODE; + // Tags begin + mailbox[2] = GET_BOARD_REVISION; // Tag identifier + mailbox[3] = 4; // Value buffer size in bytes + mailbox[4] = TAG_REQUEST_CODE; // Request/response codes + mailbox[5] = 0; // Optional value buffer + // Tags end + mailbox[6] = END_TAG; + + mbox_call(MAILBOX_CH_PROP, mailbox); // Message passing procedure call + + return mailbox[5]; +} + +void show_stack(void) +{ + uint64 sp; + + asm volatile ( + "mov x9, sp\n" + "str x9, %0\n" + : "=m" (sp) + ); + + uart_printf("[User] Stack: %llx\r\n", sp); +} + +int start(void) +{ + char buf1[0x10] = { 0 }; + int pid, revision; + + pid = getpid(); + uart_printf("[User] pid: %d\r\n", pid); + + uart_printf("[User] kill_pid(2)\r\n"); + kill_pid(2); + + uart_printf("[User] Input:\r\n"); + uart_recv(buf1, 8); + uart_printf("[User] Output: %s\r\n", buf1); + + revision = get_board_revision(); + uart_printf("[User] Revision: %x\r\n", revision); + + pid = fork(); + + if (pid == 0) { + uart_printf("[User] Child: exec userprog1\r\n"); + show_stack(); + exec("userprog1", NULL); + } else { + uart_printf("[User] Parent: child pid: %d\r\n", pid); + show_stack(); + } + + uart_printf("[User] Exit\r\n"); + exit(); + return 0; +} \ No newline at end of file diff --git a/lab8/initramfs/vfs1.img b/lab8/initramfs/vfs1.img new file mode 100644 index 000000000..2c41bd71a Binary files /dev/null and b/lab8/initramfs/vfs1.img differ diff --git a/lab8/initramfs/vfs2.img b/lab8/initramfs/vfs2.img new file mode 100644 index 000000000..f7baf4607 Binary files /dev/null and b/lab8/initramfs/vfs2.img differ diff --git a/lab8/initramfs/vm.img b/lab8/initramfs/vm.img new file mode 100644 index 000000000..8ba674e6c Binary files /dev/null and b/lab8/initramfs/vm.img differ diff --git a/lab8/src/bootloader/BCM2837.c b/lab8/src/bootloader/BCM2837.c new file mode 100644 index 000000000..dabb7940c --- /dev/null +++ b/lab8/src/bootloader/BCM2837.c @@ -0,0 +1,18 @@ +#include + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +void BCM2837_reset(int tick) { // reboot after watchdog timer expire + put32(PM_RSTC, PM_PASSWORD | 0x20); // full reset + put32(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick + + // Never return + while (1) {} +} + +void BCM2837_cancel_reset() { + put32(PM_RSTC, PM_PASSWORD | 0); // full reset + put32(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} diff --git a/lab8/src/bootloader/head.S b/lab8/src/bootloader/head.S new file mode 100644 index 000000000..655e021cf --- /dev/null +++ b/lab8/src/bootloader/head.S @@ -0,0 +1,71 @@ +// Reference: https://github.com/s-matyukevich/raspberry-pi-os +.section ".text.boot" + +.globl _start +_start: + // Preserve flattened devicetree pointer + mov x19, x0 + + // Check CPU id + mrs x0, mpidr_el1 + and x0, x0, #0xff + + // Hang other CPUs + cbnz x0, proc_hang + + // Get offset + bl get_offset +_get_offset_ret: + + // Relocate bootloader + b.ne relocate + + // Initialize bss + adr x0, _sbss + adr x1, _ebss + sub x1, x1, x0 + bl memzero + + // Initialize stack + ldr x0, =_stack_top + mov sp, x0 + // Pass flattened devicetree pointer + mov x0, x19 + bl start_bootloader + + // Should never return +proc_hang: + b proc_hang + +get_offset: + adr x0, _get_offset_ret + adr x1, _start + sub x0, x0, x1 + sub x0, lr, x0 + ldr x1, =_bootloader + subs x0, x0, x1 + ret + +relocate: + mov x2, x0 + + // Get Dest + ldr x0, =_bootloader + + // Get source + adr x3, _get_offset_ret + adr x1, _start + sub x1, x3, x1 + sub x1, lr, x1 + + // Get length + ldr x2, =_bootloader + ldr x3, =_edata + sub x2, x3, x2 + bl memncpy + + // Pass flattened devicetree pointer + mov x0, x19 + ldr x1, =_bootloader + br x1 + // No return \ No newline at end of file diff --git a/lab8/src/bootloader/linker.ld b/lab8/src/bootloader/linker.ld new file mode 100644 index 000000000..5bc75a912 --- /dev/null +++ b/lab8/src/bootloader/linker.ld @@ -0,0 +1,36 @@ +_bootloader = 0x60000; +_kernel = 0x80000; +_stack_top = 0x400000; + +SECTIONS +{ + . = _bootloader; + + .text.boot : { + *(.text.boot) + } + + .text : { + *(.text) + } + + .rodata : { + *(.rodata) + } + + .data : { + *(.got) + *(.got.plt) + *(.data) + } + _edata = .; + + _sbss = .; + .bss : { + *(.bss*) + } + _ebss = .; + + . = _stack_top; + _sstack = .; +} \ No newline at end of file diff --git a/lab8/src/bootloader/main.c b/lab8/src/bootloader/main.c new file mode 100644 index 000000000..65973ab7b --- /dev/null +++ b/lab8/src/bootloader/main.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include + +#define BUFSIZE 0x100 + +extern char _kernel[]; +char shell_buf[BUFSIZE]; +char *fdt_base; + +typedef void (*kernel_funcp)(char *fdt); + +static void load_kernel(void) +{ + // Loading kernel Protocol: + // 4 bytes: The kernel image length n + // n bytes: The kernel image + // Bootloader will store kernel to 0x80000 and then jump to it + unsigned int len; + char *p = _kernel; + + uart_printf("[*] Kernel base address: %x\r\n", _kernel); + + len = uart_recv_uint(); + + uart_printf("[*] Kernel image length: %d\r\n", len); + + while (len--) { + *p++ = uart_recv(); + } + + // Execute kernel + ((kernel_funcp)_kernel)(fdt_base); +} + +static void cmd_help(void) +{ + uart_printf( + "help\t: " "print this help menu" "\r\n" + "hello\t: " "print Hello World!" "\r\n" + "hwinfo\t: " "print hardware info" "\r\n" + "load\t: " "load kernel" "\r\n" + "reboot\t: " "reboot the device" "\r\n" + ); +} + +static void cmd_hello(void) +{ + uart_printf("Hello World!\r\n"); +} + +static void cmd_hwinfo(void) +{ + unsigned int rev; + struct arm_memory_info ami; + + // Board revision + rev = get_board_revision(); + uart_printf("[*] Revision: %x\r\n", rev); + + // ARM memory base address and size + get_arm_memory(&ami); + uart_printf("[*] ARM memory base address: %x\r\n", ami.baseaddr); + uart_printf("[*] ARM memory size: %d\r\n", ami.size); +} + +static void cmd_loadkernel(void) +{ + uart_printf("[*] Loading kernel ...\r\n"); + load_kernel(); +} + +static void cmd_reboot(void) +{ + BCM2837_reset(10); +} + +static int shell_read_cmd(void) +{ + return uart_recvline(shell_buf, BUFSIZE); +} + +static void shell(void) +{ + // One char maybe be received + uart_recv(); + + while (1) { + uart_printf("# "); + shell_read_cmd(); + uart_printf("\r\n"); + if (!strcmp("help", shell_buf)) { + cmd_help(); + } else if (!strcmp("hello", shell_buf)) { + cmd_hello(); + } else if (!strcmp("hwinfo", shell_buf)) { + cmd_hwinfo(); + } else if (!strcmp("load", shell_buf)) { + cmd_loadkernel(); + } else if (!strcmp("reboot", shell_buf)) { + cmd_reboot(); + } else { + // Just echo back + uart_printf("%s\r\n", shell_buf); + } + } +} + +void start_bootloader(char *fdt) +{ + fdt_base = fdt; + + uart_init(); + uart_printf("[*] Bootloader\r\n"); + + shell(); +} \ No newline at end of file diff --git a/lab8/src/bootloader/mini_uart.c b/lab8/src/bootloader/mini_uart.c new file mode 100644 index 000000000..217f65d37 --- /dev/null +++ b/lab8/src/bootloader/mini_uart.c @@ -0,0 +1,191 @@ +// Ref: https://github.com/s-matyukevich/raspberry-pi-os/blob/master/src/lesson01/src/mini_uart.c +#include +#include +#include +#include + +#define SIGN 1 + +#define BUFSIZE 0x100 + +char uart_recv(void) +{ + while (!(get32(AUX_MU_LSR_REG) & 0x01)) {}; + + return (get32(AUX_MU_IO_REG) & 0xFF); +} + +void uart_send(char c) +{ + while (!(get32(AUX_MU_LSR_REG) & 0x20)) {}; + + put32(AUX_MU_IO_REG, c); +} + +uint32 uart_recv_uint(void) +{ + char buf[4]; + + for (int i = 0; i < 4; ++i) { + buf[i] = uart_recv(); + } + + return *((uint32*)buf); +} + +uint32 uart_recvline(char *buff, int maxlen) +{ + uint32 cnt = 0; + + // Reserve space for NULL byte + maxlen--; + + while (maxlen) { + char c = uart_recv(); + + if (c == '\r') { + // TODO: what if c == '\0'? + break; + } + + uart_send(c); + *buff = c; + buff++; + cnt += 1; + maxlen -= 1; + } + + *buff = 0; + + return cnt; +} + +void uart_sendn(char *str, int n) +{ + while (n--) { + uart_send(*str++); + } +} + +static void uart_send_string(const char *str) +{ + for (int i = 0; str[i] != '\0'; i++) { + uart_send(str[i]); + } +} + +// Ref: https://elixir.bootlin.com/linux/v3.5/source/arch/x86/boot/printf.c#L43 +/* + * @num: output number + * @base: 10 or 16 + */ +static void uart_send_num(int64 num, int base, int type) +{ + static const char digits[16] = "0123456789ABCDEF"; + char tmp[66]; + int i; + + if (type & SIGN) { + if (num < 0) { + uart_send('-'); + } + } + + i = 0; + + if (num == 0) { + tmp[i++] = '0'; + } else { + while (num != 0) { + uint8 r = ((uint64)num) % base; + num = ((uint64)num) / base; + tmp[i++] = digits[r]; + } + } + + while (--i >= 0) { + uart_send(tmp[i]); + } +} + +// Ref: https://elixir.bootlin.com/linux/v3.5/source/arch/x86/boot/printf.c#L115 +void uart_printf(char *fmt, ...) +{ + const char *s; + char c; + uint64 num; + char width; + + va_list args; + va_start(args, fmt); + + for (; *fmt; ++fmt) { + if (*fmt != '%') { + uart_send(*fmt); + continue; + } + + ++fmt; + + // Get width + width = 0; + if (fmt[0] == 'l' && fmt[1] == 'l') { + width = 1; + fmt += 2; + } + + switch (*fmt) { + case 'c': + c = va_arg(args, uint32) & 0xff; + uart_send(c); + continue; + case 'd': + if (width) { + num = va_arg(args, int64); + } else { + num = va_arg(args, int32); + } + uart_send_num(num, 10, SIGN); + continue; + case 's': + s = va_arg(args, char *); + uart_send_string(s); + continue; + case 'x': + if (width) { + num = va_arg(args, uint64); + } else { + num = va_arg(args, uint32); + } + uart_send_num(num, 16, 0); + continue; + } + } +} + +void uart_init(void) +{ + unsigned int selector; + + selector = get32(GPFSEL1); + selector &= ~(7 << 12); // Clean gpio14 + selector |= 2 << 12; // Set alt5 for gpio14 + selector &= ~(7 << 15); // Clean gpio15 + selector |= 2 << 15; // Set alt5 for gpio15 + put32(GPFSEL1, selector); + + put32(GPPUD, 0); + delay(150); + put32(GPPUDCLK0, (1 << 14) | (1 << 15)); + delay(150); + put32(GPPUDCLK0, 0); + + put32(AUX_ENABLES, 1); // Enable mini uart (this also enables access to its registers) + put32(AUX_MU_CNTL_REG, 0); // Disable auto flow control and disable receiver and transmitter (for now) + put32(AUX_MU_IER_REG, 0); // Disable receive and transmit interrupts + put32(AUX_MU_LCR_REG, 3); // Enable 8 bit mode + put32(AUX_MU_MCR_REG, 0); // Set RTS line to be always high + put32(AUX_MU_BAUD_REG, 270); // Set baud rate to 115200 + put32(AUX_MU_IIR_REG, 6); // Clear the Rx/Tx FIFO + put32(AUX_MU_CNTL_REG, 3); // Finally, enable transmitter and receiver +} \ No newline at end of file diff --git a/lab8/src/bootloader/rpi3.c b/lab8/src/bootloader/rpi3.c new file mode 100644 index 000000000..471e2a308 --- /dev/null +++ b/lab8/src/bootloader/rpi3.c @@ -0,0 +1,101 @@ +// Ref: +// https://github.com/bztsrc/raspi3-tutorial/blob/master/04_mailboxes/mbox.h +// https://github.com/raspberrypi/firmware/wiki/Mailboxes +// https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes +#include +#include +#include + +/* Mailbox registers */ +#define MAILBOX_BASE PERIPHERALS_BASE + 0xb880 +#define MAILBOX_READ MAILBOX_BASE +#define MAILBOX_STATUS MAILBOX_BASE + 0x18 +#define MAILBOX_WRITE MAILBOX_BASE + 0x20 + +/* Tags */ +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_MEMORY 0x00010005 + +/* Channels */ +#define MAILBOX_CH_POWER 0 +#define MAILBOX_CH_FB 1 +#define MAILBOX_CH_VUART 2 +#define MAILBOX_CH_VCHIQ 3 +#define MAILBOX_CH_LEDS 4 +#define MAILBOX_CH_BTNS 5 +#define MAILBOX_CH_TOUCH 6 +#define MAILBOX_CH_COUNT 7 +#define MAILBOX_CH_PROP 8 + +/* Others */ +#define MAILBOX_EMPTY 0x40000000 +#define MAILBOX_FULL 0x80000000 + +#define REQUEST_CODE 0x00000000 +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +// Aligned buffer +static unsigned int __attribute__((aligned(0x10))) mailbox[16]; + +void mailbox_call(unsigned char channel, unsigned int *mb) +{ + // Write the data (shifted into the upper 28 bits) combined with + // the channel (in the lower four bits) to the write register. + unsigned int r = (((unsigned long)mb) & ~0xf) | channel; + + // Check if Mailbox 0 status register’s full flag is set. + while ((get32(MAILBOX_STATUS) & MAILBOX_FULL)) {}; + + // If not, then you can write to Mailbox 1 Read/Write register. + put32(MAILBOX_WRITE, r); + + while (1) { + // Check if Mailbox 0 status register’s empty flag is set. + while ((get32(MAILBOX_STATUS) & MAILBOX_EMPTY)) {}; + + // If not, then you can read from Mailbox 0 Read/Write register. + // Check if the value is the same as you wrote in step 1. + if (r == get32(MAILBOX_READ)) + return; + } +} + +// It should be 0xa020d3 for rpi3 b+ +unsigned int get_board_revision(void) +{ + mailbox[0] = 7 * 4; // Buffer size in bytes + mailbox[1] = REQUEST_CODE; + // Tags begin + mailbox[2] = GET_BOARD_REVISION; // Tag identifier + mailbox[3] = 4; // Value buffer size in bytes + mailbox[4] = TAG_REQUEST_CODE; // Request/response codes + mailbox[5] = 0; // Optional value buffer + // Tags end + mailbox[6] = END_TAG; + + mailbox_call(MAILBOX_CH_PROP, mailbox); // Message passing procedure call + + return mailbox[5]; +} + +void get_arm_memory(struct arm_memory_info *info) +{ + mailbox[0] = 8 * 4; // Buffer size in bytes + mailbox[1] = REQUEST_CODE; + // Tags begin + mailbox[2] = GET_ARM_MEMORY; // Tag identifier + mailbox[3] = 8; // Value buffer size in bytes + mailbox[4] = TAG_REQUEST_CODE; // Request/response codes + mailbox[5] = 0; // Optional value buffer + mailbox[6] = 0; // Optional value buffer + // Tags end + mailbox[7] = END_TAG; + + mailbox_call(MAILBOX_CH_PROP, mailbox); // Message passing procedure call + + info->baseaddr = mailbox[5]; + info->size = mailbox[6]; +} diff --git a/lab8/src/kernel/BCM2837.c b/lab8/src/kernel/BCM2837.c new file mode 100644 index 000000000..64d2ebdc3 --- /dev/null +++ b/lab8/src/kernel/BCM2837.c @@ -0,0 +1,18 @@ +#include + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +void BCM2837_reset(int tick) { // reboot after watchdog timer expire + put32(PA2VA(PM_RSTC), PM_PASSWORD | 0x20); // full reset + put32(PA2VA(PM_WDOG), PM_PASSWORD | tick); // number of watchdog tick + + // Never return + while (1) {} +} + +void BCM2837_cancel_reset() { + put32(PA2VA(PM_RSTC), PM_PASSWORD | 0); // full reset + put32(PA2VA(PM_WDOG), PM_PASSWORD | 0); // number of watchdog tick +} diff --git a/lab8/src/kernel/cpio.c b/lab8/src/kernel/cpio.c new file mode 100644 index 000000000..20716e9cb --- /dev/null +++ b/lab8/src/kernel/cpio.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include + +void *initramfs_base; +void *initramfs_end; + +static int initramfs_fdt_parser(int level, char *cur, char *dt_strings) +{ + struct fdt_node_header *nodehdr = (struct fdt_node_header *)cur; + struct fdt_property *prop; + + uint32 ok = 0; + uint32 tag = fdtn_tag(nodehdr); + + switch (tag) { + case FDT_PROP: + prop = (struct fdt_property *)nodehdr; + if (!strcmp("linux,initrd-start", dt_strings + fdtp_nameoff(prop))) { + initramfs_base = TO_CHAR_PTR(PA2VA(fdt32_ld((fdt32_t *)&prop->data))); + uart_printf("[*] initrd addr base: %x\r\n", initramfs_base); + ok += 1; + } else if (!strcmp("linux,initrd-end", dt_strings + fdtp_nameoff(prop))) { + initramfs_end = TO_CHAR_PTR(PA2VA(fdt32_ld((fdt32_t *)&prop->data))); + uart_printf("[*] initrd addr end : %x\r\n", initramfs_end); + ok += 1; + } + if (ok == 2) { + return 1; + } + break; + case FDT_BEGIN_NODE: + case FDT_END_NODE: + case FDT_NOP: + case FDT_END: + break; + } + + return 0; +} + +void initramfs_init(void) +{ + // Get initramfs address from devicetree + parse_dtb(fdt_base, initramfs_fdt_parser); + if (!initramfs_base) { + uart_printf("[x] Cannot find initrd address!!!\r\n"); + } +} \ No newline at end of file diff --git a/lab8/src/kernel/entry.c b/lab8/src/kernel/entry.c new file mode 100644 index 000000000..7e62b4681 --- /dev/null +++ b/lab8/src/kernel/entry.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include + +void el0_sync_handler(trapframe *regs, uint32 syn) +{ + esr_el1_t *esr; + + esr = (esr_el1_t *)&syn; + + switch (esr->ec) { + case EC_SVC_64: + syscall_handler(regs); + break; + case EC_IA_LE: + case EC_DA_LE: + mem_abort(esr); + break; + default: + show_trapframe(regs); + panic("esr->ec: %x", esr->ec); + } +} \ No newline at end of file diff --git a/lab8/src/kernel/exec.S b/lab8/src/kernel/exec.S new file mode 100644 index 000000000..64fb98abe --- /dev/null +++ b/lab8/src/kernel/exec.S @@ -0,0 +1,40 @@ +// See include/kernel/exec.h and src/kernel/exec.c for function declaration + +.globl enter_el0_run_user_prog +enter_el0_run_user_prog: + // Set exception return address + msr elr_el1, x0 + + // Set user stack + msr sp_el0, x1 + + // Enable interrupt ({D, A, I, F} = 0 (unmasked)) + // EL0 ({M[3:0]} = 0) + mov x0, 0 + msr spsr_el1, x0 + + // TODO: Clear all general registers + + // return to EL0 + eret + +.globl exec_user_prog +exec_user_prog: + // Set exception return address + msr elr_el1, x0 + + // Set user stack + msr sp_el0, x1 + + // Enable interrupt ({D, A, I, F} = 0 (unmasked)) + // EL0 ({M[3:0]} = 0) + mov x0, 0 + msr spsr_el1, x0 + + // Set kernel stack + mov sp, x2 + + // TODO: Clear all general registers + + // return to EL0 + eret \ No newline at end of file diff --git a/lab8/src/kernel/exec.c b/lab8/src/kernel/exec.c new file mode 100644 index 000000000..225192315 --- /dev/null +++ b/lab8/src/kernel/exec.c @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +// Change current EL to EL0 and execute the user program at @entry +// Set user stack to @user_sp +void enter_el0_run_user_prog(void *entry, char *user_sp); + +static void user_prog_start(void) +{ + enter_el0_run_user_prog((void *)0, (char *)0xffffffffeff0); + + // User program should call exit() to terminate +} + +static inline void pt_regs_init(struct pt_regs *regs) +{ + regs->x19 = 0; + regs->x20 = 0; + regs->x21 = 0; + regs->x22 = 0; + regs->x23 = 0; + regs->x24 = 0; + regs->x25 = 0; + regs->x26 = 0; + regs->x27 = 0; + regs->x28 = 0; + regs->fp = 0; + regs->lr = user_prog_start; +} + +// TODO: Add argv & envp +void sched_new_user_prog(char *pathname) +{ + void *data; + int datalen, adj_datalen; + task_struct *task; + struct file f; + int ret; + + ret = vfs_open(pathname, 0, &f); + + if (ret < 0) { + return; + } + + datalen = f.vnode->v_ops->getsize(f.vnode); + + if (datalen < 0) { + return; + } + + adj_datalen = ALIGN(datalen, PAGE_SIZE); + + data = kmalloc(adj_datalen); + + memzero(data, adj_datalen); + + ret = vfs_read(&f, data, datalen); + + if (ret < 0) { + kfree(data); + return; + } + + vfs_close(&f); + + task = task_create(); + + task->kernel_stack = kmalloc(STACK_SIZE); + + task->regs.sp = (char *)task->kernel_stack + STACK_SIZE - 0x10; + pt_regs_init(&task->regs); + + task_init_map(task); + + // 0x000000000000 ~ : rwx: Code + vma_map(task->address_space, (void *)0, adj_datalen, + VMA_R | VMA_W | VMA_X | VMA_KVA, data); + + sched_add_task(task); +} + +void exit_user_prog(void) +{ + kthread_fini(); + + // Never reach +} \ No newline at end of file diff --git a/lab8/src/kernel/fdt.c b/lab8/src/kernel/fdt.c new file mode 100644 index 000000000..f3d433374 --- /dev/null +++ b/lab8/src/kernel/fdt.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include + +char *fdt_base; + +static void _print_tab(int level) +{ + while (level--) { + uart_printf("\t"); + } +} + +static void _dump(char *start, int len) +{ + while (len--) { + char c = *start++; + if ((0x20 <= c && c <= 0x7e)) { + uart_printf("%c", c); + } else { + uart_printf("%x", c); + } + } +} + +static int fdt_traversal_parser(int level, char *cur, char *dt_strings) +{ + struct fdt_node_header *nodehdr = (struct fdt_node_header *)cur; + struct fdt_property *prop; + + uint32 tag = fdtn_tag(nodehdr); + + switch (tag) { + case FDT_BEGIN_NODE: + _print_tab(level); + uart_printf("[*] Node: %s\n", nodehdr->name); + break; + case FDT_END_NODE: + _print_tab(level); + uart_printf("[*] Node end\r\n"); + break; + case FDT_PROP: + prop = (struct fdt_property *)nodehdr; + _print_tab(level); + uart_printf("[*] %s:", dt_strings + fdtp_nameoff(prop)); + _dump(prop->data, fdtp_len(prop)); + uart_printf("\r\n"); + break; + case FDT_NOP: + break; + case FDT_END: + uart_printf("[*] END!\r\n"); + } + + return 0; +} + +static void parse_dt_struct( + char *dt_struct, + char *dt_strings, + fdt_parser parser) +{ + char *cur = dt_struct; + int level = 0; + + while (1) { + cur = (char *)ALIGN((uint64)cur, 4); + struct fdt_node_header *nodehdr = (struct fdt_node_header *)cur; + struct fdt_property *prop; + + uint32 tag = fdtn_tag(nodehdr); + + switch (tag) { + case FDT_BEGIN_NODE: + if (parser(level, cur, dt_strings)) { + return; + } + level++; + cur += sizeof(struct fdt_node_header) + strlen(nodehdr->name) + 1; + while (*cur != 0) { + cur++; + } + break; + case FDT_END_NODE: + level--; + if (parser(level, cur, dt_strings)) { + return; + } + cur += sizeof(struct fdt_node_header); + break; + case FDT_PROP: + prop = (struct fdt_property *)nodehdr; + if (parser(level, cur, dt_strings)) { + return; + } + cur += sizeof(struct fdt_property); + cur += fdtp_len(prop); + break; + case FDT_NOP: + if (parser(level, cur, dt_strings)) { + return; + } + cur += sizeof(struct fdt_node_header); + break; + case FDT_END: + parser(level, cur, dt_strings); + return; + } + } +} + +void parse_dtb(char *dtb, fdt_parser parser) +{ + struct fdt_header *hdr = (struct fdt_header *)dtb; + + if (fdt_magic(hdr) != FDT_MAGIC) { + uart_printf("[x] Not valid fdt_header\r\n"); + } + + if (fdt_last_comp_version(hdr) > 17) { + uart_printf("[x] Only support v17 dtb\r\n"); + } + + char *dt_struct = dtb + fdt_off_dt_struct(hdr); + char *dt_strings = dtb + fdt_off_dt_strings(hdr); + // TODO: Parse memory reservation block + + parse_dt_struct(dt_struct, dt_strings, parser); +} + +void fdt_traversal(char *dtb) +{ + parse_dtb(dtb, fdt_traversal_parser); +} \ No newline at end of file diff --git a/lab8/src/kernel/fs/cpiofs.c b/lab8/src/kernel/fs/cpiofs.c new file mode 100644 index 000000000..4aea5160b --- /dev/null +++ b/lab8/src/kernel/fs/cpiofs.c @@ -0,0 +1,573 @@ +#include +#include +#include +#include +#include +#include +#include + +#define CPIO_TYPE_MASK 0060000 +#define CPIO_TYPE_DIR 0040000 +#define CPIO_TYPE_FILE 0000000 + +struct cpio_newc_header { + char c_magic[6]; + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[8]; + char c_filesize[8]; + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; + char c_check[8]; +}; + +struct cpiofs_file_t { + const char *data; + int size; +}; + +struct cpiofs_dir_t { + /* Link cpiofs_internal */ + struct list_head list; +}; + +#define CPIOFS_TYPE_UNDEFINE 0x0 +#define CPIOFS_TYPE_FILE 0x1 +#define CPIOFS_TYPE_DIR 0x2 + +struct cpiofs_internal { + const char *name; + int type; + union { + struct cpiofs_file_t file; + struct cpiofs_dir_t dir; + }; + struct vnode *node; + struct list_head list; +}; + +static struct vnode cpio_root_node; +static struct vnode mount_old_node; +static int cpio_mounted; + +static int cpiofs_mount(struct filesystem *fs, struct mount *mount); +static int cpiofs_sync(struct filesystem *fs); + +static struct filesystem cpiofs = { + .name = "cpiofs", + .mount = cpiofs_mount, + .sync = cpiofs_sync +}; + +static int cpiofs_lookup(struct vnode *dir_node, struct vnode **target, + const char *component_name); +static int cpiofs_create(struct vnode *dir_node, struct vnode **target, + const char *component_name); +static int cpiofs_mkdir(struct vnode *dir_node, struct vnode **target, + const char *component_name); +static int cpiofs_isdir(struct vnode *dir_node); +static int cpiofs_getname(struct vnode *dir_node, const char **name); +static int cpiofs_getsize(struct vnode *dir_node); + +static struct vnode_operations cpiofs_v_ops = { + .lookup = cpiofs_lookup, + .create = cpiofs_create, + .mkdir = cpiofs_mkdir, + .isdir = cpiofs_isdir, + .getname = cpiofs_getname, + .getsize = cpiofs_getsize +}; + +static int cpiofs_write(struct file *file, const void *buf, size_t len); +static int cpiofs_read(struct file *file, void *buf, size_t len); +static int cpiofs_open(struct vnode *file_node, struct file *target); +static int cpiofs_close(struct file *file); +static long cpiofs_lseek64(struct file *file, long offset, int whence); +static int cpiofs_ioctl(struct file *file, uint64 request, va_list args); + +static struct file_operations cpiofs_f_ops = { + .write = cpiofs_write, + .read = cpiofs_read, + .open = cpiofs_open, + .close = cpiofs_close, + .lseek64 = cpiofs_lseek64, + .ioctl = cpiofs_ioctl +}; + +/* filesystem methods */ +static int cpiofs_mount(struct filesystem *fs, struct mount *mount) +{ + struct vnode *oldnode; + struct cpiofs_internal *internal; + const char *name; + + preempt_disable(); + + if (cpio_mounted) { + preempt_enable(); + + return -1; + } + + cpio_mounted = 1; + + preempt_enable(); + + oldnode = mount->root; + + oldnode->v_ops->getname(oldnode, &name); + + internal = cpio_root_node.internal; + + internal->name = name; + + mount_old_node.mount = oldnode->mount; + mount_old_node.v_ops = oldnode->v_ops; + mount_old_node.f_ops = oldnode->f_ops; + mount_old_node.parent = oldnode->parent; + mount_old_node.internal = oldnode->internal; + + oldnode->mount = mount; + oldnode->v_ops = cpio_root_node.v_ops; + oldnode->f_ops = cpio_root_node.f_ops; + oldnode->internal = internal; + + return 0; +} + +static int cpiofs_sync(struct filesystem *fs) +{ + return 0; +} + +/* vnode_operations methods */ + +static int cpiofs_lookup(struct vnode *dir_node, struct vnode **target, + const char *component_name) +{ + struct cpiofs_internal *internal, *entry; + + internal = dir_node->internal; + + if (internal->type != CPIOFS_TYPE_DIR) { + return -1; + } + + list_for_each_entry(entry, &internal->dir.list, list) { + if (!strcmp(entry->name, component_name)) { + break; + } + } + + if (&entry->list == &internal->dir.list) { + return -1; + } + + *target = entry->node; + + return 0; +} + +static int cpiofs_create(struct vnode *dir_node, struct vnode **target, + const char *component_name) +{ + return -1; +} + +static int cpiofs_mkdir(struct vnode *dir_node, struct vnode **target, + const char *component_name) +{ + return -1; +} + +static int cpiofs_isdir(struct vnode *dir_node) +{ + struct cpiofs_internal *internal; + + internal = dir_node->internal; + + if (internal->type != CPIOFS_TYPE_DIR) { + return 0; + } + + return 1; +} + +static int cpiofs_getname(struct vnode *dir_node, const char **name) +{ + struct cpiofs_internal *internal; + + internal = dir_node->internal; + + *name = internal->name; + + return 0; +} + +static int cpiofs_getsize(struct vnode *dir_node) +{ + struct cpiofs_internal *internal; + + internal = dir_node->internal; + + if (internal->type != CPIOFS_TYPE_FILE) { + return -1; + } + + return internal->file.size; +} + +/* file_operations methods */ + +static int cpiofs_write(struct file *file, const void *buf, size_t len) +{ + return -1; +} + +static int cpiofs_read(struct file *file, void *buf, size_t len) +{ + struct cpiofs_internal *internal; + + internal = file->vnode->internal; + + if (internal->type != CPIOFS_TYPE_FILE) { + return -1; + } + + if (len > internal->file.size - file->f_pos) { + len = internal->file.size - file->f_pos; + } + + if (!len) { + return 0; + } + + memncpy(buf, &internal->file.data[file->f_pos], len); + + file->f_pos += len; + + return len; +} + +static int cpiofs_open(struct vnode *file_node, struct file *target) +{ + target->vnode = file_node; + target->f_pos = 0; + target->f_ops = file_node->f_ops; + + return 0; +} + +static int cpiofs_close(struct file *file) +{ + file->vnode = NULL; + file->f_pos = 0; + file->f_ops = NULL; + + return 0; +} + +static long cpiofs_lseek64(struct file *file, long offset, int whence) +{ + int filesize; + int base; + + filesize = file->vnode->v_ops->getsize(file->vnode); + + if (filesize < 0) { + return -1; + } + + switch (whence) { + case SEEK_SET: + base = 0; + break; + case SEEK_CUR: + base = file->f_pos; + break; + case SEEK_END: + base = filesize; + break; + default: + return -1; + } + + if (base + offset > filesize) { + return -1; + } + + file->f_pos = base + offset; + + return 0; +} + +static int cpiofs_ioctl(struct file *file, uint64 request, va_list args) +{ + return -1; +} + +/* Others */ + +// Convert "0000000A" to 10 +static uint32 cpio_read_8hex(const char *p) +{ + uint32 result = 0; + + for (int i = 0; i < 8; ++i) { + char c = *p; + + result <<= 4; + + if ('0' <= c && c <= '9') { + result += c - '0'; + } + else if ('A' <= c && c <= 'F') { + result += c - 'A' + 10; + } + + p++; + } + + return result; +} + +/* + * Return directory vnode, and set @pathname to the last component name. + * If the @pathname is end with '/', set @pathname to NULL + * + * For example: + * + * If @pathname is "/abc/def/ghi". + * Return the vnode of "/abc/def", and set @pathname to "ghi". + * + * If @pathname is "/abc/def/". + * Return the vnode of "/abc/def", and set @pathname to NULL. + * + */ +static struct vnode *get_dir_vnode(struct vnode *dir_node, + const char **pathname) +{ + struct vnode *result; + const char *start; + const char *end; + char buf[0x100]; + + start = end = *pathname; + + if (*start == '/') { + result = &cpio_root_node; + } else { + result = dir_node; + } + + while (1) { + if (!strncmp("./", start, 2)) { + start += 2; + end = start; + continue; + } else if (!strncmp("../", start, 3)) { + if (result->parent) { + result = result->parent; + } + + start += 3; + end = start; + continue; + } + + // Find next component + while (*end != '\0' && *end != '/') { + end++; + } + + if (*end == '/') { + int ret; + + if (start == end) { + // Case like "//" + end++; + start = end; + continue; + } + + // TODO: Check if the length is less than 0x100 + memncpy(buf, start, end - start); + buf[end - start] = 0; + + ret = result->v_ops->lookup(result, &result, buf); + + if (ret < 0) { + return NULL; + } + + end++; + start = end; + } else { + break; + } + } + + *pathname = *start ? start : NULL; + + return result; +} + +static void cpio_init_mkdir(const char *pathname) +{ + const char *curname; + struct vnode *dir_node; + struct vnode *newdir_node; + struct cpiofs_internal *internal, *dirint; + + curname = pathname; + dir_node = get_dir_vnode(&cpio_root_node, &curname); + + if (!dir_node) { + return; + } + + if (!curname) { + return; + } + + dirint = dir_node->internal; + + if (dirint->type != CPIOFS_TYPE_DIR) { + return; + } + + internal = kmalloc(sizeof(struct cpiofs_internal)); + newdir_node = kmalloc(sizeof(struct vnode)); + + internal->name = curname; + internal->type = CPIOFS_TYPE_DIR; + INIT_LIST_HEAD(&internal->dir.list); + internal->node = newdir_node; + list_add_tail(&internal->list, &dirint->dir.list); + + newdir_node->mount = NULL; + newdir_node->v_ops = &cpiofs_v_ops; + newdir_node->f_ops = &cpiofs_f_ops; + newdir_node->parent = dir_node; + newdir_node->internal = internal; + + return; +} + +static void cpio_init_create(const char *pathname, + const char *data, + uint64 size) +{ + const char *curname; + struct vnode *dir_node; + struct vnode *newdir_node; + struct cpiofs_internal *internal, *dirint; + + curname = pathname; + dir_node = get_dir_vnode(&cpio_root_node, &curname); + + if (!dir_node) { + return; + } + + if (!curname) { + return; + } + + dirint = dir_node->internal; + + if (dirint->type != CPIOFS_TYPE_DIR) { + return; + } + + internal = kmalloc(sizeof(struct cpiofs_internal)); + newdir_node = kmalloc(sizeof(struct vnode)); + + internal->name = curname; + internal->type = CPIOFS_TYPE_FILE; + internal->file.data = data; + internal->file.size = size; + internal->node = newdir_node; + list_add_tail(&internal->list, &dirint->dir.list); + + newdir_node->mount = NULL; + newdir_node->v_ops = &cpiofs_v_ops; + newdir_node->f_ops = &cpiofs_f_ops; + newdir_node->parent = dir_node; + newdir_node->internal = internal; + + return; +} + +struct filesystem *cpiofs_init(void) +{ + char *cur; + struct cpiofs_internal *internal; + + internal = kmalloc(sizeof(struct cpiofs_internal)); + + internal->name = NULL; + internal->type = CPIOFS_TYPE_DIR; + INIT_LIST_HEAD(&internal->dir.list); + internal->node = &cpio_root_node; + INIT_LIST_HEAD(&internal->list); + + cpio_root_node.mount = NULL; + cpio_root_node.v_ops = &cpiofs_v_ops; + cpio_root_node.f_ops = &cpiofs_f_ops; + cpio_root_node.parent = NULL; + cpio_root_node.internal = internal; + + cur = initramfs_base; + + while (1) { + char *component_name, *content; + struct cpio_newc_header *pheader; + uint32 namesize, filesize, adj_namesize, adj_filesize, type; + + pheader = (struct cpio_newc_header *)cur; + cur += sizeof(struct cpio_newc_header); + + // 070701 + if (*(uint32 *)&pheader->c_magic[0] != 0x37303730 && + *(uint16 *)&pheader->c_magic[4] != 0x3130) { + panic("[*] Only support new ASCII format of cpio.\r\n"); + } + + namesize = cpio_read_8hex(pheader->c_namesize); + filesize = cpio_read_8hex(pheader->c_filesize); + type = cpio_read_8hex(pheader->c_mode) & CPIO_TYPE_MASK; + + // The pathname is followed by NUL bytes so that the total size of the + // fixed header plus pathname is a multiple of four. Likewise, the file + // data is padded to a multiple of four bytes + adj_namesize = ALIGN(namesize + + sizeof(struct cpio_newc_header), 4) + - sizeof(struct cpio_newc_header); + adj_filesize = ALIGN(filesize, 4); + + component_name = cur; + cur += adj_namesize; + content = cur; + cur += adj_filesize; + + if (type == CPIO_TYPE_DIR) { + cpio_init_mkdir(component_name); + } else if (type == CPIO_TYPE_FILE) { + cpio_init_create(component_name, content, filesize); + } + + // TRAILER!!! + if (namesize == 0xb && !strcmp(component_name, "TRAILER!!!")) { + break; + } + } + + return &cpiofs; +} \ No newline at end of file diff --git a/lab8/src/kernel/fs/fat32fs.c b/lab8/src/kernel/fs/fat32fs.c new file mode 100644 index 000000000..021002d0b --- /dev/null +++ b/lab8/src/kernel/fs/fat32fs.c @@ -0,0 +1,1673 @@ +#include +#include +#include +#include +#include +#include +#include + +#define BLOCK_SIZE 512 +#define CLUSTER_ENTRY_PER_BLOCK (BLOCK_SIZE / sizeof(struct cluster_entry_t)) +#define DIR_PER_BLOCK (BLOCK_SIZE / sizeof(struct dir_t)) +#define INVALID_CID 0x0ffffff8 + +struct partition_t { + uint8 status; + uint8 chss_head; + uint8 chss_sector; + uint8 chss_cylinder; + uint8 type; + uint8 chse_head; + uint8 chse_sector; + uint8 chse_cylinder; + uint32 lba; + uint32 sectors; +} __attribute__((packed)); + +struct boot_sector_t { + uint8 jmpboot[3]; + uint8 oemname[8]; + uint16 bytes_per_sector; // Bytes Per Sector + uint8 sector_per_cluster; // Sectors Per Cluster + uint16 reserved_sector_cnt; // Number of Reserved Sectors + uint8 fat_cnt; // Number of FATs + uint16 root_entry_cnt; + uint16 old_sector_cnt; + uint8 media; + uint16 sector_per_fat16; + uint16 sector_per_track; + uint16 head_cnt; + uint32 hidden_sector_cnt; + uint32 sector_cnt; + uint32 sector_per_fat32; // Sectors Per FAT + uint16 extflags; + uint16 ver; + uint32 root_cluster; // Root Directory First Cluster + uint16 info; + uint16 bkbooksec; + uint8 reserved[12]; + uint8 drvnum; + uint8 reserved1; + uint8 bootsig; + uint32 volid; + uint8 vollab[11]; + uint8 fstype[8]; +} __attribute__((packed)); + +// attr of dir_t +#define ATTR_READ_ONLY 0x01 +#define ATTR_HIDDEN 0x02 +#define ATTR_SYSTEM 0x04 +#define ATTR_VOLUME_ID 0x08 +#define ATTR_LFN 0x0f +#define ATTR_DIRECTORY 0x10 +#define ATTR_ARCHIVE 0x20 +#define ATTR_FILE_DIR_MASK (ATTR_DIRECTORY | ATTR_ARCHIVE) + +struct dir_t { + uint8 name[11]; + uint8 attr; + uint8 ntres; // windows nt reserve + uint8 crttimetenth; // create tiem tenth + uint16 crttime; // creat time + uint16 crtdate; // creat date + uint16 lstaccdate; // last access data + uint16 ch; // clster high + uint16 wrttime; // write time + uint16 wrtdate; // write date + uint16 cl; // cluster low + uint32 size; // file size +} __attribute__((packed)); + +struct long_dir_t { + uint8 order; + uint8 name1[10]; + uint8 attr; + uint8 type; + uint8 checksum; + uint8 name2[12]; + uint16 fstcluslo; // first cluster + uint8 name3[4]; +} __attribute__((packed)); + +struct cluster_entry_t { + union { + uint32 val; + struct { + uint32 idx: 28; + uint32 reserved: 4; + }; + }; +}; + +struct filename_t { + union { + uint8 fullname[256]; + struct { + uint8 name[13]; + } part[20]; + }; +} __attribute__((packed)); + +struct fat_file_block_t { + /* Link fat_file_block_t */ + struct list_head list; + /* + * offset id of file + * offset id N corresponds to offset N * BLOCKS_SIZE of file + */ + uint32 oid; + /* cluster id */ + uint32 cid; + /* Already read the data into buf */ + uint32 read; + uint32 dirty; + uint8 buf[BLOCK_SIZE]; +}; + +struct fat_file_t { + /* Head of fat_file_block_t chain */ + struct list_head list; + uint32 size; +}; + +struct fat_dir_t { + /* Head of fat_internal chain */ + struct list_head list; +}; + +struct fat_info_t { + struct boot_sector_t bs; + uint32 fat_lba; + uint32 cluster_lba; +}; + +// type of struct fat_internal +#define FAT_DIR 1 +#define FAT_FILE 2 + +struct fat_internal { + const char *name; + struct vnode *node; + struct fat_info_t *fat; + /* Link fat_internal */ + struct list_head list; + /* cluster id */ + uint32 cid; + uint32 type; + union { + struct fat_dir_t *dir; + struct fat_file_t *file; + }; +}; + +struct fat_mount_t { + /* Link fat_mount_t */ + struct list_head list; + struct mount *mount; +}; + +/* Head of fat_mount_t chain */ +static struct list_head mounts; + +static int fat32fs_mount(struct filesystem *fs, struct mount *mount); +static int fat32fs_sync(struct filesystem *fs); + +static struct filesystem fat32fs = { + .name = "fat32fs", + .mount = fat32fs_mount, + .sync = fat32fs_sync +}; + +static int fat32fs_lookup(struct vnode *dir_node, struct vnode **target, + const char *component_name); +static int fat32fs_create(struct vnode *dir_node, struct vnode **target, + const char *component_name); +static int fat32fs_mkdir(struct vnode *dir_node, struct vnode **target, + const char *component_name); +static int fat32fs_isdir(struct vnode *dir_node); +static int fat32fs_getname(struct vnode *dir_node, const char **name); +static int fat32fs_getsize(struct vnode *dir_node); + +static struct vnode_operations fat32fs_v_ops = { + .lookup = fat32fs_lookup, + .create = fat32fs_create, + .mkdir = fat32fs_mkdir, + .isdir = fat32fs_isdir, + .getname = fat32fs_getname, + .getsize = fat32fs_getsize +}; + +static int fat32fs_write(struct file *file, const void *buf, size_t len); +static int fat32fs_read(struct file *file, void *buf, size_t len); +static int fat32fs_open(struct vnode *file_node, struct file *target); +static int fat32fs_close(struct file *file); +static long fat32fs_lseek64(struct file *file, long offset, int whence); +static int fat32fs_ioctl(struct file *file, uint64 request, va_list args); + +static struct file_operations fat32fs_f_ops = { + .write = fat32fs_write, + .read = fat32fs_read, + .open = fat32fs_open, + .close = fat32fs_close, + .lseek64 = fat32fs_lseek64, + .ioctl = fat32fs_ioctl +}; + +static uint32 get_next_cluster(uint32 fat_lba, uint32 cluster_id); +// TODO: Check alloc_cluster ok +static uint32 alloc_cluster(struct fat_info_t *fat, uint32 prev_cid); +static int invalid_cid(uint32 cid); +static struct dir_t *__lookup_fat32(struct vnode *dir_node, + const char *component_name, + uint8 *buf, int *buflba); + +/* filesystem methods */ + +static int fat32fs_mount(struct filesystem *fs, struct mount *mount) +{ + struct partition_t *partition; + struct fat_info_t *fat; + struct fat_dir_t *dir; + struct fat_internal *data; + struct vnode *oldnode, *node; + struct fat_mount_t *newmount; + const char *name; + uint32 lba; + uint8 buf[BLOCK_SIZE]; + + sd_readblock(0, buf); + + partition = (struct partition_t *)&buf[0x1be]; + + if (buf[510] != 0x55 || buf[511] != 0xaa) { + return -1; + } + + if (partition[0].type != 0xb && partition[0].type != 0xc) { + return -1; + } + + lba = partition[0].lba; + + sd_readblock(partition[0].lba, buf); + + node = kmalloc(sizeof(struct vnode)); + data = kmalloc(sizeof(struct fat_internal)); + fat = kmalloc(sizeof(struct fat_info_t)); + dir = kmalloc(sizeof(struct fat_dir_t)); + newmount = kmalloc(sizeof(struct fat_mount_t)); + + memncpy((void *)&fat->bs, (void *)buf, sizeof(fat->bs)); + + fat->fat_lba = lba + fat->bs.reserved_sector_cnt; // fat_begin_lba + fat->cluster_lba = fat->fat_lba + + fat->bs.fat_cnt * fat->bs.sector_per_fat32; // cluster_begin_lba + + INIT_LIST_HEAD(&dir->list); + + oldnode = mount->root; + + oldnode->v_ops->getname(oldnode, &name); + + node->mount = oldnode->mount; + node->v_ops = oldnode->v_ops; + node->f_ops = oldnode->f_ops; + node->parent = oldnode->parent; + node->internal = oldnode->internal; + + data->name = name; + data->node = node; + data->fat = fat; + data->cid = 2; // cluster id + data->type = FAT_DIR; + data->dir = dir; + + oldnode->mount = mount; + oldnode->v_ops = &fat32fs_v_ops; + oldnode->f_ops = &fat32fs_f_ops; + oldnode->internal = data; + + preempt_disable(); + + list_add(&newmount->list, &mounts); + + preempt_enable(); + + newmount->mount = mount; + + return 0; +} + +static void _do_sync_dir(struct vnode *dirnode) +{ + struct fat_internal *data, *entry; + struct list_head *head; + struct dir_t *dir; + struct long_dir_t *ldir; + uint32 cid; + int lba, idx, lfnidx; + uint8 buf[BLOCK_SIZE]; + + data = dirnode->internal; + head = &data->dir->list; + cid = data->cid; + idx = 0; + lfnidx = 1; + + if (invalid_cid(cid)) { + panic("fat32 _do_sync_dir: invalid dirnode->data->cid"); + } + + lba = data->fat->cluster_lba + + (cid - 2) * data->fat->bs.sector_per_cluster; + + // TODO: Cache data block of directory + sd_readblock(lba, buf); + + list_for_each_entry(entry, head, list) { + struct dir_t *origindir; + const char *name; + const char *ext; + int lfn, namelen, extpos, i, buflba; + uint8 lookupbuf[BLOCK_SIZE]; + + name = entry->name; + + // If entry is a old file, update its size + origindir = __lookup_fat32(dirnode, name, lookupbuf, &buflba); + + if (origindir) { + if (entry->type == FAT_FILE) { + origindir->size = entry->file->size; + sd_writeblock(buflba, lookupbuf); + } + + continue; + } + + // Else if entry is a new file + ext = NULL; + extpos = -1; + + do { + namelen = strlen(name); + + // is LFM? + if (namelen >= 13) { + lfn = 1; + break; + } + + for (i = 0; i < namelen; ++i) { + if (name[namelen - 1 - i] == '.') { + break; + } + } + + if (i < namelen) { + ext = &name[namelen - i]; + extpos = namelen - 1 - i; + } + + // is long file name? + if (i >= 4) { + lfn = 1; + break; + } + + if (namelen - 1 - i > 8) { + lfn = 1; + break; + } + + lfn = 0; + } while(0); + + // Seek idx to the end of dir + while (1) { + dir = (struct dir_t *)(&buf[sizeof(struct dir_t) * idx]); + + if (dir->name[0] == 0) { + break; + } + + idx += 1; + + if (idx >= 16) { + uint32 newcid; + + sd_writeblock(lba, buf); // full use an cluster + + newcid = get_next_cluster(data->fat->fat_lba, cid); + if (invalid_cid(newcid)) { + newcid = alloc_cluster(data->fat, cid); + } + + cid = newcid; + + lba = data->fat->cluster_lba + + (cid - 2) * data->fat->bs.sector_per_cluster; + + // TODO: Cache data block of directory + sd_readblock(lba, buf); + + idx = 0; + } + } + + // Write LFN + if (lfn) { + int ord; + int first; + + ord = ((namelen - 1) / 13) + 1; + first = 0x40; + + for (; ord > 0; --ord) { + int end; + + ldir = (struct long_dir_t *) + (&buf[sizeof(struct long_dir_t) * idx]); + + ldir->order = first | ord; + ldir->attr = ATTR_LFN; + ldir->type = 0; + // TODO: Calculate checksum + ldir->checksum = 0; + ldir->fstcluslo = 0; + + first = 0; + end = 0; + + for (i = 0; i < 10; i += 2) { + if (end) { + ldir->name1[i] = 0xff; + ldir->name1[i + 1] = 0xff; + } else { + ldir->name1[i] = name[(ord - 1) * 13 + i / 2]; + ldir->name1[i + 1] = 0; + if (ldir->name1[i] == 0) { + end = 1; + } + } + } + for (i = 0; i < 12; i += 2) { + if (end) { + ldir->name2[i] = 0xff; + ldir->name2[i + 1] = 0xff; + } else { + ldir->name2[i] = name[(ord - 1) * 13 + 5 + i / 2]; + ldir->name2[i + 1] = 0; + if (ldir->name2[i] == 0) { + end = 1; + } + } + } + for (i = 0; i < 4; i += 2) { + if (end) { + ldir->name3[i] = 0xff; + ldir->name3[i + 1] = 0xff; + } else { + ldir->name3[i] = name[(ord - 1) * 13 + 11 + i / 2]; + ldir->name3[i + 1] = 0; + if (ldir->name3[i] == 0) { + end = 1; + } + } + } + + idx += 1; + + if (idx >= 16) { + uint32 newcid; + + sd_writeblock(lba, buf); + + newcid = get_next_cluster(data->fat->fat_lba, cid); + if (invalid_cid(newcid)) { + newcid = alloc_cluster(data->fat, cid); + } + + cid = newcid; + + lba = data->fat->cluster_lba + + (cid - 2) * data->fat->bs.sector_per_cluster; + + // TODO: Cache data block of directory + sd_readblock(lba, buf); + + idx = 0; + } + } + } + + // Write SFN + dir = (struct dir_t *)(&buf[sizeof(struct dir_t) * idx]); + + // TODO: Set these properties properly + dir->ntres = 0; + dir->crttimetenth = 0; + dir->crttime = 0; + dir->crtdate = 0; + dir->lstaccdate = 0; + dir->wrttime = 0; + dir->wrtdate = 0; + + if (entry->type == FAT_DIR) { + dir->attr = ATTR_DIRECTORY; + dir->size = 0; + } else { + dir->attr = ATTR_ARCHIVE; + dir->size = entry->file->size; + } + + if (invalid_cid(entry->cid)) { + entry->cid = alloc_cluster(data->fat, 0); + } + + dir->ch = (entry->cid >> 16) & 0xffff; + dir->cl = entry->cid & 0xffff; + + if (lfn) { + int lfni; + + // TODO: handle lfnidx + for (i = 7, lfni = lfnidx; i >= 0 && lfni;) { + dir->name[i--] = '0' + lfni % 10; + lfni /= 10; + } + + lfnidx++; + + dir->name[i--] = '~'; + + // TODO: handle letter case + memncpy((void *)dir->name, name, i + 1); + } else { + // TODO: handle letter case + for (i = 0; i != extpos && name[i]; ++i) { + dir->name[i] = name[i]; + } + + for (; i < 8; ++i) { + dir->name[i] = ' '; + } + } + + // TODO: handle letter case + for (i = 0; i < 3 && ext[i]; ++i) { + dir->name[8 + i] = ext[i]; + } + + for (; i < 3; ++i) { + dir->name[8 + i] = ' '; + } + + idx += 1; + + if (idx >= 16) { + int newcid; + + sd_writeblock(lba, buf); + + newcid = get_next_cluster(data->fat->fat_lba, cid); + if (invalid_cid(newcid)) { + newcid = alloc_cluster(data->fat, cid); + } + + cid = newcid; + + lba = data->fat->cluster_lba + + (cid - 2) * data->fat->bs.sector_per_cluster; + + // TODO: Cache data block of directory + sd_readblock(lba, buf); + + idx = 0; + } + } + + if (idx) { + sd_writeblock(lba, buf); + } +} + +static void _do_sync_file(struct vnode *filenode) +{ + struct fat_file_block_t *entry; + struct fat_internal *data; + struct list_head *head; + uint32 cid; + + data = filenode->internal; + head = &data->file->list; + cid = data->cid; + + if (invalid_cid(cid)) { + panic("fat32 _do_sync_file: invalid cid"); + } + + list_for_each_entry(entry, head, list) { + int lba; + + if (entry->oid == 0) { + if (!invalid_cid(entry->cid) && data->cid != entry->cid) { + panic("_do_sync_file: cid isn't sync"); + } + + entry->cid = data->cid; + } + + if (invalid_cid(entry->cid)) { + entry->cid = alloc_cluster(data->fat, cid); + } + + if (!entry->dirty) { + continue; + } + + if (!entry->read) { + memset(entry->buf, 0, BLOCK_SIZE); + entry->read = 1; + } + + lba = data->fat->cluster_lba + + (entry->cid - 2) * data->fat->bs.sector_per_cluster; + + sd_writeblock(lba, entry->buf); + + entry->dirty = 0; + + cid = entry->cid; + } +} + +static void _sync_dir(struct vnode *dirnode) +{ + struct fat_internal *data, *entry; + struct list_head *head; + + data = dirnode->internal; + head = &data->dir->list; + + _do_sync_dir(dirnode); + + list_for_each_entry(entry, head, list) { + if (entry->type == FAT_DIR) { + _sync_dir(entry->node); + } else { + _do_sync_file(entry->node); + } + } +} + +static int fat32fs_sync(struct filesystem *fs) +{ + struct fat_mount_t *entry; + + list_for_each_entry(entry, &mounts, list) { + _sync_dir(entry->mount->root); + } + + return 0; +} + +/* vnode_operations methods */ + +static struct vnode *_create_vnode(struct vnode *parent, + const char *name, + uint32 type, + uint32 cid, + uint32 size) +{ + struct vnode *node; + struct fat_internal *info, *data; + char *buf; + int len; + + info = parent->internal; + len = strlen(name); + + buf = kmalloc(len + 1); + node = kmalloc(sizeof(struct vnode)); + data = kmalloc(sizeof(struct fat_internal)); + + strcpy(buf, name); + + data->name = buf; + data->node = node; + data->fat = info->fat; + data->cid = cid; + data->type = type; + + if (type == FAT_DIR) { + struct fat_dir_t *dir; + + dir = kmalloc(sizeof(struct fat_dir_t)); + + INIT_LIST_HEAD(&dir->list); + + data->dir = dir; + } else { + struct fat_file_t *file; + + file = kmalloc(sizeof(struct fat_file_t)); + + INIT_LIST_HEAD(&file->list); + file->size = size; + + data->file = file; + } + + node->mount = parent->mount; + node->v_ops = &fat32fs_v_ops; + node->f_ops = &fat32fs_f_ops; + node->parent = parent; + node->internal = data; + + list_add(&data->list, &info->dir->list); + + return node; +} + +static int _lookup_cache(struct vnode *dir_node, struct vnode **target, + const char *component_name) +{ + struct fat_internal *data, *entry; + struct fat_dir_t *dir; + int found; + + data = dir_node->internal; + dir = data->dir; + + found = 0; + + list_for_each_entry(entry, &dir->list, list) { + if (!strcasecmp(component_name, entry->name)) { + found = 1; + break; + } + } + + if (!found) { + return -1; + } + + *target = entry->node; + + return 0; +} + +static struct dir_t *__lookup_fat32(struct vnode *dir_node, + const char *component_name, + uint8 *buf, int *buflba) +{ + struct dir_t *dir; + struct fat_internal *data; + struct fat_info_t *fat; + struct filename_t name; + uint32 cid; + int found, dirend, lfn; + + data = dir_node->internal; + fat = data->fat; + cid = data->cid; + + found = 0; + dirend = 0; + + memset(&name, 0, sizeof(struct filename_t)); + + while (1) { + int lba; + + lba = fat->cluster_lba + (cid - 2) * fat->bs.sector_per_cluster; + + // TODO: Cache data block of directory + sd_readblock(lba, buf); + + if (buflba) { + *buflba = lba; + } + + for (int i = 0; i < DIR_PER_BLOCK; ++i) { + uint8 len; + + dir = (struct dir_t *)(&buf[sizeof(struct dir_t) * i]); + + if (dir->name[0] == 0) { + dirend = 1; + break; + } + + if ((dir->attr & ATTR_LFN) == ATTR_LFN) { + struct long_dir_t *ldir; + int n; + + lfn = 1; + + ldir = (struct long_dir_t *)dir; + n = (dir->name[0] & 0x3f) - 1; + + for (int i = 0; ldir->name1[i] != 0xff && i < 10; i += 2) { + name.part[n].name[i / 2] = ldir->name1[i]; + } + for (int i = 0; ldir->name2[i] != 0xff && i < 12; i += 2) { + name.part[n].name[5 + i / 2] = ldir->name2[i]; + } + for (int i = 0; ldir->name3[i] != 0xff && i < 4; i += 2) { + name.part[n].name[11 + i / 2] = ldir->name3[i]; + } + + continue; + } + + if (lfn == 1) { + if (!strcasecmp(component_name, (void *)name.fullname)) { + found = 1; + break; + } + + lfn = 0; + memset(&name, 0, sizeof(struct filename_t)); // clear name + + continue; + } + + // shoter name + lfn = 0; + len = 8; + + while (len) { + if (dir->name[len - 1] != 0x20) { + break; + } + len -= 1; + } + + memncpy((void *)name.fullname, (void *)dir->name, len); + name.fullname[len] = 0; + + // extension name + len = 3; + + while (len) { + if (dir->name[8 + len - 1] != 0x20) { + break; + } + len -= 1; + } + + if (len >= 0) { + strcat((void *)name.fullname, "."); + strncat((void *)name.fullname, (void *)&dir->name[8], len); + } + + if (!strcasecmp(component_name, (void *)name.fullname)) { + found = 1; + break; + } + + memset(&name, 0, sizeof(struct filename_t)); + } + + if (found) { + break; + } + + if (dirend) { + break; + } + + cid = get_next_cluster(fat->fat_lba, cid); + + if (invalid_cid(cid)) { + break; + } + } + + if (!found) { + return NULL; + } + + return dir; +} + +static int _lookup_fat32(struct vnode *dir_node, struct vnode **target, + const char *component_name) +{ + struct vnode *node; + struct dir_t *dir; + uint32 type, cid; + uint8 buf[BLOCK_SIZE]; + + dir = __lookup_fat32(dir_node, component_name, buf, NULL); + + if (!dir) { + return -1; + } + + if (!(dir->attr & ATTR_FILE_DIR_MASK)) { + return -1; + } + + cid = (dir->ch << 16) | dir->cl; + + if (dir->attr & ATTR_ARCHIVE) { + type = FAT_FILE; + } else { + type = FAT_DIR; + } + + node = _create_vnode(dir_node, component_name, type, cid, dir->size); + + *target = node; + + return 0; +} + +static int fat32fs_lookup(struct vnode *dir_node, struct vnode **target, + const char *component_name) +{ + struct fat_internal *data; + int ret; + + data = dir_node->internal; + + if (data->type != FAT_DIR) { + return -1; + } + + ret = _lookup_cache(dir_node, target, component_name); + + if (ret >= 0) { + return ret; + } + + return _lookup_fat32(dir_node, target, component_name); +} + +static int fat32fs_create(struct vnode *dir_node, struct vnode **target, + const char *component_name) +{ + struct vnode *node; + struct fat_internal *internal; + int ret; + + internal = dir_node->internal; + + if (internal->type != FAT_DIR) { + return -1; + } + + ret = fat32fs_lookup(dir_node, target, component_name); + + if (!ret) { + return -1; + } + + node = _create_vnode(dir_node, component_name, FAT_FILE, -1, 0); + + *target = node; + + return 0; +} + +static int fat32fs_mkdir(struct vnode *dir_node, struct vnode **target, + const char *component_name) +{ + struct vnode *node; + struct fat_internal *internal; + int ret; + + internal = dir_node->internal; + + if (internal->type != FAT_DIR) { + return -1; + } + + ret = fat32fs_lookup(dir_node, target, component_name); + + if (!ret) { + return -1; + } + + node = _create_vnode(dir_node, component_name, FAT_DIR, -1, 0); + + *target = node; + + return 0; +} + +static int fat32fs_isdir(struct vnode *dir_node) +{ + struct fat_internal *internal; + + internal = dir_node->internal; + + if (internal->type != FAT_DIR) { + return 0; + } + + return 1; +} + +static int fat32fs_getname(struct vnode *dir_node, const char **name) +{ + struct fat_internal *internal; + + internal = dir_node->internal; + + *name = internal->name; + + return 0; +} + +static int fat32fs_getsize(struct vnode *dir_node) +{ + struct fat_internal *internal; + + internal = dir_node->internal; + + if (internal->type == FAT_DIR) { + return 0; + } + + return internal->file->size; +} + +/* file_operations methods */ + +static int _writefile_seek_cache(struct fat_internal *data, uint32 foid, + struct fat_file_block_t **block) +{ + struct fat_file_block_t *entry; + struct list_head *head; + + head = &data->file->list; + + if (list_empty(head)) { + return -1; + } + + list_for_each_entry(entry, head, list) { + *block = entry; + + if (foid == entry->oid) { + return 0; + } + } + + return -1; +} + +static int _writefile_seek_fat32(struct fat_internal *data, + uint32 foid, uint32 fcid, + struct fat_file_block_t **block) +{ + struct fat_info_t *info; + uint32 curoid, curcid; + + info = data->fat; + + if (*block) { + curoid = (*block)->oid; + curcid = (*block)->cid; + + if (curoid == foid) { + return 0; + } + + curoid++; + curcid = get_next_cluster(info->fat_lba, curcid); + } else { + curoid = 0; + curcid = fcid; + } + + while (1) { + struct fat_file_block_t *newblock; + + newblock = kmalloc(sizeof(struct fat_file_block_t)); + + newblock->oid = curoid; + newblock->cid = curcid; + newblock->read = 0; + newblock->dirty = 1; + + list_add_tail(&newblock->list, &data->file->list); + + *block = newblock; + + if (curoid == foid) { + return 0; + } + + curoid++; + curcid = get_next_cluster(info->fat_lba, curcid); + } +} + +static int _writefile_cache(struct fat_internal *data, uint64 bckoff, + const uint8 *buf, uint64 bufoff, uint32 size, + struct fat_file_block_t *block) +{ + int wsize; + + if (!block->read) { + // read the data from sdcard + struct fat_info_t *info; + int lba; + + info = data->fat; + lba = info->cluster_lba + + (block->cid - 2) * info->bs.sector_per_cluster; + + sd_readblock(lba, block->buf); + + block->read = 1; + } + + wsize = size > BLOCK_SIZE - bckoff ? BLOCK_SIZE - bckoff : size; + + memncpy((void *)&block->buf[bckoff], (void *)&buf[bufoff], wsize); + + return wsize; +} + +static int _writefile_fat32(struct fat_internal *data, uint64 bckoff, + const uint8 *buf, uint32 bufoff, uint32 size, + uint32 oid, uint32 cid) +{ + struct list_head *head; + struct fat_info_t *info; + struct fat_file_block_t *block; + int lba; + int wsize; + + head = &data->file->list; + info = data->fat; + + block = kmalloc(sizeof(struct fat_file_block_t)); + + wsize = size > BLOCK_SIZE - bckoff ? BLOCK_SIZE - bckoff : size; + + if (invalid_cid(cid)) { + memset(block->buf, 0, BLOCK_SIZE); + } else { + lba = info->cluster_lba + (cid - 2) * info->bs.sector_per_cluster; + + sd_readblock(lba, block->buf); + } + + memncpy((void *)&block->buf[bckoff], (void *)&buf[bufoff], wsize); + + block->oid = oid; + block->cid = cid; + block->read = 1; + block->dirty = 1; + + list_add_tail(&block->list, head); + + return wsize; +} + +static int _writefile(const void *buf, struct fat_internal *data, + uint64 fileoff, uint64 len) +{ + struct fat_file_block_t *block; + struct list_head *head; + uint32 foid; // first block id + uint32 coid; // current block id + uint32 cid; // target cluster id + uint64 bufoff, result; + int ret; + + block = NULL; + head = &data->file->list; + foid = fileoff / BLOCK_SIZE; + coid = 0; + cid = data->cid; + bufoff = 0; + result = 0; + + // Seek + + ret = _writefile_seek_cache(data, foid, &block); + + if (ret < 0) { + ret = _writefile_seek_fat32(data, foid, cid, &block); + } + + if (ret < 0) { + return 0; + } + + // if (block->oid != foid) error! + + // Write + + while (len) { + uint64 bckoff; + + bckoff = (fileoff + result) % BLOCK_SIZE; + + if (&block->list != head) { + ret = _writefile_cache(data, bckoff, buf, bufoff, len, block); + + cid = block->cid; + block = list_first_entry(&block->list, + struct fat_file_block_t, list); + } else { + // Read block from sdcard, create cache, then write it + cid = get_next_cluster(data->fat->fat_lba, cid); + + ret = _writefile_fat32(data, bckoff, buf, bufoff, len, coid, cid); + } + + if (ret < 0) { + break; + } + + bufoff += ret; + result += ret; + coid += 1; + len -= ret; + } + + return result; +} + +static int fat32fs_write(struct file *file, const void *buf, size_t len) +{ + struct fat_internal *data; + int filesize; + int ret; + + if (fat32fs_isdir(file->vnode)) { // is dir --> return 1 + return -1; + } + + if (!len) { + return len; + } + + filesize = fat32fs_getsize(file->vnode); + + data = file->vnode->internal; + + ret = _writefile(buf, data, file->f_pos, len); + + if (ret <= 0) { + return ret; + } + + file->f_pos += ret; + + if (file->f_pos > filesize) { + data->file->size = file->f_pos; + } + + return ret; +} + +static int _readfile_seek_cache(struct fat_internal *data, uint32 foid, + struct fat_file_block_t **block) +{ + struct fat_file_block_t *entry; + struct list_head *head; + + head = &data->file->list; + + if (list_empty(head)) { + return -1; + } + + list_for_each_entry(entry, head, list) { + *block = entry; + + if (foid == entry->oid) { + return 0; + } + } + + return -1; +} + +static int _readfile_seek_fat32(struct fat_internal *data, + uint32 foid, uint32 fcid, + struct fat_file_block_t **block) +{ + struct fat_info_t *info; + uint32 curoid, curcid; + + info = data->fat; + + if (*block) { + curoid = (*block)->oid; + curcid = (*block)->cid; + + if (curoid == foid) { + return 0; + } + + curoid++; + curcid = get_next_cluster(info->fat_lba, curcid); + + if (invalid_cid(curcid)) { + return -1; + } + } else { + curoid = 0; + curcid = fcid; + } + + while (1) { + struct fat_file_block_t *newblock; + + newblock = kmalloc(sizeof(struct fat_file_block_t)); + + newblock->oid = curoid; + newblock->cid = curcid; + newblock->read = 0; + newblock->dirty = 0; + + list_add_tail(&newblock->list, &data->file->list); + + *block = newblock; + + if (curoid == foid) { + return 0; + } + + curoid++; + curcid = get_next_cluster(info->fat_lba, curcid); + + if (invalid_cid(curcid)) { + return -1; + } + } +} + +static int _readfile_cache(struct fat_internal *data, uint64 bckoff, + uint8 *buf, uint64 bufoff, uint32 size, + struct fat_file_block_t *block) +{ + int rsize; + + if (!block->read) { + // read the data from sdcard + struct fat_info_t *info; + int lba; + + info = data->fat; + lba = info->cluster_lba + + (block->cid - 2) * info->bs.sector_per_cluster; + + sd_readblock(lba, block->buf); + + block->read = 1; + } + + rsize = size > BLOCK_SIZE - bckoff ? BLOCK_SIZE - bckoff : size; + + memncpy((void *)&buf[bufoff], (void *)&block->buf[bckoff], rsize); + + return rsize; +} + +static int _readfile_fat32(struct fat_internal *data, uint64 bckoff, + uint8 *buf, uint32 bufoff, uint32 size, + uint32 oid, uint32 cid) +{ + struct list_head *head; + struct fat_info_t *info; + struct fat_file_block_t *block; + int lba; + int rsize; + + head = &data->file->list; + info = data->fat; + + block = kmalloc(sizeof(struct fat_file_block_t)); + + rsize = size > BLOCK_SIZE - bckoff ? BLOCK_SIZE - bckoff : size; + lba = info->cluster_lba + (cid - 2) * info->bs.sector_per_cluster; + + sd_readblock(lba, block->buf); + + memncpy((void *)&buf[bufoff], (void *)&block->buf[bckoff], rsize); + + block->oid = oid; + block->cid = cid; + block->read = 1; + block->dirty = 0; + + list_add_tail(&block->list, head); + + return rsize; +} + +static int _readfile(void *buf, struct fat_internal *data, + uint64 fileoff, uint64 len) +{ + struct fat_file_block_t *block; + struct list_head *head; + uint32 foid; // first block id + uint32 coid; // current block id + uint32 cid; // target cluster id + uint64 bufoff, result; + int ret; + + block = NULL; + head = &data->file->list; + foid = fileoff / BLOCK_SIZE; + coid = 0; + cid = data->cid; + bufoff = 0; + result = 0; + + // Seek + + ret = _readfile_seek_cache(data, foid, &block); + + if (ret < 0) { + ret = _readfile_seek_fat32(data, foid, cid, &block); + } + + if (ret < 0) { + return 0; + } + + // if (block->oid != foid) error! + + // Start read + + while (len) { + uint64 bckoff; + + bckoff = (fileoff + result) % BLOCK_SIZE; + + if (&block->list != head) { + ret = _readfile_cache(data, bckoff, buf, bufoff, len, block); + + cid = block->cid; + block = list_first_entry(&block->list, + struct fat_file_block_t, list); + } else { + // Read block from sdcard, create cache + cid = get_next_cluster(data->fat->fat_lba, cid); + + if (invalid_cid(cid)) { + break; + } + + ret = _readfile_fat32(data, bckoff, buf, bufoff, len, coid, cid); + } + + if (ret < 0) { + break; + } + + bufoff += ret; + result += ret; + coid += 1; + len -= ret; + } + + return result; +} + +static int fat32fs_read(struct file *file, void *buf, size_t len) +{ + struct fat_internal *data; + int filesize; + int ret; + + if (fat32fs_isdir(file->vnode)) { + return -1; + } + + filesize = fat32fs_getsize(file->vnode); + + data = file->vnode->internal; + + if (file->f_pos + len > filesize) { + len = filesize - file->f_pos; + } + + if (!len) { + return len; + } + + ret = _readfile(buf, data, file->f_pos, len); + + if (ret <= 0) { + return ret; + } + + file->f_pos += ret; + + return ret; +} + +static int fat32fs_open(struct vnode *file_node, struct file *target) +{ + target->vnode = file_node; + target->f_pos = 0; + target->f_ops = file_node->f_ops; + + return 0; +} + +static int fat32fs_close(struct file *file) +{ + file->vnode = NULL; + file->f_pos = 0; + file->f_ops = NULL; + + return 0; +} + +static long fat32fs_lseek64(struct file *file, long offset, int whence) +{ + int filesize; + int base; + + if (!fat32fs_isdir(file->vnode)) { + return -1; + } + + filesize = fat32fs_getsize(file->vnode); + + if (filesize < 0) { + return -1; + } + + switch (whence) { + case SEEK_SET: + base = 0; + break; + case SEEK_CUR: + base = file->f_pos; + break; + case SEEK_END: + base = filesize; + break; + default: + return -1; + } + + if (base + offset > filesize) { + return -1; + } + + file->f_pos = base + offset; + + return 0; +} + +static int fat32fs_ioctl(struct file *file, uint64 request, va_list args) +{ + return -1; +} + +/* Others */ + +static uint32 get_next_cluster(uint32 fat_lba, uint32 cluster_id) +{ + struct cluster_entry_t *ce; + uint32 idx; + uint8 buf[BLOCK_SIZE]; + + if (invalid_cid(cluster_id)) { + return cluster_id; + } + + fat_lba += cluster_id / CLUSTER_ENTRY_PER_BLOCK; + idx = cluster_id % CLUSTER_ENTRY_PER_BLOCK; + + // TODO: Cache FAT + sd_readblock(fat_lba, buf); + + ce = &(((struct cluster_entry_t *)buf)[idx]); + + return ce->val; +} + +static uint32 alloc_cluster(struct fat_info_t *fat, uint32 prev_cid) +{ + struct cluster_entry_t *ce; + uint32 fat_lba; + uint32 cid; + int found; + uint8 buf[BLOCK_SIZE]; + + fat_lba = fat->fat_lba; // FAT location + cid = 0; + + while (fat_lba < fat->cluster_lba) { + found = 0; + + // TODO: Cache FAT + sd_readblock(fat_lba, buf); + + for (int i = 0; i < CLUSTER_ENTRY_PER_BLOCK; ++i) { + ce = &(((struct cluster_entry_t *)buf)[i]); + + if (!ce->val) { + found = 1; + break; + } + + ++cid; + } + + if (found) { + break; + } + + fat_lba += 1; + } + + if (found && prev_cid) { + uint32 target_lba; + uint32 target_idx; + + target_lba = fat_lba + prev_cid / CLUSTER_ENTRY_PER_BLOCK; + target_idx = prev_cid % CLUSTER_ENTRY_PER_BLOCK; + + // TODO: Cache FAT + sd_readblock(target_lba, buf); + + ce = &(((struct cluster_entry_t *)buf)[target_idx]); + + ce->val = cid; + + sd_writeblock(target_lba, buf); + } + + if (!found) { + panic("fat32 alloc_cluster: No space!"); + return -1; + } + + return cid; +} + +static int invalid_cid(uint32 cid) +{ + if (cid >= INVALID_CID) { + return 1; + } + + return 0; +} + +struct filesystem *fat32fs_init(void) +{ + INIT_LIST_HEAD(&mounts); + + return &fat32fs; +} \ No newline at end of file diff --git a/lab8/src/kernel/fs/framebufferfs.c b/lab8/src/kernel/fs/framebufferfs.c new file mode 100644 index 000000000..0a245c6c8 --- /dev/null +++ b/lab8/src/kernel/fs/framebufferfs.c @@ -0,0 +1,337 @@ +#include +#include +#include +#include +#include + +static uint32 __attribute__((aligned(0x10))) mbox[36]; + +struct fb_info { + uint32 width; + uint32 height; + uint32 pitch; + uint32 isrgb; +}; + +struct fbfs_internal { + const char *name; + struct vnode oldnode; + /* raw frame buffer address */ + uint8 *lfb; + uint32 lfbsize; + int isopened; + int isinit; +}; + +static int fbfs_mount(struct filesystem *fs, struct mount *mount); +static int fbfs_sync(struct filesystem *fs); + +static struct filesystem fbfs = { + .name = "framebufferfs", + .mount = fbfs_mount, + .sync = fbfs_sync +}; + +static int fbfs_lookup(struct vnode *dir_node, struct vnode **target, + const char *component_name); +static int fbfs_create(struct vnode *dir_node, struct vnode **target, + const char *component_name); +static int fbfs_mkdir(struct vnode *dir_node, struct vnode **target, + const char *component_name); +static int fbfs_isdir(struct vnode *dir_node); +static int fbfs_getname(struct vnode *dir_node, const char **name); +static int fbfs_getsize(struct vnode *dir_node); + +static struct vnode_operations fbfs_v_ops = { + .lookup = fbfs_lookup, + .create = fbfs_create, + .mkdir = fbfs_mkdir, + .isdir = fbfs_isdir, + .getname = fbfs_getname, + .getsize = fbfs_getsize +}; + +static int fbfs_write(struct file *file, const void *buf, size_t len); +static int fbfs_read(struct file *file, void *buf, size_t len); +static int fbfs_open(struct vnode *file_node, struct file *target); +static int fbfs_close(struct file *file); +static long fbfs_lseek64(struct file *file, long offset, int whence); +static int fbfs_ioctl(struct file *file, uint64 request, va_list args); + +static struct file_operations fbfs_f_ops = { + .write = fbfs_write, + .read = fbfs_read, + .open = fbfs_open, + .close = fbfs_close, + .lseek64 = fbfs_lseek64, + .ioctl = fbfs_ioctl +}; + +/* filesystem methods */ + +static int fbfs_mount(struct filesystem *fs, struct mount *mount) +{ + struct vnode *oldnode; + struct fbfs_internal *internal; + const char *name; + + internal = kmalloc(sizeof(struct fbfs_internal)); + + oldnode = mount->root; + + oldnode->v_ops->getname(oldnode, &name); + + internal->name = name; + internal->oldnode.mount = oldnode->mount; + internal->oldnode.v_ops = oldnode->v_ops; + internal->oldnode.f_ops = oldnode->f_ops; + internal->oldnode.parent = oldnode->parent; + internal->oldnode.internal = oldnode->internal; + internal->lfb = NULL; + internal->isopened = 0; + internal->isinit = 0; + + oldnode->mount = mount; + oldnode->v_ops = &fbfs_v_ops; + oldnode->f_ops = &fbfs_f_ops; + oldnode->internal = internal; + + return 0; +} + +static int fbfs_sync(struct filesystem *fs) +{ + return 0; +} + +/* vnode_operations methods */ + +static int fbfs_lookup(struct vnode *dir_node, struct vnode **target, + const char *component_name) +{ + return -1; +} + +static int fbfs_create(struct vnode *dir_node, struct vnode **target, + const char *component_name) +{ + return -1; +} + +static int fbfs_mkdir(struct vnode *dir_node, struct vnode **target, + const char *component_name) +{ + return -1; +} + +static int fbfs_isdir(struct vnode *dir_node) +{ + return 0; +} + +static int fbfs_getname(struct vnode *dir_node, const char **name) +{ + struct fbfs_internal *internal; + + internal = dir_node->internal; + + *name = internal->name; + + return 0; +} + +static int fbfs_getsize(struct vnode *dir_node) +{ + return -1; +} + +/* file_operations methods */ + +static int fbfs_write(struct file *file, const void *buf, size_t len) +{ + struct fbfs_internal *internal; + + internal = file->vnode->internal; + + if (!internal->isinit) { + return -1; + } + + if (file->f_pos + len > internal->lfbsize) { + return -1; + } + + memncpy((void *)(internal->lfb + file->f_pos), buf, len); + + file->f_pos += len; + + return len; +} + +static int fbfs_read(struct file *file, void *buf, size_t len) +{ + return -1; +} + +static int fbfs_open(struct vnode *file_node, struct file *target) +{ + struct fbfs_internal *internal; + + preempt_disable(); + + internal = file_node->internal; + + if (internal->isopened) { + preempt_enable(); + + return -1; + } + + internal->isopened = 1; + + preempt_enable(); + + target->vnode = file_node; + target->f_pos = 0; + target->f_ops = file_node->f_ops; + + return 0; +} + +static int fbfs_close(struct file *file) +{ + struct fbfs_internal *internal; + + internal = file->vnode->internal; + + file->vnode = NULL; + file->f_pos = 0; + file->f_ops = NULL; + + internal->isopened = 0; + + return 0; +} + +static long fbfs_lseek64(struct file *file, long offset, int whence) +{ + struct fbfs_internal *internal; + int base; + + internal = file->vnode->internal; + + switch (whence) { + case SEEK_SET: + base = 0; + break; + case SEEK_CUR: + base = file->f_pos; + break; + case SEEK_END: + base = internal->lfbsize; + default: + return -1; + } + + if (base + offset > internal->lfbsize) { + return -1; + } + + file->f_pos = base + offset; + + return 0; +} + +static int fbfs_ioctl(struct file *file, uint64 request, va_list args) +{ + struct fb_info *user_fb_info; + struct fbfs_internal *internal; + /* dimensions and channel order */ + uint32 width, height, pitch, isrgb; + + if (request != 0) { + return -1; + } + + internal = file->vnode->internal; + + mbox[0] = 35 * 4; + mbox[1] = MBOX_REQUEST_CODE; + + mbox[2] = 0x48003; // set phy wh + mbox[3] = 8; + mbox[4] = 8; + mbox[5] = 1024; // FrameBufferInfo.width + mbox[6] = 768; // FrameBufferInfo.height + + mbox[7] = 0x48004; // set virt wh + mbox[8] = 8; + mbox[9] = 8; + mbox[10] = 1024; // FrameBufferInfo.virtual_width + mbox[11] = 768; // FrameBufferInfo.virtual_height + + mbox[12] = 0x48009; // set virt offset + mbox[13] = 8; + mbox[14] = 8; + mbox[15] = 0; // FrameBufferInfo.x_offset + mbox[16] = 0; // FrameBufferInfo.y.offset + + mbox[17] = 0x48005; // set depth + mbox[18] = 4; + mbox[19] = 4; + mbox[20] = 32; // FrameBufferInfo.depth + + mbox[21] = 0x48006; // set pixel order + mbox[22] = 4; + mbox[23] = 4; + mbox[24] = 1; // RGB, not BGR preferably + + mbox[25] = 0x40001; // get framebuffer, gets alignment on request + mbox[26] = 8; + mbox[27] = 8; + mbox[28] = 4096; // FrameBufferInfo.pointer + mbox[29] = 0; // FrameBufferInfo.size + + mbox[30] = 0x40008; // get pitch + mbox[31] = 4; + mbox[32] = 4; + mbox[33] = 0; // FrameBufferInfo.pitch + + mbox[34] = MBOX_END_TAG; + + // this might not return exactly what we asked for, could be + // the closest supported resolution instead + + mailbox_call(MAILBOX_CH_PROP, mbox); + + if (mbox[20] == 32 && mbox[28] != 0) { + mbox[28] &= 0x3FFFFFFF; // convert GPU address to ARM address + width = mbox[5]; // get actual physical width + height = mbox[6]; // get actual physical height + pitch = mbox[33]; // get number of bytes per line + isrgb = mbox[24]; // get the actual channel order + internal->lfb = (void *)PA2VA(mbox[28]); + internal->lfbsize = mbox[29]; + } else { + // Unable to set screen resolution to 1024x768x32 + return -1; + } + + user_fb_info = va_arg(args, void *); + + user_fb_info->width = width; + user_fb_info->height = height; + user_fb_info->pitch = pitch; + user_fb_info->isrgb = isrgb; + + internal->isinit = 1; + + return 0; +} + +/* Others */ + +struct filesystem *framebufferfs_init(void) +{ + return &fbfs; +} \ No newline at end of file diff --git a/lab8/src/kernel/fs/fsinit.c b/lab8/src/kernel/fs/fsinit.c new file mode 100644 index 000000000..3cec57085 --- /dev/null +++ b/lab8/src/kernel/fs/fsinit.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include + +void fs_init(void) +{ + struct filesystem *tmpfs, *cpiofs, *uartfs, *fbfs, *fat32fs; + + vfs_init(); + sd_init(); + + tmpfs = tmpfs_init(); + cpiofs = cpiofs_init(); + uartfs = uartfs_init(); + fbfs = framebufferfs_init(); + fat32fs = fat32fs_init(); + register_filesystem(tmpfs); + register_filesystem(cpiofs); + register_filesystem(uartfs); + register_filesystem(fbfs); + register_filesystem(fat32fs); + + vfs_init_rootmount(tmpfs); + + vfs_mkdir("/initramfs"); + vfs_mount("/initramfs", "cpiofs"); + + vfs_mkdir("/dev"); + + vfs_mkdir("/dev/uart"); + vfs_mount("/dev/uart", "uartfs"); + + vfs_mkdir("/dev/framebuffer"); + vfs_mount("/dev/framebuffer", "framebufferfs"); + + vfs_mkdir("/boot"); + vfs_mount("/boot", "fat32fs"); +} \ No newline at end of file diff --git a/lab8/src/kernel/fs/tmpfs.c b/lab8/src/kernel/fs/tmpfs.c new file mode 100644 index 000000000..2619b0c70 --- /dev/null +++ b/lab8/src/kernel/fs/tmpfs.c @@ -0,0 +1,477 @@ +#include +#include +#include +#include + +#define TMPFS_FILE_MAXSIZE PAGE_SIZE + +struct tmpfs_file_t { + char *data; + int size; + int capacity; +}; + +#define TMPFS_DIR_MAXSIZE 0x10 + +struct tmpfs_dir_t { + int size; + struct vnode *entries[TMPFS_DIR_MAXSIZE]; +}; + +#define TMPFS_TYPE_UNDEFINE 0x0 +#define TMPFS_TYPE_FILE 0x1 +#define TMPFS_TYPE_DIR 0x2 + +#define TMPFS_NAME_MAXLEN 0x10 + +struct tmpfs_internal { + char name[TMPFS_NAME_MAXLEN]; + int type; + union { + struct tmpfs_file_t *file; + struct tmpfs_dir_t *dir; + }; + struct vnode *oldnode; +}; + +static int tmpfs_mount(struct filesystem *fs, struct mount *mount); +static int tmpfs_alloc_vnode(struct filesystem *fs, struct vnode **target); +static int tmpfs_sync(struct filesystem *fs); + +static struct filesystem tmpfs = { + .name = "tmpfs", + .mount = tmpfs_mount, + .alloc_vnode = tmpfs_alloc_vnode, + .sync = tmpfs_sync +}; + +static int tmpfs_lookup(struct vnode *dir_node, struct vnode **target, + const char *component_name); +static int tmpfs_create(struct vnode *dir_node, struct vnode **target, + const char *component_name); +static int tmpfs_mkdir(struct vnode *dir_node, struct vnode **target, + const char *component_name); +static int tmpfs_isdir(struct vnode *dir_node); +static int tmpfs_getname(struct vnode *dir_node, const char **name); +static int tmpfs_getsize(struct vnode *dir_node); + +static struct vnode_operations tmpfs_v_ops = { + .lookup = tmpfs_lookup, + .create = tmpfs_create, + .mkdir = tmpfs_mkdir, + .isdir = tmpfs_isdir, + .getname = tmpfs_getname, + .getsize = tmpfs_getsize +}; + +static int tmpfs_write(struct file *file, const void *buf, size_t len); +static int tmpfs_read(struct file *file, void *buf, size_t len); +static int tmpfs_open(struct vnode *file_node, struct file *target); +static int tmpfs_close(struct file *file); +static long tmpfs_lseek64(struct file *file, long offset, int whence); +static int tmpfs_ioctl(struct file *file, uint64 request, va_list args); + +static struct file_operations tmpfs_f_ops = { + .write = tmpfs_write, + .read = tmpfs_read, + .open = tmpfs_open, + .close = tmpfs_close, + .lseek64 = tmpfs_lseek64, + .ioctl = tmpfs_ioctl +}; + +/* filesystem methods */ + +static int tmpfs_mount(struct filesystem *fs, struct mount *mount) +{ + struct vnode *node, *oldnode; + struct tmpfs_internal *internal; + struct tmpfs_dir_t *dir; + const char *name; + + oldnode = mount->root; + + oldnode->v_ops->getname(oldnode, &name); + + if (strlen(name) >= TMPFS_NAME_MAXLEN) { + return -1; + } + + node = kmalloc(sizeof(struct vnode)); + internal = kmalloc(sizeof(struct tmpfs_internal)); + dir = kmalloc(sizeof(struct tmpfs_dir_t)); + + dir->size = 0; + + node->mount = oldnode->mount; + node->v_ops = oldnode->v_ops; + node->f_ops = oldnode->f_ops; + node->internal = oldnode->internal; + + strcpy(internal->name, name); + internal->type = TMPFS_TYPE_DIR; + internal->dir = dir; + internal->oldnode = node; + + oldnode->mount = mount; + oldnode->v_ops = &tmpfs_v_ops; + oldnode->f_ops = &tmpfs_f_ops; + oldnode->internal = internal; + + return 0; +} + +static int tmpfs_alloc_vnode(struct filesystem *fs, struct vnode **target) +{ + struct vnode *node; + struct tmpfs_internal *internal; + struct tmpfs_dir_t *dir; + + node = kmalloc(sizeof(struct vnode)); + internal = kmalloc(sizeof(struct tmpfs_internal)); + dir = kmalloc(sizeof(struct tmpfs_dir_t)); + + dir->size = 0; + + internal->name[0] = '\0'; + internal->type = TMPFS_TYPE_DIR; + internal->dir = dir; + internal->oldnode = NULL; + + node->mount = NULL; + node->v_ops = &tmpfs_v_ops; + node->f_ops = &tmpfs_f_ops; + node->internal = internal; + + *target = node; + + return 0; +} + +static int tmpfs_sync(struct filesystem *fs) +{ + return 0; +} + +/* vnode_operations methods */ + +static int tmpfs_lookup(struct vnode *dir_node, struct vnode **target, + const char *component_name) +{ + struct tmpfs_internal *internal; + struct tmpfs_dir_t *dir; + int i; + + internal = dir_node->internal; + + if (internal->type != TMPFS_TYPE_DIR) { + return -1; + } + + dir = internal->dir; + + for (i = 0; i < dir->size ; ++i) { + struct vnode *node; + const char *name; + int ret; + + node = dir->entries[i]; + + ret = node->v_ops->getname(node, &name); + + if (ret < 0) { + continue; + } + + if (!strcmp(name, component_name)) { + break; + } + } + + if (i >= dir->size) { + return -1; + } + + *target = dir->entries[i]; + + return 0; +} + +static int tmpfs_create(struct vnode *dir_node, struct vnode **target, + const char *component_name) +{ + struct tmpfs_internal *internal, *newint; + struct tmpfs_file_t *file; + struct tmpfs_dir_t *dir; + struct vnode *node; + int ret; + + if (strlen(component_name) >= 0x10) { + return -1; + } + + internal = dir_node->internal; + + if (internal->type != TMPFS_TYPE_DIR) { + return -1; + } + + dir = internal->dir; + + if (dir->size >= TMPFS_DIR_MAXSIZE) { + return -1; + } + + ret = tmpfs_lookup(dir_node, &node, component_name); + + if (!ret) { + return -1; + } + + node = kmalloc(sizeof(struct vnode)); + newint = kmalloc(sizeof(struct tmpfs_internal)); + file = kmalloc(sizeof(struct tmpfs_file_t)); + + file->data = kmalloc(TMPFS_FILE_MAXSIZE); + file->size = 0; + file->capacity = TMPFS_FILE_MAXSIZE; + + strcpy(newint->name, component_name); + newint->type = TMPFS_TYPE_FILE; + newint->file = file; + newint->oldnode = NULL; + + node->mount = dir_node->mount; + node->v_ops = &tmpfs_v_ops; + node->f_ops = &tmpfs_f_ops; + node->parent = dir_node; + node->internal = newint; + + dir->entries[dir->size] = node; + dir->size++; + + *target = node; + + return 0; +} + +static int tmpfs_mkdir(struct vnode *dir_node, struct vnode **target, + const char *component_name) +{ + struct tmpfs_internal *internal, *newint; + struct tmpfs_dir_t *dir, *newdir; + struct vnode *node; + int ret; + + if (strlen(component_name) >= 0x10) { + return -1; + } + + internal = dir_node->internal; + + if (internal->type != TMPFS_TYPE_DIR) { + return -1; + } + + dir = internal->dir; + + if (dir->size >= TMPFS_DIR_MAXSIZE) { + return -1; + } + + ret = tmpfs_lookup(dir_node, &node, component_name); + + if (!ret) { + return -1; + } + + node = kmalloc(sizeof(struct vnode)); + newint = kmalloc(sizeof(struct tmpfs_internal)); + newdir = kmalloc(sizeof(struct tmpfs_dir_t)); + + newdir->size = 0; + + strcpy(newint->name, component_name); + newint->type = TMPFS_TYPE_DIR; + newint->dir = newdir; + newint->oldnode = NULL; + + node->mount = dir_node->mount; + node->v_ops = &tmpfs_v_ops; + node->f_ops = &tmpfs_f_ops; + node->parent = dir_node; + node->internal = newint; + + dir->entries[dir->size] = node; + dir->size++; + + *target = node; + + return 0; +} + +static int tmpfs_isdir(struct vnode *dir_node) +{ + struct tmpfs_internal *internal; + + internal = dir_node->internal; + + if (internal->type != TMPFS_TYPE_DIR) { + return 0; + } + + return 1; +} + +static int tmpfs_getname(struct vnode *dir_node, const char **name) +{ + struct tmpfs_internal *internal; + + internal = dir_node->internal; + + *name = internal->name; + + return 0; +} + +static int tmpfs_getsize(struct vnode *dir_node) +{ + struct tmpfs_internal *internal; + + internal = dir_node->internal; + + if (internal->type != TMPFS_TYPE_FILE) { + return -1; + } + + return internal->file->size; +} + +/* file_operations methods */ + +static int tmpfs_write(struct file *file, const void *buf, size_t len) +{ + struct tmpfs_internal *internal; + struct tmpfs_file_t *f; + + internal = file->vnode->internal; + + if (internal->type != TMPFS_TYPE_FILE) { + return -1; + } + + f = internal->file; + + if (len > f->capacity - file->f_pos) { + len = f->capacity - file->f_pos; + } + + if (!len) { + return 0; + } + + memncpy(&f->data[file->f_pos], buf, len); + + file->f_pos += len; + + if (file->f_pos > f->size) { + f->size = file->f_pos; + } + + return len; +} + +static int tmpfs_read(struct file *file, void *buf, size_t len) +{ + struct tmpfs_internal *internal; + struct tmpfs_file_t *f; + + internal = file->vnode->internal; + + if (internal->type != TMPFS_TYPE_FILE) { + return -1; + } + + f = internal->file; + + if (len > f->size - file->f_pos) { + len = f->size - file->f_pos; + } + + if (!len) { + return 0; + } + + memncpy(buf, &f->data[file->f_pos], len); + + file->f_pos += len; + + return len; +} + +static int tmpfs_open(struct vnode *file_node, struct file *target) +{ + // TODO: Verify file access permission + + target->vnode = file_node; + target->f_pos = 0; + target->f_ops = file_node->f_ops; + + return 0; +} + +static int tmpfs_close(struct file *file) +{ + file->vnode = NULL; + file->f_pos = 0; + file->f_ops = NULL; + + return 0; +} + +static long tmpfs_lseek64(struct file *file, long offset, int whence) +{ + int filesize; + int base; + + filesize = file->vnode->v_ops->getsize(file->vnode); + + if (filesize < 0) { + return -1; + } + + switch (whence) { + case SEEK_SET: + base = 0; + break; + case SEEK_CUR: + base = file->f_pos; + break; + case SEEK_END: + base = filesize; + break; + default: + return -1; + } + + if (base + offset > filesize) { + // TODO: Create a gap (a "hole") + return -1; + } + + file->f_pos = base + offset; + + return 0; +} + +static int tmpfs_ioctl(struct file *file, uint64 request, va_list args) +{ + return -1; +} + +/* Others */ + +struct filesystem *tmpfs_init(void) +{ + return &tmpfs; +} \ No newline at end of file diff --git a/lab8/src/kernel/fs/uartfs.c b/lab8/src/kernel/fs/uartfs.c new file mode 100644 index 000000000..533451d87 --- /dev/null +++ b/lab8/src/kernel/fs/uartfs.c @@ -0,0 +1,178 @@ +#include +#include +#include + +struct uartfs_internal { + const char *name; + struct vnode oldnode; +}; + +static int uartfs_mount(struct filesystem *fs, struct mount *mount); +static int uartfs_sync(struct filesystem *fs); + +static struct filesystem uartfs = { + .name = "uartfs", + .mount = uartfs_mount, + .sync = uartfs_sync +}; + +static int uartfs_lookup(struct vnode *dir_node, struct vnode **target, + const char *component_name); +static int uartfs_create(struct vnode *dir_node, struct vnode **target, + const char *component_name); +static int uartfs_mkdir(struct vnode *dir_node, struct vnode **target, + const char *component_name); +static int uartfs_isdir(struct vnode *dir_node); +static int uartfs_getname(struct vnode *dir_node, const char **name); +static int uartfs_getsize(struct vnode *dir_node); + +static struct vnode_operations uartfs_v_ops = { + .lookup = uartfs_lookup, + .create = uartfs_create, + .mkdir = uartfs_mkdir, + .isdir = uartfs_isdir, + .getname = uartfs_getname, + .getsize = uartfs_getsize +}; + +static int uartfs_write(struct file *file, const void *buf, size_t len); +static int uartfs_read(struct file *file, void *buf, size_t len); +static int uartfs_open(struct vnode *file_node, struct file *target); +static int uartfs_close(struct file *file); +static long uartfs_lseek64(struct file *file, long offset, int whence); +static int uartfs_ioctl(struct file *file, uint64 request, va_list args); + +static struct file_operations uartfs_f_ops = { + .write = uartfs_write, + .read = uartfs_read, + .open = uartfs_open, + .close = uartfs_close, + .lseek64 = uartfs_lseek64, + .ioctl = uartfs_ioctl +}; + +/* filesystem methods */ + +static int uartfs_mount(struct filesystem *fs, struct mount *mount) +{ + struct vnode *oldnode; + struct uartfs_internal *internal; + const char *name; + + internal = kmalloc(sizeof(struct uartfs_internal)); + + oldnode = mount->root; + + oldnode->v_ops->getname(oldnode, &name); + + internal->name = name; + internal->oldnode.mount = oldnode->mount; + internal->oldnode.v_ops = oldnode->v_ops; + internal->oldnode.f_ops = oldnode->f_ops; + internal->oldnode.parent = oldnode->parent; + internal->oldnode.internal = oldnode->internal; + + oldnode->mount = mount; + oldnode->v_ops = &uartfs_v_ops; + oldnode->f_ops = &uartfs_f_ops; + oldnode->internal = internal; + + return 0; +} + +static int uartfs_sync(struct filesystem *fs) +{ + return 0; +} + +/* vnode_operations methods */ + +static int uartfs_lookup(struct vnode *dir_node, struct vnode **target, + const char *component_name) +{ + return -1; +} + +static int uartfs_create(struct vnode *dir_node, struct vnode **target, + const char *component_name) +{ + return -1; +} + +static int uartfs_mkdir(struct vnode *dir_node, struct vnode **target, + const char *component_name) +{ + return -1; +} + +static int uartfs_isdir(struct vnode *dir_node) +{ + return 0; +} + +static int uartfs_getname(struct vnode *dir_node, const char **name) +{ + struct uartfs_internal *internal; + + internal = dir_node->internal; + + *name = internal->name; + + return 0; +} + +static int uartfs_getsize(struct vnode *dir_node) +{ + return -1; +} + +/* file_operations methods */ + +static int uartfs_write(struct file *file, const void *buf, size_t len) +{ + uart_sendn(buf, len); + + return len; +} + +static int uartfs_read(struct file *file, void *buf, size_t len) +{ + uart_recvn(buf, len); + + return len; +} + +static int uartfs_open(struct vnode *file_node, struct file *target) +{ + target->vnode = file_node; + target->f_pos = 0; + target->f_ops = file_node->f_ops; + + return 0; +} + +static int uartfs_close(struct file *file) +{ + file->vnode = NULL; + file->f_pos = 0; + file->f_ops = NULL; + + return 0; +} + +static long uartfs_lseek64(struct file *file, long offset, int whence) +{ + return -1; +} + +static int uartfs_ioctl(struct file *file, uint64 request, va_list args) +{ + return -1; +} + +/* Others */ + +struct filesystem *uartfs_init(void) +{ + return &uartfs; +} \ No newline at end of file diff --git a/lab8/src/kernel/fs/vfs.c b/lab8/src/kernel/fs/vfs.c new file mode 100644 index 000000000..e8115d5c2 --- /dev/null +++ b/lab8/src/kernel/fs/vfs.c @@ -0,0 +1,585 @@ +#include +#include +#include +#include +#include +#include +#include + +struct mount *rootmount; + +static struct list_head filesystems; + +/* + * Return directory vnode, and set @pathname to the last component name. + * If the @pathname is end with '/', set @pathname to NULL + * + * For example: + * + * If @pathname is "/abc/def/ghi". + * Return the vnode of "/abc/def", and set @pathname to "ghi". + * + * If @pathname is "/abc/def/". + * Return the vnode of "/abc/def", and set @pathname to NULL. + * + */ +static struct vnode *get_dir_vnode(struct vnode *dir_node, + const char **pathname) +{ + struct vnode *result; + const char *start; + const char *end; + char buf[0x100]; + + start = end = *pathname; + + if (*start == '/') { + result = rootmount->root; + } else { + result = dir_node; + } + + while (1) { + if (!strncmp("./", start, 2)) { + start += 2; + end = start; + continue; + } else if (!strncmp("../", start, 3)) { + if (result->parent) { + result = result->parent; + } + + start += 3; + end = start; + continue; + } + + // Find next component + while (*end != '\0' && *end != '/') { + end++; + } + + if (*end == '/') { + int ret; + + if (start == end) { + // Case like "//" + end++; + start = end; + continue; + } + + // TODO: Check if the length is less than 0x100 + memncpy(buf, start, end - start); + buf[end - start] = 0; + + ret = result->v_ops->lookup(result, &result, buf); + + if (ret < 0) { + return NULL; + } + + end++; + start = end; + } else { + break; + } + } + + *pathname = *start ? start : NULL; + + return result; +} + +static struct filesystem *find_filesystem(const char *filesystem) +{ + struct filesystem *fs; + + list_for_each_entry(fs, &filesystems, fs_list) { + if (!strcmp(fs->name, filesystem)) { + return fs; + } + } + + return NULL; +} + +void vfs_init(void) +{ + INIT_LIST_HEAD(&filesystems); +} + +void vfs_init_rootmount(struct filesystem *fs) +{ + struct vnode *n; + int ret; + + ret = fs->alloc_vnode(fs, &n); + if (ret < 0) { + panic("vfs_init_rootmount failed"); + } + + rootmount = kmalloc(sizeof(struct mount)); + + rootmount->root = n; + rootmount->fs = fs; + + n->mount = rootmount; + n->parent = NULL; +} + +int register_filesystem(struct filesystem *fs) +{ + list_add_tail(&fs->fs_list, &filesystems); + + return 0; +} + +int vfs_open(const char *pathname, int flags, struct file *target) +{ + const char *curname; + struct vnode *dir_node; + struct vnode *file_node; + int ret; + + curname = pathname; + dir_node = get_dir_vnode(current->work_dir, &curname); + + if (!dir_node) { + return -1; + } + + if (!curname) { + return -1; + } + + ret = dir_node->v_ops->lookup(dir_node, &file_node, curname); + + if (flags & O_CREAT) { + // TODO: Support overwrite a existed + + if (ret == 0) { + return -1; + } + + ret = dir_node->v_ops->create(dir_node, &file_node, curname); + } + + if (ret < 0) { + return ret; + } + + if (!file_node) { + return -1; + } + + ret = file_node->f_ops->open(file_node, target); + + if (ret < 0) { + return ret; + } + + target->flags = 0; + + return 0; +} + +int vfs_close(struct file *file) +{ + return file->f_ops->close(file); +} + +int vfs_write(struct file *file, const void *buf, size_t len) +{ + return file->f_ops->write(file, buf, len); +} + +int vfs_read(struct file *file, void *buf, size_t len) +{ + return file->f_ops->read(file, buf, len); +} + +long vfs_lseek64(struct file *file, long offset, int whence) +{ + return file->f_ops->lseek64(file, offset, whence); +} + +int vfs_ioctl(struct file *file, uint64 request, va_list args) +{ + return file->f_ops->ioctl(file, request, args); +} + +int vfs_mkdir(const char *pathname) +{ + const char *curname; + struct vnode *dir_node; + struct vnode *newdir_node; + int ret; + + curname = pathname; + + if (current) { + dir_node = get_dir_vnode(current->work_dir, &curname); + } else { + dir_node = get_dir_vnode(rootmount->root, &curname); + } + + if (!dir_node) { + return -1; + } + + if (!curname) { + return -1; + } + + ret = dir_node->v_ops->mkdir(dir_node, &newdir_node, curname); + + return ret; +} + +int vfs_mount(const char *mountpath, const char *filesystem) +{ + const char *curname; + struct vnode *dir_node; + struct filesystem *fs; + struct mount *mo; + int ret; + + curname = mountpath; + + if (current) { + dir_node = get_dir_vnode(current->work_dir, &curname); + } else { + dir_node = get_dir_vnode(rootmount->root, &curname); + } + + if (!dir_node) { + return -1; + } + + if (curname) { + // find return 0 + ret = dir_node->v_ops->lookup(dir_node, &dir_node, curname); + if (ret < 0) { + return ret; + } + } + + if (!dir_node->v_ops->isdir(dir_node)) { + return -1; + } + + fs = find_filesystem(filesystem); + + if (!fs) { + return -1; + } + + mo = kmalloc(sizeof(struct mount)); + + mo->root = dir_node; + mo->fs = fs; + + ret = fs->mount(fs, mo); + + if (ret < 0) { + kfree(mo); + return ret; + } + + return 0; +} + +int vfs_lookup(const char *pathname, struct vnode **target) +{ + const char *curname; + struct vnode *dir_node; + struct vnode *file_node; + int ret; + + curname = pathname; + dir_node = get_dir_vnode(current->work_dir, &curname); + + if (!dir_node) { + return -1; + } + + if (!curname) { + *target = dir_node; + + return 0; + } + + ret = dir_node->v_ops->lookup(dir_node, &file_node, curname); + + if (ret < 0) { + return ret; + } + + *target = file_node; + + return 0; +} + +int vfs_sync(struct filesystem *fs) +{ + return fs->sync(fs); +} + +static int do_open(const char *pathname, int flags) +{ + int i, ret; + + for (i = 0; i <= current->maxfd; ++i) { + if (current->fds[i].vnode == NULL) { + break; + } + } + + if (i > current->maxfd) { + if (current->maxfd >= TASK_MAX_FD) { + return -1; + } + + current->maxfd += 1; + i = current->maxfd; + } + + ret = vfs_open(pathname, flags, ¤t->fds[i]); + + if (ret < 0) { + current->fds[i].vnode = NULL; + + return ret; + } + + return i; +} + +static int do_close(int fd) +{ + int ret; + + if (fd < 0 || current->maxfd < fd) { + return -1; + } + + if (current->fds[fd].vnode == NULL) { + return -1; + } + + ret = vfs_close(¤t->fds[fd]); + + if (ret < 0) { + return ret; + } + + return 0; +} + +static int do_write(int fd, const void *buf, uint64 count) +{ + int ret; + + if (fd < 0 || current->maxfd < fd) { + return -1; + } + + if (current->fds[fd].vnode == NULL) { + return -1; + } + + ret = vfs_write(¤t->fds[fd], buf, count); + + return ret; +} + +static int do_read(int fd, void *buf, uint64 count) +{ + int ret; + + if (fd < 0 || current->maxfd < fd) { + return -1; + } + + if (current->fds[fd].vnode == NULL) { + return -1; + } + + ret = vfs_read(¤t->fds[fd], buf, count); + + return ret; +} + +static int do_mkdir(const char *pathname, uint32 mode) +{ + int ret; + + ret = vfs_mkdir(pathname); + + return ret; +} + +static int do_mount(const char *target, const char *filesystem) +{ + int ret; + + ret = vfs_mount(target, filesystem); + + return ret; +} + +static int do_chdir(const char *path) +{ + struct vnode *result; + int ret; + + ret = vfs_lookup(path, &result); + + if (ret < 0) { + return ret; + } + + if (!result->v_ops->isdir(result)) { + return -1; + } + + current->work_dir = result; + + return 0; +} + +static long do_lseek64(int fd, int64 offset, int whence) +{ + long ret; + + if (fd < 0 || current->maxfd < fd) { + return -1; + } + + if (current->fds[fd].vnode == NULL) { + return -1; + } + + ret = vfs_lseek64(¤t->fds[fd], offset, whence); + + return ret; +} + +static int do_ioctl(int fd, uint64 request, va_list args) +{ + int ret; + + if (fd < 0 || current->maxfd < fd) { + return -1; + } + + if (current->fds[fd].vnode == NULL) { + return -1; + } + + ret = vfs_ioctl(¤t->fds[fd], request, args); + + return ret; +} + +static int do_sync(void) +{ + struct filesystem *entry; + + list_for_each_entry(entry, &filesystems, fs_list) { + vfs_sync(entry); + } + + return 0; +} + +void syscall_open(trapframe *frame, const char *pathname, int flags) +{ + int fd = do_open(pathname, flags); + + frame->x0 = fd; + + uart_sync_printf("[open] (\"%s\", 0x%x) = %d\r\n", pathname, flags, fd); +} + +void syscall_close(trapframe *frame, int fd) +{ + int ret = do_close(fd); + + frame->x0 = ret; + + uart_sync_printf("[close] (%d) = %d\r\n", fd, ret); +} + +void syscall_write(trapframe *frame, int fd, const void *buf, uint64 count) +{ + int ret = do_write(fd, buf, count); + + frame->x0 = ret; + + uart_sync_printf("[write] (%d, \"%s\", 0x%x) = %d\r\n", fd, buf, count, ret); +} + +void syscall_read(trapframe *frame, int fd, void *buf, uint64 count) +{ + int ret = do_read(fd, buf, count); + + frame->x0 = ret; + + uart_sync_printf("[read] (%d, \"%s\", 0x%x) = %d\r\n", fd, buf, count, ret); +} + +void syscall_mkdir(trapframe *frame, const char *pathname, uint32 mode) +{ + int ret = do_mkdir(pathname, mode); + + frame->x0 = ret; +} + +void syscall_mount(trapframe *frame, const char *src, const char *target, + const char *filesystem, uint64 flags, const void *data) +{ + int ret = do_mount(target, filesystem); + + frame->x0 = ret; +} + +void syscall_chdir(trapframe *frame, const char *path) +{ + int ret = do_chdir(path); + + frame->x0 = ret; +} + +void syscall_lseek64(trapframe *frame, int fd, int64 offset, int whence) +{ + long ret = do_lseek64(fd, offset, whence); + + frame->x0 = ret; + + uart_sync_printf("[lseek64] (%d, 0x%x, 0x%x) = %d\r\n", fd, offset, whence, ret); +} + +void syscall_ioctl(trapframe *frame, int fd, uint64 request, ...) +{ + int ret; + va_list args; + + va_start(args, request); + + ret = do_ioctl(fd, request, args); + + va_end(args); + + frame->x0 = ret; +} + +void syscall_sync(trapframe *frame) +{ + int ret = do_sync(); + + frame->x0 = ret; + + uart_sync_printf("[sync] = %d\r\n", ret); +} \ No newline at end of file diff --git a/lab8/src/kernel/head.S b/lab8/src/kernel/head.S new file mode 100644 index 000000000..1deaeaa08 --- /dev/null +++ b/lab8/src/kernel/head.S @@ -0,0 +1,316 @@ +// Reference: https://github.com/s-matyukevich/raspberry-pi-os +.section ".text.boot" + +.globl _start +_start: + // Preserve flattened devicetree pointer + mov x19, x0 + + bl from_el2_to_el1 + // the next instruction runs in EL1 + + // Set booting stack + ldr x0, =_PA_stack_top + mov sp, x0 + + bl mmu_init + + // Use virtual address after mmu_init + ldr x0, =_va_trampoline + br x0 +_va_trampoline: + + bl set_exception_vector_table + + bl enable_core0_timer + + // Initialize bss + ldr x0, =_sbss + ldr x1, =_ebss + sub x1, x1, x0 + bl memzero + + // Initialize stack + ldr x0, =_stack_top + mov sp, x0 + // Pass flattened devicetree pointer + mov x0, x19 + bl start_kernel + + // Should never return +proc_hang: + b proc_hang + +from_el2_to_el1: + // EL1 uses aarch64 + mov x0, (1 << 31) + msr hcr_el2, x0 + // Disable interrupt ({D, A, I, F} = 1 (masked)) + // EL1h ({M[3:0]} = 5) + mov x0, 0x3c5 + msr spsr_el2, x0 + msr elr_el2, lr + // return to EL1 + eret + +set_exception_vector_table: + adr x0, exception_vector_table + msr vbar_el1, x0 + ret + +// 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 + +// save exception registers to stack +.macro save_exception_reg + sub sp, sp, 2 * 8 + mrs x0, elr_el1 + mrs x1, spsr_el1 + stp x0, x1, [sp, 0] +.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 + +// load exception registers from stack +.macro load_exception_reg + ldp x0, x1, [sp, 0] + msr elr_el1, x0 + msr spsr_el1, x1 + add sp, sp, 2 * 8 +.endm + +.macro kernel_entry el + sub sp, sp, 17 * 16 + stp x0, x1, [sp ,16 * 0] + stp x2, x3, [sp ,16 * 1] + stp x4, x5, [sp ,16 * 2] + stp x6, x7, [sp ,16 * 3] + stp x8, x9, [sp ,16 * 4] + stp x10, x11, [sp ,16 * 5] + stp x12, x13, [sp ,16 * 6] + stp x14, x15, [sp ,16 * 7] + stp x16, x17, [sp ,16 * 8] + stp x18, x19, [sp ,16 * 9] + stp x20, x21, [sp ,16 * 10] + stp x22, x23, [sp ,16 * 11] + stp x24, x25, [sp ,16 * 12] + stp x26, x27, [sp ,16 * 13] + stp x28, x29, [sp ,16 * 14] + + .if \el == 0 + mrs x0, sp_el\el + stp x30, x0, [sp, 16 * 15] + .else + str x30, [sp, 16 * 15] + .endif + + mrs x0, elr_el1 + mrs x1, spsr_el1 + stp x0, x1, [sp, 16 * 16] +.endm + +.macro kernel_exit el + ldp x0, x1, [sp, 16 * 16] + msr elr_el1, x0 + msr spsr_el1, x1 + + .if \el ==0 + ldp x30, x0, [sp, 16 * 15] + msr sp_el\el, x0 + .else + ldr x30, [sp, 16 * 15] + .endif + + ldp x28, x29, [sp ,16 * 14] + ldp x26, x27, [sp ,16 * 13] + ldp x24, x25, [sp ,16 * 12] + ldp x22, x23, [sp ,16 * 11] + ldp x20, x21, [sp ,16 * 10] + ldp x18, x19, [sp ,16 * 9] + ldp x16, x17, [sp ,16 * 8] + ldp x14, x15, [sp ,16 * 7] + ldp x12, x13, [sp ,16 * 6] + ldp x10, x11, [sp ,16 * 5] + ldp x8, x9, [sp ,16 * 4] + ldp x6, x7, [sp ,16 * 3] + ldp x4, x5, [sp ,16 * 2] + ldp x2, x3, [sp ,16 * 1] + ldp x0, x1, [sp ,16 * 0] + add sp, sp, 17 * 16 + + eret +.endm + +exception_handler: + // Do nothing + save_all + + mov x0, 0 + bl exception_default_handler + + load_all + eret + +l64_syn_eh: + kernel_entry 0 + + mov x0, sp + mrs x1, esr_el1 + bl el0_sync_handler + + mov x0, sp + bl exit_to_user_mode + + kernel_exit 0 + +l64_irq_eh: + kernel_entry 0 + + bl irq_handler + + mov x0, sp + bl exit_to_user_mode + + kernel_exit 0 + +curr_syn_eh: + save_all + + mov x0, 1 + bl exception_default_handler + + load_all + eret + +curr_irq_eh: + kernel_entry 1 + + bl irq_handler + + kernel_exit 1 + +curr_fiq_eh: + save_all + + mov x0, 2 + bl exception_default_handler + + load_all + eret + +curr_se_eh: + save_all + + mov x0, 3 + bl exception_default_handler + + load_all + eret + +.align 11 // vector table should be aligned to 0x800 +.global exception_vector_table +exception_vector_table: + // Exception from the current EL while using SP_EL0 + // Synchronous + b exception_handler + .align 7 + + // IRQ + b exception_handler + .align 7 + + // FIQ + b exception_handler + .align 7 + + // SError + b exception_handler + .align 7 + + // Exception from the current EL while using SP_ELx + // Synchronous + b curr_syn_eh + .align 7 + + // IRQ + b curr_irq_eh + .align 7 + + // FIQ + b curr_fiq_eh + .align 7 + + // SError + b curr_se_eh + .align 7 + + // Exception from a lower EL and at least one lower EL is AArch64 + // Synchronous + b l64_syn_eh + .align 7 + + // IRQ + b l64_irq_eh + .align 7 + + // FIQ + b exception_handler + .align 7 + + // SError + b exception_handler + .align 7 + + // Exception from a lower EL and all lower ELs are AArch32 + // Synchronous + b exception_handler + .align 7 + + // IRQ + b exception_handler + .align 7 + + // FIQ + b exception_handler + .align 7 + + // SError + b exception_handler + .align 7 \ No newline at end of file diff --git a/lab8/src/kernel/irq.c b/lab8/src/kernel/irq.c new file mode 100644 index 000000000..d72a4f463 --- /dev/null +++ b/lab8/src/kernel/irq.c @@ -0,0 +1,255 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IRQ_TASK_NUM 32 + +typedef struct { + /* cb(args) */ + void (*cb)(void *); + void *args; + /* Priority, the lowest priority is 0 */ + uint32 prio; + uint32 is_running; + /* Link to next priority */ + struct list_head np_list; + /* Link all tasks that is same priority */ + struct list_head sp_list; +} irq_task; + +irq_task irq_tasks[IRQ_TASK_NUM]; + +/* Metadata of irq_tasks + * This list links tasks with different priorities and is structured + * as shown below: + * @irq_tasks_meta <-> task (prio: 5) <-> task (prio: 2) <-> task (prio: 0) + * ^ ^ ^ + * | | | + * v v v + * task (prio: 5) task (prio: 2) task (prio: 0) + * + * If a task isn't in the irq_tasks_meta list, its np_list isn't used. + */ +struct list_head irq_tasks_meta; + +/* This variable has 32 bits, n-th bit stands for the status of irq_tasks[n]. + * If n-th bit is 1, it means irq_tasks[n] is available. + * If n-th bit is 0, it means irq_tasks[n] is unavailable. + */ +uint32 irq_tasks_status; + +uint32 irq_nested_layer; + +/* + * Interrupts must be disabled before calling this function. + */ +static irq_task *it_alloc() +{ + uint32 idx; + + idx = ffs(irq_tasks_status); + + if (idx == 0) { + return NULL; + } + + irq_tasks_status &= ~(1 << (idx - 1)); + + return &irq_tasks[idx - 1]; +} + +static void it_release(irq_task *it) +{ + if (!it) { + return; + } + + uint32 idx = get_elem_idx(it, irq_tasks); + + irq_tasks_status |= (1 << idx); +} + +static void it_remove(irq_task *it) +{ + if (!list_empty(&it->np_list)) { + if (!list_empty(&it->sp_list)) { + irq_task *prev_np = list_last_entry(&it->np_list, irq_task, np_list); + irq_task *next_sp = list_first_entry(&it->sp_list, irq_task, sp_list); + + list_del(&it->np_list); + list_add(&next_sp->np_list, &prev_np->np_list); + } else { + list_del(&it->np_list); + } + } + + list_del(&it->sp_list); + it_release(it); +} + +/* + * Interrupts must be disabled before calling this function. + * + * Return 1 if @it can preempt the currently running irq_task. + */ +static int it_insert(irq_task *it) +{ + irq_task *iter; + int preempt; + int inserted; + + // Insert irq_task + preempt = 1; + inserted = 0; + + list_for_each_entry(iter, &irq_tasks_meta, np_list) { + if (it->prio > iter->prio) { + list_add_tail(&it->np_list, &iter->np_list); + inserted = 1; + break; + } else if (it->prio == iter->prio) { + list_add_tail(&it->sp_list, &iter->sp_list); + preempt = 0; + inserted = 1; + break; + } + preempt = 0; + } + + if (!inserted) { + list_add_tail(&it->np_list, &irq_tasks_meta); + } + + return preempt; +} + +static irq_task *it_get_next_task_to_run() +{ + irq_task *it; + + if (list_empty(&irq_tasks_meta)) { + return NULL; + } + + it = list_first_entry(&irq_tasks_meta, irq_task, np_list); + + if (it->is_running) { + return NULL; + } + + return it; +} + +/* + * Run irq_tasks + */ +static inline void it_run() +{ + while (1) { + irq_task *it = it_get_next_task_to_run(); + + if (!it) { + break; + } + + it->is_running = 1; + + enable_interrupt(); + + (it->cb)(it->args); + + disable_interrupt(); + + it_remove(it); + } +} + +void irq_init() +{ + INIT_LIST_HEAD(&irq_tasks_meta); + irq_tasks_status = 0xffffffff; +} + +/* + * Interrupts must be disabled before calling this function. + */ +int irq_run_task(void (*task)(void *), + void *args, + void (*fini)(void), + uint32 prio) +{ + irq_task *it; + int preempt; + + it = it_alloc(); + + if (!it) { + return -1; + } + + it->cb = task; + it->args = args; + it->prio = prio; + it->is_running = 0; + INIT_LIST_HEAD(&it->np_list); + INIT_LIST_HEAD(&it->sp_list); + preempt = it_insert(it); + + if (preempt) { + it->is_running = 1; + + enable_interrupt(); + + (task)(args); + + disable_interrupt(); + + (fini)(); + + it_remove(it); + } + + it_run(); + + return 0; +} + +void irq_handler() +{ + irq_nested_layer++; + + // These check functions may add irq_task and run it. + if (!timer_irq_check()) {} + else if (!uart_irq_check()) {} + + irq_nested_layer--; + + // IRQ handling completed + + // Reschedule + if (irq_nested_layer || !current->need_resched || current->preempt) { + return; + } + + enable_interrupt(); + + schedule(); + + disable_interrupt(); +} + +void exception_default_handler(uint32 n) +{ + uart_printf("[exception] %d\r\n", n); +} + +void irq1_enable(int bit) +{ + put32(PA2VA(IRQ_ENABLE_1_REG), 1 << bit); +} \ No newline at end of file diff --git a/lab8/src/kernel/kthread.c b/lab8/src/kernel/kthread.c new file mode 100644 index 000000000..a13f4daa1 --- /dev/null +++ b/lab8/src/kernel/kthread.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include +#include + +static wait_queue_head *wait_queue; + +static void kthread_start(void) +{ + void (*main)(void); + + asm volatile("mov %0, x19\n" + "mov x19, xzr" + : "=r" (main)); + + main(); + + kthread_fini(); +} + +void kthread_add_wait_queue(task_struct *task) +{ + wq_add_task(task, wait_queue); +} + +/* + * Add to wait_queue to wait some process to recycle this kthread + */ +void kthread_fini(void) +{ + preempt_disable(); + + current->status = TASK_DEAD; + + sched_del_task(current); + + wq_add_task(current, wait_queue); + + preempt_enable(); + + schedule(); + + // Never reach +} + +void kthread_early_init(void) +{ + set_current(NULL); +} + +void kthread_init(void) +{ + task_struct *task; + + // Initialze current task + task = task_create(); + + // Must set current first + set_current(task); + + sched_add_task(task); + + // Create wait_queue + wait_queue = wq_create(); +} + +static inline void pt_regs_init(struct pt_regs *regs, void *main) +{ + regs->x19 = main; + regs->x20 = 0; + regs->x21 = 0; + regs->x22 = 0; + regs->x23 = 0; + regs->x24 = 0; + regs->x25 = 0; + regs->x26 = 0; + regs->x27 = 0; + regs->x28 = 0; + regs->fp = 0; + regs->lr = kthread_start; +} + +void kthread_create(void (*start)(void)) +{ + task_struct *task; + + task = task_create(); + + task->kernel_stack = kmalloc(STACK_SIZE); + task->regs.sp = (char *)task->kernel_stack + STACK_SIZE - 0x10; + pt_regs_init(&task->regs, start); + + sched_add_task(task); +} + +void kthread_kill_zombies(void) +{ + while (1) { + task_struct *task; + + if (wq_empty(wait_queue)) { + return; + } + + preempt_disable(); + + task = wq_get_first_task(wait_queue); + + wq_del_task(task); + + preempt_enable(); + + task_free(task); + } +} \ No newline at end of file diff --git a/lab8/src/kernel/linker.ld b/lab8/src/kernel/linker.ld new file mode 100644 index 000000000..e2dc7a44c --- /dev/null +++ b/lab8/src/kernel/linker.ld @@ -0,0 +1,46 @@ +_stack_top = 0xffff000000400000; +_PA_stack_top = 0x0000000000400000; +_early_mem_base = 0xffff000007000000; +_early_mem_end = 0xffff000007ffffff; + +SECTIONS +{ + . = 0xffff000000080000; + + .text.boot : { + *(.text.boot) + } + + .text : { + *(.text) + } + + . = ALIGN(0x1000); + + _stext_user_shared = .; + .text.user.shared : { + *(.text.user.shared) + } + + . = ALIGN(0x1000); + _etext_user_shared = .; + + .rodata : { + *(.rodata) + } + + .data : { + *(.got) + *(.got.plt) + *(.data*) + } + + _sbss = .; + .bss : { + *(.bss*) + } + _ebss = .; + + . = _stack_top; + _sstack = .; +} \ No newline at end of file diff --git a/lab8/src/kernel/main.c b/lab8/src/kernel/main.c new file mode 100644 index 000000000..e56a8a8e5 --- /dev/null +++ b/lab8/src/kernel/main.c @@ -0,0 +1,306 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFSIZE 0x100 + +static char shell_buf[BUFSIZE]; + +#define TEST_PTR_CNT 0x10 + +static uint8 test_ptrs_inused[TEST_PTR_CNT]; +static char *test_ptrs[TEST_PTR_CNT]; + +static void timeout_print(char *str) +{ + uart_printf("%s\r\n", str); + + kfree(str); +} + +static void foo(void) +{ + for (int i = 0; i < 10; ++i) { + uart_sync_printf("Thread id: %d %d\r\n", current->tid, i); + delay(1000000); + schedule(); + } +} + +static void cmd_alloc(char *ssize) +{ + int size, idx; + + size = atoi(ssize); + + if (size == 0) { + return; + } + + for (idx = 0; idx < TEST_PTR_CNT; ++idx) { + if (!test_ptrs_inused[idx]) { + break; + } + } + + if (idx == TEST_PTR_CNT) { + return; + } + + test_ptrs_inused[idx] = 1; + + test_ptrs[idx] = kmalloc(size); + + uart_printf("[*] ptrs[%d]: %llx\r\n", idx + 1, test_ptrs[idx]); +} + +static void cmd_free(char *sidx) +{ + int idx = atoi(sidx); + + if (idx == 0) { + return; + } + + idx -= 1; + + if (!test_ptrs_inused[idx]) { + return; + } + + test_ptrs_inused[idx] = 0; + + kfree(test_ptrs[idx]); +} + +static void cmd_help(void) +{ + uart_printf( + "alloc \t: " "test allocator" "\r\n" + "exec \t: " "execute file" "\r\n" + "free \t: " "test allocator" "\r\n" + "help\t: " "print this help menu" "\r\n" + "hello\t: " "print Hello World!" "\r\n" + "hwinfo\t: " "print hardware info" "\r\n" + "parsedtb\t: " "parse devicetree blob (dtb)" "\r\n" + "reboot\t: " "reboot the device" "\r\n" + "setTimeout \t: " + "print @msg after @sec seconds" "\r\n" + "sw_timer\t: " "turn on/off timer debug info" "\r\n" + "sw_uart_mode\t: " "use sync/async UART" "\r\n" + "thread_test\t: " "test kthread" "\r\n" + ); +} + +static void cmd_hello(void) +{ + uart_printf("Hello World!\r\n"); +} + +static void cmd_hwinfo(void) +{ + unsigned int rev; + struct arm_memory_info ami; + + // Board revision + rev = get_board_revision(); + uart_printf("[*] Revision: %x\r\n", rev); + + // ARM memory base address and size + get_arm_memory(&ami); + uart_printf("[*] ARM memory base address: %x\r\n", ami.baseaddr); + uart_printf("[*] ARM memory size: %d\r\n", ami.size); +} + +static void cmd_reboot(void) +{ + BCM2837_reset(10); +} + +static void cmd_setTimeout(char *msg, char *ssec) +{ + int len; + char *m; + + len = strlen(msg) + 1; + m = kmalloc(len); + + if (!m) { + return; + } + + memncpy(m, msg, len); + + uart_printf("[*] time: %d\r\n", atoi(ssec)); + timer_add_proc_after((void (*)(void *))timeout_print, m, atoi(ssec)); +} + +static void cmd_sw_timer(void) +{ + timer_switch_info(); +} + +static void cmd_sw_uart_mode(void) +{ + int mode = uart_switch_mode(); + + if (mode == 0) { + uart_printf("[*] Use synchronous UART\r\n"); + } else { + uart_printf("[*] Use asynchronous UART\r\n"); + } +} + +static void cmd_exec(char *filename) +{ + // TODO: Add argv & envp + sched_new_user_prog(filename); +} + +static void cmd_parsedtb(void) +{ + fdt_traversal(fdt_base); +} + +static void cmd_thread_test(void) +{ + for (int i = 0; i < 3; ++i) { + kthread_create(foo); + } +} + +static int shell_read_cmd(void) +{ + return uart_recvline(shell_buf, BUFSIZE); +} + +static void shell(void) +{ + while (1) { + int cmd_len; + uart_printf("# "); + cmd_len = shell_read_cmd(); + uart_printf("\r\n"); + if (!strncmp("alloc", shell_buf, 5)) { + if (cmd_len >= 7) { + cmd_alloc(&shell_buf[6]); + } + } else if (!strncmp("free", shell_buf, 4)) { + if (cmd_len >= 6) { + cmd_free(&shell_buf[5]); + } + } else if (!strcmp("help", shell_buf)) { + cmd_help(); + } else if (!strcmp("hello", shell_buf)) { + cmd_hello(); + } else if (!strcmp("hwinfo", shell_buf)) { + cmd_hwinfo(); + } else if (!strcmp("reboot", shell_buf)) { + cmd_reboot(); + } else if (!strncmp("setTimeout", shell_buf, 10)) { + char *msg, *ssec; + + msg = shell_buf + 10; + + if (*msg != ' ') { + continue; + } + + msg++; + + if (!*msg) { + continue; + } + + ssec = msg; + + while (*(++ssec)) { + if (*ssec == ' ') { + break; + } + } + + if (*ssec != ' ') { + continue; + } + + *ssec = 0; + + ssec++; + + if (!*ssec) { + continue; + } + + cmd_setTimeout(msg, ssec); + } else if (!strcmp("sw_timer", shell_buf)) { + cmd_sw_timer(); + } else if (!strcmp("sw_uart_mode", shell_buf)) { + cmd_sw_uart_mode(); + } else if (!strcmp("parsedtb", shell_buf)) { + cmd_parsedtb(); + } else if (!strcmp("thread_test", shell_buf)) { + cmd_thread_test(); + } else if (!strncmp("exec", shell_buf, 4)) { + if (cmd_len >= 6) { + cmd_exec(&shell_buf[5]); + } + } else { + // Just echo back + uart_printf("%s\r\n", shell_buf); + } + } +} + +static void idle(void) +{ + while (1) { + kthread_kill_zombies(); + schedule(); + } +} + +void start_kernel(char *fdt) +{ + fdt_base = fdt; + + irq_init(); + uart_init(); + initramfs_init(); + mm_init(); + timer_init(); + task_init(); + scheduler_init(); + kthread_early_init(); + fs_init(); + kthread_init(); + + uart_printf("[*] fdt base: %x\r\n", fdt_base); + uart_printf("[*] Kernel start!\r\n"); + + // TODO: Remove shell? + // kthread_create(shell); + + // TODO: Add argv & envp + // First user program + sched_new_user_prog("/initramfs/vfs2.img"); + + // Enable interrupt from Auxiliary peripherals + irq1_enable(29); + + enable_interrupt(); + + idle(); +} \ No newline at end of file diff --git a/lab8/src/kernel/mini_uart.c b/lab8/src/kernel/mini_uart.c new file mode 100644 index 000000000..383e044f5 --- /dev/null +++ b/lab8/src/kernel/mini_uart.c @@ -0,0 +1,373 @@ +// Ref: https://github.com/s-matyukevich/raspberry-pi-os/blob/master/src/lesson01/src/mini_uart.c +#include +#include +#include +#include + +#define SIGN 1 + +#define BUFSIZE 0x100 + +static void uart_irq_handler(void *); +static void uart_irq_fini(void); + +// UART asynchronous/synchronous mode +// 0: Synchronous mode +// 1: Asynchronous mode +static int uart_sync_mode; + +// UART read / write function pointer +typedef char (*recvfp)(void); +typedef void (*sendfp)(char); + +recvfp uart_recv_fp; +sendfp uart_send_fp; + +// Data structure for async RW +static char r_ringbuf[BUFSIZE]; +static char w_ringbuf[BUFSIZE]; +static int r_head, r_tail; +static int w_head, w_tail; + +static char uart_asyn_recv(void) +{ + uint32 ier; + char tmp; + + // Enable R interrupt + ier = get32(PA2VA(AUX_MU_IER_REG)); + ier = ier | 0x01; + put32(PA2VA(AUX_MU_IER_REG), ier); + + while (r_head == r_tail) {} + + tmp = r_ringbuf[r_head]; + r_head = (r_head + 1) % BUFSIZE; + + return tmp; +} + +static void uart_asyn_send(char c) +{ + uint32 ier; + + while (w_head == (w_tail + 1) % BUFSIZE) { + } + + w_ringbuf[w_tail] = c; + w_tail = (w_tail + 1) % BUFSIZE; + + // Enable W interrupt + ier = get32(PA2VA(AUX_MU_IER_REG)); + ier = ier | 0x02; + put32(PA2VA(AUX_MU_IER_REG), ier); +} + +static char uart_sync_recv(void) +{ + while (!(get32(PA2VA(AUX_MU_LSR_REG)) & 0x01)) {}; + + return (get32(PA2VA(AUX_MU_IO_REG)) & 0xFF); +} + +static void uart_sync_send(char c) +{ + while (!(get32(PA2VA(AUX_MU_LSR_REG)) & 0x20)) {}; + + put32(PA2VA(AUX_MU_IO_REG), c); +} + +char uart_recv(void) +{ + return (uart_recv_fp)(); +} + +void uart_send(char c) +{ + (uart_send_fp)(c); +} + +void uart_recvn(char *buff, int n) +{ + while (n--) { + *buff++ = (uart_recv_fp)(); + } +} + +uint32 uart_recv_uint(void) +{ + char buf[4]; + + for (int i = 0; i < 4; ++i) { + buf[i] = (uart_recv_fp)(); + } + + return *((uint32*)buf); +} + +uint32 uart_recvline(char *buff, int maxlen) +{ + uint32 cnt = 0; + + // Reserve space for NULL byte + maxlen--; + + while (maxlen) { + char c = (uart_recv_fp)(); + + if (c == '\r') { + // TODO: what if c == '\0'? + break; + } + + (uart_send_fp)(c); + *buff = c; + buff++; + cnt += 1; + maxlen -= 1; + } + + *buff = 0; + + return cnt; +} + +void uart_sendn(const char *str, int n) +{ + while (n--) { + (uart_send_fp)(*str++); + } +} + +static void uart_send_string(sendfp _send_fp, const char *str) +{ + for (int i = 0; str[i] != '\0'; i++) { + (_send_fp)(str[i]); + } +} + +// Ref: https://elixir.bootlin.com/linux/v3.5/source/arch/x86/boot/printf.c#L43 +/* + * @num: output number + * @base: 10 or 16 + */ +static void uart_send_num(sendfp _send_fp, int64 num, int base, int type) +{ + static const char digits[16] = "0123456789ABCDEF"; + char tmp[66]; + int i; + + if (type & SIGN) { + if (num < 0) { + (_send_fp)('-'); + } + } + + i = 0; + + if (num == 0) { + tmp[i++] = '0'; + } else { + while (num != 0) { + uint8 r = (uint64)num % base; + num = (uint64)num / base; + tmp[i++] = digits[r]; + } + } + + while (--i >= 0) { + (_send_fp)(tmp[i]); + } +} + +// Ref: https://elixir.bootlin.com/linux/v3.5/source/arch/x86/boot/printf.c#L115 +static void _uart_printf(sendfp _send_fp, const char *fmt, va_list args) +{ + const char *s; + char c; + uint64 num; + char width; + + for (; *fmt; ++fmt) { + if (*fmt != '%') { + (_send_fp)(*fmt); + continue; + } + + ++fmt; + + // Get width + width = 0; + if (fmt[0] == 'l' && fmt[1] == 'l') { + width = 1; + fmt += 2; + } + + switch (*fmt) { + case 'c': + c = va_arg(args, uint32) & 0xff; + (_send_fp)(c); + continue; + case 'd': + if (width) { + num = va_arg(args, int64); + } else { + num = va_arg(args, int32); + } + uart_send_num(_send_fp, num, 10, SIGN); + continue; + case 's': + s = va_arg(args, char *); + uart_send_string(_send_fp, s); + continue; + case 'x': + if (width) { + num = va_arg(args, uint64); + } else { + num = va_arg(args, uint32); + } + uart_send_num(_send_fp, num, 16, 0); + continue; + } + } +} + +void uart_printf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + _uart_printf(uart_send_fp, fmt, args); + + va_end(args); +} + +void uart_sync_printf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + _uart_printf(uart_sync_send, fmt, args); + + va_end(args); +} + +void uart_sync_vprintf(const char *fmt, va_list args) +{ + _uart_printf(uart_sync_send, fmt, args); +} + +void uart_init(void) +{ + unsigned int selector; + + selector = get32(PA2VA(GPFSEL1)); + selector &= ~(7 << 12); // Clean gpio14 + selector |= 2 << 12; // Set alt5 for gpio14 + selector &= ~(7 << 15); // Clean gpio15 + selector |= 2 << 15; // Set alt5 for gpio15 + put32(PA2VA(GPFSEL1), selector); + + put32(PA2VA(GPPUD), 0); + delay(150); + put32(PA2VA(GPPUDCLK0), (1 << 14) | (1 << 15)); + delay(150); + put32(PA2VA(GPPUDCLK0), 0); + + put32(PA2VA(AUX_ENABLES), 1); // Enable mini uart (this also enables access to its registers) + put32(PA2VA(AUX_MU_CNTL_REG), 0); // Disable auto flow control and disable receiver and transmitter (for now) + put32(PA2VA(AUX_MU_IER_REG), 0); // Disable receive and transmit interrupts + put32(PA2VA(AUX_MU_LCR_REG), 3); // Enable 8 bit mode + put32(PA2VA(AUX_MU_MCR_REG), 0); // Set RTS line to be always high + put32(PA2VA(AUX_MU_BAUD_REG), 270); // Set baud rate to 115200 + put32(PA2VA(AUX_MU_IIR_REG), 6); // Clear the Rx/Tx FIFO + put32(PA2VA(AUX_MU_CNTL_REG), 3); // Finally, enable transmitter and receiver + + // UART start from synchronous mode + uart_sync_mode = 0; + uart_recv_fp = uart_sync_recv; + uart_send_fp = uart_sync_send; +} + +int uart_irq_check(void) +{ + uint32 iir = get32(PA2VA(AUX_MU_IIR_REG)); + + if (iir & 0x01) { + // No interrupt + return 0; + } + + // Disable RW interrupt + put32(PA2VA(AUX_MU_IER_REG), 0); + if (irq_run_task(uart_irq_handler, NULL, uart_irq_fini, 1)) { + put32(PA2VA(AUX_MU_IER_REG), 0x03); + } + + return 1; +} + +static void uart_irq_handler(void *_) +{ + uint32 iir = get32(PA2VA(AUX_MU_IIR_REG)); + + if (iir & 0x02) { + // Transmit holding register empty + if (w_head != w_tail) { + put32(PA2VA(AUX_MU_IO_REG), w_ringbuf[w_head]); + w_head = (w_head + 1) % BUFSIZE; + } + } else if (iir & 0x04) { + // Receiver holds valid byte + if (r_head != (r_tail + 1) % BUFSIZE) { + r_ringbuf[r_tail] = get32(PA2VA(AUX_MU_IO_REG)) & 0xFF; + r_tail = (r_tail + 1) % BUFSIZE; + } + } +} + +static void uart_irq_fini(void) +{ + uint32 ier = get32(PA2VA(AUX_MU_IER_REG)); + ier = ier & ~(0x03); + + // Set RW interrupt + if (r_head != (r_tail + 1) % BUFSIZE) { + ier = ier | 0x01; + } + + if (w_head != w_tail) { + ier = ier | 0x02; + } + + put32(PA2VA(AUX_MU_IER_REG), ier); +} + +int uart_switch_mode(void) +{ + uart_sync_mode = !uart_sync_mode; + uint32 ier = get32(PA2VA(AUX_MU_IER_REG)); + ier = ier & ~(0x03); + + if (uart_sync_mode == 0) { + // Synchronous mode + uart_recv_fp = uart_sync_recv; + uart_send_fp = uart_sync_send; + + // Disable RW interrupt + put32(PA2VA(AUX_MU_IER_REG), ier); + } else { + // Asynchronous mode + uart_recv_fp = uart_asyn_recv; + uart_send_fp = uart_asyn_send; + + // Clear the Rx/Tx FIFO + put32(PA2VA(AUX_MU_IIR_REG), 6); + + // Enable R interrupt + ier = ier | 0x01; + put32(PA2VA(AUX_MU_IER_REG), ier); + } + + return uart_sync_mode; +} \ No newline at end of file diff --git a/lab8/src/kernel/mm/early_alloc.c b/lab8/src/kernel/mm/early_alloc.c new file mode 100644 index 000000000..8494a9d1d --- /dev/null +++ b/lab8/src/kernel/mm/early_alloc.c @@ -0,0 +1,26 @@ +#include +#include +#include + +static char *cur = EARLY_MEM_BASE; + +void *early_malloc(size_t size) +{ + char *tmp; + + size = ALIGN(size, 4); + + if ((uint64)cur + size > (uint64)EARLY_MEM_END) { + uart_printf("[!] No enough space!\r\n"); + return NULL; + } + + tmp = cur; + cur += size; + +#ifdef MM_DEBUG + uart_printf("[*] Early allocate: %llx ~ %llx\r\n", tmp, cur - 1); +#endif + + return tmp; +} \ No newline at end of file diff --git a/lab8/src/kernel/mm/mm.c b/lab8/src/kernel/mm/mm.c new file mode 100644 index 000000000..62002b75c --- /dev/null +++ b/lab8/src/kernel/mm/mm.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include +#include +#include + +/* From linker.ld */ +extern char _stack_top; + +static uint64 memory_end; +static uint32 memory_node; + +// Load 64-bit number (big-endian) +static uint64 ld64(char *start) +{ + uint64 ret = 0; + uint32 i = 8; + + while (i--) { + ret <<= 8; + ret += (uint8)(*start++); + } + + return ret; +} + +static int memory_fdt_parser(int level, char *cur, char *dt_strings) +{ + struct fdt_node_header *nodehdr = (struct fdt_node_header *)cur; + struct fdt_property *prop; + + uint32 tag = fdtn_tag(nodehdr); + + switch (tag) { + case FDT_PROP: + if (!memory_node) { + break; + } + prop = (struct fdt_property *)nodehdr; + if (!strcmp("reg", dt_strings + fdtp_nameoff(prop))) { + memory_end = ld64(prop->data); + return 1; + } + break; + case FDT_BEGIN_NODE: + if (!strcmp("memory@0", nodehdr->name)) { + memory_node = 1; + } + break; + case FDT_END_NODE: + memory_node = 0; + break; + case FDT_NOP: + case FDT_END: + break; + } + + return 0; +} + +void mm_init(void) +{ + parse_dtb(fdt_base, memory_fdt_parser); + + page_allocator_early_init((void *)PA2VA(0), (void *)PA2VA(memory_end)); + sc_early_init(); + + // Spin tables for multicore boot & Booting page tables + mem_reserve((void *)PA2VA(0), (void *)PA2VA(0x4000)); + + // Kernel image in the physical memory + mem_reserve(_start, &_stack_top); + + // Initramfs + mem_reserve(initramfs_base, initramfs_end); + + // TODO: Devicetree + + // early_malloc + mem_reserve(EARLY_MEM_BASE, EARLY_MEM_END); + + /* + * page_allocator_init() might output some debug information via mini-uart. + * uart_init() needs to be called before calling page_allocator_init(). + */ + page_allocator_init(); + sc_init(); + +#ifdef MM_DEBUG + page_allocator_test(); + sc_test(); +#endif +} + +void *kmalloc(int size) +{ + uint32 daif; + void *ret; + + daif = save_and_disable_interrupt(); + + if (size <= PAGE_SIZE) { + // Use the Small Chunk allocator + ret = sc_alloc(size); + } else { + // Use the Buddy System allocator + int page_cnt = ALIGN(size, PAGE_SIZE) / PAGE_SIZE; + + ret = alloc_pages(page_cnt); + } + + restore_interrupt(daif); + + return ret; +} + +void kfree(void *ptr) +{ + uint32 daif; + + daif = save_and_disable_interrupt(); + + if (!sc_free(ptr)) { + /* + * The chunk pointed to by ptr is managed by the Small Chunk + * allocator. + */ + goto _KFREE_END; + } + + free_page(ptr); + +_KFREE_END: + + restore_interrupt(daif); +} \ No newline at end of file diff --git a/lab8/src/kernel/mm/page_alloc.c b/lab8/src/kernel/mm/page_alloc.c new file mode 100644 index 000000000..710c1444a --- /dev/null +++ b/lab8/src/kernel/mm/page_alloc.c @@ -0,0 +1,291 @@ +/* + * Implementation of Buddy System. + */ + +// TODO: Consider critical section + +#include +#include +#include +#include +#include +#include + +#define FREELIST_CNT 16 + +typedef struct { + uint8 exp:7; + uint8 allocated:1; +} frame_ent; + +typedef struct { + /* Linked to next free frame_hdr */ + struct list_head list; +} frame_hdr; + +uint64 buddy_base; +uint64 buddy_end; + +frame_ent *frame_ents; +uint32 frame_ents_size; + +struct list_head freelists[FREELIST_CNT]; + +/* + * Convert number of pages to the corresponding idx (or say exp) of freelists + * + * num -> size -> exp + * 0b1 -> 1 -> 0 + * 0b11 -> 4 -> 2 + * 0b110 -> 8 -> 3 + * 0b10000 -> 16 -> 4 + * 0b10001 -> 32 -> 5 + */ +static inline int num2exp(int num) +{ + return fls(num - 1); +} + +static inline int is_valid_page(void *page) +{ + if (buddy_base > (uint64)page || + (uint64)page >= buddy_end || + (uint64)page & (PAGE_SIZE - 1)) { + return 0; + } + + return 1; +} + +void page_allocator_early_init(void *start, void *end) +{ + buddy_base = (uint64)start; + buddy_end = (uint64)end; + + frame_ents_size = (buddy_end - buddy_base) / PAGE_SIZE; + + frame_ents = early_malloc(sizeof(frame_ent) * frame_ents_size); + + for (int i = 0; i < frame_ents_size; ++i) { + frame_ents[i].exp = 0; + frame_ents[i].allocated = 0; + } + +#ifdef MM_DEBUG + uart_sync_printf("[*] init buddy (%llx ~ %llx)\r\n", buddy_base, buddy_end); +#endif +} + +void mem_reserve(void *start, void *end) +{ + start = (void *)((uint64)start & ~(PAGE_SIZE - 1)); + end = (void *)ALIGN((uint64)end, PAGE_SIZE); + + for (; start < end; start = (void *)((uint64)start + PAGE_SIZE)) { + int idx = addr2idx(start); + + frame_ents[idx].allocated = 1; + +#ifdef MM_DEBUG + uart_sync_printf("[*] preserve page idx %d (%llx)\r\n", idx, start); +#endif + } +} + +void page_allocator_init(void) +{ + for (int i = 0; i < FREELIST_CNT; ++i) { + INIT_LIST_HEAD(&freelists[i]); + } + + // Merge buddys from bottom to top + for (int exp = 0, idx; exp + 1 < FREELIST_CNT; exp++) { + idx = 0; + + while (1) { + int buddy_idx; + + buddy_idx = idx ^ (1 << exp); + + if (buddy_idx >= frame_ents_size) { + break; + } + + if (!frame_ents[idx].allocated && + frame_ents[idx].exp == exp && + !frame_ents[buddy_idx].allocated && + frame_ents[buddy_idx].exp == exp) { + frame_ents[idx].exp = exp + 1; + } + + idx += (1 << (exp + 1)); + + if (idx >= frame_ents_size) { + break; + } + } + } + + // Update freelists + for (int idx = 0, exp; idx < frame_ents_size; idx += (1 << exp)) { + exp = frame_ents[idx].exp; + + if (!frame_ents[idx].allocated) { + frame_hdr *hdr; + + hdr = idx2addr(idx); + list_add_tail(&hdr->list, &freelists[exp]); + +#ifdef MM_DEBUG + uart_sync_printf("[*] page init, idx %d belong to exp %d\r\n", + idx, exp); +#endif + } + } +} + +void *alloc_pages(int num) +{ + frame_hdr *hdr; + int idx, topexp, exp; + +#ifdef MM_DEBUG + uart_sync_printf("[*] alloc_pages %d pages\r\n", num); +#endif + + if (!num) { + return NULL; + } + + exp = num2exp(num); + + if (exp >= FREELIST_CNT) { + return NULL; + } + + for (topexp = exp; topexp < FREELIST_CNT; topexp++) { + if (!list_empty(&freelists[topexp])) { + break; + } + } + + if (topexp == FREELIST_CNT) { + return NULL; + } + + // Allocate + hdr = list_first_entry(&freelists[topexp], frame_hdr, list); + idx = addr2idx(hdr); + + list_del(&hdr->list); + + // Expand + while (topexp != exp) { + frame_hdr *buddy_hdr; + int buddy_idx; + + topexp -= 1; + buddy_idx = idx ^ (1 << topexp); + + frame_ents[buddy_idx].exp = topexp; + frame_ents[buddy_idx].allocated = 0; + + buddy_hdr = idx2addr(buddy_idx); + list_add(&buddy_hdr->list, &freelists[topexp]); + +#ifdef MM_DEBUG + uart_sync_printf("[*] Expand to idx (%d, %d) to exp (%d)\r\n", + idx, buddy_idx, topexp); +#endif + } + + frame_ents[idx].exp = exp; + frame_ents[idx].allocated = 1; + +#ifdef MM_DEBUG + uart_sync_printf("[*] Allocate idx %d exp %d\r\n", + idx, exp); +#endif + + return (void *)hdr; +} + +void *alloc_page(void) +{ + return alloc_pages(1); +} + +static inline void _free_page(frame_hdr *page) +{ + int idx, buddy_idx, exp; + + idx = addr2idx(page); + exp = frame_ents[idx].exp; + + frame_ents[idx].allocated = 0; + list_add(&page->list, &freelists[exp]); + + buddy_idx = idx ^ (1 << exp); + + // Merge buddy + while (exp + 1 < FREELIST_CNT && + !frame_ents[buddy_idx].allocated && + frame_ents[buddy_idx].exp == exp) { +#ifdef MM_DEBUG + uart_sync_printf("[*] merge idx (%d, %d) to exp (%d)\r\n", + idx, buddy_idx, exp + 1); +#endif + + frame_hdr *hdr; + + exp += 1; + + hdr = idx2addr(idx); + list_del(&hdr->list); + + hdr = idx2addr(buddy_idx); + list_del(&hdr->list); + + idx = idx & buddy_idx; + hdr = idx2addr(idx); + + frame_ents[idx].exp = exp; + list_add(&hdr->list, &freelists[exp]); + + buddy_idx = idx ^ (1 << exp); + } +} + +void free_page(void *page) +{ + if (!is_valid_page(page)) { + return; + } + +#ifdef MM_DEBUG + uart_sync_printf("[*] free_page idx %d\r\n", addr2idx(page)); +#endif + + _free_page((frame_hdr *)page); +} + +#ifdef MM_DEBUG +void page_allocator_test(void) +{ + char *ptr1 = alloc_pages(2); + char *ptr2 = alloc_pages(2); + char *ptr3 = alloc_pages(2); + char *ptr4 = alloc_pages(2); + + free_page(ptr3); + + char *ptr5 = alloc_pages(1); // Split ptr3 + char *ptr6 = alloc_pages(1); + + free_page(ptr4); + free_page(ptr2); + free_page(ptr1); // Merge with ptr2 + free_page(ptr5); + free_page(ptr6); // Merge with ptr5, then merge with ptr4, then merge with ptr1 +} +#endif \ No newline at end of file diff --git a/lab8/src/kernel/mm/sc_alloc.c b/lab8/src/kernel/mm/sc_alloc.c new file mode 100644 index 000000000..d50526ed2 --- /dev/null +++ b/lab8/src/kernel/mm/sc_alloc.c @@ -0,0 +1,192 @@ +/* + * Implementation of Small Chunk allocator. + */ + +// TODO: Consider critical section + +#include +#include +#include +#include +#include +#include + +uint32 sc_sizes[] = { + 0x10, // Minimum size cannot be less than 0x10 (sizeof(sc_hdr)) + 0x20, + 0x30, + 0x40, + 0x60, + 0x80, + 0xc0, + 0x100, + 0x400, + 0x1000 // Maximum size cannot be larger than 0x1000 (PAGE_SIZE) +}; + +typedef struct { + uint8 size_idx:7; + uint8 splitted:1; +} sc_frame_ent; + +typedef struct { + /* Link to next free chunk */ + struct list_head list; +} sc_hdr; + +sc_frame_ent *sc_frame_ents; + +struct list_head sc_freelists[ARRAY_SIZE(sc_sizes)]; + +static uint8 find_size_idx(int size) +{ + if (size <= 0x10) return 0; + if (size <= 0x20) return 1; + if (size <= 0x30) return 2; + if (size <= 0x40) return 3; + if (size <= 0x60) return 4; + if (size <= 0x80) return 5; + if (size <= 0xc0) return 6; + if (size <= 0x100) return 7; + if (size <= 0x400) return 8; + if (size <= 0x1000) return 9; + /* Never reach */ + return -1; +} + +void sc_early_init(void) +{ + sc_frame_ents = early_malloc(sizeof(sc_frame_ent) * frame_ents_size); + + for (int i = 0; i < frame_ents_size; ++i) { + sc_frame_ents[i].splitted = 0; + } +} + +void sc_init(void) +{ + for (int i = 0; i < ARRAY_SIZE(sc_sizes); ++i) { + INIT_LIST_HEAD(&sc_freelists[i]); + } +} + +void *sc_alloc(int size) +{ + sc_hdr *hdr; + uint8 size_idx; + + size_idx = find_size_idx(size); + + if (list_empty(&sc_freelists[size_idx])) { + // Allocate a page and split it into small chunks + void *page; + int frame_idx; + + page = alloc_page(); + + if (!page) { + return NULL; + } + + frame_idx = addr2idx(page); + sc_frame_ents[frame_idx].size_idx = size_idx; + sc_frame_ents[frame_idx].splitted = 1; + + for (int i = 0; + i + sc_sizes[size_idx] <= PAGE_SIZE; + i += sc_sizes[size_idx]) { + hdr = (sc_hdr *)((char *)page + i); + list_add_tail(&hdr->list, &sc_freelists[size_idx]); + } + +#ifdef MM_DEBUG + uart_sync_printf("[sc] Create chunks (page: %d; size: %d)\r\n", + frame_idx, sc_sizes[size_idx]); +#endif + } + + hdr = list_first_entry(&sc_freelists[size_idx], sc_hdr, list); + list_del(&hdr->list); + +#ifdef MM_DEBUG + uart_sync_printf("[sc] Allocate chunks %llx (request: %d; chunksize: %d)\r\n", + hdr, + size, + sc_sizes[size_idx]); +#endif + + return hdr; +} + +int sc_free(void *sc) +{ + sc_hdr *hdr; + int frame_idx, size_idx; + + frame_idx = addr2idx(sc); + + if (!sc_frame_ents[frame_idx].splitted) { + /* This frame isn't managed by the Small Chunk allocator */ + return -1; + } + + size_idx = sc_frame_ents[frame_idx].size_idx; + + hdr = (sc_hdr *)sc; + list_add(&hdr->list, &sc_freelists[size_idx]); + +#ifdef MM_DEBUG + uart_sync_printf("[sc] Free chunks %llx(size: %d)\r\n", + sc, + sc_sizes[size_idx]); +#endif + + return 0; +} + +#ifdef MM_DEBUG +void sc_test(void) +{ + char *ptr1 = sc_alloc(0x18); // A; Allocate a page and create 0x20 chunks + char *ptr2 = sc_alloc(0x19); // B + char *ptr3 = sc_alloc(0x1a); // C + + sc_free(ptr1); // 0x20 freelist: A + sc_free(ptr3); // 0x20 freelist: C -> A + + char *ptr4 = sc_alloc(0x17); // C; 0x20 freelist: A + + sc_free(ptr2); // 0x20 freelist: B -> A + + char *ptr5 = sc_alloc(0x17); // B; 0x20 freelist: A + char *ptr6 = sc_alloc(0x17); // A; 0x20 freelist: + + sc_free(ptr4); + sc_free(ptr5); + sc_free(ptr6); + + ptr1 = sc_alloc(0x3f0); // A; Allocate a page and create 0x400 chunks + ptr2 = sc_alloc(0x3f0); // B + ptr3 = sc_alloc(0x3f0); // C + ptr4 = sc_alloc(0x3f0); // D + ptr5 = sc_alloc(0x3f0); // E; Allocate a page and create 0x400 chunks + + sc_free(ptr1); + sc_free(ptr2); + sc_free(ptr3); + sc_free(ptr5); + sc_free(ptr4); + + ptr1 = sc_alloc(0x3f0); // D + ptr2 = sc_alloc(0x3f0); // E + ptr3 = sc_alloc(0x3f0); // C + ptr4 = sc_alloc(0x3f0); // B + ptr5 = sc_alloc(0x3f0); // A + + sc_free(ptr1); + sc_free(ptr2); + sc_free(ptr3); + sc_free(ptr5); + sc_free(ptr4); +} +#endif \ No newline at end of file diff --git a/lab8/src/kernel/mmu.c b/lab8/src/kernel/mmu.c new file mode 100644 index 000000000..38727340e --- /dev/null +++ b/lab8/src/kernel/mmu.c @@ -0,0 +1,546 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 PD_PXN ((uint64)1 << 53) +#define PD_NSTABLE ((uint64)1 << 63) +#define PD_UXNTABLE ((uint64)1 << 60) +#define PD_MAIR_DEVICE_IDX (MAIR_IDX_DEVICE_nGnRnE << 2) +#define PD_MAIR_NORMAL_IDX (MAIR_IDX_NORMAL_NOCACHE << 2) +// Block Entry +#define PD_BE PD_ACCESS | PD_BLOCK +// Level 3 Block Entry +#define PD_L3BE PD_ACCESS | PD_TABLE + +#define BOOT_PGD ((pd_t *)0x1000) +#define BOOT_PUD ((pd_t *)0x2000) +#define BOOT_PMD ((pd_t *)0x3000) + +static void segmentation_fault(void) +{ + uart_sync_printf("[Segmentation fault]: Kill Process\r\n"); + exit_user_prog(); + + // Never reach +} + +static vm_area_t *vma_create(void *va, uint64 size, uint64 flag, void *addr) +{ + vm_area_t *vma; + + vma = kmalloc(sizeof(vm_area_t)); + size = ALIGN(size, PAGE_SIZE); + + vma->va_begin = (uint64)va; + vma->va_end = (uint64)va + size; + vma->flag = flag; + + if (vma->flag & VMA_ANON) { + vma->kva = 0; + } else if (vma->flag & VMA_PA) { + vma->kva = PA2VA(addr); + } else if (vma->flag & VMA_KVA) { + vma->kva = (uint64)addr; + } else { + // Unexpected + panic("vma_create flag error"); + } + + return vma; +} + +static void clone_uva_region(uint64 uva_begin, uint64 uva_end, + pd_t *pt, uint64 flag) +{ + for (uint64 addr = uva_begin; addr < uva_end; addr += PAGE_SIZE) { + void *new_kva; + uint64 par; + + // try to get the PA of UVA + asm volatile ( + "at s1e0r, %0" + :: "r" (addr) + ); + + par = read_sysreg(PAR_EL1); + + if (PAR_FAILED(par)) { + // VA to PA conversion aborted + continue; + } + + // convert PA to KVA + par = PA2VA(PAR_PA(par)); + + // Allocate a page and copy content to this page + new_kva = kmalloc(PAGE_SIZE); + memncpy(new_kva, (void *)par, PAGE_SIZE); + + // map @new_kva into @pt + pt_map(pt, (void *)addr, PAGE_SIZE, (void *)VA2PA(new_kva), flag); + } +} + +static vm_area_t *vma_clone(vm_area_t *vma, pd_t *page_table) +{ + vm_area_t *new_vma; + + new_vma = kmalloc(sizeof(vm_area_t)); + + new_vma->va_begin = vma->va_begin; + new_vma->va_end = vma->va_end; + new_vma->flag = vma->flag; + + if (vma->flag & VMA_ANON) { + clone_uva_region(vma->va_begin, vma->va_end, page_table, vma->flag); + new_vma->kva = 0; + } else if (vma->flag & VMA_PA) { + new_vma->kva = vma->kva; + } else if (vma->flag & VMA_KVA) { + void *new_kva; + + new_kva = kmalloc(vma->va_end - vma->va_begin); + memncpy(new_kva, (void *)vma->kva, vma->va_end - vma->va_begin); + + new_vma->kva = (uint64)new_kva; + } else { + // Unexpected + panic("vma_clone flag error"); + } + + return new_vma; +} + +static void free_uva_region(uint64 uva_begin, uint64 uva_end) +{ + for (uint64 addr = uva_begin; addr < uva_end; addr += PAGE_SIZE) { + uint64 par; + + // try to get the PA of UVA + asm volatile ( + "at s1e0r, %0" + :: "r" (addr) + ); + + par = read_sysreg(PAR_EL1); + + if (PAR_FAILED(par)) { + // VA to PA conversion aborted + continue; + } + + // convert PA to KVA + par = PA2VA(PAR_PA(par)); + + // free KVA + kfree((void *)par); + } +} + +static void vma_free(vm_area_t *vma) +{ + if (vma->kva && vma->flag & VMA_KVA) { + kfree((void *)vma->kva); + } else if (vma->flag & VMA_ANON) { + free_uva_region(vma->va_begin, vma->va_end); + } else if (!(vma->flag & VMA_PA)){ + // Unexpected + panic("vma_free flag error"); + } + + kfree(vma); +} + +static vm_area_t *vma_find(vm_area_meta_t *vma_meta, uint64 addr) +{ + vm_area_t *vma; + + list_for_each_entry(vma, &vma_meta->vma, list) { + if (vma->va_begin <= addr && addr < vma->va_end) { + return vma; + } + } + + return NULL; +} + +void mmu_init(void) +{ + uint32 sctlr_el1; + + // Set Translation Control Register + write_sysreg(TCR_EL1, TCR_CONFIG_DEFAULT); + + // Set Memory Attribute Indirection Register + write_sysreg(MAIR_EL1, + (MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | + (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8))); + + // Set Identity Paging + // 0x00000000 ~ 0x3f000000: Normal + // 0x3f000000 ~ 0x40000000: Device + // 0x40000000 ~ 0x80000000: Device + BOOT_PGD[0] = (uint64)BOOT_PUD | PD_NSTABLE | PD_UXNTABLE | PD_TABLE; + + BOOT_PUD[0] = (uint64)BOOT_PMD | PD_TABLE; + BOOT_PUD[1] = 0x40000000 | PD_MAIR_DEVICE_IDX | PD_BE; + + for (int i = 0; i < 504; ++i) { + BOOT_PMD[i] = (i * (1 << 21)) | PD_MAIR_NORMAL_IDX | PD_BE; + } + + for (int i = 504; i < 512; ++i) { + BOOT_PMD[i] = (i * (1 << 21)) | PD_MAIR_DEVICE_IDX | PD_BE; + } + + write_sysreg(TTBR0_EL1, BOOT_PGD); + write_sysreg(TTBR1_EL1, BOOT_PGD); + + // Enable MMU + sctlr_el1 = read_sysreg(SCTLR_EL1); + write_sysreg(SCTLR_EL1, sctlr_el1 | 1); +} + +pd_t *pt_create(void) +{ + pd_t *pt = kmalloc(PAGE_TABLE_SIZE); + + for (int i = 0; i < PAGE_TABLE_SIZE / sizeof(pt[0]); ++i) { + pt[i] = 0; + } + + return pt; +} + +void pt_free(pd_t *pt) +{ + // TODO +} + +static void _pt_map(pd_t *pt, void *va, void *pa, uint64 flag) +{ + pd_t pd; + int idx; + + // 47 ~ 39, 38 ~ 30, 29 ~ 21, 20 ~ 12 + for (int layer = 3; layer > 0; --layer) { + idx = ((uint64)va >> (12 + 9 * layer)) & 0b111111111; + pd = pt[idx]; + + if (!(pd & 1)) { + // Invalid entry + pd_t *tmp = pt_create(); + pt[idx] = VA2PA(tmp) | PD_TABLE; + pt = tmp; + continue; + } + + // Must be a table entry + pt = (pd_t *)PA2VA(pd & ~((uint64)0xfff)); + } + + idx = ((uint64)va >> 12) & 0b111111111; + pd = pt[idx]; + + if (!(pd & 1)) { + // Invalid entry + // Access permissions + uint64 ap; + uint64 uxn; + + if (flag & PT_R) { + if (flag & PT_W) { + ap = 0b01; + } else { + ap = 0b11; + } + } else { + ap = 0b00; + } + + if (flag & PT_X) { + uxn = 0; + } else { + uxn = 1; + } + + pt[idx] = (uint64)pa | (uxn << 54) | PD_PXN | + PD_MAIR_NORMAL_IDX | (ap << 6) | PD_L3BE; + } + + // TODO: Already mapping, do nothing? +} + +void pt_map(pd_t *pt, void *va, uint64 size, void *pa, uint64 flag) +{ + if ((uint64)va & (PAGE_SIZE - 1)) { + return; + } + + if ((uint64)pa & (PAGE_SIZE - 1)) { + return; + } + + size = ALIGN(size, PAGE_SIZE); + + for (uint64 i = 0; i < size; i += PAGE_SIZE) { + _pt_map(pt, (void *)((uint64)va + i), (void *)((uint64)pa + i), flag); + } +} + +vm_area_meta_t *vma_meta_create(void) +{ + vm_area_meta_t *vma_meta; + + vma_meta = kmalloc(sizeof(vm_area_meta_t)); + INIT_LIST_HEAD(&vma_meta->vma); + + return vma_meta; +} + +void vma_meta_free(vm_area_meta_t *vma_meta, pd_t *page_table) +{ + uint64 old_page_table; + vm_area_t *vma, *safe; + + old_page_table = get_page_table(); + set_page_table(page_table); + + preempt_disable(); + + list_for_each_entry_safe(vma, safe, &vma_meta->vma, list) { + vma_free(vma); + } + + preempt_enable(); + + kfree(vma_meta); + + set_page_table(old_page_table); +} + +void vma_meta_copy(vm_area_meta_t *to, vm_area_meta_t *from, pd_t *page_table) +{ + uint64 old_page_table; + vm_area_t *vma, *new_vma; + + old_page_table = get_page_table(); + set_page_table(page_table); + + preempt_disable(); + + list_for_each_entry(vma, &from->vma, list) { + new_vma = vma_clone(vma, (pd_t *)old_page_table); + + list_add_tail(&new_vma->list, &to->vma); + } + + preempt_enable(); + + set_page_table(old_page_table); +} + +void vma_map(vm_area_meta_t *vma_meta, void *va, uint64 size, + uint64 flag, void *addr) +{ + vm_area_t *vma; + int cnt = 0; + + if (flag & VMA_PA) cnt++; + if (flag & VMA_KVA) cnt++; + if (flag & VMA_ANON) cnt++; + + if (cnt != 1) { + return; + } + + if ((uint64)va & (PAGE_SIZE - 1)) { + return; + } + + vma = vma_find(vma_meta, (uint64)va); + if (vma) { + return; + } + + vma = vma_find(vma_meta, (uint64)va + size - 1); + if (vma) { + return; + } + + vma = vma_create(va, size, flag, addr); + + list_add_tail(&vma->list, &vma_meta->vma); +} + +static void do_page_fault(esr_el1_t *esr) +{ + uint64 far; + uint64 va; + uint64 fault_perm; + vm_area_t *vma; + + far = read_sysreg(FAR_EL1); + + vma = vma_find(current->address_space, far); + + if (!vma) { + segmentation_fault(); + // Never reach + } + + // Check permission + if (esr->ec == EC_IA_LE) { + // Execute abort + fault_perm = VMA_X; + } else if (ISS_WnR(esr)) { + // Write abort + fault_perm = VMA_W; + } else { + // Read abort + fault_perm = VMA_R; + } + + if (!(vma->flag & fault_perm)) { + goto PAGE_FAULT_INVALID; + } + + va = far & ~(PAGE_SIZE - 1); + + if (vma->kva) { + uint64 offset; + + offset = va - vma->va_begin; + + pt_map(current->page_table, (void *)va, PAGE_SIZE, + (void *)VA2PA(vma->kva + offset), vma->flag); + } else if (vma->flag & VMA_ANON) { + void *kva = kmalloc(PAGE_SIZE); + + memzero(kva, PAGE_SIZE); + + pt_map(current->page_table, (void *)va, PAGE_SIZE, + (void *)VA2PA(kva), vma->flag); + } else { + // Unexpected result + goto PAGE_FAULT_INVALID; + } + + return; + +PAGE_FAULT_INVALID: + segmentation_fault(); + + // Never reach +} + +void mem_abort(esr_el1_t *esr) +{ + int fsc; +#ifdef DEMANDING_PAGE_DEBUG + uint64 addr; + + addr = read_sysreg(FAR_EL1); +#endif + + fsc = ISS_FSC(esr); + + switch (fsc) { + case FSC_TF_L0: + case FSC_TF_L1: + case FSC_TF_L2: + case FSC_TF_L3: +#ifdef DEMANDING_PAGE_DEBUG + uart_sync_printf("[Translation fault]: 0x%llx\r\n", addr); +#endif + do_page_fault(esr); + break; + default: + segmentation_fault(); + + // Never reach + } +} + +void syscall_mmap(trapframe *frame, void *addr, size_t len, int prot, + int flags, int fd, int file_offset) +{ + vm_area_t *vma; + int mapflag; + + // do some initial work + len = ALIGN(len, PAGE_SIZE); + + if (addr == NULL) { + addr = (void *)0x550000000000; + } + + while (1) { + if ((uint64)addr > 0x0000ffffffffffff) { + frame->x0 = 0; + return; + } + + vma = vma_find(current->address_space, (uint64)addr); + if (vma) { + addr = (void *)((uint64)addr + 0x10000000); + continue; + } + + vma = vma_find(current->address_space, (uint64)addr + len - 1); + if (vma) { + addr = (void *)((uint64)addr + 0x10000000); + continue; + } + + break; + } + + mapflag = 0; + + if (prot & PROT_READ) mapflag |= VMA_R; + if (prot & PROT_WRITE) mapflag |= VMA_W; + if (prot & PROT_EXEC) mapflag |= VMA_X; + + if (flags & MAP_POPULATE) { + void *kva; + + mapflag |= VMA_KVA; + + kva = kmalloc(len); + memzero(kva, len); + + vma_map(current->address_space, addr, len, mapflag, kva); + + pt_map(current->page_table, addr, len, (void *)VA2PA(kva), mapflag); + } else if (flags & MAP_ANONYMOUS) { + mapflag |= VMA_ANON; + + vma_map(current->address_space, addr, len, mapflag, NULL); + } else { + // Unexpected. + frame->x0 = 0; + return; + } + + frame->x0 = (uint64)addr; +} \ No newline at end of file diff --git a/lab8/src/kernel/mode_switch.c b/lab8/src/kernel/mode_switch.c new file mode 100644 index 000000000..eb516daa4 --- /dev/null +++ b/lab8/src/kernel/mode_switch.c @@ -0,0 +1,12 @@ +#include +#include +#include + +void exit_to_user_mode(trapframe regs) +{ + enable_interrupt(); + + handle_signal(®s); + + disable_interrupt(); +} \ No newline at end of file diff --git a/lab8/src/kernel/panic.c b/lab8/src/kernel/panic.c new file mode 100644 index 000000000..0c814cfb0 --- /dev/null +++ b/lab8/src/kernel/panic.c @@ -0,0 +1,20 @@ +#include +#include + +void panic(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + uart_sync_printf("\r\n[Kernel Panic] \r\n"); + + uart_sync_vprintf(fmt, args); + va_end(args); + + uart_sync_printf("\r\n"); + + // TODO: Show more information + + // Never return + while (1) {} +} \ No newline at end of file diff --git a/lab8/src/kernel/preempt.c b/lab8/src/kernel/preempt.c new file mode 100644 index 000000000..5132698f5 --- /dev/null +++ b/lab8/src/kernel/preempt.c @@ -0,0 +1,25 @@ +#include +#include +#include + +void preempt_disable(void) +{ + uint32 daif; + + daif = save_and_disable_interrupt(); + + current->preempt += 1; + + restore_interrupt(daif); +} + +void preempt_enable(void) +{ + uint32 daif; + + daif = save_and_disable_interrupt(); + + current->preempt -= 1; + + restore_interrupt(daif); +} \ No newline at end of file diff --git a/lab8/src/kernel/rpi3.c b/lab8/src/kernel/rpi3.c new file mode 100644 index 000000000..b9dbc0b4e --- /dev/null +++ b/lab8/src/kernel/rpi3.c @@ -0,0 +1,87 @@ +// Ref: +// https://github.com/bztsrc/raspi3-tutorial/blob/master/04_mailboxes/mbox.h +// https://github.com/raspberrypi/firmware/wiki/Mailboxes +// https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes +#include +#include +#include + +/* Mailbox registers */ +#define MAILBOX_BASE PA2VA(PERIPHERALS_BASE + 0xb880) +#define MAILBOX_READ MAILBOX_BASE +#define MAILBOX_STATUS MAILBOX_BASE + 0x18 +#define MAILBOX_WRITE MAILBOX_BASE + 0x20 + +/* Tags */ +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_MEMORY 0x00010005 + +/* Others */ +#define MAILBOX_EMPTY 0x40000000 +#define MAILBOX_FULL 0x80000000 + +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 + +// Aligned buffer +static unsigned int __attribute__((aligned(0x10))) mailbox[16]; + +void mailbox_call(unsigned char channel, unsigned int *mb) +{ + // Write the data (shifted into the upper 28 bits) combined with + // the channel (in the lower four bits) to the write register. + unsigned int r = (((unsigned long)mb) & ~0xf) | channel; + + // Check if Mailbox 0 status register’s full flag is set. + while ((get32(MAILBOX_STATUS) & MAILBOX_FULL)) {}; + + // If not, then you can write to Mailbox 1 Read/Write register. + put32(MAILBOX_WRITE, r); + + while (1) { + // Check if Mailbox 0 status register’s empty flag is set. + while ((get32(MAILBOX_STATUS) & MAILBOX_EMPTY)) {}; + + // If not, then you can read from Mailbox 0 Read/Write register. + // Check if the value is the same as you wrote in step 1. + if (r == get32(MAILBOX_READ)) + return; + } +} + +// It should be 0xa020d3 for rpi3 b+ +unsigned int get_board_revision(void) +{ + mailbox[0] = 7 * 4; // Buffer size in bytes + mailbox[1] = MBOX_REQUEST_CODE; + // Tags begin + mailbox[2] = GET_BOARD_REVISION; // Tag identifier + mailbox[3] = 4; // Value buffer size in bytes + mailbox[4] = MBOX_TAG_REQUEST; // Request/response codes + mailbox[5] = 0; // Optional value buffer + // Tags end + mailbox[6] = MBOX_END_TAG; + + mailbox_call(MAILBOX_CH_PROP, mailbox); // Message passing procedure call + + return mailbox[5]; +} + +void get_arm_memory(struct arm_memory_info *info) +{ + mailbox[0] = 8 * 4; // Buffer size in bytes + mailbox[1] = MBOX_REQUEST_CODE; + // Tags begin + mailbox[2] = GET_ARM_MEMORY; // Tag identifier + mailbox[3] = 8; // Value buffer size in bytes + mailbox[4] = MBOX_TAG_REQUEST; // Request/response codes + mailbox[5] = 0; // Optional value buffer + mailbox[6] = 0; // Optional value buffer + // Tags end + mailbox[7] = MBOX_END_TAG; + + mailbox_call(MAILBOX_CH_PROP, mailbox); // Message passing procedure call + + info->baseaddr = mailbox[5]; + info->size = mailbox[6]; +} diff --git a/lab8/src/kernel/sched.S b/lab8/src/kernel/sched.S new file mode 100644 index 000000000..c099ab1ca --- /dev/null +++ b/lab8/src/kernel/sched.S @@ -0,0 +1,33 @@ +.globl switch_to +switch_to: + stp x19, x20, [x0, 16 * 0] + stp x21, x22, [x0, 16 * 1] + stp x23, x24, [x0, 16 * 2] + stp x25, x26, [x0, 16 * 3] + stp x27, x28, [x0, 16 * 4] + stp fp, lr, [x0, 16 * 5] + mov x9, sp + str x9, [x0, 16 * 6] + + ldp x19, x20, [x1, 16 * 0] + ldp x21, x22, [x1, 16 * 1] + ldp x23, x24, [x1, 16 * 2] + ldp x25, x26, [x1, 16 * 3] + ldp x27, x28, [x1, 16 * 4] + ldp fp, lr, [x1, 16 * 5] + ldr x9, [x1, 16 * 6] + mov sp, x9 + + // set_current + msr tpidr_el1, x1 + + // Switch page table 0 + ldr x9, [x1, 8 * 13] + and x9, x9, #0x0000ffffffffffff + dsb ish // ensure write has completed + msr ttbr0_el1, x9 // switch translation based address. + tlbi vmalle1is // invalidate all TLB entries + dsb ish // ensure completion of TLB invalidatation + isb // clear pipeline + + ret diff --git a/lab8/src/kernel/sched.c b/lab8/src/kernel/sched.c new file mode 100644 index 000000000..bf3817374 --- /dev/null +++ b/lab8/src/kernel/sched.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include +#include + +#define SCHEDULER_TIMER_HZ 32 +#define SCHEDULER_WATERMARK 1 + +static struct list_head run_queue; + +static uint32 schedule_ticks; + +static void timer_schdule_tick(void *_) +{ + schedule_tick(); + + timer_add_proc_freq(timer_schdule_tick, NULL, SCHEDULER_TIMER_HZ); +} + +void scheduler_init(void) +{ + INIT_LIST_HEAD(&run_queue); + + timer_add_proc_freq(timer_schdule_tick, NULL, SCHEDULER_TIMER_HZ); +} + +void schedule(void) +{ + uint64 daif; + task_struct *task; + + daif = save_and_disable_interrupt(); + + task = list_first_entry(&run_queue, task_struct, list); + + list_del(&task->list); + list_add_tail(&task->list, &run_queue); + + current->need_resched = 0; + + restore_interrupt(daif); + + // Set registers. Set current to task + switch_to(current, task); +} + +void schedule_tick(void) +{ + schedule_ticks += 1; + + if (schedule_ticks >= SCHEDULER_WATERMARK) { + schedule_ticks = 0; + + current->need_resched = 1; + } +} + +void sched_add_task(task_struct *task) +{ + preempt_disable(); + + task->status = TASK_RUNNING; + + list_add_tail(&task->list, &run_queue); + + preempt_enable(); +} + +void sched_del_task(task_struct *task) +{ + preempt_disable(); + + list_del(&task->list); + + preempt_enable(); +} \ No newline at end of file diff --git a/lab8/src/kernel/sdhost.c b/lab8/src/kernel/sdhost.c new file mode 100644 index 000000000..4daa5797d --- /dev/null +++ b/lab8/src/kernel/sdhost.c @@ -0,0 +1,234 @@ +#include +#include +#include + +// 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 + +// sdhost +#define SDHOST_BASE PA2VA(PERIPHERALS_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) + +static int is_hcs; // high capcacity(SDHC) + +static void pin_setup(void) +{ + put32(PA2VA(GPFSEL4), 0x24000000); + put32(PA2VA(GPFSEL5), 0x924); + put32(PA2VA(GPPUD), 0); + delay(15000); + put32(PA2VA(GPPUDCLK1), 0xffffffff); + delay(15000); + put32(PA2VA(GPPUDCLK1), 0); +} + +static void sdhost_setup(void) +{ + unsigned int tmp; + put32(SDHOST_PWR, 0); + put32(SDHOST_CMD, 0); + put32(SDHOST_ARG, 0); + put32(SDHOST_TOUT, SDHOST_TOUT_DEFAULT); + put32(SDHOST_CDIV, 0); + put32(SDHOST_HSTS, SDHOST_HSTS_MASK); + put32(SDHOST_CFG, 0); + put32(SDHOST_CNT, 0); + put32(SDHOST_SIZE, 0); + tmp = get32(SDHOST_DBG); + tmp &= ~SDHOST_DBG_MASK; + tmp |= SDHOST_DBG_FIFO; + put32(SDHOST_DBG, tmp); + delay(250000); + put32(SDHOST_PWR, 1); + delay(250000); + put32(SDHOST_CFG, SDHOST_CFG_SLOW | SDHOST_CFG_INTBUS | SDHOST_CFG_DATA_EN); + put32(SDHOST_CDIV, SDHOST_CDIV_DEFAULT); +} + +static int wait_sd(void) +{ + int cnt = 1000000; + unsigned int cmd; + do { + if (cnt == 0) { + return -1; + } + cmd = get32(SDHOST_CMD); + --cnt; + } while (cmd & SDHOST_NEW_CMD); + return 0; +} + +static int sd_cmd(unsigned cmd, unsigned int arg) +{ + put32(SDHOST_ARG, arg); + put32(SDHOST_CMD, cmd | SDHOST_NEW_CMD); + return wait_sd(); +} + +static int sdcard_setup(void) +{ + unsigned int tmp; + sd_cmd(GO_IDLE_STATE | SDHOST_NO_REPONSE, 0); + sd_cmd(SEND_IF_COND, VOLTAGE_CHECK_PATTERN); + tmp = get32(SDHOST_RESP0); + 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); + tmp = get32(SDHOST_RESP0); + 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); + tmp = get32(SDHOST_RESP0); + sd_cmd(SELECT_CARD, tmp); + sd_cmd(SET_BLOCKLEN, BLOCK_SIZE); + return 0; +} + +static int wait_fifo(void) +{ + int cnt = 1000000; + unsigned int hsts; + do { + if (cnt == 0) { + return -1; + } + hsts = get32(SDHOST_HSTS); + --cnt; + } while ((hsts & SDHOST_HSTS_DATA) == 0); + return 0; +} + +static void set_block(int size, int cnt) +{ + put32(SDHOST_SIZE, size); + put32(SDHOST_CNT, cnt); +} + +static void wait_finish(void) +{ + unsigned int dbg; + do { + dbg = get32(SDHOST_DBG); + } while ((dbg & SDHOST_DBG_FSM_MASK) != SDHOST_HSTS_DATA); +} + +void sd_readblock(int block_idx, void *buf) +{ + unsigned int *buf_u = (unsigned int *)buf; + int succ = 0; + if (!is_hcs) { + block_idx <<= 9; + } + do { + unsigned int hsts; + set_block(BLOCK_SIZE, 1); + sd_cmd(READ_SINGLE_BLOCK | SDHOST_READ, block_idx); + for (int i = 0; i < 128; ++i) { + wait_fifo(); + buf_u[i] = get32(SDHOST_DATA); + } + hsts = get32(SDHOST_HSTS); + if (hsts & SDHOST_HSTS_ERR_MASK) { + put32(SDHOST_HSTS, SDHOST_HSTS_ERR_MASK); + sd_cmd(STOP_TRANSMISSION | SDHOST_BUSY, 0); + } else { + succ = 1; + } + } while(!succ); + wait_finish(); +} + +void sd_writeblock(int block_idx, const void *buf) +{ + const unsigned int *buf_u = (const unsigned int *)buf; + int succ = 0; + if (!is_hcs) { + block_idx <<= 9; + } + do { + unsigned int hsts; + set_block(BLOCK_SIZE, 1); + sd_cmd(WRITE_SINGLE_BLOCK | SDHOST_WRITE, block_idx); + for (int i = 0; i < 128; ++i) { + wait_fifo(); + put32(SDHOST_DATA, buf_u[i]); + } + hsts = get32(SDHOST_HSTS); + if (hsts & SDHOST_HSTS_ERR_MASK) { + put32(SDHOST_HSTS, SDHOST_HSTS_ERR_MASK); + sd_cmd(STOP_TRANSMISSION | SDHOST_BUSY, 0); + } else { + succ = 1; + } + } while(!succ); + wait_finish(); +} + +void sd_init(void) +{ + pin_setup(); + sdhost_setup(); + sdcard_setup(); +} \ No newline at end of file diff --git a/lab8/src/kernel/signal.c b/lab8/src/kernel/signal.c new file mode 100644 index 000000000..ed9bab02b --- /dev/null +++ b/lab8/src/kernel/signal.c @@ -0,0 +1,253 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +// TODO: implement SIGSTOP & SIGCONT kernel handler + +/* Kernel defined sighandler_t */ +#define SIG_DFL (sighandler_t)0 +#define SIG_IGN (sighandler_t)1 + +// SIG_DFL +static void sig_termiante(int); + +// SIG_IGN +static void sig_ignore(int); + +static void sig_termiante(int _) +{ + exit_user_prog(); + + // Never reach +} + +static void sig_ignore(int _) +{ + return; +} + +void sigreturn(void) SECTION_TUS; +void sigreturn(void) +{ + asm volatile( + "mov x8, " MC2STR(SCNUM_SIGRETURN) "\n" + "svc 0\n" + ); +} + +/* + * Try to get the pending signal of current task. + */ +static struct signal_t *signal_try_get(void) +{ + if (list_empty(¤t->signal->list)) { + return NULL; + } + + return list_first_entry(¤t->signal->list, struct signal_t, list); +} + +static void signal_add(uint32 signum, struct signal_head_t *head) +{ + struct signal_t *signal; + + signal = kmalloc(sizeof(struct signal_t)); + + signal->signum = signum; + + list_add(&signal->list, &head->list); +} + +static void signal_del(struct signal_t *signal) +{ + list_del(&signal->list); + kfree(signal); +} + +static void save_context(void *user_sp, trapframe *frame) +{ + memncpy(user_sp, (char *)frame, sizeof(trapframe)); +} + +struct signal_head_t *signal_head_create(void) +{ + struct signal_head_t *head; + + head = kmalloc(sizeof(struct signal_head_t)); + + INIT_LIST_HEAD(&head->list); + + return head; +} + +void signal_head_free(struct signal_head_t *head) +{ + struct signal_t *signal, *safe; + + list_for_each_entry_safe(signal, safe, &head->list, list) { + signal_del(signal); + } + + kfree(head); +} + +void signal_head_reset(struct signal_head_t *head) +{ + struct signal_t *signal, *safe; + + list_for_each_entry_safe(signal, safe, &head->list, list) { + signal_del(signal); + } +} + +void handle_signal(trapframe *frame) +{ + struct signal_t *signal; + struct sigaction_t *sigaction; + + preempt_disable(); + + signal = signal_try_get(); + + preempt_enable(); + + if (signal == NULL) { + return; + } + + sigaction = ¤t->sighand->sigactions[signal->signum]; + + if (sigaction->kernel_hand) { + sigaction->sighand(signal->signum); + } else { + char *user_sp; + uint32 reserve_size; + + // Reserve space on user stack + reserve_size = sizeof(trapframe); + user_sp = frame->sp_el0 - ALIGN(reserve_size, 0x10); + + // Save cpu context onto user stack + save_context(user_sp, frame); + + // Set user sp + frame->sp_el0 = user_sp; + + // Set parameter of handler + frame->x0 = signal->signum; + + // Set user pc to handler + frame->elr_el1 = sigaction->sighand; + + // Set user lr to sigreturn + frame->x30 = TUS2VA(sigreturn); + } + + signal_del(signal); +} + +struct sighand_t *sighand_create(void) +{ + struct sighand_t *sighand; + + sighand = kmalloc(sizeof(struct sighand_t)); + + for (int i = 1; i < NSIG; ++i) { + sighand->sigactions[i].kernel_hand = 1; + sighand->sigactions[i].sighand = sig_ignore; + } + + sighand->sigactions[SIGKILL].sighand = sig_termiante; + + return sighand; +} + +void sighand_free(struct sighand_t *sighand) +{ + kfree(sighand); +} + +void sighand_reset(struct sighand_t *sighand) +{ + for (int i = 1; i < NSIG; ++i) { + sighand->sigactions[i].kernel_hand = 1; + sighand->sigactions[i].sighand = sig_ignore; + } + + sighand->sigactions[SIGKILL].sighand = sig_termiante; +} + +static inline void _sighand_copy(struct sigaction_t *to, + struct sigaction_t *from) +{ + to->kernel_hand = from->kernel_hand; + to->sighand = from->sighand; +} + +/* Copy current signal handler to @sighand */ +void sighand_copy(struct sighand_t *sighand) +{ + struct sighand_t *currhand; + + currhand = current->sighand; + + for (int i = 1; i < NSIG; ++i) { + _sighand_copy(&sighand->sigactions[i], &currhand->sigactions[i]); + } +} + +void syscall_signal(trapframe *_, uint32 signal, void (*handler)(int)) +{ + struct sigaction_t *sigaction; + + // Check if signal is valid + if (signal >= NSIG) { + return; + } + + sigaction = ¤t->sighand->sigactions[signal]; + + if (handler == SIG_DFL) { + sigaction->kernel_hand = 1; + sigaction->sighand = sig_termiante; + } else if (handler == SIG_IGN) { + sigaction->kernel_hand = 1; + sigaction->sighand = sig_ignore; + } else { + sigaction->kernel_hand = 0; + sigaction->sighand = handler; + } +} + +void syscall_kill(trapframe *_, int pid, int signal) +{ + task_struct *task; + + preempt_disable(); + + task = task_get_by_tid(pid); + + if (!task || task->status != TASK_RUNNING) { + goto SYSCALL_KILL_END; + } + + signal_add((uint32)signal, task->signal); + +SYSCALL_KILL_END: + preempt_enable(); +} + +// restore context +void syscall_sigreturn(trapframe *frame) +{ + trapframe *user_sp; + + user_sp = frame->sp_el0; + + memncpy((char *)frame, (char *)user_sp, sizeof(trapframe)); +} \ No newline at end of file diff --git a/lab8/src/kernel/syscall.c b/lab8/src/kernel/syscall.c new file mode 100644 index 000000000..0699cf132 --- /dev/null +++ b/lab8/src/kernel/syscall.c @@ -0,0 +1,292 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KSTACK_VARIABLE(x) \ + (void *)((uint64)x - \ + (uint64)current->kernel_stack + \ + (uint64)child->kernel_stack) + +typedef void (*syscall_funcp)(); + +void syscall_getpid(trapframe *_); +void syscall_uart_read(trapframe *_, char buf[], size_t size); +void syscall_uart_write(trapframe *_, const char buf[], size_t size); +void syscall_exec(trapframe *_, const char *name, char *const argv[]); +void syscall_fork(trapframe *_); +void syscall_exit(trapframe *_); +void syscall_mbox_call(trapframe *_, unsigned char ch, unsigned int *mbox); +void syscall_kill_pid(trapframe *_, int pid); +void syscall_show_info(trapframe *_); + +syscall_funcp syscall_table[] = { + (syscall_funcp) syscall_getpid, // 0 + (syscall_funcp) syscall_uart_read, + (syscall_funcp) syscall_uart_write, + (syscall_funcp) syscall_exec, + (syscall_funcp) syscall_fork, // 4 + (syscall_funcp) syscall_exit, + (syscall_funcp) syscall_mbox_call, + (syscall_funcp) syscall_kill_pid, + (syscall_funcp) syscall_signal, // 8 + (syscall_funcp) syscall_kill, + (syscall_funcp) syscall_mmap, + (syscall_funcp) syscall_open, + (syscall_funcp) syscall_close, // 12 + (syscall_funcp) syscall_write, + (syscall_funcp) syscall_read, + (syscall_funcp) syscall_mkdir, + (syscall_funcp) syscall_mount, // 16 + (syscall_funcp) syscall_chdir, + (syscall_funcp) syscall_lseek64, + (syscall_funcp) syscall_ioctl, + (syscall_funcp) syscall_sync, // 20 + (syscall_funcp) syscall_sigreturn, + (syscall_funcp) syscall_show_info, +}; + +void syscall_handler(trapframe *regs) +{ + uint64 syscall_num; + + syscall_num = regs->x8; + + if (syscall_num > ARRAY_SIZE(syscall_table)) { + // Invalid syscall + return; + } + + enable_interrupt(); + + (syscall_table[syscall_num])(regs, + regs->x0, + regs->x1, + regs->x2, + regs->x3, + regs->x4, + regs->x5); + + disable_interrupt(); +} + +void syscall_getpid(trapframe *frame) +{ + frame->x0 = current->tid; +} + +void syscall_uart_read(trapframe *_, char buf[], size_t size) +{ + uart_recvn(buf, size); +} + +void syscall_uart_write(trapframe *_, const char buf[], size_t size) +{ + uart_sendn(buf, size); +} + +// TODO: Passing argv +void syscall_exec(trapframe *_, const char *name, char *const argv[]) +{ + void *data; + char *kernel_sp; + int datalen, adj_datalen; + struct file f; + int ret; + + ret = vfs_open(name, 0, &f); + + if (ret < 0) { + return; + } + + datalen = f.vnode->v_ops->getsize(f.vnode); + + if (datalen < 0) { + return; + } + + adj_datalen = ALIGN(datalen, PAGE_SIZE); + + data = kmalloc(adj_datalen); + + memzero(data, adj_datalen); + + ret = vfs_read(&f, data, datalen); + + if (ret < 0) { + kfree(data); + return; + } + + vfs_close(&f); + + // Use origin kernel stack + + // TODO: Clear user stack + + kernel_sp = (char *)current->kernel_stack + STACK_SIZE - 0x10; + + // Reset signal + signal_head_reset(current->signal); + sighand_reset(current->sighand); + + // Reset address_space & page table + task_reset_mm(current); + + task_init_map(current); + + // 0x000000000000 ~ : rwx: Code + vma_map(current->address_space, (void *)0, adj_datalen, + VMA_R | VMA_W | VMA_X | VMA_KVA, data); + + set_page_table(current->page_table); + + exec_user_prog((void *)0, (char *)0xffffffffeff0, kernel_sp); +} + +static inline void copy_regs(struct pt_regs *regs) +{ + regs->x19 = current->regs.x19; + regs->x20 = current->regs.x20; + regs->x21 = current->regs.x21; + regs->x22 = current->regs.x22; + regs->x23 = current->regs.x23; + regs->x24 = current->regs.x24; + regs->x25 = current->regs.x25; + regs->x26 = current->regs.x26; + regs->x27 = current->regs.x27; + regs->x28 = current->regs.x28; +} + +void syscall_fork(trapframe *frame) +{ + task_struct *child; + trapframe *child_frame; + + child = task_create(); + + child->kernel_stack = kmalloc(STACK_SIZE); + memncpy(child->kernel_stack, current->kernel_stack, STACK_SIZE); + + // TODO: Implement copy on write + + // Copy address_space + vma_meta_copy(child->address_space, + current->address_space, + current->page_table); + + // Copy signal handler + sighand_copy(child->sighand); + + // Save registers + SAVE_REGS(current); + + // Copy registers + copy_regs(&child->regs); + + // Copy stack related registers + child->regs.fp = KSTACK_VARIABLE(current->regs.fp); + child->regs.sp = KSTACK_VARIABLE(current->regs.sp); + + // https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html + child->regs.lr = &&SYSCALL_FORK_END; + + // Adjust child trapframe + child_frame = KSTACK_VARIABLE(frame); + + child_frame->x0 = 0; + + sched_add_task(child); + + // Set return value + frame->x0 = child->tid; + +SYSCALL_FORK_END: + + asm volatile("nop"); +} + +void syscall_exit(trapframe *_) +{ + exit_user_prog(); + + // Never reach +} + +/* + * TODO: map the return addres of mailbox_call + */ +void syscall_mbox_call(trapframe *_, unsigned char ch, unsigned int *mbox) +{ + int mbox_size; + char *kmbox; + + mbox_size = (int)mbox[0]; + + if (mbox_size <= 0) + return; + + kmbox = kmalloc(mbox_size); + + memncpy(kmbox, (char *)mbox, mbox_size); + + mailbox_call(ch, (unsigned int *)kmbox); + + memncpy((char *)mbox, kmbox, mbox_size); + + kfree(kmbox); +} + +void syscall_kill_pid(trapframe *_, int pid) +{ + task_struct *task; + + if (current->tid == pid) { + exit_user_prog(); + + // Never reach + return; + } + + preempt_disable(); + + task = task_get_by_tid(pid); + + if (!task || task->status != TASK_RUNNING) { + goto SYSCALL_KILL_PID_END; + } + + list_del(&task->list); + kthread_add_wait_queue(task); + +SYSCALL_KILL_PID_END: + preempt_enable(); +} + +// Print the content of spsr_el1, elr_el1 and esr_el1 +void syscall_show_info(trapframe *_) +{ + uint64 spsr_el1; + uint64 elr_el1; + uint64 esr_el1; + + spsr_el1 = read_sysreg(spsr_el1); + elr_el1 = read_sysreg(elr_el1); + esr_el1 = read_sysreg(esr_el1); + + uart_printf("[TEST] spsr_el1: %llx; elr_el1: %llx; esr_el1: %llx\r\n", + spsr_el1, elr_el1, esr_el1); +} \ No newline at end of file diff --git a/lab8/src/kernel/task.c b/lab8/src/kernel/task.c new file mode 100644 index 000000000..95fdfec40 --- /dev/null +++ b/lab8/src/kernel/task.c @@ -0,0 +1,123 @@ +#include +#include +#include +#include +#include + +// TODO: Use rbtree to manage tasks +static struct list_head task_queue; + +// TODO: recycle usable tid +uint32 max_tid; + +static uint32 alloc_tid(void) +{ + uint32 tid; + + tid = max_tid; + max_tid += 1; + + return tid; +} + +void task_init(void) +{ + INIT_LIST_HEAD(&task_queue); +} + +task_struct *task_create(void) +{ + task_struct *task; + struct signal_head_t *signal; + struct sighand_t *sighand; + pd_t *page_table; + vm_area_meta_t *as; + + task = kmalloc(sizeof(task_struct)); + signal = signal_head_create(); + sighand = sighand_create(); + page_table = pt_create(); + as = vma_meta_create(); + + task->address_space = as; + task->kernel_stack = NULL; + task->page_table = page_table; + INIT_LIST_HEAD(&task->list); + list_add_tail(&task->task_list, &task_queue); + task->status = TASK_NEW; + task->need_resched = 0; + task->tid = alloc_tid(); + task->preempt = 0; + + task->signal = signal; + task->sighand = sighand; + + task->work_dir = rootmount->root; + + vfs_open("/dev/uart", 0, &task->fds[0]); + vfs_open("/dev/uart", 0, &task->fds[1]); + vfs_open("/dev/uart", 0, &task->fds[2]); + + task->maxfd = 2; + + return task; +} + +void task_free(task_struct *task) +{ + if (task->kernel_stack) + kfree(task->kernel_stack); + + list_del(&task->task_list); + + signal_head_free(task->signal); + sighand_free(task->sighand); + + vma_meta_free(task->address_space, task->page_table); + pt_free(task->page_table); + + // TODO: release tid + + for (int i = 0; i <= task->maxfd; ++i) { + if (task->fds[i].vnode != NULL) { + vfs_close(&task->fds[i]); + } + } + + kfree(task); +} + +task_struct *task_get_by_tid(uint32 tid) +{ + task_struct *task; + + list_for_each_entry(task, &task_queue, task_list) { + if (task->tid == tid) { + return task; + } + } + + return NULL; +} + +void task_init_map(task_struct *task) +{ + // TODO: map the return addres of mailbox_call + vma_map(task->address_space, (void *)0x3c000000, 0x03000000, + VMA_R | VMA_W | VMA_PA, (void *)0x3c000000); + + vma_map(task->address_space, (void *)0x7f0000000000, TEXT_USER_SHARED_LEN, + VMA_R | VMA_X | VMA_PA, (void *)VA2PA(TEXT_USER_SHARED_BASE)); + + vma_map(task->address_space, (void *)0xffffffffb000, STACK_SIZE, + VMA_R | VMA_W | VMA_ANON, NULL); +} + +void task_reset_mm(task_struct *task) +{ + vma_meta_free(task->address_space, task->page_table); + pt_free(task->page_table); + + task->page_table = pt_create(); + task->address_space = vma_meta_create(); +} \ No newline at end of file diff --git a/lab8/src/kernel/timer.S b/lab8/src/kernel/timer.S new file mode 100644 index 000000000..a3d9a4fb4 --- /dev/null +++ b/lab8/src/kernel/timer.S @@ -0,0 +1,18 @@ +#define CORE0_TIMER_IRQ_CTRL 0x40000040 + +.globl enable_core0_timer +enable_core0_timer: + // Enable cntp timer (EL1 physical timer) + mov x0, 1 + msr cntp_ctl_el0, x0 + + // Set expired time + mrs x0, cntfrq_el0 + msr cntp_tval_el0, x0 + + // Unmask timer interrupt (Enable nCNTPNSIRQ IRQ control) + mov x0, 0x02 + ldr x1, =CORE0_TIMER_IRQ_CTRL + str w0, [x1] + + ret \ No newline at end of file diff --git a/lab8/src/kernel/timer.c b/lab8/src/kernel/timer.c new file mode 100644 index 000000000..79f603226 --- /dev/null +++ b/lab8/src/kernel/timer.c @@ -0,0 +1,314 @@ +#include +#include +#include +#include +#include +#include + +#define CORE0_TIMER_IRQ_CTRL 0x40000040 +#define CORE0_IRQ_SOURCE 0x40000060 + +#define TIMER_PROC_NUM 32 + +static void timer_irq_handler(void *); +static void timer_irq_fini(void); + +typedef struct { + // cb(args) + void (*cb)(void *); + void *args; + uint32 remain_time; + struct list_head list; +} timer_proc; + +typedef struct { + struct list_head head; + int size; +} timer_meta; + +/* Used to store procudures that will be called after a period of time. */ +timer_proc t_procs[TIMER_PROC_NUM]; + +/* Metadata of t_procs. + * The linked list is sorted by remain_time. + */ +timer_meta t_meta; + +/* This variable has 32 bits, n-th bit stands for the status of t_procs[n]. + * If n-th bit is 1, it means t_procs[n] is available. + * If n-th bit is 0, it means t_procs[n] is unavailable. + */ +uint32 t_status; + +/* When setting a timer, this variable will store the interval. + * It is 0 when timer is not set. + */ +uint32 t_interval; + +int timer_show_enable; +uint64 timer_boot_cnt; + +static void timer_enable() +{ + // Enable core0 cntp timer + put32(PA2VA(CORE0_TIMER_IRQ_CTRL), 2); +} + +static void timer_disable() +{ + // Disable core0 cntp timer + put32(PA2VA(CORE0_TIMER_IRQ_CTRL), 0); +} + +static timer_proc *tp_alloc() +{ + uint32 daif; + uint32 idx; + + daif = save_and_disable_interrupt(); + + idx = ffs(t_status); + + if (idx == 0) { + restore_interrupt(daif); + + return NULL; + } + + t_status &= ~(1 << (idx - 1)); + + restore_interrupt(daif); + + return &t_procs[idx - 1]; +} + +static void tp_release(timer_proc *tp) +{ + if (!tp) { + return; + } + + uint32 idx = get_elem_idx(tp, t_procs); + + t_status |= (1 << idx); +} + +/* + * Need to disable interrupt before calling this function. + */ +static void timer_update_remain_time() +{ + timer_proc *iter; + int32 cntp_tval_el0; + uint32 diff; + + if (!t_meta.size) { + return; + } + + cntp_tval_el0 = read_sysreg(cntp_tval_el0); + diff = t_interval - cntp_tval_el0; + t_interval = cntp_tval_el0; + + list_for_each_entry(iter, &t_meta.head, list) { + if (diff > iter->remain_time) { + iter->remain_time = 0; + } else { + iter->remain_time -= diff; + } + } +} + +/* + * Return 1 if @tp was inserted at the first position, otherwise return 0. + */ +static int tp_insert(timer_proc *tp) +{ + uint32 daif; + timer_proc *iter; + int first; + + daif = save_and_disable_interrupt(); + + // Update remain_time + timer_update_remain_time(); + + // Insert tp + first = 1; + list_for_each_entry(iter, &t_meta.head, list) { + if (tp->remain_time < iter->remain_time) { + break; + } + first = 0; + } + + list_add_tail(&tp->list, &iter->list); + + t_meta.size += 1; + + restore_interrupt(daif); + + return first; +} + +/* + * Set timer + */ +static void timer_set() +{ + uint32 daif; + timer_proc *tp; + + daif = save_and_disable_interrupt(); + + if (!t_meta.size) { + restore_interrupt(daif); + + return; + } + + tp = list_first_entry(&t_meta.head, timer_proc, list); + + // Set timer + t_interval = tp->remain_time; + write_sysreg(cntp_tval_el0, t_interval); + + restore_interrupt(daif); +} + +static void timer_set_boot_cnt() +{ + timer_boot_cnt = read_sysreg(cntpct_el0); +} + +static void timer_show_boot_time(void *_) +{ + if (timer_show_enable) { + uint32 cntfrq_el0 = read_sysreg(cntfrq_el0); + uint64 cntpct_el0 = read_sysreg(cntpct_el0); + uart_printf("[Boot time: %lld seconds...]\r\n", + (cntpct_el0 - timer_boot_cnt) / cntfrq_el0); + } + + timer_add_proc_after(timer_show_boot_time, NULL, 2); +} + +void timer_init() +{ + uint64 cntkctl_el1; + + timer_set_boot_cnt(); + + INIT_LIST_HEAD(&t_meta.head); + t_meta.size = 0; + + t_interval = 0; + t_status = 0xffffffff; + + // Allow EL0 to access timer + cntkctl_el1 = read_sysreg(CNTKCTL_EL1); + cntkctl_el1 |= 1; + write_sysreg(CNTKCTL_EL1, cntkctl_el1); + + timer_add_proc_after(timer_show_boot_time, NULL, 2); +} + +int timer_irq_check() +{ + uint32 core0_irq_src = get32(PA2VA(CORE0_IRQ_SOURCE)); + + if (!(core0_irq_src & 0x02)) { + return 0; + } + + timer_disable(); + if (irq_run_task(timer_irq_handler, NULL, timer_irq_fini, 0)) { + timer_enable(); + } + + return 1; +} + +static void timer_irq_handler(void *_) +{ + timer_proc *tp; + + if (!t_meta.size) { + return; + } + + // Set next timer before calling any functions which may interrupt + tp = list_first_entry(&t_meta.head, timer_proc, list); + + list_del(&tp->list); + t_meta.size -= 1; + + timer_update_remain_time(); + timer_set(); + + // Execute the callback function + (tp->cb)(tp->args); + tp_release(tp); +} + +static void timer_irq_fini(void) +{ + timer_enable(); +} + +void timer_switch_info() +{ + timer_show_enable = !timer_show_enable; +} + +static void timer_add_proc(timer_proc *tp) +{ + int need_update; + + need_update = tp_insert(tp); + + if (need_update) { + timer_set(); + timer_enable(); + } +} + +void timer_add_proc_after(void (*proc)(void *), void *args, uint32 after) +{ + timer_proc *tp; + uint32 cntfrq_el0; + + tp = tp_alloc(); + + if (!tp) { + return; + } + + cntfrq_el0 = read_sysreg(cntfrq_el0); + + tp->cb = proc; + tp->args = args; + tp->remain_time = after * cntfrq_el0; + + timer_add_proc(tp); +} + +void timer_add_proc_freq(void (*proc)(void *), void *args, uint32 freq) +{ + timer_proc *tp; + uint32 cntfrq_el0; + + tp = tp_alloc(); + + if (!tp) { + return; + } + + cntfrq_el0 = read_sysreg(cntfrq_el0); + + tp->cb = proc; + tp->args = args; + tp->remain_time = cntfrq_el0 / freq; + + timer_add_proc(tp); +} \ No newline at end of file diff --git a/lab8/src/kernel/waitqueue.c b/lab8/src/kernel/waitqueue.c new file mode 100644 index 000000000..9e2a69484 --- /dev/null +++ b/lab8/src/kernel/waitqueue.c @@ -0,0 +1,50 @@ +#include +#include +#include + +wait_queue_head *wq_create(void) +{ + wait_queue_head *head; + + head = kmalloc(sizeof(wait_queue_head)); + + INIT_LIST_HEAD(&head->list); + + return head; +} + +int wq_empty(wait_queue_head *head) +{ + return list_empty(&head->list); +} + +void wq_add_task(task_struct *task, wait_queue_head *head) +{ + preempt_disable(); + + list_add_tail(&task->list, &head->list); + + preempt_enable(); +} + +void wq_del_task(task_struct *task) +{ + preempt_disable(); + + list_del(&task->list); + + preempt_enable(); +} + +task_struct *wq_get_first_task(wait_queue_head *head) +{ + task_struct *task; + + preempt_disable(); + + task = list_first_entry(&head->list, task_struct, list); + + preempt_enable(); + + return task; +} \ No newline at end of file diff --git a/lab8/src/lib/string.c b/lab8/src/lib/string.c new file mode 100644 index 000000000..76ed9586a --- /dev/null +++ b/lab8/src/lib/string.c @@ -0,0 +1,146 @@ +#include + +int strcmp(const char *str1, const char *str2) +{ + char c1, c2; + + while ((c1 = *str1++) == (c2 = *str2++) && c1 && c2) {}; + + return c1 - c2; +} + +int strncmp(const char *str1, const char *str2, int n) +{ + char c1, c2; + + if (n <= 0) + return 0; + + while ((c1 = *str1++) == (c2 = *str2++) && c1 && c2 && --n > 0) {}; + + return n ? c1 - c2 : 0; +} + +int strcasecmp(const char *s1, const char *s2) +{ + char c1, c2; + + while (1) { + c1 = *s1++; + c2 = *s2++; + + if (!c1 || !c2) { + break; + } + + if ('A' <= c1 && c1 <= 'Z') { + c1 |= 0x20; + } + + if ('A' <= c2 && c2 <= 'Z') { + c2 |= 0x20; + } + + if (c1 != c2) { + break; + } + } + + return c1 - c2; +} + +int strlen(const char *str) +{ + int ret = 0; + + while (*str++) { + ret += 1; + } + + return ret; +} + +int strcpy(char *dst, const char *src) +{ + int ret = 0; + + while (*src) { + *dst = *src; + dst++; + src++; + ret++; + } + + *dst = '\0'; + + return ret; +} + +char *strcat(char *dest, const char *src) +{ + char *t; + + t = dest; + + while (*t) { + t++; + } + + while (*src) { + *t = *src; + t++; + src++; + } + + *t = '\0'; + + return dest; +} + +char *strncat(char *dest, const char *src, int n) +{ + char *t; + + t = dest; + + while (*t) { + t++; + } + + while (n > 0 && *src) { + *t = *src; + t++; + src++; + n--; + } + + *t = '\0'; + + return dest; +} + +int atoi(const char *str) +{ + int i = 0, tmp = 0; + + while (*str) { + if ('0' > *str || *str > '9') { + return 0; + } + + i *= 10; + + tmp = i + (*str - '0'); + + if (tmp < i) { + // Maybe overflow + return 0; + } + + i = tmp; + + str++; + } + + return i; +} diff --git a/lab8/src/lib/utils.S b/lab8/src/lib/utils.S new file mode 100644 index 000000000..34aa2d825 --- /dev/null +++ b/lab8/src/lib/utils.S @@ -0,0 +1,47 @@ +.globl put32 +put32: + str w1, [x0] + ret + +.globl get32 +get32: + ldr w0, [x0] + ret + +.globl delay +delay: + subs x0, x0, #1 + bne delay + ret + +.globl memzero +memzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero + ret + +.globl memncpy +memncpy: + b memncpy_1_cmp +memncpy_1: + ldrb w3, [x1], #1 + strb w3, [x0], #1 + subs x2, x2, #1 +memncpy_1_cmp: + cmp x2, 1 + bge memncpy_1 +memncpy_ok: + ret + +.globl memset +memset: + b memset_1_cmp +memset_1: + strb w1, [x0], #1 + subs x2, x2, #1 +memset_1_cmp: + cmp x2, 1 + bge memset_1 +memset_ok: + ret \ No newline at end of file diff --git a/lab8/tools/buildimg.sh b/lab8/tools/buildimg.sh new file mode 100644 index 000000000..e36fd7f21 --- /dev/null +++ b/lab8/tools/buildimg.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +# $1: bootloader.img +# $2: target.img (which will be dd to sd-card) +# $3: initramfs.cpio + +echo "[*] Mount $2 to ./mnt ..." +mkdir -p mnt + +# sudo losetup --partscan --show --find test.img +LOOPBACK=`sudo losetup --partscan --show --find $2` + +echo "[*] Create loopback" ${LOOPBACK} + +# "$LOOPBACK" is some string like "/dev/loop0" +echo ${LOOPBACK} | grep --quiet "/dev/loop" + +if [ $? = 1 ] +then + echo "[!] losetup failed!" + exit 1 +fi + +# sudo mkfs.vfat -F 32 /dev/loop0p1 +sudo mkfs.vfat -F 32 ${LOOPBACK}p1 + +# sudo mount /dev/loop0p1 mnt +sudo mount ${LOOPBACK}p1 mnt + +echo "[*] Copy the necessary files to $2 ..." +sudo cp -r img/* mnt + +echo "[*] Copy booting image $1 to $2 ..." +sudo cp $1 mnt/bootloader.img + +# echo "[*] Copy kernel image prebuild/kernel8.img to $2 ..." +# sudo cp prebuild/kernel8.img mnt/kernel8.img + +echo "[*] Copy initrmafs.cpio $3 to $2 ..." +sudo cp $3 mnt/initramfs.cpio + +echo "[*] Umount $2 ..." +sudo umount mnt + +# sudo losetup -d /dev/loop0 +sudo losetup -d ${LOOPBACK} + +echo "[*] Use following command to write $2 to your SD card:" +echo "\t" "dd if=./$2 of=/dev/" +echo "[*] Use following command to check your SD card device:" +echo "\t" "lsblk" \ No newline at end of file diff --git a/lab8/tools/createimg.sh b/lab8/tools/createimg.sh new file mode 100644 index 000000000..aa3ee33bd --- /dev/null +++ b/lab8/tools/createimg.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +truncate -s 50M $1 + +# fdisk test.img +( +echo o # Create a new empty DOS partition table +echo n # Add a new partition +echo p # Primary partition +echo 1 # Partition number +echo # First sector (Accept default: 1) +echo # Last sector (Accept default: varies) +echo t # Change partition type +echo c # Master Boot Record primary partitions type:LBA +echo w # Write changes +) | sudo fdisk $1 + +# sudo losetup --partscan --show --find test.img +LOOPBACK=`sudo losetup --partscan --show --find $1` + +# "$LOOPBACK" is some string like "/dev/loop0" +echo ${LOOPBACK} | grep --quiet "/dev/loop" + +if [ $? = 1 ] +then + echo "[!] losetup failed!" + exit 1 +fi + +# sudo mkfs.vfat -F 32 /dev/loop0p1 +sudo mkfs.vfat -F 32 ${LOOPBACK}p1 + +# sudo losetup -d /dev/loop0 +sudo losetup -d ${LOOPBACK} \ No newline at end of file diff --git a/lab8/tools/loadkernel.py b/lab8/tools/loadkernel.py new file mode 100644 index 000000000..2569cb600 --- /dev/null +++ b/lab8/tools/loadkernel.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +import sys +import argparse +import struct +import serial +import time + +def pty_mode(args): + with open(args.filepath, 'rb') as f: + kernel = f.read() + + with open(args.devpath, 'wb', buffering = 0) as f: + f.write(struct.pack('/dev/null 2>/dev/null || true + +run: + qemu-system-aarch64 -M raspi3b -serial null -serial stdio -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb -display none -kernel kernel8.img diff --git a/lab_asyn/shell/allocator.c b/lab_asyn/shell/allocator.c new file mode 100644 index 000000000..4ca648ee9 --- /dev/null +++ b/lab_asyn/shell/allocator.c @@ -0,0 +1,20 @@ +#include "header/allocator.h" +#include "header/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; +} diff --git a/lab_asyn/shell/allocator.o b/lab_asyn/shell/allocator.o new file mode 100644 index 000000000..42047e4bf Binary files /dev/null and b/lab_asyn/shell/allocator.o differ diff --git a/lab_asyn/shell/bcm2710-rpi-3-b-plus.dtb b/lab_asyn/shell/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..0dd0e2f43 Binary files /dev/null and b/lab_asyn/shell/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab_asyn/shell/cpio.c b/lab_asyn/shell/cpio.c new file mode 100644 index 000000000..a38879c9c --- /dev/null +++ b/lab_asyn/shell/cpio.c @@ -0,0 +1,96 @@ +#include "header/cpio.h" +#include "header/uart.h" +#include "header/utils.h" +#include "header/allocator.h" + +int file_num = 0; +struct file *f = NULL; + +void allocate_file_array() { + if (f == NULL) { + f = (struct file *)simple_malloc(MAX_FILE_NUM * sizeof(struct file)); + if (f == NULL) { + uart_send_string("Memory allocation error\n"); + // Handle memory allocation error + } + } +} + +void traverse_file() +{ + allocate_file_array(); + char* addr = (char *)cpio_addr; + + + while(utils_string_compare((char *)(addr+sizeof(struct cpio_header)),"TRAILER!!!") == 0){ + + struct cpio_header *header = (struct cpio_header *)addr; + unsigned long filename_size = utils_atoi(header->c_namesize, (int)sizeof(header->c_namesize)); + unsigned long headerPathname_size = sizeof(struct cpio_header) + filename_size; + unsigned long file_size = utils_atoi(header->c_filesize, (int)sizeof(header->c_filesize)); + + utils_align(&headerPathname_size, 4); + utils_align(&file_size, 4); + + f[file_num].file_header = header; + f[file_num].filename_size = filename_size; + f[file_num].headerPathname_size = headerPathname_size; + f[file_num].file_size = file_size; + f[file_num].file_content_head = (char*) header + headerPathname_size; + + addr += (headerPathname_size + file_size); + file_num += 1; + } +} + +int findfile(char* filename) { + for(int n=0;n<=file_num;n++) { + if ((utils_string_compare(((char *)f[n].file_header)+sizeof(struct cpio_header), filename) != 0)){ + return n; + } + } + return -1; +} + +void cpio_ls() +{ + for(int n=0;n<=file_num;n++) { + uart_send_string(((char *)f[n].file_header)+sizeof(struct cpio_header)); + uart_send_string("\n"); + } +} + + +void cpio_cat(char *filename) +{ + int targetfile_num = findfile(filename); + + if(targetfile_num != -1) { + for (unsigned int i = 0; i < f[targetfile_num].file_size; i++) + { + uart_send_char(f[targetfile_num].file_content_head[i]); + } + uart_send_string("\n"); + + } else { + uart_send_string("Can not Find the file\n"); + } + +} + +void cpio_exec_program(char* filename) { + int targetfile_num = findfile(filename); + + char* target = (char*) 0x20000; + for(unsigned i = 0; imagic)); + + if (magic != 0xd00dfeed){ + + uart_send_string("The header magic is wrong\n"); + return -1; + } + + /* + +-----------------+ + | fdt_header | <- dtb_ptr + +-----------------+ + | reserved memory | + +-----------------+ + | structure block | <- dtb_ptr + header->off_dt_struct (struct_ptr) + +-----------------+ + | strings block | <- dtb_ptr + header->off_dt_strings (strings_ptr) + +-----------------+ + */ + + 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); + parse_struct(cb, struct_ptr,strings_ptr,totalsize); + return 1; + +} + +//5. Implement the initramfs_callback function: +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_string("cpio address is at: "); + uart_hex((uintptr_t)fdt_u32_le2be(data)); + // uart_send_char('\n'); + uart_send_string("\r\n"); + } +} + +//6. Implement print_dtb callback function: + +void print_dtb(int token, const char* name, const void* data, uint32_t size) { + UNUSED(data); + UNUSED(size); + + switch(token){ + case FDT_BEGIN_NODE: + uart_send_string("\n"); + send_space(space); + uart_send_string((char*)name); + uart_send_string("{\n "); + space++; + break; + case FDT_END_NODE: + uart_send_string("\n"); + space--; + if(space >0) send_space(space); + uart_send_string("}\n"); + break; + case FDT_NOP: + break; + case FDT_PROP: + send_space(space); + uart_send_string((char*)name); + break; + case FDT_END: + break; + } +} diff --git a/lab_asyn/shell/dtb.o b/lab_asyn/shell/dtb.o new file mode 100644 index 000000000..52e6b26dd Binary files /dev/null and b/lab_asyn/shell/dtb.o differ diff --git a/lab_asyn/shell/except.c b/lab_asyn/shell/except.c new file mode 100644 index 000000000..54f355426 --- /dev/null +++ b/lab_asyn/shell/except.c @@ -0,0 +1,166 @@ + +#include "header/uart.h" +#include "header/irq.h" +#include "header/shell.h" +#include "header/timer.h" +#include "header/tasklist.h" +#include "header/utils.h" + +#define CNTPSIRQ_BIT_POSITION 0x02 +#define AUXINIT_BIT_POSTION 1<<29 + + +void except_handler_c() { + uart_send_string("In Exception handle\n"); + + //read spsr_el1 + unsigned long long spsr_el1 = 0; + asm volatile("mrs %0, spsr_el1":"=r"(spsr_el1)); + uart_send_string("spsr_el1: "); + uart_hex(spsr_el1); + uart_send_string("\n"); + + //read elr_el1 + unsigned long long elr_el1 = 0; + asm volatile("mrs %0, elr_el1":"=r"(elr_el1)); + uart_send_string("elr_el1: "); + uart_hex(elr_el1); + uart_send_string("\n"); + + //esr_el1 + unsigned long long esr_el1 = 0; + asm volatile("mrs %0, esr_el1":"=r"(esr_el1)); + uart_hex(esr_el1); + uart_send_string("\n"); + + //ec + unsigned ec = (esr_el1 >> 26) & 0x3F; //0x3F = 0b111111(6) + uart_send_string("ec: "); + uart_hex(ec); + uart_send_string("\n"); + + + while(1){ + + } + +} + +void timer_irq_handler() { + //enable core_0_timer + unsigned int* address = (unsigned int*) CORE0_TIMER_IRQ_CTRL; + *address = 2; + + asm volatile("msr cntp_ctl_el0,%0"::"r"(0)); + // Disable interrupts to protect critical section + asm volatile("msr DAIFSet, 0xf"); + + uint64_t current_time; + asm volatile("mrs %0, cntpct_el0":"=r"(current_time)); + + while(timer_head && timer_head->expiry <= current_time) { + timer_t *timer = timer_head; + + //Execute the callback + timer->callback(timer->data); + + // Remove timer from the list + timer_head = timer->next; + if (timer_head) { + timer_head->prev = NULL; + } + + //free timer + + // Reprogram the hardware timer if there are still timers left + if(timer_head) { + asm volatile("msr cntp_cval_el0, %0"::"r"(timer_head->expiry)); + asm volatile("msr cntp_ctl_el0,%0"::"r"(1)); + } else { + asm volatile("msr cntp_ctl_el0,%0"::"r"(0)); + } + + + //enable interrupt + asm volatile("msr DAIFClr,0xf"); + } + +} + +void uart_irq_handler(){ + // uart_send_string("in uart_irq_handler\n"); + ///uart_hex(uart_write_index); + ///uart_hex(uart_write_head); + ///uart_send_string("\r\n"); + uint32_t iir = mmio_read(AUX_MU_IIR); + + // IF Receive Interrupt + if ((iir & 0x06) == 0x04) { + // Read data(8 bytes) and store it in the read buffer + uart_send_string("in uart_irq_handler_receive\n"); + char data = mmio_read(AUX_MU_IO) & 0xff; + uart_read_buffer[uart_read_index++] = data; + if (uart_read_index >= UART_BUFFER_SIZE) { + uart_read_index = 0; + } + + // Enqueue the received data into the write buffer for echo + uart_write_buffer[uart_write_index++] = data; + // uart_send_string(&data); + if (uart_write_index >= UART_BUFFER_SIZE) { + uart_write_index = 0; + } + + // Enable tx interrupt + mmio_write(AUX_MU_IER, mmio_read(AUX_MU_IER) | 0x2); + } + + // IF Transmit Interrupt + if ((iir & 0x06) == 0x02) { + if (uart_write_head >= UART_BUFFER_SIZE) { + uart_write_head = 0; + } + uart_send_string("in uart_irq_handler_transmit\n"); + // uart_hex(uart_write_index); + // uart_hex(uart_write_head); + // Send data from the write buffer + if (uart_write_head != uart_write_index) { + uart_send_string("in uart_irq_handler_trans idx!=\n"); + char data = uart_write_buffer[uart_write_head]; + // uart_send_char(data); + // uart_send_string("\r\n"); + // mmio_write(AUX_MU_IO, 0); + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); + *AUX_MU_IO = (unsigned int) data; + uart_send_string("\r\n"); + uart_write_head++; + // mmio_write(AUX_MU_IO, uart_write_buffer[uart_write_head++]); + // uart_write_head ++; + if (uart_write_index >= UART_BUFFER_SIZE) { + uart_write_index = 0; + } + } + else + { + uart_send_string("in uart_irq_handler_trans idx=\n"); + uart_send_string("----------------------------------\n"); + // Disable tx interrupt when there is no data left to send + mmio_write(AUX_MU_IER, mmio_read(AUX_MU_IER) & ~0x2); + // mmio_write(AUX_MU_IO, 0); + + /* + if(uart_read_buffer[uart_read_index-1] == '\r' || uart_read_buffer[uart_read_index-1] == '\n'){ + uart_read_buffer[uart_read_index-1] = '\0'; + uart_read_index = 0; + uart_write_index = 0; + uart_write_head = 0; + // parse_command(uart_read_buffer); + // uart_write_index = 0; + } + */ + } + } + // uart_send_string("out uart_irq_handler\n"); +} + + diff --git a/lab_asyn/shell/except.o b/lab_asyn/shell/except.o new file mode 100644 index 000000000..7fbb0e527 Binary files /dev/null and b/lab_asyn/shell/except.o differ diff --git a/lab_asyn/shell/header/allocator.h b/lab_asyn/shell/header/allocator.h new file mode 100644 index 000000000..56f46666f --- /dev/null +++ b/lab_asyn/shell/header/allocator.h @@ -0,0 +1,7 @@ +#ifndef ALLOCATOR_H +#define ALLOCATOR_H + + +void* simple_malloc(unsigned long size); + +#endif diff --git a/lab_asyn/shell/header/cpio.h b/lab_asyn/shell/header/cpio.h new file mode 100644 index 000000000..be0e36b9f --- /dev/null +++ b/lab_asyn/shell/header/cpio.h @@ -0,0 +1,39 @@ +//#define QEMU_CPIO_ADDR (char *)0x8000000; //qemu +//#define RASP_CPIO_ADDR (char *)0x20000000;//rasperrypi + +#define MAX_FILE_NUM 10 + +extern char* cpio_addr; + +void traverse_file(); +void cpio_ls(); +void cpio_cat(char* filename); +void cpio_exec_program(char* filename); + +struct 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 file { + struct cpio_header* file_header; + unsigned long filename_size; + unsigned long headerPathname_size; + unsigned long file_size; + char* file_content_head; +}; + diff --git a/lab_asyn/shell/header/dtb.h b/lab_asyn/shell/header/dtb.h new file mode 100644 index 000000000..16af25520 --- /dev/null +++ b/lab_asyn/shell/header/dtb.h @@ -0,0 +1,26 @@ +#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 type,const char* name,const void *data,uint32_t size); + +struct __attribute__((packed)) fdt_header { + uint32_t magic; // contain the value 0xd00dfeed (big-endian). + uint32_t totalsize; // in byte + uint32_t off_dt_struct; // the offset in bytes of the structure block from the beginning of the header + 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; // the length in bytes of the strings block section + uint32_t size_dt_struct; +}; + +int fdt_traverse(fdt_callback cb,void *dtb_ptr); +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); diff --git a/lab_asyn/shell/header/gpio.h b/lab_asyn/shell/header/gpio.h new file mode 100644 index 000000000..38ca70635 --- /dev/null +++ b/lab_asyn/shell/header/gpio.h @@ -0,0 +1,38 @@ +#ifndef GPIO_H +#define GPIO_H + +#include +//Page 90, Physical/bus addr diff +#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 diff --git a/lab_asyn/shell/header/irq.h b/lab_asyn/shell/header/irq.h new file mode 100644 index 000000000..9085cb30c --- /dev/null +++ b/lab_asyn/shell/header/irq.h @@ -0,0 +1,22 @@ +#ifndef IRQ_H +#define IRQ_H + +#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 CORE0_TIMER_IRQ_CTRL ((volatile unsigned int*)(0x40000040)) +#define CORE0_INTERRUPT_SOURCE ((volatile unsigned int*)(0x40000060)) + + +#endif + diff --git a/lab_asyn/shell/header/mailbox.h b/lab_asyn/shell/header/mailbox.h new file mode 100644 index 000000000..d13ac3ce9 --- /dev/null +++ b/lab_asyn/shell/header/mailbox.h @@ -0,0 +1,38 @@ +#include "gpio.h" + +extern volatile unsigned int mailbox[36]; + +#define MBOX_REQUEST 0 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define TAG_REQUEST_CODE 0x00000000 +#define MBOX_TAG_GETSERIAL 0x00010004 +#define MBOX_TAG_GETBOARD 0x00010002 +#define MBOX_TAG_GETARMMEM 0x00010005 +#define MBOX_TAG_LAST 0x00000000 + +int mailbox_call(); +void get_board_revision(); +void get_arm_mem(); + +#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880) +#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0)) +#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10)) +#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14)) +#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18)) +#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C)) +#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20)) +#define MBOX_RESPONSE 0x80000000 +#define MBOX_FULL 0x80000000 +#define MBOX_EMPTY 0x40000000 diff --git a/lab_asyn/shell/header/reboot.h b/lab_asyn/shell/header/reboot.h new file mode 100644 index 000000000..e1d44aa1b --- /dev/null +++ b/lab_asyn/shell/header/reboot.h @@ -0,0 +1,8 @@ +#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(); diff --git a/lab_asyn/shell/header/shell.h b/lab_asyn/shell/header/shell.h new file mode 100644 index 000000000..9784c1ccb --- /dev/null +++ b/lab_asyn/shell/header/shell.h @@ -0,0 +1,2 @@ +void shell(); +void parse_command(char* buffer); diff --git a/lab_asyn/shell/header/tasklist.h b/lab_asyn/shell/header/tasklist.h new file mode 100644 index 000000000..de876b84c --- /dev/null +++ b/lab_asyn/shell/header/tasklist.h @@ -0,0 +1,21 @@ +#ifndef TASKLIST_H +#define TASKLIST_H + +// #include +#include + +typedef void (*task_callback)(); + +typedef struct task { + struct task *prev; + struct task *next; + task_callback callback; + uint64_t priority; +} task_t; + +void execute_tasks(); +void create_task(task_callback callback,uint64_t priority); +void enqueue_task(task_t *new_task); +extern task_t *task_head; + +#endif diff --git a/lab_asyn/shell/header/timer.h b/lab_asyn/shell/header/timer.h new file mode 100644 index 000000000..a9a8c65da --- /dev/null +++ b/lab_asyn/shell/header/timer.h @@ -0,0 +1,20 @@ +#ifndef TIMER_H +#define TIMER_H + +#include +// #include + +typedef void (*timer_callback)(void *data); + +typedef struct timer { + struct timer *prev; // previous timer in the list + struct timer *next; // next timer in the list + timer_callback callback; // the function to call when the timer expires + void *data; // data to be passed to the callback + uint64_t expiry; // the time at which the timer will expire +} timer_t; + +extern timer_t *timer_head; // head of the timer list + +void setTimeout(char *message,uint64_t seconds); +#endif diff --git a/lab_asyn/shell/header/uart.h b/lab_asyn/shell/header/uart.h new file mode 100644 index 000000000..0c3ff1bd8 --- /dev/null +++ b/lab_asyn/shell/header/uart.h @@ -0,0 +1,39 @@ +#ifndef UART_H +#define UART_H + +#include "gpio.h" +#include +#define UART_BUFFER_SIZE 1024 + +void uart_init(); +void uart_send_char(unsigned int c); +char uart_get_char(); +void uart_send_string(char* s); +void uart_hex(unsigned long long d); +void uart_enable_interrupt(); +int uart_async_read(char *buffer); +void uart_async_write(const char *buffer, int length); +void uart_async_send(const char *str); + + +extern char uart_read_buffer[UART_BUFFER_SIZE]; +extern char uart_write_buffer[UART_BUFFER_SIZE]; +extern int uart_read_index; +extern int uart_read_head; +extern int uart_write_index; +extern int uart_write_head; + +#define AUX_ENABLE ((volatile unsigned int*)(MMIO_BASE+0x00215004)) +#define AUX_MU_IO ((volatile unsigned int*)(MMIO_BASE+0x00215040)) +#define AUX_MU_IER ((volatile unsigned int*)(MMIO_BASE+0x00215044)) +#define AUX_MU_IIR ((volatile unsigned int*)(MMIO_BASE+0x00215048)) +#define AUX_MU_LCR ((volatile unsigned int*)(MMIO_BASE+0x0021504C)) +#define AUX_MU_MCR ((volatile unsigned int*)(MMIO_BASE+0x00215050)) +#define AUX_MU_LSR ((volatile unsigned int*)(MMIO_BASE+0x00215054)) +#define AUX_MU_MSR ((volatile unsigned int*)(MMIO_BASE+0x00215058)) +#define AUX_MU_SCRATCH ((volatile unsigned int*)(MMIO_BASE+0x0021505C)) +#define AUX_MU_CNTL ((volatile unsigned int*)(MMIO_BASE+0x00215060)) +#define AUX_MU_STAT ((volatile unsigned int*)(MMIO_BASE+0x00215064)) +#define AUX_MU_BAUD ((volatile unsigned int*)(MMIO_BASE+0x00215068)) + +#endif diff --git a/lab_asyn/shell/header/utils.h b/lab_asyn/shell/header/utils.h new file mode 100644 index 000000000..3ba6dd719 --- /dev/null +++ b/lab_asyn/shell/header/utils.h @@ -0,0 +1,25 @@ +#include +// #include + +#define nop asm volatile("nop") + +#ifdef _cplusplus +#define NULL 0 +#else +#define NULL (void*)0 +#endif + +#ifndef __SIZE_TYPE__ +#define __SIZE_TYPE__ long unsigned int +#endif +// #if !(defined (__GNUG__) && defined (size_t)) +typedef __SIZE_TYPE__ size_t; + + +int utils_string_compare(const char* i, const char* j); +unsigned long utils_atoi(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); +char *utils_strcpy(char* dst, const char *src); +char *utils_strdup(const char *src); diff --git a/lab_asyn/shell/initramfs.cpio b/lab_asyn/shell/initramfs.cpio new file mode 100644 index 000000000..faf47b52f Binary files /dev/null and b/lab_asyn/shell/initramfs.cpio differ diff --git a/lab_asyn/shell/kernel8.elf b/lab_asyn/shell/kernel8.elf new file mode 100644 index 000000000..d614a9c4d Binary files /dev/null and b/lab_asyn/shell/kernel8.elf differ diff --git a/lab_asyn/shell/kernel8.img b/lab_asyn/shell/kernel8.img new file mode 100644 index 000000000..b2bad916e Binary files /dev/null and b/lab_asyn/shell/kernel8.img differ diff --git a/lab_asyn/shell/linker.ld b/lab_asyn/shell/linker.ld new file mode 100644 index 000000000..5018defb6 --- /dev/null +++ b/lab_asyn/shell/linker.ld @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +SECTIONS +{ + . = 0x80000; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { . = ALIGN(16); *(.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/lab_asyn/shell/mailbox.c b/lab_asyn/shell/mailbox.c new file mode 100644 index 000000000..7e0c5d99c --- /dev/null +++ b/lab_asyn/shell/mailbox.c @@ -0,0 +1,51 @@ +#include "header/mailbox.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){ + /* is it a valid successful response? */ + if(mailbox[1] == MBOX_RESPONSE) + return 1; + } + } + 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. +} diff --git a/lab_asyn/shell/mailbox.o b/lab_asyn/shell/mailbox.o new file mode 100644 index 000000000..8e2118f24 Binary files /dev/null and b/lab_asyn/shell/mailbox.o differ diff --git a/lab_asyn/shell/main.c b/lab_asyn/shell/main.c new file mode 100644 index 000000000..09914b45e --- /dev/null +++ b/lab_asyn/shell/main.c @@ -0,0 +1,81 @@ +#include "header/uart.h" +#include "header/shell.h" +#include "header/dtb.h" +#include "header/utils.h" +#include "header/cpio.h" +#include "header/timer.h" + +void test_read_command(char* buffer) { + int index = 0; + while(1) { + buffer[index] = uart_get_char(); + if(buffer[index] == '\n') { + buffer[index] = '\0'; + buffer[index+1] = '\n'; + uart_send_string("\r\n"); + break; + } + else + { + uart_send_char(buffer[index]); + } + index++; + } +} + +extern void *_dtb_ptr; +void main() +{ + + uart_init(); + // pre test ////////////////////////// + char buffer[256]; + while(1) + { + uart_send_string("# "); + test_read_command(buffer); + char * input_string = buffer; + if(utils_string_compare(input_string,"in")) + { + break; + } + else + { + // uart_send_hex((uintptr_t) _dtb_addr); + uart_send_string("The instruct is not exist.\n"); + } + } + ///////////////////////////////////////// + + // set up serial console + uart_init(); + + unsigned long el = 0; + asm volatile ("mrs %0, CurrentEL":"=r"(el)); + uart_send_string("Current exception level: "); + uart_hex(el>>2); // CurrentEL store el level at [3:2] + uart_send_string("\r\n"); + + asm volatile("mov %0, sp"::"r"(el)); + uart_send_string("Current stack pointer address: "); + uart_hex(el); + uart_send_string("\r\n"); + + // say hello + fdt_traverse(get_cpio_addr,_dtb_ptr); + traverse_file(); + uart_send_string("Type in `help` to get instruction menu!\n"); + + uart_enable_interrupt(); + + shell(); + /* + while(1){ + asm volatile("nop"); + } + */ + //echo everything back + //shell(); +} + + diff --git a/lab_asyn/shell/main.o b/lab_asyn/shell/main.o new file mode 100644 index 000000000..c24ccc361 Binary files /dev/null and b/lab_asyn/shell/main.o differ diff --git a/lab_asyn/shell/reboot.c b/lab_asyn/shell/reboot.c new file mode 100644 index 000000000..048f2d348 --- /dev/null +++ b/lab_asyn/shell/reboot.c @@ -0,0 +1,16 @@ +#include "header/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); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick +} + +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} diff --git a/lab_asyn/shell/reboot.o b/lab_asyn/shell/reboot.o new file mode 100644 index 000000000..dda9e2825 Binary files /dev/null and b/lab_asyn/shell/reboot.o differ diff --git a/lab_asyn/shell/rootfs/file1.txt b/lab_asyn/shell/rootfs/file1.txt new file mode 100644 index 000000000..5c275ef57 --- /dev/null +++ b/lab_asyn/shell/rootfs/file1.txt @@ -0,0 +1 @@ +This is file one. diff --git a/lab_asyn/shell/rootfs/one.img b/lab_asyn/shell/rootfs/one.img new file mode 100644 index 000000000..13bb5c616 Binary files /dev/null and b/lab_asyn/shell/rootfs/one.img differ diff --git a/lab_asyn/shell/rootfs/pack.sh b/lab_asyn/shell/rootfs/pack.sh new file mode 100644 index 000000000..d837d685d --- /dev/null +++ b/lab_asyn/shell/rootfs/pack.sh @@ -0,0 +1,2 @@ +find . | cpio -o -H newc > ../initramfs.cpio + diff --git a/lab_asyn/shell/rootfs/thisisfile2.txt b/lab_asyn/shell/rootfs/thisisfile2.txt new file mode 100644 index 000000000..0a8a2c0d7 --- /dev/null +++ b/lab_asyn/shell/rootfs/thisisfile2.txt @@ -0,0 +1 @@ +Here is file two with longer size. diff --git a/lab_asyn/shell/shell.c b/lab_asyn/shell/shell.c new file mode 100644 index 000000000..8a4702237 --- /dev/null +++ b/lab_asyn/shell/shell.c @@ -0,0 +1,141 @@ +#include "header/shell.h" +#include "header/uart.h" +#include "header/utils.h" +#include "header/mailbox.h" +#include "header/reboot.h" +#include "header/cpio.h" +#include "header/allocator.h" +#include "header/dtb.h" +#include "header/irq.h" +#include "header/timer.h" +#define BUFFER_MAX_SIZE 256u + + +extern void *_dtb_ptr; + +void async_read_command(char* buffer) { + int index = 0; + char tmp[1]; + + while (1) { + if (uart_async_read(tmp) > 0) { + buffer[index] = tmp[0]; + // uart_send_char(tmp[0]); + if (tmp[0] == '\r' || tmp[0] == '\n' || tmp[0] == '\0') { + buffer[index] = '\0'; + break; + } + index++; + } + } + // uart_send_string("out read_commandppppppppppppppp\n"); +} + + +void parse_command(char* buffer){ + uart_send_string("in parse command ========================\n"); + char* input_string = buffer; + char* parameter[5]; //5 is the available parameter length + int para_idx = 0; + int input_string_len = utils_strlen(input_string); + for(int i=0; i < input_string_len; i++){ + if(*(input_string+i) == ' '){ + *(input_string+i) = '\0'; + parameter[para_idx++] = (input_string+i+1); + } + } + + if(utils_string_compare(input_string,"help")) { + uart_async_send("help :print this help menu\n"); + uart_async_send("hello :print Hello World!\n"); + uart_async_send("info :Get the hardware's information\n"); + uart_async_send("reboot :reboot the device\n"); + uart_async_send("ls :list the file\n"); + uart_async_send("cat :print file content\n"); + uart_async_send("malloc :give dynamic memory space\n"); + uart_async_send("dtb :print device tree\n"); + uart_async_send("exec :execute user program\n"); + } else if (utils_string_compare(input_string,"hello")) { + // uart_send_string("Hello World!\n"); + uart_async_send("Hi\n"); + } else if (utils_string_compare(input_string,"info")) { + get_board_revision(); + uart_async_send("My board revision is: "); + uart_hex(mailbox[5]); + uart_async_send("\n"); + get_arm_mem(); + uart_async_send("My ARM memory base address is: "); + uart_hex(mailbox[5]); + uart_async_send("\n"); + uart_async_send("My ARM memory size is: "); + uart_hex(mailbox[6]); + uart_async_send("\n"); + } else if (utils_string_compare(input_string,"reboot")) { + uart_async_send("Rebooting....\n"); + reset(1000); + } else if (utils_string_compare(input_string,"ls")) { + cpio_ls(); + } else if (utils_string_compare(input_string,"cat")){ + //uart_send_string("Filename: "); + //char filename[BUFFER_MAX_SIZE]; + //read_command(filename); + //cpio_cat(filename); + cpio_cat(parameter[0]); + } else if (utils_string_compare(input_string,"malloc")){ + char *a = simple_malloc(sizeof("9876")); + char *b = simple_malloc(sizeof("345")); + a[0] = '9'; + a[1] = '8'; + a[2] = '7'; + a[3] = '6'; + a[4] = '\0'; + b[0] = '3'; + b[1] = '4'; + b[2] = '5'; + b[3] = '\0'; + uart_async_send(a); + uart_async_send("\n"); + uart_async_send(b); + uart_async_send("\n"); + } else if (utils_string_compare(input_string,"dtb")) { + fdt_traverse(print_dtb,_dtb_ptr); + } else if (utils_string_compare(input_string,"exec")) { + //uart_send_string("Program name: "); + //char buffer[BUFFER_MAX_SIZE]; + //read_command(buffer); + cpio_exec_program(parameter[0]); + } else if (utils_string_compare(input_string,"timer")) { + + setTimeout("hello world1",3); + setTimeout("hello world2",6); + setTimeout("hello world3",9); + + } else if (utils_string_compare(input_string,"settimeout")) { + char *message = (char *)parameter[0]; + size_t second_str_len = utils_strlen(parameter[1]); + uint64_t seconds = (uint64_t) utils_atoi(parameter[1],second_str_len-1); + setTimeout(message,seconds); + } else { + uart_async_send("The instruction "); + uart_async_send(input_string); + uart_async_send(" is not exist.\n"); + } + // uart_send_string("out parse command\n"); +} + + +void shell(){ + while(1) { + // uart_send_string("in shell\n"); + char buffer[BUFFER_MAX_SIZE]; + uart_send_string("# "); + async_read_command(buffer); + // uart_send_string("testyyyyyyyyyyyyyyyyyyyyyyy\n"); + parse_command(buffer); + // uart_send_string("out shell\n"); + } + +} + + + diff --git a/lab_asyn/shell/shell.o b/lab_asyn/shell/shell.o new file mode 100644 index 000000000..6f1dc7949 Binary files /dev/null and b/lab_asyn/shell/shell.o differ diff --git a/lab_asyn/shell/start.S b/lab_asyn/shell/start.S new file mode 100644 index 000000000..4f9f5ba36 --- /dev/null +++ b/lab_asyn/shell/start.S @@ -0,0 +1,163 @@ + +.section ".text.kernel" + +.global _start + + + +_start: + ldr x1, =_dtb_ptr //put _dtb_ptr into register1 + str x0, [x1] //store dtb address from x0 to _dtb_ptr + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, 2f + // cpu id > 0, stop +1: wfe + b 1b +2: // cpu id == 0 + + ldr x1, =_start + bl from_el2_to_el1 + mov sp, x1 + + + /* set exception vector table */ + adr x0, exception_vector_table + msr vbar_el1, x0 // vbar -> Vector Base Address Register + + //bl core_timer_enable + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size + +3: cbz w2, 4f + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, 3b + //bl core_timer_enable + // jump to C code, should not return +4: bl main + // for failsafe, halt this core too + b 1b + +from_el2_to_el1: + mov x0,#(1<<31) + msr hcr_el2,x0 + mov x0,#0x345 // 0x3c5 [4:0]->ELH1 / ASH(SEerr) IRQ FRQ disable + msr spsr_el2,x0 // spsr -> saved program status register + msr elr_el2,lr // lr->link register elr->Eeception Link Register + eret +/* +core_timer_enable: + //mov x0,1 + //msr cntp_ctl_el0, x0 //enable + //mrs x0, cntfrq_el0 + //mov x3,5 + //mul x0, x0, x3 + //msr cntp_tval_el0,x0 // set expired time + //mov x0,2 + //ldr x1, =CORE0_TIMER_IRQ_CTRL + //str w0,[x1] //unmask timer interrupt + //ret +*/ +// 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 except_handler_c + load_all + eret + +irq_exception_handler: + save_all + bl uart_irq_handler + load_all + eret + +.align 11 // vector table should be aligned to 0x800 +.global exception_vector_table +exception_vector_table: + 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 + + b exception_handler + .align 7 + b irq_exception_handler + .align 7 + b irq_exception_handler + .align 7 + b exception_handler + .align 7 + + b exception_handler + .align 7 + b irq_exception_handler + .align 7 + b irq_exception_handler + .align 7 + b exception_handler + .align 7 + + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + +.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 + diff --git a/lab_asyn/shell/start.o b/lab_asyn/shell/start.o new file mode 100644 index 000000000..2a7d92cb0 Binary files /dev/null and b/lab_asyn/shell/start.o differ diff --git a/lab_asyn/shell/tasklist.c b/lab_asyn/shell/tasklist.c new file mode 100644 index 000000000..75c0d2d6d --- /dev/null +++ b/lab_asyn/shell/tasklist.c @@ -0,0 +1,67 @@ +#include "header/tasklist.h" +#include "header/allocator.h" +#include "header/uart.h" +#include "header/utils.h" + +task_t *task_head = NULL; + +void enqueue_task(task_t *new_task) { + // Disable interrupts to protect the critical section + asm volatile("msr DAIFSet, 0xf"); + // Special case: the list is empty or the new task has higher priority + if (!task_head || new_task->priority < task_head->priority) { + new_task->next = task_head; + new_task->prev = NULL; + if (task_head) { + 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; + } + + // Enable interrupts + asm volatile("msr DAIFClr, 0xf"); +} + +void create_task(task_callback callback, uint64_t priority) { + + task_t* task = simple_malloc(sizeof(task_t)); + if(!task) { + return; + } + + task->callback = callback; + task->priority = priority; + + enqueue_task(task); +} + +void execute_tasks() { + + uart_send_string("in exe \n"); + while (task_head) { + task_head->callback(); + task_head = task_head->next; + if (task_head) { + task_head->prev = NULL; + } + asm volatile("msr DAIFSet, 0xf"); // Disable interrupts + //simple_free(task); + } + + asm volatile("msr DAIFClr, 0xf"); // Enable interrupts +} + diff --git a/lab_asyn/shell/tasklist.o b/lab_asyn/shell/tasklist.o new file mode 100644 index 000000000..146e1ff6e Binary files /dev/null and b/lab_asyn/shell/tasklist.o differ diff --git a/lab_asyn/shell/timer.c b/lab_asyn/shell/timer.c new file mode 100644 index 000000000..7e84400b9 --- /dev/null +++ b/lab_asyn/shell/timer.c @@ -0,0 +1,102 @@ +#include "header/timer.h" +#include "header/allocator.h" +#include "header/uart.h" +#include "header/irq.h" +#include "header/utils.h" + +timer_t *timer_head = NULL; + +void add_timer(timer_t *new_timer) { + + timer_t *current = timer_head; + + // Disable interrupts to protect the critical section + asm volatile("msr DAIFSet, 0xf"); + // Special case: the list is empty or the new timer is the earliest + if (!timer_head || new_timer->expiry < timer_head->expiry) { + new_timer->next = timer_head; + new_timer->prev = NULL; + if (timer_head) { + timer_head->prev = new_timer; + } + timer_head = new_timer; + + // Reprogram the hardware timer + asm volatile ("msr cntp_cval_el0, %0"::"r"(new_timer->expiry)); + asm volatile("msr cntp_ctl_el0,%0"::"r"(1)); + + // Enable interrupts + asm volatile("msr DAIFClr, 0xf"); + return; + } + + // Find the correct position in the list + while (current->next && current->next->expiry < new_timer->expiry) { + current = current->next; + } + + // Insert the new timer + new_timer->next = current->next; + new_timer->prev = current; + if (current->next) { + current->next->prev = new_timer; + } + current->next = new_timer; + // Enable interrupts + asm volatile("msr DAIFClr, 0xf"); +} + + +void create_timer(timer_callback callback, void* data, uint64_t after) { + //Allocate memory for the timer + timer_t* timer = simple_malloc(sizeof(timer_t)); + if(!timer) { + return; + } + + //Set the callback and data + timer->callback = callback; + timer->data = data; + + //Calculate the expiry time + uint64_t current_time, cntfrq; + asm volatile("mrs %0, cntpct_el0":"=r"(current_time)); + asm volatile("mrs %0, cntfrq_el0":"=r"(cntfrq)); + timer->expiry = current_time + after * cntfrq; + //Add the time to the list + add_timer(timer); +} + + +void print_message(void *data) { + char *message = data; + uint64_t current_time, cntfrq; + asm volatile("mrs %0, cntpct_el0" : "=r"(current_time)); + asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq)); + uint64_t seconds = current_time / cntfrq; + + uart_send_string("Timeout message: "); + uart_send_string(message); + uart_send_string(" occurs at "); + uart_hex(seconds); + uart_send_string("\n"); +} + +void setTimeout(char *message,uint64_t seconds) { + + char *message_copy = utils_strdup(message); + + if(!message_copy){ + return; + } + + if (!timer_head) { + //enable core_timer_interrupt + unsigned int value = 2; + unsigned int* address = (unsigned int*) CORE0_TIMER_IRQ_CTRL; // unmask timer interrupt + *address = value; + } + + create_timer(print_message,message_copy,seconds); +} + diff --git a/lab_asyn/shell/timer.o b/lab_asyn/shell/timer.o new file mode 100644 index 000000000..2073fbde9 Binary files /dev/null and b/lab_asyn/shell/timer.o differ diff --git a/lab_asyn/shell/uart.c b/lab_asyn/shell/uart.c new file mode 100644 index 000000000..ca50673c8 --- /dev/null +++ b/lab_asyn/shell/uart.c @@ -0,0 +1,211 @@ +#include "header/uart.h" +#include "header/irq.h" +#include "header/utils.h" + +#define RX_INTERRUPT_BIT 0x01 +#define TX_INTERRUPT_BIT 0x02 + +#define AUXINIT_BIT_POSTION 1<<29 + +char uart_read_buffer[UART_BUFFER_SIZE]; +char uart_write_buffer[UART_BUFFER_SIZE]; +int uart_read_head = 0; +int uart_read_index = 0; +int uart_write_index = 0; +int uart_write_head = 0; + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init() +{ + register unsigned int r; + // P.104 Since I need UART 1 Transmit/Receive Data -> TXD1/RXD1 + // p.102 I find These two in GPIO 14/15 Fun5 + // Since each GPFSEL controls 10 pin, GPFSEL1 controls 10-19 + // That's why I need GPFSEL1 + 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 + + //Since We've set alt5, we want to disable basic input/output + //To achieve this, we need diable pull-up and pull-dwon + *GPPUD = 0; // P101 top. 00- = off - disable pull-up/down + //Wait 150 cycles + //this provides the required set-up time for the control signal + r=150; while(r--) { asm volatile("nop"); } + // 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 + *GPPUDCLK0 = (1<<14)|(1<<15); + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = 0; // flush GPIO setup + + + r=1000; while(r--) { asm volatile("nop"); } + + /* initialize UART */ + *AUX_ENABLE |=1; + //P.9: If set the mini UART is enabled. The UART will + //immediately start receiving data, especially if the + //UART1_RX line is low. + //If clear the mini UART is disabled. That also disables + //any mini UART register access + *AUX_MU_CNTL = 0; + //P.17 If this bit is set the mini UART receiver is enabled. + //If this bit is clear the mini UART receiver is disabled + //Prevent data exchange in initialization process + *AUX_MU_IER = 0; + //Set AUX_MU_IER_REG to 0. + //Disable interrupt because currently you don’t need interrupt. + *AUX_MU_LCR = 3; + //P.14: 00 : the UART works in 7-bit mode + //11(3) : the UART works in 8-bit mode + //Cause 8 bits can use in ASCII, Unicode, Char + *AUX_MU_MCR = 0; + //Don’t need auto flow control. + //AUX_MU_MCR is for basic serial communication. Don't be too smart + *AUX_MU_BAUD = 270; + //set BAUD rate to 115200(transmit speed) + //so we need set AUX_MU_BAUD to 270 to meet the goal + *AUX_MU_IIR = 0xc6; + // bit 6 bit 7 No FIFO. Sacrifice reliability(buffer) to get low latency // 0xc6 = 11000110 + // Writing with bit 1 set will clear the receive FIFO + // Writing with bit 2 set will clear the transmit FIFO + // Both bits always read as 1 as the FIFOs are always enabled + /* map UART1 to GPIO pins */ + *AUX_MU_CNTL = 3; // enable Transmitter,Receiver + +} + + +/** + * Send a character + */ +void uart_send_char(unsigned int c) { + /* wait until we can send */ + // P.15 AUX_MU_LSR register shows the data(line) status + // AUX_MU_LSR bit 5 => 0x20 = 00100000 + // bit 5 is set if the transmit FIFO can accept at least one byte. + // &0x20 can preserve 5th bit, if bit 5 set 1 can get !true = false leave loop + // else FIFO can not accept at lease one byte then still wait + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); + /* write the character to the buffer */ + //P.11 The AUX_MU_IO_REG register is primary used to write data to and read data from the + //UART FIFOs. + //communicate with(send to) the minicom and print to the screen + *AUX_MU_IO=c; +} + +/** + * Display a string + */ +void uart_send_string(char* s) { + while(*s) { + /* convert newline to carriage return + newline */ + if(*s=='\n') + uart_send_char('\r'); + uart_send_char(*s++); + } +} + +/** + * Receive a character + */ +char uart_get_char() { + char r; + /* wait until something is in the buffer */ + //bit 0 is set if the receive FIFO holds at least 1 symbol. + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01)); + /* read it and return */ + r=(char)(*AUX_MU_IO); + /* convert carriage return to newline */ + return r=='\r'?'\n':r; +} + + +/** + * Display a binary value in hexadecimal + */ +void uart_hex(unsigned long long d) { + unsigned long long n; + int c; + uart_send_string("0x"); + for(c=28;c>=0;c-=4) { + // get highest tetrad + n=(d>>c)&0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n+=n>9?0x57:0x30; + uart_send_char(n); + } +} + +void uart_enable_interrupt() { + + // Enable RX and TX interrupt for mini UART + uint32_t ier = mmio_read(AUX_MU_IER); + ier |= RX_INTERRUPT_BIT; + //ier |= (RX_INTERRUPT_BIT | TX_INTERRUPT_BIT); + mmio_write(AUX_MU_IER, ier); + + // Enable the mini UART interrupt in the second-level interrupt controller + // uint32_t enable_irqs1 = (uint32_t) ENABLE_IRQS_1; + uint32_t enable_irqs1 = mmio_read(ENABLE_IRQS_1); + enable_irqs1 |= AUXINIT_BIT_POSTION; // Set bit29 + mmio_write(ENABLE_IRQS_1, enable_irqs1); +} + +void uart_disable_interrupt() { + // uint32_t disable_irqs1 = (uint32_t) DISABLE_IRQS_1; + uint32_t disable_irqs1 = mmio_read(DISABLE_IRQS_1); + disable_irqs1 |= AUXINIT_BIT_POSTION; + mmio_write(DISABLE_IRQS_1,disable_irqs1); +} + +int uart_async_read(char *buffer) { + // uart_send_string("in uart_async_read\n"); + if (uart_read_head == uart_read_index) { + // No characters available + return 0; + } else { + // uart_send_string("flag \n"); + buffer[0] = uart_read_buffer[uart_read_head++]; + if (uart_read_head >= UART_BUFFER_SIZE) { + uart_read_head = 0; + } + return 1; + } +} +void uart_async_write(const char *buffer, int length) { + uart_send_string("in uart_async_write\n"); + // uart_write_head = 1; + // uart_read_index = 1; + for (int i = 0; i < length; i++) + { + // uart_send_string("qq\n"); + uart_write_buffer[uart_write_index++] = buffer[i]; + if (uart_write_head >= UART_BUFFER_SIZE) { + uart_write_head = 0; + } + } + // Trigger TX interrupt + /// uart_send_string("Triiger TX interrupt\n"); + /// uart_hex(uart_write_index); + /// uart_hex(uart_write_head); + // unable transmit interrupt + mmio_write(AUX_MU_IER, mmio_read(AUX_MU_IER) | (0x2)); + /// uart_send_string("flag1\n"); + /// uart_hex(uart_write_index); + /// uart_hex(uart_write_head); +} + +void uart_async_send(const char *str) { + uart_send_string("in uart asy send ===========================\n"); + int length = utils_strlen(str); + uart_async_write(str, length); +} + + diff --git a/lab_asyn/shell/uart.o b/lab_asyn/shell/uart.o new file mode 100644 index 000000000..e8811ae32 Binary files /dev/null and b/lab_asyn/shell/uart.o differ diff --git a/lab_asyn/shell/userprogram/Makefile b/lab_asyn/shell/userprogram/Makefile new file mode 100644 index 000000000..19cefe3cf --- /dev/null +++ b/lab_asyn/shell/userprogram/Makefile @@ -0,0 +1,11 @@ +all: one.img + +one.o: one.S + aarch64-linux-gnu-gcc -c one.S -o one.o + +one.img: one.o + aarch64-linux-gnu-ld one.o -T linker.ld -o one.elf + aarch64-linux-gnu-objcopy -O binary one.elf one.img + +clean: + rm one.o one.elf > /dev/null 2>/dev/null || true diff --git a/lab_asyn/shell/userprogram/linker.ld b/lab_asyn/shell/userprogram/linker.ld new file mode 100644 index 000000000..ab70a30ea --- /dev/null +++ b/lab_asyn/shell/userprogram/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 : { . = ALIGN(16); *(.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/lab_asyn/shell/userprogram/one.S b/lab_asyn/shell/userprogram/one.S new file mode 100644 index 000000000..4acf6f4dd --- /dev/null +++ b/lab_asyn/shell/userprogram/one.S @@ -0,0 +1,7 @@ +.section ".text" +.global _start +_start: + svc 0x1337 +1: + nop + b 1b diff --git a/lab_asyn/shell/userprogram/one.elf b/lab_asyn/shell/userprogram/one.elf new file mode 100644 index 000000000..b13e36ed9 Binary files /dev/null and b/lab_asyn/shell/userprogram/one.elf differ diff --git a/lab_asyn/shell/userprogram/one.img b/lab_asyn/shell/userprogram/one.img new file mode 100644 index 000000000..13bb5c616 Binary files /dev/null and b/lab_asyn/shell/userprogram/one.img differ diff --git a/lab_asyn/shell/userprogram/one.o b/lab_asyn/shell/userprogram/one.o new file mode 100644 index 000000000..c00c28e5b Binary files /dev/null and b/lab_asyn/shell/userprogram/one.o differ diff --git a/lab_asyn/shell/utils.c b/lab_asyn/shell/utils.c new file mode 100644 index 000000000..8242d820c --- /dev/null +++ b/lab_asyn/shell/utils.c @@ -0,0 +1,63 @@ +#include "header/utils.h" +#include "header/allocator.h" + +int utils_string_compare(const char* str1,const char* str2) { + for(;*str1 !='\0'||*str2 !='\0';str1++,str2++){ + if(*str1 != *str2) return 0; + else if(*str1 == '\0' && *str2 =='\0') return 1; + } + return 1; +} + +unsigned long utils_atoi(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); +} + +//with null-terminator -> "hello" return 6 +size_t utils_strlen(const char *s) { + size_t i = 0; + while (s[i]) i++; + return i+1; +} + + +char *utils_strcpy(char* dst, const char *src) { + char *save = dst; + while((*dst++ = *src++)); + return save; +} + + +char *utils_strdup(const char *src) { + size_t len = utils_strlen(src); + char *dst = simple_malloc(len); + if (dst == NULL) { // Check if the memory has been successfully allocated + return NULL; + } + utils_strcpy(dst, src); // Copy the string + return dst; +} + + diff --git a/lab_asyn/shell/utils.o b/lab_asyn/shell/utils.o new file mode 100644 index 000000000..74670709c Binary files /dev/null and b/lab_asyn/shell/utils.o differ