diff --git a/Makefile b/Lab1/kernel code/Makefile similarity index 100% rename from Makefile rename to Lab1/kernel code/Makefile diff --git a/Lab1/kernel code/README.md b/Lab1/kernel code/README.md new file mode 100755 index 000000000..3a6b50ddc --- /dev/null +++ b/Lab1/kernel code/README.md @@ -0,0 +1,3 @@ +| Github Account | Student ID | Name | +|----------------|------------|---------------| +|Hsu0208 | 311551158 | Wei Ling Hsu | diff --git a/gpio.h b/Lab1/kernel code/gpio.h similarity index 100% rename from gpio.h rename to Lab1/kernel code/gpio.h diff --git a/kernel8.img b/Lab1/kernel code/kernel8.img similarity index 100% rename from kernel8.img rename to Lab1/kernel code/kernel8.img diff --git a/link.ld b/Lab1/kernel code/link.ld similarity index 100% rename from link.ld rename to Lab1/kernel code/link.ld diff --git a/main.c b/Lab1/kernel code/main.c similarity index 100% rename from main.c rename to Lab1/kernel code/main.c diff --git a/mbox.c b/Lab1/kernel code/mbox.c similarity index 100% rename from mbox.c rename to Lab1/kernel code/mbox.c diff --git a/mbox.h b/Lab1/kernel code/mbox.h similarity index 100% rename from mbox.h rename to Lab1/kernel code/mbox.h diff --git a/shell.c b/Lab1/kernel code/shell.c similarity index 100% rename from shell.c rename to Lab1/kernel code/shell.c diff --git a/shell.h b/Lab1/kernel code/shell.h similarity index 100% rename from shell.h rename to Lab1/kernel code/shell.h diff --git a/start.S b/Lab1/kernel code/start.S similarity index 90% rename from start.S rename to Lab1/kernel code/start.S index 17db9b5b2..e83b58227 100755 --- a/start.S +++ b/Lab1/kernel code/start.S @@ -9,7 +9,7 @@ _start: cbz x1, 2f // cpu id > 0, stop 1: wfe - b 1b + b 1b // b uncinditional branch 1-label b- backward 2: // cpu id == 0 // set stack before our code diff --git a/string.c b/Lab1/kernel code/string.c similarity index 100% rename from string.c rename to Lab1/kernel code/string.c diff --git a/string.h b/Lab1/kernel code/string.h similarity index 100% rename from string.h rename to Lab1/kernel code/string.h diff --git a/uart.c b/Lab1/kernel code/uart.c similarity index 100% rename from uart.c rename to Lab1/kernel code/uart.c diff --git a/uart.h b/Lab1/kernel code/uart.h similarity index 100% rename from uart.h rename to Lab1/kernel code/uart.h diff --git a/Lab2/Makefile b/Lab2/Makefile new file mode 100755 index 000000000..b111770f7 --- /dev/null +++ b/Lab2/Makefile @@ -0,0 +1,34 @@ +ARMGNU = aarch64-linux-gnu + +CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles +ASMFLAGS = -Iinclude +QEMUFLAGS = -M raspi3b -display none -serial null -serial pty + +BUILD_DIR = build +SRC_DIR = src + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%.o) + +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.S + mkdir -p $(@D) + $(ARMGNU)-gcc $(ASMFLAGS) -c $< -o $@ + +all: clean kernel8.img + +kernel8.img: $(SRC_DIR)/link.ld $(OBJ_FILES) + $(ARMGNU)-ld -T $(SRC_DIR)/link.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary kernel8.img + +clean: + rm -rf $(BUILD_DIR) *.img *.elf *.o + +qemu: kernel8.img + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -initrd initramfs.cpio + diff --git a/Lab2/bash_send_kernel.sh b/Lab2/bash_send_kernel.sh new file mode 100755 index 000000000..5eb4ea73d --- /dev/null +++ b/Lab2/bash_send_kernel.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +## rapspi -> bash send_kernel.sh +## qemu -> bash send_kernel.sh i + +## Construct the device path +if [ $# -eq 0 ]; then + device="/dev/ttyUSB0" +else + index="$1" + device="/dev/pts/$index" +fi + +# Check if the device file exists +if [ ! -c "$device" ]; then + echo "Device not found: $device" + exit 1 +fi + +# Change permissions of the device file +echo chmod a+rw "$device" +sudo chmod a+rw "$device" + +# Execute send_kernel.py with the appropriate argument +python3 send_kernel.py $1 diff --git a/Lab2/bootloader/Makefile b/Lab2/bootloader/Makefile new file mode 100755 index 000000000..b345a8bcf --- /dev/null +++ b/Lab2/bootloader/Makefile @@ -0,0 +1,33 @@ +ARMGNU = aarch64-linux-gnu + +CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles +ASMFLAGS = -Iinclude +QEMUFLAGS = -M raspi3b -display none -serial null -serial pty + +BUILD_DIR = build +SRC_DIR = src + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%.o) + +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.S + mkdir -p $(@D) + $(ARMGNU)-gcc $(ASMFLAGS) -c $< -o $@ + +all: bootloader.img + +bootloader.img: $(SRC_DIR)/link.ld $(OBJ_FILES) + $(ARMGNU)-ld -T $(SRC_DIR)/link.ld -o $(BUILD_DIR)/bootloader.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/bootloader.elf -O binary bootloader.img + +clean: + rm -rf $(BUILD_DIR) *.img *.elf *.o + +qemu: bootloader.img + qemu-system-aarch64 $(QEMUFLAGS) -kernel bootloader.img -initrd ../initramfs.cpio \ No newline at end of file diff --git a/Lab2/bootloader/include/gpio.h b/Lab2/bootloader/include/gpio.h new file mode 100755 index 000000000..399ae80f2 --- /dev/null +++ b/Lab2/bootloader/include/gpio.h @@ -0,0 +1,25 @@ +#ifndef GPIO_H +#define GPIO_H + +#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)) + +#endif diff --git a/Lab2/bootloader/include/stdint.h b/Lab2/bootloader/include/stdint.h new file mode 100755 index 000000000..c54cccf50 --- /dev/null +++ b/Lab2/bootloader/include/stdint.h @@ -0,0 +1,16 @@ +#ifndef _STDINT_H +#define _STDINT_H + +typedef signed char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef unsigned int size_t; + +#endif /* _STDINT_H */ \ No newline at end of file diff --git a/Lab2/bootloader/include/uart.h b/Lab2/bootloader/include/uart.h new file mode 100755 index 000000000..2772882f8 --- /dev/null +++ b/Lab2/bootloader/include/uart.h @@ -0,0 +1,41 @@ +#include "../include/stdint.h" + +#ifndef UART_H +#define UART_H + +/* Auxilary mini UART registers */ +#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)) + + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init(); + + +/** + * Receive a character + */ +char uart_getc(); + +/** + * Display a string + */ +void uart_puts(char *s); + + +char uart_recv(); + +void itos(uint32_t value, char *str); +#endif diff --git a/Lab2/bootloader/src/link.ld b/Lab2/bootloader/src/link.ld new file mode 100755 index 000000000..10513d40b --- /dev/null +++ b/Lab2/bootloader/src/link.ld @@ -0,0 +1,21 @@ +SECTIONS +{ + . = 0x60000; + __bootloader_start = .; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; + __bootloader_end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start)>>3; +__bootloader_size = (__bootloader_end - __bootloader_start) >> 3; \ No newline at end of file diff --git a/Lab2/bootloader/src/main.c b/Lab2/bootloader/src/main.c new file mode 100755 index 000000000..54c40858b --- /dev/null +++ b/Lab2/bootloader/src/main.c @@ -0,0 +1,58 @@ +#include "../include/uart.h" +#include "../include/stdint.h" + +void main() +{ + // set up serial console + uart_init(); + uart_puts("bootloader is coming~\n"); + + uint32_t file_size = 0; + size_t index = 0; + // Buffer to store received data + uint8_t byte; + + while(1) { + if(uart_recv() == ((uint8_t)77)) break; + } + uart_puts("ready for receiving kernel size.\n"); + + + // Receive the file size as a 4-byte integer in little-endian format + for (int i = 0; i < 4; i++) { + byte = uart_recv(); + file_size |= ((uint32_t)byte) << (8 * i); + } + + char file_size_str[32]; // Adjust the buffer size as needed + itos(file_size, file_size_str); + + uart_puts("kernel size :"); + uart_puts(file_size_str); + uart_puts(" bytes.\n"); + + while(1) { + uart_puts("ready for receiving kernel.\n"); + if(uart_recv() == ((uint8_t)77)) break; + } + + + char *kernel = (char *)0x80000; + while (index < file_size) { + // Receive a byte + byte = uart_recv(); + // Write the byte to memory + *(kernel + index) = byte; + // Increment the index + index++; + } + + uart_puts("finished loading kernel~\n"); + + + // restore arguments and jump to the new kernel. + asm volatile ( + "mov x30, 0x80000;" // Move the immediate value 0x80000 to the link register (x30) + "ret;" // Return from subroutine (this will jump to the address in x30) + ); +} \ No newline at end of file diff --git a/Lab2/bootloader/src/start.S b/Lab2/bootloader/src/start.S new file mode 100755 index 000000000..6c61831dc --- /dev/null +++ b/Lab2/bootloader/src/start.S @@ -0,0 +1,40 @@ +.section ".text.boot" + +.global _start + +_start: + /* relocate bootloader */ + ldr x1, =0x80000 //address for relocation. + ldr x2, =__bootloader_start + ldr w3, =__bootloader_size + +relocate: + ldr x4, [x1], #8 + str x4, [x2], #8 + sub w3, w3, #1 + cbnz w3, relocate + + /* set stack pointer */ + ldr x1, =_start + mov sp, x1 + + +bss_init: + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size + +clear_bss_memory: + cbz w2, jump_to_main + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, clear_bss_memory + +// jump to C code, should not return +jump_to_main: + bl main-0x20000 + // for failsafe, halt this core too + b halt + +halt: + b halt diff --git a/Lab2/bootloader/src/uart.c b/Lab2/bootloader/src/uart.c new file mode 100755 index 000000000..ad9b63c17 --- /dev/null +++ b/Lab2/bootloader/src/uart.c @@ -0,0 +1,124 @@ +#include "../include/gpio.h" +#include "../include/uart.h" +#include "../include/stdint.h" + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init() +{ + register unsigned int reg; + + /* initialize UART */ + *AUX_ENABLE |= 1; /* enable mini UART */ + *AUX_MU_CNTL = 0; /* Disable transmitter and receiver during configuration. */ + + *AUX_MU_IER = 0; /* Disable interrupt */ + *AUX_MU_LCR = 3; /* Set the data size to 8 bit. */ + *AUX_MU_MCR = 0; /* Don’t need auto flow control. */ + *AUX_MU_BAUD = 270; /* 115200 baud */ + *AUX_MU_IIR = 6; /* No FIFO */ + // *AUX_MU_IIR = 0xc6; /* No FIFO */ + + /* map UART1 to GPIO pins */ + // GPFSEL1 register controls the function of GPIO pins + reg = *GPFSEL1; + reg &= ~((7<<12)|(7<<15)); /* address of gpio 14, 15 */ + reg |= (2<<12)|(2<<15); /* set to alt5 */ + + *GPFSEL1 = reg; + + // ensures that GPIO pins are not affected by internal resistors + *GPPUD = 0; /* Disable pull-up/down */ + reg=150; + while ( reg-- ) + { + asm volatile("nop"); + } + + *GPPUDCLK0 = (1<<14)|(1<<15); + + //Stabilizing the Signal to ensure Proper Configuration + reg=150; + while ( reg-- ) + { + asm volatile("nop"); + } + + // ensures that GPIO pins are returned to a neutral state + *GPPUDCLK0 = 0; /* flush GPIO setup */ + + *AUX_MU_CNTL = 3; // Enable the transmitter and receiver. + *AUX_MU_IER = 3; // Enable the interrupt. +} + +/** + * Send a character + */ +void uart_send(unsigned int c) +{ + /* Wait until UART transmitter is ready to accept new data. */ + do { + + asm volatile("nop"); + + } while( ! ( *AUX_MU_LSR&0x20 )); + + /* write the character to the buffer */ + *AUX_MU_IO = c; + + // ensure proper line termination + if ( c == '\n' ) + { + do { + + asm volatile("nop"); + + } while( ! ( *AUX_MU_LSR&0x20 )); + + //*AUX_MU_IO = '\r'; + } +} + + +/** + * Display a string + */ +void uart_puts(char *s) +{ + while( *s ) + { + + uart_send(*s++); + + } +} + +/** + * Display a binary value in hexadecimal + */ + +char uart_recv ( void ) +{ + while(! ( *AUX_MU_LSR&0x01 ) ){ + asm volatile("nop"); + } + return(*AUX_MU_IO&0xFF); +} + +void itos(uint32_t value, char *str) { + int i = 0; + do { + str[i++] = value % 10 + '0'; + value /= 10; + } while (value != 0); + str[i] = '\0'; + + // Reverse the string + int len = i; + for (int j = 0; j < len / 2; j++) { + char temp = str[j]; + str[j] = str[len - j - 1]; + str[len - j - 1] = temp; + } +} \ No newline at end of file diff --git a/Lab2/include/command.h b/Lab2/include/command.h new file mode 100755 index 000000000..aecb7a431 --- /dev/null +++ b/Lab2/include/command.h @@ -0,0 +1,31 @@ +#ifndef COMMAND_H +#define COMMAND_H + +#include "../include/my_stddef.h" + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +#define TMP_BUFFER_LEN 32 + +typedef void (*command_handler_t)(void); + +typedef struct { + const char *command; + const char *description; + command_handler_t handler; +} command_t; + +extern command_t commands[]; + +void set(long addr, unsigned int value); +char *get_string(void); +void cmd_help(void); +void cmd_hello(void); +void cmd_reboot(void); +void cmd_ls(void); +void cmd_cat(void); +void cmd_malloc(void); + +#endif \ No newline at end of file diff --git a/Lab2/include/cpio_parser.h b/Lab2/include/cpio_parser.h new file mode 100755 index 000000000..becbb1959 --- /dev/null +++ b/Lab2/include/cpio_parser.h @@ -0,0 +1,29 @@ +#ifndef MY_CPIO_PARSER_H +#define MY_CPIO_PARSER_H + +#define CPIO_NEWC_MAGIC "070701" +#define HEADER_SIZE sizeof(struct cpio_newc_header) +#define MAX_ARCHIVE_SIZE (1024 * 1024 * 1024) // 1 GB +#define RAPSPI_CPIO_ADDRESS 0x20000000 + +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]; +}; + +void cpio_ls(char *cpio_archive_start); +void cpio_cat(char *cpio_archive_start, const char *filename); + +#endif \ No newline at end of file diff --git a/Lab2/include/gpio.h b/Lab2/include/gpio.h new file mode 100755 index 000000000..399ae80f2 --- /dev/null +++ b/Lab2/include/gpio.h @@ -0,0 +1,25 @@ +#ifndef GPIO_H +#define GPIO_H + +#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)) + +#endif diff --git a/Lab2/include/my_stddef.h b/Lab2/include/my_stddef.h new file mode 100755 index 000000000..efa35140a --- /dev/null +++ b/Lab2/include/my_stddef.h @@ -0,0 +1,8 @@ +#ifndef MY_STDDEF_H +#define MY_STDDEF_H + +#define NULL ((void *)0) + +typedef unsigned int size_t; + +#endif \ No newline at end of file diff --git a/Lab2/include/my_stdint.h b/Lab2/include/my_stdint.h new file mode 100755 index 000000000..34506dafa --- /dev/null +++ b/Lab2/include/my_stdint.h @@ -0,0 +1,23 @@ +#ifndef MY_STDINT_H +#define MY_STDINT_H + +#define __LP64__ 1 // Define __LP64__ macro to indicate a 64-bit system + +typedef signed char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +// Define uintptr_t based on the size of a pointer +#if defined(__LP64__) || defined(_LP64) +typedef unsigned long int uintptr_t; +#else +typedef unsigned int uintptr_t; +#endif + +#endif /* _STDINT_H */ \ No newline at end of file diff --git a/Lab2/include/my_stdio.h b/Lab2/include/my_stdio.h new file mode 100755 index 000000000..e17a409a5 --- /dev/null +++ b/Lab2/include/my_stdio.h @@ -0,0 +1,6 @@ +#ifndef MY_STDIO_H +#define MY_STDIO_H + +#define EOF (-1) + +#endif \ No newline at end of file diff --git a/Lab2/include/my_stdlib.h b/Lab2/include/my_stdlib.h new file mode 100755 index 000000000..e79f01bc9 --- /dev/null +++ b/Lab2/include/my_stdlib.h @@ -0,0 +1,17 @@ +#ifndef MY_STDLIB_H +#define MY_STDLIB_H + +#include "../include/my_stddef.h" + +extern int __bss_end; +//have tried 1GB but kernel dead +#define HEAP_SIZE (1024) // 1 KB +#define HEAP_START (&__bss_end) +#define HEAP_END ((void *)((uintptr_t)HEAP_START + HEAP_SIZE)) + + +void* alignas(size_t alignment, void* ptr); +void initialize_heap(void); +void* simple_malloc(size_t size); + +#endif \ No newline at end of file diff --git a/Lab2/include/my_string.h b/Lab2/include/my_string.h new file mode 100755 index 000000000..fb6804417 --- /dev/null +++ b/Lab2/include/my_string.h @@ -0,0 +1,15 @@ +#ifndef MY_STRING_H +#define MY_STRING_H + +#include "../include/my_stddef.h" + +#define HEX_DIGIT_TO_INT(c) ((c >= '0' && c <= '9') ? (c - '0') : ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : (c - 'A' + 10))) + +void strset( char * s1, int c, int size ); +int strlen( char * s ); +int strncmp(const char *s1, const char *s2, size_t n); +int strcmp(const char *s1, const char *s2); +void itoa(int num, char *str, int base); +unsigned int hex_to_uint(char *hex); + +#endif diff --git a/Lab2/include/shell.h b/Lab2/include/shell.h new file mode 100755 index 000000000..75764af22 --- /dev/null +++ b/Lab2/include/shell.h @@ -0,0 +1,17 @@ +#ifndef MYSHELL_H +#define MYSHELL_H + +#include "../include/my_stddef.h" + +#define MAX_BUFFER_LEN 64 +#define NEW_LINE 1001 +#define LINE_FEED 10 +#define CRRIAGE_RETURN 13 +#define BACKSPACE 8 + + +void shell_start(); +void command_controller(char c, char buffer[], int *counter); +void execute_command(char *buffer); + +#endif diff --git a/Lab2/include/uart.h b/Lab2/include/uart.h new file mode 100755 index 000000000..2bfa7678a --- /dev/null +++ b/Lab2/include/uart.h @@ -0,0 +1,39 @@ +#ifndef UART_H +#define UART_H + +/* Auxilary mini UART registers */ +#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)) + + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init(); + +/** + * Send a character + */ +void uart_send(unsigned int c); +/** + * Receive a character + */ +char uart_getc(); + +/** + * Display a string + */ +void uart_puts(const char *s); + +void uart_hex(unsigned int d); +#endif diff --git a/Lab2/initramfs.cpio b/Lab2/initramfs.cpio new file mode 100755 index 000000000..6a6694774 Binary files /dev/null and b/Lab2/initramfs.cpio differ diff --git a/Lab2/rootfs/file1.txt b/Lab2/rootfs/file1.txt new file mode 100755 index 000000000..c0e3b6139 --- /dev/null +++ b/Lab2/rootfs/file1.txt @@ -0,0 +1 @@ +this is file1 \ No newline at end of file diff --git a/Lab2/rootfs/file2.txt b/Lab2/rootfs/file2.txt new file mode 100755 index 000000000..5040297ea --- /dev/null +++ b/Lab2/rootfs/file2.txt @@ -0,0 +1 @@ +this is file2 \ No newline at end of file diff --git a/Lab2/screen.sh b/Lab2/screen.sh new file mode 100755 index 000000000..4704fdd9a --- /dev/null +++ b/Lab2/screen.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +if [ $# -eq 0 ]; then + device="/dev/ttyUSB0" +else + index="$1" + device="/dev/pts/$index" +fi + +if [ ! -c "$device" ]; then + echo "Device not found: $device" + exit 1 +fi + +echo "screen device : $device" +sudo screen "$device" 115200 + diff --git a/Lab2/send_kernel.py b/Lab2/send_kernel.py new file mode 100755 index 000000000..13490b2ba --- /dev/null +++ b/Lab2/send_kernel.py @@ -0,0 +1,72 @@ +import time +import serial +import sys +import os +import struct + +baud_rate = 115200 # Baud rate for the serial connection +timeout = 5 # Timeout for serial read operations in seconds +kernel_img_path = './kernel8.img' + +def send_file(serial_port, file_path, baud_rate, timeout): + # Check if the file exists + if not os.path.exists(file_path): + print(f"File {file_path} does not exist.") + return + + try: + # Open the serial port + with serial.Serial(serial_port, baud_rate, timeout=timeout) as ser: + print(f"Opened serial port {serial_port} at {baud_rate} baud.") + + # Get the size of the file + file_size = os.path.getsize(file_path) + print(f"File size: {file_size} bytes.") + + #call bootloader to start + + #time.sleep(2) + # Wait for Raspberry Pi + ser.write((77).to_bytes(1, byteorder='little')) + while(1): + rasp_response = ser.readline().decode() + print("Raspberry Pi :",repr(rasp_response)) + if rasp_response == "ready for receiving kernel size.\n": + break + + print("start sending kernel size.") + # Send the file size as a 4-byte integer in little-endian format + ser.write(file_size.to_bytes(4, byteorder='little')) + #time.sleep(10) + # Wait for Raspberry Pi + + #time.sleep(2) + ser.write((77).to_bytes(1, byteorder='little')) + while(1): + rasp_response = ser.readline().decode() + print("Raspberry Pi :",repr(rasp_response)) + + if rasp_response == "ready for receiving kernel.\n": + break + + # Read the file and send it over the serial connection + print("start sending kernel.") + with open(file_path, 'rb') as f: + ser.write(f.read()) + + print(f"Successfully sent {file_path} to {serial_port}.") + ser.close() + + except serial.SerialException as e: + print(f"Error opening or using serial port {serial_port}: {e}") + except Exception as e: + print(f"Error: {e}") + +if __name__ == '__main__': + if len(sys.argv)>1: + serial_port = f"/dev/pts/{sys.argv[1]}" + else: + serial_port = "/dev/ttyUSB0" + + send_file(serial_port, kernel_img_path, baud_rate, timeout) + diff --git a/Lab2/src/command.c b/Lab2/src/command.c new file mode 100755 index 000000000..94e1c1052 --- /dev/null +++ b/Lab2/src/command.c @@ -0,0 +1,103 @@ +#include "../include/command.h" +#include "../include/uart.h" +#include "../include/cpio_parser.h" +#include "../include/shell.h" +#include "../include/my_stddef.h" +#include "../include/my_string.h" +#include "../include/my_stdlib.h" + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +char *get_string(void){ + int buffer_counter = 0; + char input_char; + static char buffer[TMP_BUFFER_LEN]; + strset(buffer, 0, TMP_BUFFER_LEN); + while (1) { + input_char = uart_getc(); + if (!(input_char < 128 && input_char >= 0)) { + uart_puts("Invalid character received\n"); + return NULL; + } else if (input_char == LINE_FEED || input_char == CRRIAGE_RETURN) { + uart_send(input_char); + buffer[buffer_counter] = '\0'; + return buffer; + }else { + uart_send(input_char); + + if (buffer_counter < TMP_BUFFER_LEN) { + buffer[buffer_counter] = input_char; + buffer_counter++; + } + else { + uart_puts("\nError: Input exceeded buffer length. Buffer reset.\n"); + buffer_counter = 0; + strset(buffer, 0, TMP_BUFFER_LEN); + + // New line head + uart_puts("# "); + } + } + } +} + +void cmd_help(void) { + uart_puts("help : print this help menu\n"); + uart_puts("hello : print Hello World!\n"); + uart_puts("reboot : reboot the device\n"); + uart_puts("ls : show file in rootfs\n"); + uart_puts("cat : show file content\n"); + uart_puts("malloc : malloc demp\n"); +} + +void cmd_hello(void) { + uart_puts("Hello World!\n"); +} + +void cmd_reboot(void) { + uart_puts("Start rebooting...\n"); + set(PM_RSTC, PM_PASSWORD | 0x20); +} + +void cmd_ls(void) { + char *cpio_archive_start = (char *)RAPSPI_CPIO_ADDRESS; + cpio_ls(cpio_archive_start); +} + +void cmd_cat(void){ + uart_puts("Filename: "); + char *filename = get_string(); + if (filename == NULL) { + uart_puts("Error: Invalid filename\n"); + return; + } + char *cpio_archive_start = (char *)RAPSPI_CPIO_ADDRESS; + cpio_cat(cpio_archive_start,filename); +} + +void cmd_malloc(void) { + char *ptr1 = simple_malloc(7); + ptr1[0]='M'; + ptr1[1]='A'; + ptr1[2]='L'; + ptr1[3]='L'; + ptr1[4]='O'; + ptr1[5]='C'; + ptr1[6]='\0'; + uart_puts(ptr1); + uart_puts("\n"); +} + + +command_t commands[] = { + {"help", "print this help menu", cmd_help}, + {"hello", "print Hello World!", cmd_hello}, + {"reboot", "reboot the device", cmd_reboot}, + {"ls", "show file in rootfs", cmd_ls}, + {"cat", "show file content", cmd_cat}, + {"malloc", "malloc demo", cmd_malloc}, + {NULL, NULL, NULL} // Sentinel value to mark the end of the array +}; \ No newline at end of file diff --git a/Lab2/src/cpio_parser.c b/Lab2/src/cpio_parser.c new file mode 100755 index 000000000..b2ae2f908 --- /dev/null +++ b/Lab2/src/cpio_parser.c @@ -0,0 +1,112 @@ +#include "../include/uart.h" +#include "../include/cpio_parser.h" +#include "../include/my_stddef.h" +#include "../include/my_string.h" +#include "../include/my_stdlib.h" +#include "../include/my_stdint.h" + +void cpio_ls(char *cpio_archive_start) { + char *ptr = cpio_archive_start; + + while (1) { + struct cpio_newc_header *header = (struct cpio_newc_header *)ptr; + + + // Safety check: Ensure ptr does not go beyond the end of the archive + if (strncmp(header->c_magic, CPIO_NEWC_MAGIC, 6) != 0) { + uart_puts("Invalid CPIO magic number\n"); + break; + } + + //The "new" ASCII format uses 8-byte hexadecimal fields for all numbers + uint64_t namesize = hex_to_uint(header->c_namesize); + uint64_t filesize = hex_to_uint(header->c_filesize); + + /*Each file system object in a cpio archive comprises a header record + with basic numeric metadata followed by the full pathname of the entry and the file data.*/ + ptr += HEADER_SIZE; + char *filename = ptr; + ptr += namesize; + + //allign to 4 byte + //the filedata is padded to a multiple of four bytes.. + ptr = alignas(4, ptr); + + if (strcmp(filename, "TRAILER!!!") == 0) { + break; + } + + // Safety check: Ensure content does not go beyond the end of the archive + if (ptr + filesize - cpio_archive_start >= MAX_ARCHIVE_SIZE) { + uart_puts("Error: File content exceeds archive size\n"); + break; + } + + ptr += filesize; + + //allign to 4 byte + ptr = alignas(4, ptr); + + + uart_puts(filename); + uart_puts("\n"); + + } +} + +void cpio_cat(char *cpio_archive_start, const char *filename) { + char *ptr = cpio_archive_start; + int file_exist=0; + while (1) { + struct cpio_newc_header *header = (struct cpio_newc_header *)ptr; + + // Safety check: Ensure ptr does not go beyond the end of the archive + if (strncmp(header->c_magic, CPIO_NEWC_MAGIC, 6) != 0) { + uart_puts("Invalid CPIO magic number\n"); + return; + } + + uint64_t namesize = hex_to_uint(header->c_namesize); + uint64_t filesize = hex_to_uint(header->c_filesize); + + ptr += HEADER_SIZE; + char *current_filename = ptr; + ptr += namesize; + + // Align to 4 bytes + ptr = alignas(4, ptr); + + // Safety check: Ensure content does not go beyond the end of the archive + if (ptr + filesize - cpio_archive_start >= MAX_ARCHIVE_SIZE) { + uart_puts("Error: File content exceeds archive size\n"); + break; + } + + + char *content = ptr; + ptr += filesize; + + //allign to 4 byte + ptr = alignas(4, ptr); + + if (strcmp(current_filename, filename) == 0) { + // Print file content + uart_puts(content); + uart_puts("\n"); + return; + } + + // Check if we've reached the end of the archive + if (strcmp(current_filename, "TRAILER!!!") == 0) { + uart_puts("File not found\n"); + uart_puts("\n"); + return; + } + } + if (file_exist==0){ + uart_puts("Can't find :"); + uart_puts(filename); + uart_puts("Please check if the file name is correct!"); + } + +} \ No newline at end of file diff --git a/Lab2/src/link.ld b/Lab2/src/link.ld new file mode 100755 index 000000000..31993e853 --- /dev/null +++ b/Lab2/src/link.ld @@ -0,0 +1,18 @@ +SECTIONS +{ + . = 0x80000; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start)>>3; diff --git a/Lab2/src/main.c b/Lab2/src/main.c new file mode 100755 index 000000000..87e2ad487 --- /dev/null +++ b/Lab2/src/main.c @@ -0,0 +1,15 @@ +#include "../include/uart.h" +#include "../include/shell.h" +#include "../include/my_stdlib.h" + +int main(){ + // set up serial console + uart_init(); + + initialize_heap(); + + // start shell + shell_start(); + + return 0; +} diff --git a/Lab2/src/my_stdlib.c b/Lab2/src/my_stdlib.c new file mode 100755 index 000000000..0129f586c --- /dev/null +++ b/Lab2/src/my_stdlib.c @@ -0,0 +1,35 @@ +#include "../include/my_stdlib.h" +#include "../include/my_stddef.h" +#include "../include/my_stdint.h" +#include "../include/uart.h" + + +static uintptr_t heap_index = (uintptr_t)HEAP_START; + +void* alignas(size_t alignment, void* ptr) { + uintptr_t ptr_value = (uintptr_t)ptr; + uintptr_t mask = alignment - 1; + return (void*)((ptr_value + mask) & ~mask); +} + +void initialize_heap() { + // Initialize heap index + heap_index = (uintptr_t)HEAP_START; + +} + +void *simple_malloc(size_t size) { + // Align size to multiple of 8 + size = (size + 7) & ~7; + + // Check if there's enough space in the heap + if (heap_index + size > (uintptr_t)HEAP_END) { + uart_puts("Error: Insufficient space in the heap\n"); + return NULL; // Out of memory + } + + // Allocate memory from the heap + void *ptr = (void *)heap_index; + heap_index += size; + return ptr; +} \ No newline at end of file diff --git a/Lab2/src/my_string.c b/Lab2/src/my_string.c new file mode 100755 index 000000000..8bfeecf8b --- /dev/null +++ b/Lab2/src/my_string.c @@ -0,0 +1,88 @@ +#include "../include/my_string.h" + + +void strset (char * s1, int c, int size ) +{ + int i; + + for ( i = 0; i < size; i ++) + s1[i] = c; +} + +int strlen ( char * s ) +{ + int i = 0; + while ( 1 ) + { + if ( *(s+i) == '\0' ) + break; + i++; + } + + return i; +} + +int strncmp(const char *s1, const char *s2, size_t n) { + while (n-- > 0) { + if (*s1 != *s2) return *(unsigned char *)s1 - *(unsigned char *)s2; + if (*s1 == '\0') return 0; + s1++; + s2++; + } + return 0; +} + +// Custom strcmp function +int strcmp(const char *s1, const char *s2) { + while (*s1 && (*s1 == *s2)) { + s1++; + s2++; + } + return *(unsigned char *)s1 - *(unsigned char *)s2; +} + +// Custom itoa function +void itoa(int num, char *str, int base) { + int i = 0; + int is_negative = 0; + + if (num == 0) { + str[i++] = '0'; + str[i] = '\0'; + return; + } + + if (num < 0 && base == 10) { + is_negative = 1; + num = -num; + } + + while (num != 0) { + int rem = num % base; + str[i++] = (rem > 9) ? (rem - 10) + 'a' : rem + '0'; + num = num / base; + } + + if (is_negative) str[i++] = '-'; + + str[i] = '\0'; + + int start = 0; + int end = i - 1; + while (start < end) { + char temp = str[start]; + str[start] = str[end]; + str[end] = temp; + start++; + end--; + } +} + + +unsigned int hex_to_uint(char *hex) { + unsigned int result = 0; + for (int i = 0; i < 8; i++) { // Assuming each field contains 8 hexadecimal characters + result = (result << 4) | HEX_DIGIT_TO_INT(hex[i]); + } + return result; +} diff --git a/Lab2/src/shell.c b/Lab2/src/shell.c new file mode 100755 index 000000000..9df297e3f --- /dev/null +++ b/Lab2/src/shell.c @@ -0,0 +1,75 @@ +#include "../include/my_string.h" +#include "../include/shell.h" +#include "../include/uart.h" +#include "../include/command.h" + +void shell_start(void) { + int buffer_counter = 0; + char input_char; + char buffer[MAX_BUFFER_LEN]; + + strset(buffer, 0, MAX_BUFFER_LEN); + + // New line head + uart_puts("# "); + + // Read input + while (1) { + input_char = uart_getc(); + command_controller(input_char, buffer, &buffer_counter); + } +} + +void command_controller(char c, char buffer[], int *counter) { + if (!(c < 128 && c >= 0)) { + uart_puts("Invalid character received\n"); + return; + } else if (c == LINE_FEED || c == CRRIAGE_RETURN) { + uart_send(c); + + buffer[*counter] = '\0'; + execute_command(buffer); + + *counter = 0; + strset(buffer, 0, MAX_BUFFER_LEN); + + // New line head + uart_puts("# "); + } else if (c == BACKSPACE) { ///not working + uart_puts("Error: Command not found\n"); + if (*counter > 0) { + uart_send('h'); + uart_send('\b'); // Send Backspace to move cursor back + uart_send(' '); // Send space to clear the character on the screen + uart_send('\b'); // Send Backspace again to move cursor back + (*counter)--; // Decrement counter to remove the last character from the buffer + } + }else { + uart_send(c); + + if (*counter < MAX_BUFFER_LEN) { + buffer[*counter] = c; + (*counter)++; + } + else { + uart_puts("\nError: Input exceeded buffer length. Buffer reset.\n"); + *counter = 0; + strset(buffer, 0, MAX_BUFFER_LEN); + + // New line head + uart_puts("# "); + } + } +} + +void execute_command(char *buffer) { + for (command_t *cmd = commands; cmd->command != NULL; cmd++) { + if (strcmp(buffer, cmd->command) == 0) { + cmd->handler(); + return; + } + } + + uart_puts("Error: Command not found\n"); + uart_puts("Try command: help\n"); +} \ No newline at end of file diff --git a/Lab2/src/start.S b/Lab2/src/start.S new file mode 100755 index 000000000..6fc2f03d8 --- /dev/null +++ b/Lab2/src/start.S @@ -0,0 +1,32 @@ +.section ".text.boot" + +.global _start + +_start: + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, bss_init + // cpu id > 0, stop + +halt: + wfe + b halt + +// cpu id == 0 +bss_init: + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size + +clear_bss_memory: + cbz w2, jump_to_main + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, clear_bss_memory + +// jump to C code, should not return +jump_to_main: + bl main + // for failsafe, halt this core too + b halt diff --git a/Lab2/src/uart.c b/Lab2/src/uart.c new file mode 100755 index 000000000..17ff11d3d --- /dev/null +++ b/Lab2/src/uart.c @@ -0,0 +1,131 @@ +#include "../include/gpio.h" +#include "../include/uart.h" + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init() +{ + register unsigned int reg; + + /* initialize UART */ + *AUX_ENABLE |= 1; /* enable mini UART */ + *AUX_MU_CNTL = 0; /* Disable transmitter and receiver during configuration. */ + + *AUX_MU_IER = 0; /* Disable interrupt */ + *AUX_MU_LCR = 3; /* Set the data size to 8 bit. */ + *AUX_MU_MCR = 0; /* Don’t need auto flow control. */ + *AUX_MU_BAUD = 270; /* 115200 baud */ + *AUX_MU_IIR = 6; /* No FIFO */ + // *AUX_MU_IIR = 0xc6; /* No FIFO */ + + /* map UART1 to GPIO pins */ + // GPFSEL1 register controls the function of GPIO pins + reg = *GPFSEL1; + reg &= ~((7<<12)|(7<<15)); /* address of gpio 14, 15 */ + reg |= (2<<12)|(2<<15); /* set to alt5 */ + + *GPFSEL1 = reg; + + // ensures that GPIO pins are not affected by internal resistors + *GPPUD = 0; /* Disable pull-up/down */ + reg=150; + while ( reg-- ) + { + asm volatile("nop"); + } + + *GPPUDCLK0 = (1<<14)|(1<<15); + + //Stabilizing the Signal to ensure Proper Configuration + reg=150; + while ( reg-- ) + { + asm volatile("nop"); + } + + // ensures that GPIO pins are returned to a neutral state + *GPPUDCLK0 = 0; /* flush GPIO setup */ + + *AUX_MU_CNTL = 3; // Enable the transmitter and receiver. + *AUX_MU_IER = 3; // Enable the interrupt. +} + +/** + * Send a character + */ +void uart_send(unsigned int c) +{ + /* Wait until UART transmitter is ready to accept new data. */ + do { + + asm volatile("nop"); + + } while( ! ( *AUX_MU_LSR&0x20 )); + + /* write the character to the buffer */ + *AUX_MU_IO = c; + + // ensure proper line termination + if ( c == '\n' ) + { + do { + + asm volatile("nop"); + + } while( ! ( *AUX_MU_LSR&0x20 )); + + *AUX_MU_IO = '\r'; + } +} + + +/** + * Receive a character + */ +char uart_getc() { + + char r; + + /* wait until something is in the buffer */ + do{ + + asm volatile("nop"); + + } while ( ! ( *AUX_MU_LSR&0x01 ) ); + + /* read the data*/ + r = ( char )( *AUX_MU_IO ); + + /* convert carrige return to newline */ + //standardize newline characters across different systems. + return r == '\r' ? '\n' : r; +} + +/** + * Display a string + */ +void uart_puts(const char *s) +{ + while( *s ) + { + + uart_send(*s++); + + } +} + +/** + * Display a binary value in hexadecimal + */ +void uart_hex(unsigned int d) { + unsigned int n; + int c; + 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?0x37:0x30; + uart_send(n); + } +} diff --git a/demo/Makefile b/demo/Makefile new file mode 100755 index 000000000..631bbefab --- /dev/null +++ b/demo/Makefile @@ -0,0 +1,37 @@ +ARMGNU = aarch64-linux-gnu + +CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -Iinclude -mgeneral-regs-only -g +ASMFLAGS = -Iinclude +QEMUFLAGS = -M raspi3b -display none -serial null -serial pty + +BUILD_DIR = build +SRC_DIR = src + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%.o) + +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.S + mkdir -p $(@D) + $(ARMGNU)-gcc $(ASMFLAGS) -c $< -o $@ + +all: clean kernel8.img + +kernel8.img: $(SRC_DIR)/link.ld $(OBJ_FILES) + $(ARMGNU)-ld -T $(SRC_DIR)/link.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary kernel8.img + +clean: + rm -rf $(BUILD_DIR) *.img *.elf *.o + +qemu: clean kernel8.img + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + +qemu_asm: clean kernel8.img + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb -d in_asm + diff --git a/demo/bash_send_kernel.sh b/demo/bash_send_kernel.sh new file mode 100755 index 000000000..5eb4ea73d --- /dev/null +++ b/demo/bash_send_kernel.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +## rapspi -> bash send_kernel.sh +## qemu -> bash send_kernel.sh i + +## Construct the device path +if [ $# -eq 0 ]; then + device="/dev/ttyUSB0" +else + index="$1" + device="/dev/pts/$index" +fi + +# Check if the device file exists +if [ ! -c "$device" ]; then + echo "Device not found: $device" + exit 1 +fi + +# Change permissions of the device file +echo chmod a+rw "$device" +sudo chmod a+rw "$device" + +# Execute send_kernel.py with the appropriate argument +python3 send_kernel.py $1 diff --git a/demo/bcm2710-rpi-3-b-plus.dtb b/demo/bcm2710-rpi-3-b-plus.dtb new file mode 100755 index 000000000..60c45b9dc Binary files /dev/null and b/demo/bcm2710-rpi-3-b-plus.dtb differ diff --git a/demo/build/allocator.o b/demo/build/allocator.o new file mode 100755 index 000000000..031a2b3fb Binary files /dev/null and b/demo/build/allocator.o differ diff --git a/demo/build/command.o b/demo/build/command.o new file mode 100755 index 000000000..292844dea Binary files /dev/null and b/demo/build/command.o differ diff --git a/demo/build/cpio_parser.o b/demo/build/cpio_parser.o new file mode 100755 index 000000000..dd2776174 Binary files /dev/null and b/demo/build/cpio_parser.o differ diff --git a/demo/build/dtb.o b/demo/build/dtb.o new file mode 100755 index 000000000..4dd651a35 Binary files /dev/null and b/demo/build/dtb.o differ diff --git a/demo/build/exception.o b/demo/build/exception.o new file mode 100755 index 000000000..fb1bd3ff3 Binary files /dev/null and b/demo/build/exception.o differ diff --git a/demo/build/kernel8.elf b/demo/build/kernel8.elf new file mode 100755 index 000000000..86bf4b39d Binary files /dev/null and b/demo/build/kernel8.elf differ diff --git a/demo/build/main.o b/demo/build/main.o new file mode 100755 index 000000000..337202573 Binary files /dev/null and b/demo/build/main.o differ diff --git a/demo/build/my_stdlib.o b/demo/build/my_stdlib.o new file mode 100755 index 000000000..2d636cf44 Binary files /dev/null and b/demo/build/my_stdlib.o differ diff --git a/demo/build/my_string.o b/demo/build/my_string.o new file mode 100755 index 000000000..566593906 Binary files /dev/null and b/demo/build/my_string.o differ diff --git a/demo/build/shell.o b/demo/build/shell.o new file mode 100755 index 000000000..782034c84 Binary files /dev/null and b/demo/build/shell.o differ diff --git a/demo/build/start.o b/demo/build/start.o new file mode 100755 index 000000000..94bab4268 Binary files /dev/null and b/demo/build/start.o differ diff --git a/demo/build/task.o b/demo/build/task.o new file mode 100755 index 000000000..f2e5b91a9 Binary files /dev/null and b/demo/build/task.o differ diff --git a/demo/build/timer.o b/demo/build/timer.o new file mode 100755 index 000000000..6923a5f02 Binary files /dev/null and b/demo/build/timer.o differ diff --git a/demo/build/uart.o b/demo/build/uart.o new file mode 100755 index 000000000..9e457445a Binary files /dev/null and b/demo/build/uart.o differ diff --git a/demo/create_initramfs.sh b/demo/create_initramfs.sh new file mode 100755 index 000000000..425a40e16 --- /dev/null +++ b/demo/create_initramfs.sh @@ -0,0 +1,2 @@ +cd ./rootfs +find . | cpio -o -H newc > ../initramfs.cpio \ No newline at end of file diff --git a/demo/include/allocator.h b/demo/include/allocator.h new file mode 100755 index 000000000..37d4971a3 --- /dev/null +++ b/demo/include/allocator.h @@ -0,0 +1,73 @@ +#ifndef ALLOCATER_H +#define ALLOCATER_H + +#include "../include/my_stddef.h" +#include "../include/my_stdint.h" +#include "../include/my_stdlib.h" +#include "../include/uart.h" +#include "../include/my_string.h" + +#define BUDDY_METADATA_ADDR 0x10000000 +#define MAX_ORDER 11 +#define MEMORY_SIZE 0x10000000 // 256 MB +#define PAGE_SIZE 4096 +#define MAX_BLOCKS (MEMORY_SIZE / PAGE_SIZE) +#define NUM_POOLS 5 + +#define STATUS_X -1 +#define STATUS_F -2 +#define STATUS_D -3 + +extern char* __end; +extern char* _start; +extern char *cpio_addr; +extern char *dtb_addr; + +typedef struct buddy_block_list_t { + void *addr; + int idx; + int order; + int size; + struct buddy_block_list_t *next; +} buddy_block_list_t; + +typedef struct buddy_system_t { + buddy_block_list_t **buddy_list; + int first_avail[MAX_ORDER]; + void *list_addr[MAX_ORDER]; + void *buddy_start_address; + void *buddy_end_address; + int max_block_amount; + int max_index; +} buddy_system_t; + +typedef struct small_block_list_t { + void *addr; + struct small_block_list_t *next; +} small_block_list_t; + +typedef struct dynamic_memory_allocator_t { + small_block_list_t **small_block_pools; + //void* block_size; +} dynamic_memory_allocator_t; + + +void buddy_init(void); +buddy_block_list_t *get_block_addr(int order,int index); +void update_first_avail_list(void); +void* buddy_malloc(unsigned int size); +buddy_block_list_t* buddy_split(int start_index, int end_index, int req_size, int curr_order); +void mark_allocated(buddy_block_list_t* start); +void buddy_free(void *addr); +void free_child(int block_index, int order); + +void dma_init(void); +void *dma_malloc(int size); +void dma_free(void *addr,int size); + +void memory_reserve(void* start, void* end); +void startup_allocation(void); +void show_available_page(void); +void show_first_available_block_idx(void); + +#endif \ No newline at end of file diff --git a/demo/include/command.h b/demo/include/command.h new file mode 100755 index 000000000..5cf9224f3 --- /dev/null +++ b/demo/include/command.h @@ -0,0 +1,45 @@ +#ifndef COMMAND_H +#define COMMAND_H + +#include "../include/uart.h" +#include "../include/cpio_parser.h" +#include "../include/shell.h" +#include "../include/my_stddef.h" +#include "../include/my_string.h" +#include "../include/my_stdlib.h" +#include "../include/timer.h" +#include "../include/task.h" +#include "../include/exception.h" +#include "../include/allocator.h" + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + + +typedef void (*command_handler_t)(int argc, char **argv); + +typedef struct { + const char *command; + const char *description; + command_handler_t handler; +} command_t; + +extern command_t commands[]; + +void set(long addr, unsigned int value); +void cmd_help(int argc, char **argv); +void cmd_hello(int argc, char **argv); +void cmd_reboot(int argc, char **argv); +void cmd_ls(int argc, char **argv); +void cmd_cat(int argc, char **argv); +void cmd_malloc(int argc, char **argv); +void cmd_rup(int argc, char **argv); +void cmd_cctf(int argc, char **argv); +void cmd_async(int argc, char **argv); +void cmd_ttm(int argc, char **argv); +void cmd_sto(int argc, char **argv); +void cmd_tci(int argc, char **argv); +void cmd_atest(void); + +#endif \ No newline at end of file diff --git a/demo/include/cpio_parser.h b/demo/include/cpio_parser.h new file mode 100755 index 000000000..08448847e --- /dev/null +++ b/demo/include/cpio_parser.h @@ -0,0 +1,29 @@ +#ifndef MY_CPIO_PARSER_H +#define MY_CPIO_PARSER_H + +#define CPIO_NEWC_MAGIC "070701" +#define HEADER_SIZE sizeof(struct cpio_newc_header) +#define MAX_ARCHIVE_SIZE (1024 * 1024 * 1024) // 1 GB + +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]; +}; + +void cpio_ls(char *cpio_archive_start); +void cpio_cat(char *cpio_archive_start, const char *filename); +char *cpio_find(char *cpio_archive_start, const char *filename); + +#endif \ No newline at end of file diff --git a/demo/include/dtb.h b/demo/include/dtb.h new file mode 100755 index 000000000..80271233d --- /dev/null +++ b/demo/include/dtb.h @@ -0,0 +1,36 @@ +#ifndef DTB_H +#define DTB_H + +#include "../include/my_stdint.h" +#include "../include/uart.h" +#include "../include/my_string.h" + + +// Define the FDT header structure +struct fdt_header { + uint32_t magic; + uint32_t totalsize; + uint32_t off_dt_struct; + uint32_t off_dt_strings; + uint32_t off_mem_rsvmap; + uint32_t version; + uint32_t last_comp_version; + uint32_t boot_cpuid_phys; + uint32_t size_dt_strings; + uint32_t size_dt_struct; +}; + +typedef void (*fdt_callback_t)(const char* name, const char* prop, const void* value, int len); + +// FDT tokens +#define FDT_BEGIN_NODE 0x1 +#define FDT_END_NODE 0x2 +#define FDT_PROP 0x3 +#define FDT_NOP 0x4 +#define FDT_END 0x9 + +uint32_t fdt32_to_cpu(uint32_t x); +void fdt_traverse(void* fdt, fdt_callback_t callback); +void initramfs_callback(const char* name, const char* prop, const void* value, int len); + +#endif \ No newline at end of file diff --git a/demo/include/exception.h b/demo/include/exception.h new file mode 100755 index 000000000..84747f972 --- /dev/null +++ b/demo/include/exception.h @@ -0,0 +1,22 @@ +#ifndef MY_EXCEPTION_H +#define MY_EXCEPTION_H + +#include "../include/uart.h" +#include "../include/my_stdint.h" +#include "../include/my_stdlib.h" +#include "../include/timer.h" +#include "../include/task.h" + +void enable_interrupt(void); +void disable_interrupt(void); + +void showinfo_exception_handler(void); +void core_timer_handler(void); +void irq_exception_handler(void); +void uart_rx_handler(void); +void uart_tx_handler(void); +void timer_interrupt_handler(void); + + + +#endif \ No newline at end of file diff --git a/demo/include/gpio.h b/demo/include/gpio.h new file mode 100755 index 000000000..399ae80f2 --- /dev/null +++ b/demo/include/gpio.h @@ -0,0 +1,25 @@ +#ifndef GPIO_H +#define GPIO_H + +#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)) + +#endif diff --git a/demo/include/my_stddef.h b/demo/include/my_stddef.h new file mode 100755 index 000000000..efa35140a --- /dev/null +++ b/demo/include/my_stddef.h @@ -0,0 +1,8 @@ +#ifndef MY_STDDEF_H +#define MY_STDDEF_H + +#define NULL ((void *)0) + +typedef unsigned int size_t; + +#endif \ No newline at end of file diff --git a/demo/include/my_stdint.h b/demo/include/my_stdint.h new file mode 100755 index 000000000..34506dafa --- /dev/null +++ b/demo/include/my_stdint.h @@ -0,0 +1,23 @@ +#ifndef MY_STDINT_H +#define MY_STDINT_H + +#define __LP64__ 1 // Define __LP64__ macro to indicate a 64-bit system + +typedef signed char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +// Define uintptr_t based on the size of a pointer +#if defined(__LP64__) || defined(_LP64) +typedef unsigned long int uintptr_t; +#else +typedef unsigned int uintptr_t; +#endif + +#endif /* _STDINT_H */ \ No newline at end of file diff --git a/demo/include/my_stdio.h b/demo/include/my_stdio.h new file mode 100755 index 000000000..e17a409a5 --- /dev/null +++ b/demo/include/my_stdio.h @@ -0,0 +1,6 @@ +#ifndef MY_STDIO_H +#define MY_STDIO_H + +#define EOF (-1) + +#endif \ No newline at end of file diff --git a/demo/include/my_stdlib.h b/demo/include/my_stdlib.h new file mode 100755 index 000000000..6be3b7f3f --- /dev/null +++ b/demo/include/my_stdlib.h @@ -0,0 +1,31 @@ +#ifndef MY_STDLIB_H +#define MY_STDLIB_H + +//#include "../include/my_stddef.h" +//#include "../include/my_stdint.h" + +#include "../include/my_stddef.h" +#include "../include/my_stdint.h" +#include "../include/uart.h" + +extern char* __end; + +#define MAX_HEAP_SIZE (1024*1024) + +#define read_register(sys) ({ \ + uint64_t _val; \ + asm volatile ("mrs %0, " #sys : "=r" (_val)); \ + _val; \ +}) + +#define write_register(sys, _val) ({ \ + asm volatile ("msr " #sys ", %0" :: "r" (_val)); \ +}) + + +void* alignas(size_t alignment, void* ptr); +void* simple_malloc(size_t size); +int log(int num, int base); + +#endif + diff --git a/demo/include/my_string.h b/demo/include/my_string.h new file mode 100755 index 000000000..11434711d --- /dev/null +++ b/demo/include/my_string.h @@ -0,0 +1,21 @@ +#ifndef MY_STRING_H +#define MY_STRING_H + +#include "../include/my_stddef.h" + +#define HEX_DIGIT_TO_INT(c) ((c >= '0' && c <= '9') ? (c - '0') : ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : (c - 'A' + 10))) + +void strset( char * s1, int c, int size ); +int strlen(const char * s ); +int strncmp(const char *s1, const char *s2, size_t n); +int strcmp(const char *s1, const char *s2); +void itoa(int num, char *str, int base); +unsigned int hex_to_uint(char *hex); +char *strrchr(const char *str, int ch); +unsigned long long strtoull(const char *str, char **endptr, int base); +char *strtok(char *str, const char *delim); +char *strcpy(char *dest, const char *src); +char *strchr(const char *str, int c); +int atoi(const char *str); + +#endif diff --git a/demo/include/shell.h b/demo/include/shell.h new file mode 100755 index 000000000..696c119de --- /dev/null +++ b/demo/include/shell.h @@ -0,0 +1,18 @@ +#ifndef MYSHELL_H +#define MYSHELL_H + +#include "../include/my_stddef.h" + +#define MAX_BUFFER_LEN 64 +#define NEW_LINE 1001 +#define LINE_FEED 10 +#define CRRIAGE_RETURN 13 +#define BACKSPACE 8 + + +void shell_start(); +void command_controller(char c, char buffer[], int *counter, char **argv); +void execute_command(int argc, char **argv); +int parse_arguments(char *buffer, char **argv); + +#endif diff --git a/demo/include/task.h b/demo/include/task.h new file mode 100755 index 000000000..adf2fffa5 --- /dev/null +++ b/demo/include/task.h @@ -0,0 +1,32 @@ +#ifndef TASK_H +#define TASK_H + +#include "../include/my_stdint.h" +#include "../include/my_stddef.h" +#include "../include/my_stdlib.h" +#include "../include/exception.h" +#include "../include/timer.h" +#include "../include/my_string.h" +#include "../include/uart.h" + +// Structure to represent a task +typedef struct task{ + struct task* prev; + struct task* next; + void (*callback)(void *); + void *data; + int priority; +}task_t; + +extern task_t* task_head; +extern task_t* task_tail; + +// Function to insert a task into the task queue based on priority +task_t* create_task(void (*callback)(void *),int priority); +int add_task_to_queue(task_t *newTask); +void test_tesk1(void); +void test_tesk2(void); +void test_tesk3(void); +void ExecTasks(void); + +#endif \ No newline at end of file diff --git a/demo/include/timer.h b/demo/include/timer.h new file mode 100755 index 000000000..cab76f878 --- /dev/null +++ b/demo/include/timer.h @@ -0,0 +1,30 @@ +#ifndef TIMER_H +#define TIMER_H + +#include "../include/my_stdint.h" +#include "../include/my_stddef.h" +#include "../include/my_stdlib.h" +#include "../include/exception.h" +#include "../include/my_string.h" +#include "../include/uart.h" + +#define CORE0_TIMER_IRQ_CTRL (volatile unsigned int*)(0x40000040) + +// timer queue made from double linked list +typedef struct task_timer{ + struct task_timer *prev; + struct task_timer *next; + void (*callback)(void *); + void *data; + unsigned long long deadline; +}task_timer_t; + +extern task_timer_t* timer_head; +extern task_timer_t* timer_tail; + +task_timer_t *create_timer(void (*callback)(void *),void* message, int seconds); +int timer_add_queue(task_timer_t *temp); +void timer_callback(void *str); +void setTimeout (char *str, int second); + +#endif \ No newline at end of file diff --git a/demo/include/uart.h b/demo/include/uart.h new file mode 100755 index 000000000..55592e631 --- /dev/null +++ b/demo/include/uart.h @@ -0,0 +1,63 @@ +#ifndef UART_H +#define UART_H + +#include "../include/gpio.h" +#include "../include/shell.h" +#include "../include/command.h" +#include "../include/my_string.h" +#include "../include/my_stdlib.h" + +#define MMIO_BASE 0x3F000000 + + +/* Auxilary mini UART registers */ +#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)) +#define AUX_IRQ 29 + +#define CORE0_INT_SRC 0x40000060 +#define ENABLE_IRQS_1 0x3F00B210 +#define IRQ_PENDING_1 0x3F00B204 + +#define TMP_BUFFER_LEN 1024 + +#define BUFFER_SIZE (16*16) +#define MAX_ARGV_LEN 32 + +// Buffers and indices +extern char read_buffer[BUFFER_SIZE]; +extern char write_buffer[BUFFER_SIZE]; +extern int read_index_cur; +extern int read_index_tail; +extern int write_index_cur; +extern int write_index_tail; + + +void uart_init(void); +void uart_send(unsigned int c); +char uart_getc(void); +void uart_puts(const char *s); +char *get_string(void); +void uart_hex(unsigned int d); + +void initialize_async_buffers(void); +void uart_send_async(char c); +char uart_getc_async(void); +void uart_puts_async(const char *str); +void get_string_async(char *buffer_async); + +void uart_int(int num); +void uart_hex_64(uint64_t d); + + +#endif diff --git a/demo/initramfs.cpio b/demo/initramfs.cpio new file mode 100755 index 000000000..c9204697d Binary files /dev/null and b/demo/initramfs.cpio differ diff --git a/demo/kernel8.img b/demo/kernel8.img new file mode 100755 index 000000000..ea58586c4 Binary files /dev/null and b/demo/kernel8.img differ diff --git a/demo/rootfs/file1.txt b/demo/rootfs/file1.txt new file mode 100755 index 000000000..c0e3b6139 --- /dev/null +++ b/demo/rootfs/file1.txt @@ -0,0 +1 @@ +this is file1 \ No newline at end of file diff --git a/demo/rootfs/file2.txt b/demo/rootfs/file2.txt new file mode 100755 index 000000000..5040297ea --- /dev/null +++ b/demo/rootfs/file2.txt @@ -0,0 +1 @@ +this is file2 \ No newline at end of file diff --git a/demo/rootfs/userprogram.img b/demo/rootfs/userprogram.img new file mode 100755 index 000000000..1adf648a4 Binary files /dev/null and b/demo/rootfs/userprogram.img differ diff --git a/demo/src/allocator.c b/demo/src/allocator.c new file mode 100755 index 000000000..0507c05cf --- /dev/null +++ b/demo/src/allocator.c @@ -0,0 +1,489 @@ +#include "../include/allocator.h" + +char *allocated = (char*)&__end; + +buddy_system_t *buddy_system; +dynamic_memory_allocator_t *dma; + +int small_block_pool[7] = {16, 32, 64, 128, 256, 512, 1024}; + +void buddy_init(void){ + buddy_system = (buddy_system_t *)BUDDY_METADATA_ADDR; + buddy_system->buddy_list = (buddy_block_list_t**)(BUDDY_METADATA_ADDR + sizeof(buddy_system_t)); + buddy_block_list_t *list = (buddy_block_list_t *)(buddy_system->buddy_list); + buddy_system->buddy_start_address = (void *)(0x0); + buddy_system->buddy_end_address = (void *)(0x3C000000); + buddy_system->max_block_amount = (1 << (MAX_ORDER - 1)); + buddy_system->max_index = buddy_system->max_block_amount-1; + + for(int i = 0; i < MAX_ORDER; i++){ + + int alloc_offset = 0; + int block_amount = (1 << (MAX_ORDER - i - 1)); + + buddy_system->first_avail[i] = -1; + buddy_system->list_addr[i] = (void*)list; + + buddy_block_list_t *cur = list; + buddy_block_list_t *prev = NULL; + + for(int j = 0; j < block_amount; j++){ + cur->idx = (j * (1 << i)); + // all block are belonged to the largest continuous memory block + cur->order = STATUS_F; + if(i == MAX_ORDER - 1){ + cur->order = MAX_ORDER - 1; + } + if(cur!=buddy_system->list_addr[0]){ + prev->next = cur; + } + + cur->next = 0; + cur->addr = buddy_system->buddy_start_address + alloc_offset; + cur->size = PAGE_SIZE * (1 << i); + // update the offset of buddy system memory + alloc_offset += cur->size; + prev = cur; + // get next block of block list + cur++; + } + // goto next block list + list += block_amount; + } + // In the begining, only the largest block is available + buddy_system->first_avail[MAX_ORDER - 1] = 0; +} + +buddy_block_list_t *get_block_addr(int order,int index){ + //buddy_system->list_addr[order] can get he base address of the list containing blocks of same order + //buddy_system->first_avail[order] / (1 << order)) translate the global index into a local index within the array of blocks of a specific order. + + //don't known order (need more research) + if(order==-1){ + buddy_block_list_t *cur = get_block_addr(0,index); + buddy_block_list_t *last = cur; + for(int i = 0; i < MAX_ORDER; i++){ + cur = get_block_addr(i,index); + // index is illegal in this order, indicate that it must belonged to lower levels + if(index % (1 << i) != 0 | cur->order != STATUS_X) + return last; + + last = cur; + } + + return cur; + } + else{ + //get first avialible block + if(index==-1){ + return (buddy_block_list_t *)((void*)buddy_system->list_addr[order] + (buddy_system->first_avail[order] / (1 << order)) * sizeof(buddy_block_list_t)); + } + else{ + return (buddy_block_list_t *)((void*)buddy_system->list_addr[order] + (index / (1 << order)) * sizeof(buddy_block_list_t)); + } + } + + + +} + +void update_first_avail_list(void){ + int order,block_index; + for(order = 0; order < MAX_ORDER; order++){ + buddy_block_list_t *cur = (buddy_block_list_t *)buddy_system->list_addr[order]; + for(block_index = 0; block_index < buddy_system->max_block_amount ; block_index += (1 << order)){ + + if(cur->order >= 0) + break; + cur = cur->next; + } + if(block_indexmax_block_amount){ + buddy_system->first_avail[order] = block_index; + } + else{ + buddy_system->first_avail[order] = -1; + } + //uart_int(buddy_system->first_avail[order]); + //uart_send(' '); + } +} + +void* buddy_malloc(unsigned int size){ + int i; + + if(size > PAGE_SIZE * (1 << (MAX_ORDER - 1))){ + uart_puts("Error : Requested size is larger than availible space\n"); + return NULL; + } + + for(i = 0; i < MAX_ORDER; i++){ + //find the big enough block + if(PAGE_SIZE * (1 << i) >= size){ + if(buddy_system->first_avail[i] >= 0){ + + buddy_block_list_t *cur = get_block_addr(i,-1); + + // first assuming that there's smaller block in lower layer + cur->order = STATUS_F; + + int avail_index = buddy_system->first_avail[i]; + + //split the block as small as possible + buddy_block_list_t *buddy_allocated = buddy_split(avail_index, avail_index + (1 << i), size, i); + mark_allocated(buddy_allocated); + update_first_avail_list(); + + uart_puts("Allocated block of order "); + uart_int(log(buddy_allocated->size/PAGE_SIZE,2)); + uart_puts(" at: "); + uart_hex_64((unsigned long long)buddy_allocated->addr); + uart_puts("\n"); + return (void*)(buddy_allocated->addr); + } + else{ + continue; + } + } + } + + return NULL; +} + +buddy_block_list_t* buddy_split(int start_index, int end_index, int req_size, int curr_order){ + int i,j; + // to get relative offset as we need to cut it to half while spliting + int block_offset= end_index-start_index; + + // if the current block is already the smallest block that can be allocated or smaller block is not enough for the request + if((PAGE_SIZE * (1 << curr_order) / 2) < req_size || curr_order == 0){ + buddy_block_list_t *start = get_block_addr(curr_order,start_index); + start->order = STATUS_X; + return start; + } + // split the block until the smallest block that can be allocated + for(i = curr_order - 1; i >= 0; i--){ + buddy_block_list_t *start = get_block_addr(i,start_index); + buddy_block_list_t *cur = (buddy_block_list_t *)start; + + for(j = start_index; j < start_index + block_offset && cur != 0; j += (1 << i)){ + // mark it as usable + if(cur->order == STATUS_F){ + cur->order = i; + if(cur != start){ + uart_puts("Release redundent block of order:"); + uart_int(cur->order); + uart_puts(" size: "); + uart_int(cur->size); + uart_puts(" at: "); + uart_hex_64((unsigned long long)cur->addr); + uart_puts("\n"); + } + } + cur = cur->next; + } + block_offset /= 2; + start->order = STATUS_F; + // if the current block is already the smallest block that can be allocated or smaller block is not enough for the request + if((PAGE_SIZE * (1 << i) / 2) < req_size || i == 0){ + start->order = STATUS_X; + return start; + } + } + return NULL; +} + +void mark_allocated(buddy_block_list_t* start){ + int i,j; + int order = log(start->size / PAGE_SIZE, 2); + int end_index = start->idx + (1 << order); + + for(i = order - 1; i >= 0; i--){ + buddy_block_list_t *cur = get_block_addr(i,start->idx); + for(j = start->idx; j < end_index && cur != 0; j += (1 << i)){ + if(cur->order == STATUS_F) + cur->order = STATUS_X; + cur = cur->next; + } + } +} + + +void buddy_free(void *addr){ + int block_index = (addr-buddy_system->buddy_start_address)/ PAGE_SIZE; + //don't known order + buddy_block_list_t *cur_block = get_block_addr(-1,block_index); + int order = log(cur_block->size / PAGE_SIZE, 2); + + uart_puts("Free :"); + uart_hex_64((unsigned long long)addr); + uart_puts(" with order:"); + uart_int(log(cur_block->size / PAGE_SIZE, 2)); + uart_puts(" at index:"); + uart_int(block_index); + uart_send('\n'); + + free_child(block_index, order); + cur_block->order = order; + + //try to merge + int i,neighbor_same_order_block_index; + buddy_block_list_t *neighbor_same_order_block; + for(i = order; i < MAX_ORDER; i++){ + //get previous block whick is always order order i + neighbor_same_order_block_index = block_index ^ (1 << i); + + cur_block = get_block_addr(i,block_index); + neighbor_same_order_block = get_block_addr(i,neighbor_same_order_block_index); + + // reaching largest block, no need to merge + if(i == MAX_ORDER - 1){ + cur_block->order = i; + break; + } + + // its neighbor block is also available, combine them into a larger block + if(neighbor_same_order_block->order >= 0){ + cur_block->order = STATUS_F; + neighbor_same_order_block->order = STATUS_F; + uart_puts("Merge two blocks:"); + uart_int(block_index); + uart_send(' '); + uart_int(neighbor_same_order_block); + uart_puts(" at order:"); + uart_int(i); + uart_send('\n'); + } + else{ + cur_block->order = i; + break; + } + } + update_first_avail_list(); + +} + + +void free_child(int block_index, int order){ + int i,j; + + for(i = order - 1; i >= 0; i--){ + buddy_block_list_t *cur = get_block_addr(i,block_index); + for(j = 0; j < (1 << order); j += (1 << i)){ + cur->order = STATUS_F; + cur = cur->next; + } + } +} + + +void dma_init(void) { + //small_block_pool = {16, 32, 64, 128, 256, 512, 1024}; + dma->small_block_pools = (small_block_list_t **)simple_malloc(7 * sizeof(small_block_list_t *)); // for sizes 16, 32, 48, etc. + + for (int i = 0; i < 10; i++) { + dma->small_block_pools[i] = NULL; + } + + buddy_init(); +} + +void *dma_malloc(int size) { + if(size>1024){ + return buddy_malloc(size); + } + + int pool_idx = log(size/16, 2); // Assume sizes are 16, 32, 48, etc. + + if (dma->small_block_pools[pool_idx] != NULL) { + small_block_list_t *block = dma->small_block_pools[pool_idx]; + dma->small_block_pools[pool_idx] = block->next; + uart_puts("dynamic malloc a size "); + uart_int(small_block_pool[pool_idx]); + uart_puts(" block at: "); + uart_hex_64(block->addr); + uart_send('\n'); + return block->addr; + } + + + // Allocate a new page from buddy system + void *page = buddy_malloc(4096); // Order 0 for a single 4096 page + + for (int i = 0; i < PAGE_SIZE / size; i++) { + small_block_list_t *block = (small_block_list_t *)simple_malloc(sizeof(small_block_list_t)); + block->addr = page + (i * size); + block->next = dma->small_block_pools[pool_idx]; + dma->small_block_pools[pool_idx] = block; + //dma->block_size[addr]=small_block_pool[pool_idx]; + } + + return dma_malloc(size); +} + +void dma_free(void *addr, int size) { + //int size = dma->block_size[addr]; + if (size <= 1024) { + int pool_idx = log(size/16, 2); + small_block_list_t *block = (small_block_list_t *)simple_malloc(sizeof(small_block_list_t)); + block->addr = addr; + block->next = dma->small_block_pools[pool_idx]; + dma->small_block_pools[pool_idx] = block; + } else { + buddy_free(addr); + } +} + + +void memory_reserve(void* start, void* end){ + + if(start < buddy_system->buddy_start_address || end > buddy_system->buddy_end_address){ + uart_puts("Error: The memory is out of range\n"); + return; + } + + int start_index = (start - buddy_system->buddy_start_address) / PAGE_SIZE; + int end_index = (end - buddy_system->buddy_start_address) / PAGE_SIZE; + if((uint64_t)end % PAGE_SIZE != 0) + end_index++; + int i; + + if(end_index < start_index){ + uart_puts("Error: The end address is smaller than the start address\n"); + return; + } + + uart_puts("Reserve memory from:"); + + uart_hex_64((unsigned long long)start); + uart_puts(" to:"); + uart_hex_64((unsigned long long)end); + uart_send(' '); + uart_puts("with index:"); + uart_int(start_index); + uart_send(' '); + uart_int(end_index); + uart_send('\n'); + + int neighbor_same_order_block_index,cur_index; + // mark the protect blocks as STATUS_X(allocated) + for(i = 0; i < MAX_ORDER; i++){ + cur_index = start_index; + while(cur_index < end_index){ + + + buddy_block_list_t *cur = get_block_addr(i,cur_index); + + + if(cur->order >= 0 || cur->order == STATUS_F || i==0) + cur->order = STATUS_X; + + + neighbor_same_order_block_index = cur_index ^ (1 << i); + buddy_block_list_t *neighbor_same_order_block = get_block_addr(i,neighbor_same_order_block_index); + if (neighbor_same_order_block_index < buddy_system->max_index){ + if(neighbor_same_order_block->order == STATUS_F){ + //uart_int(i); + //uart_send(' '); + //uart_hex_64(neighbor_same_order_block->addr); + //uart_send('\n'); + neighbor_same_order_block->order = i; + } + } + + cur_index++; + } + } + update_first_avail_list(); +} + + +void startup_allocation(void){ + dma_init(); + uart_puts("Availibel pages before startup_allocation\n"); + show_available_page(); + uart_puts("startup_allocation starting\n"); + uart_puts("reserve Spin tables for multicore boot\n"); + memory_reserve((void*)0x0, (void*)0x1000); + uart_puts("reserve Kernel image in the physical memory\n"); + memory_reserve((void*)&_start, (void*)&__end); + uart_puts("reserve CPIO archive in the physical memory\n"); + memory_reserve((void*)cpio_addr, (void*)cpio_addr + 0x100000); + uart_puts("reserve device tree blob in the physical memory\n"); + memory_reserve((void*)dtb_addr, (void*)dtb_addr + 0x100000); + uart_puts("reserve allocator metadata in the physical memory\n"); + memory_reserve((void*)BUDDY_METADATA_ADDR, (void*)BUDDY_METADATA_ADDR + sizeof(buddy_system_t) + ((1 << MAX_ORDER) - 1) * sizeof(buddy_block_list_t)); + uart_puts("reserve dma metadata in the physical memory\n"); + memory_reserve((void*)&__end, (void*)allocated); + uart_puts("startup_allocation finished\n"); + uart_puts("Availibel pages after startup_allocation\n"); + show_available_page(); +} + +void show_available_page(void){ + int avail_count; + for(int i = 0; i < MAX_ORDER; i++){ + uart_puts("Order "); + uart_int(i); + uart_puts(" availible pages number : "); + avail_count = 0; + buddy_block_list_t *cur = (buddy_block_list_t *)buddy_system->list_addr[i]; + for(int j = 0; j < (1 << (MAX_ORDER - i - 1)); j++){ + if(cur->order >= 0){ + avail_count++; + } + cur = cur->next; + } + uart_int(avail_count); + uart_send('\n'); + } +} + +void show_first_available_block_idx(void){ + uart_puts("buddy system first availible block (order 0 -> 10) :\n"); + for(int i = 0; i < MAX_ORDER; i++){ + uart_int(buddy_system->first_avail[i]); + uart_send(' '); + } + uart_send('\n'); +} + +void memory_reserve_new(void* start, void* end){ + + if(start < buddy_system->buddy_start_address || end > buddy_system->buddy_end_address){ + uart_puts("Error: The memory is out of range\n"); + return; + } + + int start_index = (start - buddy_system->buddy_start_address) / PAGE_SIZE; + int end_index = (end - buddy_system->buddy_start_address) / PAGE_SIZE; + int i; + + if(end_index < start_index){ + uart_puts("Error: The end address is smaller than the start address\n"); + return; + } + + uart_puts("Reserve memory from:"); + uart_hex_64((unsigned long long)start); + uart_puts(" to:"); + uart_hex_64((unsigned long long)end); + uart_send(' '); + uart_puts("with index:"); + uart_int(start_index); + uart_send(' '); + uart_int(end_index); + uart_send('\n'); + + + buddy_block_list_t *cur = get_block_addr(0,0); + int count=0; + while(countmax_block_amount){ + if(cur->idx>=start_index && cur->idx<=end_index){ + for(int i=0;iidx)->order=STATUS_X; + } + } + count++; + cur++; + } +} diff --git a/demo/src/command.c b/demo/src/command.c new file mode 100755 index 000000000..39f2c3c54 --- /dev/null +++ b/demo/src/command.c @@ -0,0 +1,256 @@ +#include "../include/command.h" + + + +extern char *cpio_addr; +extern int core_timer_flag; + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + + +void cmd_help(int argc, char **argv) { + uart_puts("hello : print Hello World!\n"); + uart_puts("reboot : reboot the device\n"); + uart_puts("ls : show file in rootfs\n"); + uart_puts("cat : show file content\n"); + uart_puts("malloc : malloc demp\n"); + uart_puts("rup : run user program\n"); + uart_puts("async : async UART read/write\n"); + uart_puts("sto : set time out\n"); + uart_puts("cctf : change core timer flag\n"); + uart_puts("ttm : test timer multiplexing\n"); + uart_puts("tci : test concurrent I/O devices handling\n"); +} + +command_t commands[] = { + {"help", "print this help menu", cmd_help}, + {"hello", "print Hello World!", cmd_hello}, + {"reboot", "reboot the device", cmd_reboot}, + {"ls", "show file in rootfs", cmd_ls}, + {"cat", "show file content", cmd_cat}, + {"malloc", "malloc demo", cmd_malloc}, + {"rup", "run user program", cmd_rup}, + {"async", "async UART read/write", cmd_async}, + {"sto", "set time out", cmd_sto}, + {"cctf", "change timer type", cmd_cctf}, + {"ttm", "test timer multiplexing", cmd_ttm}, + {"tci", "test concurrent I/O devices handling", cmd_tci}, + {"atest", "allocator test", cmd_atest}, + {NULL, NULL, NULL} // Sentinel value to mark the end of the array +}; + +void cmd_hello(int argc, char **argv) { + uart_puts("Hello World!\n"); +} + +void cmd_reboot(int argc, char **argv) { + uart_puts("Start rebooting...\n"); + set(PM_RSTC, PM_PASSWORD | 0x20); +} + +void cmd_ls(int argc, char **argv) { + cpio_ls(cpio_addr); +} + +void cmd_cat(int argc, char **argv){ + uart_puts("Filename: "); + char *filename = get_string(); + if (filename == NULL) { + uart_puts("Error: Invalid filename\n"); + return; + } + cpio_cat(cpio_addr,filename); +} + +void cmd_malloc(int argc, char **argv) { + char *ptr1 = simple_malloc(7); + ptr1[0]='M'; + ptr1[1]='A'; + ptr1[2]='L'; + ptr1[3]='L'; + ptr1[4]='O'; + ptr1[5]='C'; + ptr1[6]='\0'; + uart_puts(ptr1); + uart_puts("\n"); +} + +void cmd_rup(int argc, char **argv) { + uart_puts("Filename: "); + char *filename = get_string(); + if (filename == NULL) { + uart_puts("Error: Invalid filename\n"); + return; + } + char *file_addr = cpio_find(cpio_addr,filename); + //uart_hex(file_addr); + //uart_puts("\n"); + void *stack_addr = simple_malloc(2048); + //make sure stack_addr and file_addr not NULL + if(stack_addr && file_addr){ + write_register(spsr_el1,0x3c0); + write_register(elr_el1,file_addr); + write_register(sp_el0,stack_addr); + asm volatile("eret"); + } +} + +void cmd_async(int argc, char **argv){ + + /*enable uart interrupts*/ + + // Enable mini second level interrupt controller’s + *((volatile unsigned int*)ENABLE_IRQS_1) |= (1 << AUX_IRQ); + + // Enable mini UART receive interrupt to start reading the data + *((volatile unsigned int*)AUX_MU_IER) |= 0x01; + + + //uart_puts_async("Async UART testing\n"); + uart_puts_async("Type in something\n"); + + char buffer_async[TMP_BUFFER_LEN]; + strset(buffer_async, 0, TMP_BUFFER_LEN); + + get_string_async(buffer_async); + uart_puts_async("\nWhat you type in is :\n"); + uart_puts_async(buffer_async); + uart_puts_async("\n"); + + + + + /*disable uart interrupts*/ + + // Disable mini second level interrupt controller’s + *((volatile unsigned int*)ENABLE_IRQS_1) &= ~(1 << AUX_IRQ); + + // Disable mini UART receive interrupts to stop reading the data + *((volatile unsigned int*)AUX_MU_IER) &= ~(0x1); + +} + +void cmd_cctf(int argc, char **argv){ + if(core_timer_flag==0){ + uart_puts("enable core0 Timer\n"); + // enable core0 timer interrupt + *((volatile uint32_t*)CORE0_TIMER_IRQ_CTRL) = (0x2); + core_timer_flag=1; + } + else{ + uart_puts("disable core0 Timer\n"); + // disnable core0 timer interrupt + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x0); + core_timer_flag=0; + } +} + +void cmd_sto(int argc, char **argv){ + + if (argc < 3) { // Ensure at least two arguments are present + uart_puts("need to send massage and second\n"); + return; + } + unsigned long long cur_cnt, cnt_freq; + asm volatile( + "mrs %[var1], cntpct_el0;" + "mrs %[var2], cntfrq_el0;" + :[var1] "=r" (cur_cnt), [var2] "=r" (cnt_freq) + ); + uart_puts("current time:\n"); + uart_hex(cur_cnt / cnt_freq); + uart_send('\n'); + + setTimeout(argv[1], atoi(argv[2])); + +} + +void cmd_ttm(int argc, char **argv){ + + unsigned long long cur_cnt, cnt_freq; + asm volatile( + "mrs %[var1], cntpct_el0;" + "mrs %[var2], cntfrq_el0;" + :[var1] "=r" (cur_cnt), [var2] "=r" (cnt_freq) + ); + uart_puts("current time:\n"); + uart_hex(cur_cnt / cnt_freq); + uart_send('\n'); + + char test_tesk[6]; + test_tesk[0]='t'; + test_tesk[1]='a'; + test_tesk[2]='s'; + test_tesk[3]='k'; + test_tesk[4]='1'; + test_tesk[5]='\0'; + + for(int i=1; ic_magic, CPIO_NEWC_MAGIC, 6) != 0) { + uart_puts("Invalid CPIO magic number\n"); + break; + } + + //The "new" ASCII format uses 8-byte hexadecimal fields for all numbers + uint64_t namesize = hex_to_uint(header->c_namesize); + uint64_t filesize = hex_to_uint(header->c_filesize); + + /*Each file system object in a cpio archive comprises a header record + with basic numeric metadata followed by the full pathname of the entry and the file data.*/ + ptr += HEADER_SIZE; + char *filename = ptr; + ptr += namesize; + + //allign to 4 byte + //the filedata is padded to a multiple of four bytes.. + ptr = alignas(4, ptr); + + if (strcmp(filename, "TRAILER!!!") == 0) { + break; + } + + // Safety check: Ensure content does not go beyond the end of the archive + if (ptr + filesize - cpio_archive_start >= MAX_ARCHIVE_SIZE) { + uart_puts("Error: File content exceeds archive size\n"); + break; + } + + ptr += filesize; + + //allign to 4 byte + ptr = alignas(4, ptr); + + uart_puts(filename); + uart_puts("\n"); + + } +} + +void cpio_cat(char *cpio_archive_start, const char *filename) { + char *ptr = cpio_archive_start; + int file_exist=0; + while (1) { + struct cpio_newc_header *header = (struct cpio_newc_header *)ptr; + + // Safety check: Ensure ptr does not go beyond the end of the archive + if (strncmp(header->c_magic, CPIO_NEWC_MAGIC, 6) != 0) { + uart_puts("Invalid CPIO magic number\n"); + return; + } + + uint64_t namesize = hex_to_uint(header->c_namesize); + uint64_t filesize = hex_to_uint(header->c_filesize); + + ptr += HEADER_SIZE; + char *current_filename = ptr; + ptr += namesize; + + // Align to 4 bytes + ptr = alignas(4, ptr); + + // Safety check: Ensure content does not go beyond the end of the archive + if (ptr + filesize - cpio_archive_start >= MAX_ARCHIVE_SIZE) { + uart_puts("Error: File content exceeds archive size\n"); + break; + } + + + char *content = ptr; + ptr += filesize; + + //allign to 4 byte + ptr = alignas(4, ptr); + + if (strcmp(current_filename, filename) == 0) { + // Print file content + uart_puts(content); + uart_puts("\n"); + return; + } + + // Check if we've reached the end of the archive + if (strcmp(current_filename, "TRAILER!!!") == 0) { + uart_puts("File not found\n"); + uart_puts("\n"); + return; + } + } + if (file_exist==0){ + uart_puts("Can't find :"); + uart_puts(filename); + uart_puts("Please check if the file name is correct!"); + } + +} + +char *cpio_find(char *cpio_archive_start, const char *filename) { + char *ptr = cpio_archive_start; + char *content = NULL; + while (1) { + struct cpio_newc_header *header = (struct cpio_newc_header *)ptr; + + // Safety check: Ensure ptr does not go beyond the end of the archive + if (strncmp(header->c_magic, CPIO_NEWC_MAGIC, 6) != 0) { + uart_puts("Invalid CPIO magic number\n"); + content = NULL; + return content; + } + + unsigned int namesize = hex_to_uint(header->c_namesize); + unsigned int filesize = hex_to_uint(header->c_filesize); + + ptr += HEADER_SIZE; + char *current_filename = ptr; + ptr += namesize; + + // Align to 4 bytes + ptr = alignas(4, ptr); + + + content = ptr; + ptr += filesize; + + //allign to 4 byte + ptr = alignas(4, ptr); + + // Safety check: Ensure content does not go beyond the end of the archive + if (ptr + filesize - cpio_archive_start >= MAX_ARCHIVE_SIZE) { + uart_puts("Error: File content exceeds archive size\n"); + content = NULL; + return content; + } + + + if (strcmp(current_filename, filename) == 0) { + return content; + } + + if (strcmp(current_filename, "TRAILER!!!") == 0) { + uart_puts("File not found\n"); + uart_puts("\n"); + content = NULL; + return content; + } + + } +} \ No newline at end of file diff --git a/demo/src/dtb.c b/demo/src/dtb.c new file mode 100755 index 000000000..a060fb182 --- /dev/null +++ b/demo/src/dtb.c @@ -0,0 +1,137 @@ +#include "../include/dtb.h" + + +char *cpio_addr; +char *dtb_addr; + +/*bcm2710-rpi-3-b-plus.dtb is a binary representation of the device tree for the Raspberry Pi 3 Model B Plus. +It contains the hardware description necessary for the operating system to understand the hardware layout and resources. +*/ + + +/* structur of DTB format (page 53) + * + * --------------------------- * + * | struct fdt_header | + * --------------------------- * + * | (free space) | + * --------------------------- * + * | memory reservation block| + * --------------------------- * + * | (free space) | + * --------------------------- * + * | structure block | + * --------------------------- * + * | (free space) | + * --------------------------- * + * | strings block | + * --------------------------- * + * | (free space) | + * --------------------------- * + */ + + +// FDT uses big-endian format, while the ARM CPU in Raspberry Pi uses little-endian +// swaps the endianness of a 32-bit integer from big-endian to little-endian. +uint32_t fdt32_to_cpu(uint32_t x) { + return ((x >> 24) & 0x000000FF) | + ((x >> 8) & 0x0000FF00) | + ((x << 8) & 0x00FF0000) | + ((x << 24) & 0xFF000000); +} + + +void fdt_traverse(void* fdt, fdt_callback_t callback) { + struct fdt_header* header = (struct fdt_header*)fdt; + + // Validate the magic number + if (fdt32_to_cpu(header->magic) != 0xd00dfeed) { + uart_puts("Invalid FDT magic number\n"); + return; + } + + uint32_t off_dt_struct = fdt32_to_cpu(header->off_dt_struct); + uint32_t off_dt_strings = fdt32_to_cpu(header->off_dt_strings); + + // Pointers to the structure and strings blocks + uint8_t* struct_block = (uint8_t*)fdt + off_dt_struct; + char* strings_block = (char*)fdt + off_dt_strings; + + uint8_t* p = struct_block; + while (p < struct_block + fdt32_to_cpu(header->size_dt_struct)) { + /* The structure block is composed of a sequence of pieces, each beginning with a token (a big-endian 32-bit integer). + Some tokens are followed by extra data, the format of which is determined by the token value. (pg. 56) + */ + + uint32_t token = fdt32_to_cpu(*(uint32_t*)p); + p += 4; + + //The FDT_BEGIN_NODE token marks the beginning of a node’s representation. + // followed by the node’s unit name as extra data + if (token == FDT_BEGIN_NODE) { + const char* name = (const char*)p; + p += strlen(name) + 1; + + // All tokens in Structure Block shall be aligned on a 32-bit boundary (pg. 56) + p = (uint8_t*)(((uintptr_t)p + 3) & ~3); + + // Traverse properties + // The FDT_PROP token marks the beginning of the representation of one property in the devicetree. + /* + struct { + uint32_t len; //len gives the length of the property’s value in bytes + uint32_t nameoff; //nameoff gives an offset into the strings block + } + */ + while (fdt32_to_cpu(*(uint32_t*)p) == FDT_PROP) { + p += 4; + uint32_t len = fdt32_to_cpu(*(uint32_t*)p); + p += 4; + uint32_t nameoff = fdt32_to_cpu(*(uint32_t*)p); + p += 4; + + const char* prop_name = strings_block + nameoff; + + //After the structure, the property’s value is given as a byte string of length len. + //This value is followed by zeroed padding bytes (if necessary) to align to the next 32-bit boundary + const void* value = (const void*)p; + + // prevent execute a NLLL function + if (callback) { + callback(name, prop_name, value, len); + } + + p += len; + // Align to 4 bytes + p = (uint8_t*)(((uintptr_t)p + 3) & ~3); + } + //The FDT_END_NODE token marks the end of a node’s representation. + } else if (token == FDT_END_NODE) { + // Do nothing, just move to the next token + + //The FDT_NOP token will be ignored by any program parsing the device tree. + } else if (token == FDT_NOP) { + // Do nothing, just move to the next token + + //The FDT_END token marks the end of the structure block. + } else if (token == FDT_END) { + break; + } else { + uart_puts("Unknown token\n"); + break; + } + } +} + + + +void initramfs_callback(const char* name, const char* prop, const void* value, int len) { + if (strcmp(prop, "linux,initrd-start") == 0) { + cpio_addr = (char *)(uintptr_t)fdt32_to_cpu(*(uint32_t*)value); + uart_puts("Initramfs start address: 0x"); + uart_hex(cpio_addr); + uart_puts("\n"); + } +} + + diff --git a/demo/src/exception.c b/demo/src/exception.c new file mode 100755 index 000000000..e2d23b804 --- /dev/null +++ b/demo/src/exception.c @@ -0,0 +1,242 @@ +#include "../include/exception.h" + +extern char read_buffer[BUFFER_SIZE]; +extern char write_buffer[BUFFER_SIZE]; +extern int read_index_cur; +extern int read_index_tail; +extern int write_index_cur; +extern int write_index_tail; + +extern int core_timer_flag; + +void enable_interrupt(void){ + //write_register(daifclr,0xf); //fail + asm volatile ("msr daifclr, 0xf"); +} + +void disable_interrupt(void){ + //write_register(DAIFSet,0xf); //fail + asm volatile ("msr daifset, 0xf"); +} + + +void showinfo_exception_handler(void) { + + disable_interrupt(); + + + uint64_t spsr, elr, esr, el; + spsr = read_register(spsr_el1); + elr = read_register(elr_el1); + esr = read_register(esr_el1); + el = read_register(CurrentEL); + + uart_puts("Current exception level: "); + uart_hex(el>>2); // first two bits are preserved bit. + uart_puts("\n"); + uart_puts("spsr_el1: 0x"); + uart_hex(spsr); + uart_puts("\r\n"); + uart_puts("elr_el1: 0x"); + uart_hex(elr); + uart_puts("\r\n"); + uart_puts("esr_el1: 0x"); + uart_hex(esr); + uart_puts("\r\n"); + + enable_interrupt(); +} + +void irq_exception_handler(void) { + + disable_interrupt(); + + uint32_t cpu_irq_src, uart_irq_src, iir; + + //CORE0_INT_SRC provides information about the interrupt sources, specific to Core 0 + //bit 2 for interrupt request + cpu_irq_src = *((volatile unsigned int*)CORE0_INT_SRC); + + //IRQ_PENDING_1 indicates which interrupts are pending, System-wide, covers all interrupt sources across the entire system. + //bit 29 for UART interrupt + uart_irq_src = *((volatile unsigned int*)IRQ_PENDING_1); + + iir = *((volatile unsigned int*)AUX_MU_IIR); + + + + //uart_puts("In to Interrrupt\n"); + + // Handle timer interrupt + if(cpu_irq_src & (0x2)){ + + //uart_puts("Timer Interrrupt\n"); + if (core_timer_flag == 1){ + //uart_puts("In to core timer \n"); + //core_timer_handler(); + task_t* newtask = create_task(core_timer_handler, 1); + add_task_to_queue(newtask); + + } + else{ + //uart_puts("In to system timer \n"); + // disnable core0 timer interrupt, remove will lead to core0 timer infinite interrupt + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x0); + //timer_interrupt_handler(); + task_t* newtask = create_task(timer_interrupt_handler, 1); + add_task_to_queue(newtask); + } + + } + + + + //uart_hex(gpu_irq_src & (1 << AUX_IRQ)); + // Handle UART interrupt + if (uart_irq_src & (1 << AUX_IRQ)) { + //uart_puts("Uart Interrrupt\n"); + // Check if it is a TX or RX interrupt + // [2:1]=10 : Receiver holds valid byte + if (iir & 0x4) { + // disable receive interrupt + *((volatile unsigned int*)AUX_MU_IER) &= ~(0x1); + //uart_puts("in rx handler\n"); + task_t* newtask = create_task(uart_rx_handler, 1); + add_task_to_queue(newtask); + + // [2:1]=01 : Transmit holding register empty + } else if (iir & 0x2) { + // disable transmit interrupt + *((volatile unsigned int*)AUX_MU_IER) &= ~(0x2); + //uart_puts("in tx handler\n"); + task_t* newtask = create_task(uart_tx_handler, 0); + add_task_to_queue(newtask); + } + } + + enable_interrupt(); + + ExecTasks(); + + +} + +void core_timer_handler(void){ + + uint64_t cur_cnt, cnt_freq; + cur_cnt = read_register(cntpct_el0); + cnt_freq = read_register(cntfrq_el0); + + + uart_puts("\nTime after boots: "); + uart_hex(cur_cnt / cnt_freq); + uart_puts(" sec.\n"); + uart_puts("# "); + cnt_freq *= 2; + write_register(cntp_tval_el0,cnt_freq); + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x2); +} + + + +//AUX_MU_IER 0x1 for reciev 0x2 for transmit + +//reciev data +void uart_rx_handler(void) { + //uart_puts("in rx_handler\n"); + // wait until something is in the buffer + while ( ! ( (*AUX_MU_LSR) & 0x01 ) ); + + char c = ( char )( *AUX_MU_IO ); + //c ='\r'?'\n':c; + //uart_send_async(c); + read_buffer[read_index_tail++] = c; + write_buffer[write_index_tail++] = c; + + // Enable mini UART transmiter interrupt + *((volatile unsigned int*)AUX_MU_IER) |= (0x2); + +} + +//transmit data +void uart_tx_handler(void) { + + char check; + while(write_index_cur != write_index_tail){ + + char c = write_buffer[write_index_cur++]; + check = c; + + while(!((*AUX_MU_LSR) & 0x20) ){ + // if bit 5 is set, break and return IO_REG + asm volatile("nop"); + } + *AUX_MU_IO = c; + if(c == '\n'){ + break; + } + } + + // If there is more data to send, ensure the interrupt is enabled + if (write_index_cur != write_index_tail) { + *((volatile unsigned int*)AUX_MU_IER) |= 0x02; + } else { + // Disable transmit interrupt if no more data to send + *((volatile unsigned int*)AUX_MU_IER) &= ~0x02; + //if(check != '\n'){ + //int time=150; + //while(time--); + //*((volatile unsigned int*)AUX_MU_IER) |= (0x1); + //} + + } + // enable mini UART receiver interrupt + //*((volatile unsigned int*)AUX_MU_IER) |= (0x1); + +} + +void timer_interrupt_handler(void) { + unsigned long long cur_cnt; + task_timer_t *cur = timer_head; + + if(cur==0){ + return; + } + + disable_interrupt(); + + cur_cnt = read_register(cntpct_el0); + //Processing Expired Timers + while(cur_cnt >= cur->deadline){ + + cur->callback(cur->data); + + timer_head = cur->next; + + //if list not empty + if(timer_head != 0){ + + timer_head->prev = 0; + write_register(cntp_cval_el0,timer_head->deadline); + // enable timer + write_register(cntp_ctl_el0,1); + + //asd turn on core0 timer interrupt + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x2); + } + else{ + uart_puts("Finish all timer\n"); + uart_puts("# "); + + // disable timer + write_register(cntp_ctl_el0,0); + + break; + } + cur = cur->next; + } + + enable_interrupt(); + +} + diff --git a/demo/src/link.ld b/demo/src/link.ld new file mode 100755 index 000000000..33118ef56 --- /dev/null +++ b/demo/src/link.ld @@ -0,0 +1,18 @@ +ENTRY(_start) + +SECTIONS +{ + . = 0x80000; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + __end = .; +} +__bss_size = (__bss_end - __bss_start)>>3; diff --git a/demo/src/main.c b/demo/src/main.c new file mode 100755 index 000000000..722d3ee1e --- /dev/null +++ b/demo/src/main.c @@ -0,0 +1,38 @@ +#include "../include/uart.h" +#include "../include/shell.h" +#include "../include/dtb.h" +#include "../include/exception.h" +#include "../include/my_stdlib.h" +#include "../include/my_stdint.h" +#include "../include/allocator.h" + +extern char *cpio_addr; +extern char *dtb_addr; + +int main(uint64_t x0){ + // set up serial console + uart_init(); + + uint64_t el = 0; + //asm volatile ("mrs %0, CurrentEL":"=r"(el)); + el = read_register(CurrentEL); + uart_puts("Current exception level: "); + uart_hex(el>>2); // first two bits are preserved bit. + uart_puts("\n"); + + + dtb_addr = (void *) x0; + fdt_traverse(dtb_addr, initramfs_callback); + + startup_allocation(); + + enable_interrupt(); + + initialize_async_buffers(); + // start shell + shell_start(); + + + + return 0; +} diff --git a/demo/src/my_stdlib.c b/demo/src/my_stdlib.c new file mode 100755 index 000000000..475a8e8b8 --- /dev/null +++ b/demo/src/my_stdlib.c @@ -0,0 +1,38 @@ +#include "../include/my_stdlib.h" + +char *heap_curr = (char*)&__end; +int offset=0; + +void* alignas(size_t alignment, void* ptr) { + uintptr_t ptr_value = (uintptr_t)ptr; + uintptr_t mask = alignment - 1; + return (void*)((ptr_value + mask) & ~mask); +} + +void *simple_malloc(size_t size) { + // Align size to multiple of 8 + size = (size + 7) & ~7; + + // Check if there's enough space in the heap + if (offset + size > MAX_HEAP_SIZE) { + uart_puts("Error: Insufficient space in the heap\n"); + return NULL; // Out of memory + } + + // Allocate memory from the heap + void *ptr = (void *)heap_curr; + heap_curr += size; + offset += size; + + return ptr; +} + + +int log(int num, int base){ + int i=0; + while(num!=1){ + num/=base; + i++; + } + return i; +} diff --git a/demo/src/my_string.c b/demo/src/my_string.c new file mode 100755 index 000000000..08d7b8885 --- /dev/null +++ b/demo/src/my_string.c @@ -0,0 +1,271 @@ +#include "../include/my_string.h" + + +void strset (char * s1, int c, int size ) +{ + int i; + + for ( i = 0; i < size; i ++) + s1[i] = c; +} + +int strlen (const char * s ) +{ + int i = 0; + while ( 1 ) + { + if ( *(s+i) == '\0' ) + break; + i++; + } + + return i; +} + +int strncmp(const char *s1, const char *s2, size_t n) { + while (n-- > 0) { + if (*s1 != *s2) return *(unsigned char *)s1 - *(unsigned char *)s2; + if (*s1 == '\0') return 0; + s1++; + s2++; + } + return 0; +} + +// Custom strcmp function +int strcmp(const char *s1, const char *s2) { + while (*s1 && (*s1 == *s2)) { + s1++; + s2++; + } + return *(unsigned char *)s1 - *(unsigned char *)s2; +} + +// Custom itoa function +void itoa(int num, char *str, int base) { + int i = 0; + int is_negative = 0; + + if (num == 0) { + str[i++] = '0'; + str[i] = '\0'; + return; + } + + if (num < 0 && base == 10) { + is_negative = 1; + num = -num; + } + + while (num != 0) { + int rem = num % base; + str[i++] = (rem > 9) ? (rem - 10) + 'a' : rem + '0'; + num = num / base; + } + + if (is_negative) str[i++] = '-'; + + str[i] = '\0'; + + int start = 0; + int end = i - 1; + while (start < end) { + char temp = str[start]; + str[start] = str[end]; + str[end] = temp; + start++; + end--; + } +} + + +unsigned int hex_to_uint(char *hex) { + unsigned int result = 0; + for (int i = 0; i < 8; i++) { // Assuming each field contains 8 hexadecimal characters + result = (result << 4) | HEX_DIGIT_TO_INT(hex[i]); + } + return result; +} + +char *strrchr(const char *str, int ch) { + const char *last_occurrence = NULL; + + // Traverse the string from beginning to end + while (*str != '\0') { + if (*str == ch) { + last_occurrence = str; // Update last occurrence pointer + } + str++; + } + + // Special case: check for '\0' (null terminator) if looking for '\0' + if (ch == '\0') { + return (char*)str; // Return pointer to the null terminator + } + + return (char*)last_occurrence; // Return pointer to the last occurrence of ch +} + +unsigned long long strtoull(const char *str, char **endptr, int base) { + unsigned long long result = 0; + int negative = 0; + + // Skip leading whitespace + while (*str == ' ' || (*str >= '\t' && *str <= '\r')) { + str++; + } + + // Handle optional sign + if (*str == '+' || *str == '-') { + negative = (*str == '-'); + str++; + } + + // Determine base if not specified + if (base == 0) { + if (*str == '0') { + str++; + if (*str == 'x' || *str == 'X') { + base = 16; + str++; + } else { + base = 8; + } + } else { + base = 10; + } + } else if (base == 16 && *str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X')) { + str += 2; + } + + // Convert characters to unsigned long long integer + while (*str != '\0') { + int digit; + + if (*str >= '0' && *str <= '9') { + digit = *str - '0'; + } else if (*str >= 'a' && *str <= 'z') { + digit = *str - 'a' + 10; + } else if (*str >= 'A' && *str <= 'Z') { + digit = *str - 'A' + 10; + } else { + break; // Invalid character encountered + } + + if (digit >= base) { + break; // Digit out of range for current base + } + + result = result * base + digit; + str++; + } + + // Set endptr if it's not NULL + if (endptr != NULL) { + *endptr = (char*)str; + } + + // Handle negative sign + if (negative) { + result = -result; + } + + return result; +} + +char *strtok(char *str, const char *delim) { + static char *next_token = NULL; + // If str is NULL, continue with the last token found + if (str == NULL && next_token == NULL) { + return NULL; + } + + // Initialize str to start tokenization + if (str != NULL) { + next_token = str; + } + + // Skip leading delimiters + while (*next_token != '\0' && strchr(delim, *next_token) != NULL) { + next_token++; + } + + // If reached end of string, return NULL + if (*next_token == '\0') { + next_token = NULL; + return NULL; + } + + // Save the beginning of the token + char *token = next_token; + + // Find the end of the token + while (*next_token != '\0' && strchr(delim, *next_token) == NULL) { + next_token++; + } + + // If not reached end of string, replace delimiter with '\0' + if (*next_token != '\0') { + *next_token = '\0'; + next_token++; + } else { + next_token = NULL; // Mark end of tokenization + } + + return token; +} + +char *strcpy(char *dest, const char *src) { + char *original_dest = dest; // Store original destination pointer + + // Copy characters from src to dest + while ((*dest++ = *src++) != '\0') + ; + + return original_dest; // Return original destination pointer +} + +char *strchr(const char *str, int c) { + while (*str != '\0') { + if (*str == c) { + return (char *)str; // Cast away constness for return type compatibility + } + str++; + } + + if (c == '\0') { + return (char *)str; // Return pointer to null terminator if c is '\0' + } + + return NULL; // Character not found +} + +int atoi(const char *str) { + int result = 0; + int sign = 1; + int i = 0; + + // Handle optional leading whitespace + while (str[i] == ' ') { + i++; + } + + // Handle optional sign + if (str[i] == '-') { + sign = -1; + i++; + } else if (str[i] == '+') { + i++; + } + + // Convert digits to integer + while (str[i] >= '0' && str[i] <= '9') { + result = result * 10 + (str[i] - '0'); + i++; + } + + // Apply sign + result *= sign; + + return result; +} diff --git a/demo/src/shell.c b/demo/src/shell.c new file mode 100755 index 000000000..c49148f09 --- /dev/null +++ b/demo/src/shell.c @@ -0,0 +1,103 @@ +#include "../include/my_string.h" +#include "../include/shell.h" +#include "../include/uart.h" +#include "../include/command.h" +#include "../include/my_stdint.h" +#include "../include/my_stdlib.h" +#include "../include/timer.h" + +void shell_start(void) { + int buffer_counter = 0; + char input_char; + char buffer[MAX_BUFFER_LEN]; + + strset(buffer, 0, MAX_BUFFER_LEN); + + char *argv[5]; + int buf_index; + //char input_char; + for(buf_index = 0; buf_index < 5; buf_index++){ + argv[buf_index] = simple_malloc(MAX_ARGV_LEN); + strset(argv[buf_index], 0, MAX_ARGV_LEN); + } + // New line head + uart_puts("# "); + + // Read input + while (1) { + input_char = uart_getc(); + command_controller(input_char, buffer, &buffer_counter, argv); + } +} + +void command_controller(char c, char buffer[], int *counter, char **argv) { + + if (!(c < 128 && c >= 0)) { + uart_puts("Invalid character received\n"); + return; + } else if (c == LINE_FEED || c == CRRIAGE_RETURN) { + uart_send(c); + + buffer[*counter] = '\0'; + int argc = parse_arguments(buffer, argv); + + if (argc > 0) { + execute_command(argc, argv); + } + + *counter = 0; + strset(buffer, 0, MAX_BUFFER_LEN); + + // New line head + uart_puts("# "); + } else if (c == BACKSPACE) { ///not working + uart_puts("Error: Command not found\n"); + if (*counter > 0) { + uart_send('h'); + uart_send('\b'); // Send Backspace to move cursor back + uart_send(' '); // Send space to clear the character on the screen + uart_send('\b'); // Send Backspace again to move cursor back + (*counter)--; // Decrement counter to remove the last character from the buffer + } + }else { + uart_send(c); + + if (*counter < MAX_BUFFER_LEN) { + buffer[*counter] = c; + (*counter)++; + } + else { + uart_puts("\nError: Input exceeded buffer length. Buffer reset.\n"); + *counter = 0; + strset(buffer, 0, MAX_BUFFER_LEN); + + // New line head + uart_puts("# "); + } + } +} + +void execute_command(int argc, char **argv) { + for (command_t *cmd = commands; cmd->command != NULL; cmd++) { + if (strcmp(argv[0], cmd->command) == 0) { + cmd->handler(argc,argv); + return; + } + } + + uart_puts("Error: Command not found\n"); + uart_puts("Try command: help\n"); +} + +int parse_arguments(char *buffer, char **argv) { + int argc = 0; + char *token = strtok(buffer, " "); // Tokenize buffer by space + + while (token != NULL && argc < 5) { + strcpy(argv[argc], token); // Copy token to argv + token = strtok(NULL, " "); + argc++; + } + + return argc; +} \ No newline at end of file diff --git a/demo/src/start.S b/demo/src/start.S new file mode 100755 index 000000000..7c7542e78 --- /dev/null +++ b/demo/src/start.S @@ -0,0 +1,184 @@ +.section ".text.boot" + +#define CORE0_TIMER_IRQ_CTRL 0x40000040 + +.global _start + +_start: + // bootloader loads a dtb into memory and passes the loading address specified at register x0 to the kernel. + // store x0 value for dtb + mov x10, x0 + + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbnz x1, halt + // cpu id > 0, stop + +change_ell_stat: + bl from_el2_to_el1 + b init_sp + +//Set stack pointer before code starts +init_sp: + ldr x1, =_start + mov sp, x1 + b set_exception_vector_table + +set_exception_vector_table: + adr x0, exception_vector_table + msr vbar_el1, x0 + b bss_init + +// cpu id == 0 +bss_init: + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size + +clear_bss_memory: + cbz w2, enable_Core_Timer + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, clear_bss_memory + +enable_Core_Timer: + bl core_timer_enable + b jump_to_main + +// jump to C code, should not return +jump_to_main: + mov x0, x10 + + bl main + // for failsafe, halt this core too + b halt + +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 + +halt: + wfe + b halt + +//exception +.macro exception_entry function + b \function + .align 7 // entry size is 0x80, .align will pad 0 +.endm + + +.align 11 // vector table should be aligned to 0x800 +.global exception_vector_table + +exception_vector_table: +// Exception from the current EL while using SP_EL0 + exception_entry showinfo_exception + exception_entry showinfo_exception + exception_entry showinfo_exception + exception_entry showinfo_exception + +// Exception from the current EL while using SP_ELx + exception_entry showinfo_exception + exception_entry irq_exception // el1 + exception_entry showinfo_exception + exception_entry showinfo_exception + +// Exception from a lower EL and at least one lower EL is AArch64 + exception_entry showinfo_exception + exception_entry irq_exception // el0 + exception_entry showinfo_exception + exception_entry showinfo_exception + +// Exception from a lower EL and all lower EL are AArch32 + exception_entry showinfo_exception + exception_entry showinfo_exception + exception_entry showinfo_exception + exception_entry showinfo_exception + + +// save general registers to stack +.macro save_all + sub sp, sp, 32 * 9 + 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] + + mrs x0, spsr_el1 + mrs x1, elr_el1 + stp x0, x1, [sp, 16 * 16] + // restore x0 and x1(as we just use it to save the information of spsr and elr) + ldp x0, x1, [sp, 16 * 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] + + ldp x0, x1, [sp, 16 * 16] + msr spsr_el1, x0 + msr elr_el1, x1 + // restore x0 and x1(as we just use it to restore the information of spsr and elr) + ldp x0, x1, [sp ,16 * 0] + add sp, sp, 32 * 9 +.endm + + +showinfo_exception: + save_all + bl showinfo_exception_handler + load_all + eret + +irq_exception: + save_all + bl irq_exception_handler + load_all + eret + + +core_timer_enable: + mov x0, 1 + msr cntp_ctl_el0, x0 // enable + mrs x0, cntfrq_el0 + msr cntp_tval_el0, x0 // set expired time + mov x0, 2 + ldr x1, =CORE0_TIMER_IRQ_CTRL + str w0, [x1] // unmask timer interrupt + ret + + diff --git a/demo/src/task.c b/demo/src/task.c new file mode 100755 index 000000000..6e6da328b --- /dev/null +++ b/demo/src/task.c @@ -0,0 +1,110 @@ +#include "../include/task.h" + +task_t* task_head = 0; +task_t* task_tail = 0; + +task_t * create_task(void (*callback)(void *), int priority){ + if(priority < 0){ + uart_puts("pririty should >= 0\n"); + return 0; + } + + + disable_interrupt(); + task_t *newTask = (task_t*)simple_malloc(sizeof(task_t)); + if(!newTask){ + uart_puts("Fail to create task: Memory allocation error\n"); + return 0; + } + + //disable core0 timer interrupt, otherwise will stuck in here + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x0); + + newTask->prev = 0; + newTask->next = 0; + newTask->callback = callback; + newTask->data = (void *)0; + newTask->priority = priority; + enable_interrupt(); + + return newTask; +} + +int add_task_to_queue(task_t *newTask){ + + disable_interrupt(); + //disable core0 timer interrupt, otherwise will stuck in here + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x0); + + task_t *cur = task_head; + + if(task_head == 0){ + task_head = newTask; + task_tail = newTask; + return 0; + } + + while(1){ + // insert into appropiate location based on increase-order + if(newTask->priority <= cur->priority){ + newTask->prev = cur->prev; + if(cur->prev != 0) + cur->prev->next = newTask; + cur->prev = newTask; + newTask->next = cur; + // if it is inserted into the head of queue + if(cur == task_head){ + task_head = newTask; + } + break; + } + // traverse to last element + else if(cur == task_tail){ + task_tail->next = newTask; + newTask->prev = task_tail; + task_tail = newTask; + break; + } + cur = cur->next; + } + + // enable all interrupt + enable_interrupt(); + + return 1; + +} + + +void test_tesk1(void){ + uart_puts("tesk1 finished\n"); +} + +void test_tesk2(void){ + uart_puts("tesk2 finished\n"); +} + +void test_tesk3(void){ + uart_puts("tesk3 finished\n"); +} + +// Function to print the tasks in the task queue +void ExecTasks(void) { + task_t* cur = task_head; + //uart_puts("exec\n"); + //if not empty + while(cur != 0){ + task_head = cur->next; + if(task_head != 0){ + task_head->prev = 0; + } + //uart_puts((char*)cur->data); + cur->callback(cur->data); + + cur = cur->next; + } + //uart_puts("Finish all task\n"); + + // enable all interrupt + //enable_interrupt(); +} \ No newline at end of file diff --git a/demo/src/timer.c b/demo/src/timer.c new file mode 100755 index 000000000..82ee3819f --- /dev/null +++ b/demo/src/timer.c @@ -0,0 +1,154 @@ +#include "../include/timer.h" + + +task_timer_t* timer_head = 0; +task_timer_t* timer_tail = 0; + +int core_timer_flag = 1; + +task_timer_t *create_timer(void (*callback)(void *),void* message, int seconds){ + unsigned long long cur_cnt, cnt_freq; + + if(seconds == 0) + return NULL; + + + disable_interrupt(); + + cur_cnt = read_register(cntpct_el0); + cnt_freq = read_register(cntfrq_el0); + + // preserve data + char *copy = simple_malloc(strlen((char*)message) + 1); + if(!copy){ + + enable_interrupt(); + uart_puts("Fail to create timer: Memory allocation error\n"); + return NULL; + } + + strcpy(copy, (char*)message); + task_timer_t *temp = simple_malloc(sizeof(task_timer_t)); + + if(!temp){ + enable_interrupt(); + uart_puts("Fail to create timer: Memory allocation error\n"); + return NULL; + } + + temp->callback = callback; + temp->data = (void*)copy; + // set to current_time + waiting seconds, as this is be compared with current_time in the irq_handler + temp->deadline = cur_cnt + seconds * cnt_freq; + temp->next = 0; + temp->prev = 0; + + enable_interrupt(); + + return temp; +} + +int timer_add_queue(task_timer_t *temp){ + int run_timer_flag = 0; + unsigned long long cur_cnt, cnt_freq; + + disable_interrupt(); + + cur_cnt = read_register(cntpct_el0); + cnt_freq = read_register(cntfrq_el0); + + task_timer_t *cur = timer_head; + + if(timer_head == 0){ + timer_head = temp; + timer_tail = temp; + // enable core0 timer interrupt + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x2); + write_register(cntp_cval_el0,temp->deadline); + write_register(cntp_ctl_el0,1); + enable_interrupt(); + return 1; + + + } + + //list not empty + while(1){ + // insert into appropiate location based on increase-order + if(temp->deadline <= cur->deadline){ + if(temp->deadline < cur->deadline){ + temp->prev = cur->prev; + if(cur->prev != 0) + cur->prev->next = temp; + cur->prev = temp; + temp->next = cur; + } + else{ + temp->prev = cur; + temp->next = cur->next; + if(cur->next != 0) + cur->next->prev = temp; + cur->next = temp; + } + + // if it is inserted into the timer_head of queue and have the smallest deadline + if(cur == timer_head && temp->deadline < cur->deadline){ + timer_head = temp; + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x2); + write_register(cntp_cval_el0,temp->deadline); + write_register(cntp_ctl_el0,1); + enable_interrupt(); + return 1; + } + + break; + } + // traverse to last element and have the biggest deadline + if(cur == timer_tail){ + timer_tail->next = temp; + temp->prev = timer_tail; + + timer_tail = temp; + break; + } + cur = cur->next; + } + + enable_interrupt(); + + return 1; +} + + +void timer_callback(void *str){ + unsigned long long cur_cnt, cnt_freq; + uart_puts("The message is: "); + uart_puts((char*)str); + + cur_cnt = read_register(cntpct_el0); + cnt_freq = read_register(cntfrq_el0); + + uart_puts(" wake up at: "); + uart_hex(cur_cnt / cnt_freq); + uart_send('\n'); +} + +void setTimeout (char *message, int seconds) { + + //if(add_timer(timer_callback, (void*)message, seconds) == 0) + // uart_puts("Fail to set timeout\n"); + + + //strcpy(copy, message); + task_timer_t *newtimer = create_timer(timer_callback, message, seconds); + if(!newtimer){ + uart_puts("Fail to set timeout\n"); + } + + if (timer_add_queue(newtimer) == 0) { + uart_puts("Fail to set timeout\n"); + } + + +} + diff --git a/demo/src/uart.c b/demo/src/uart.c new file mode 100755 index 000000000..b3c6ae971 --- /dev/null +++ b/demo/src/uart.c @@ -0,0 +1,307 @@ + +#include "../include/uart.h" + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init() +{ + register unsigned int reg; + + /* initialize UART */ + *AUX_ENABLE |= 1; /* enable mini UART */ + *AUX_MU_CNTL = 0; /* Disable transmitter and receiver during configuration. */ + + *AUX_MU_IER = 0; /* Disable interrupt */ + *AUX_MU_LCR = 3; /* Set the data size to 8 bit. */ + *AUX_MU_MCR = 0; /* Don’t need auto flow control. */ + *AUX_MU_BAUD = 270; /* 115200 baud */ + *AUX_MU_IIR = 6; /* No FIFO */ + // *AUX_MU_IIR = 0xc6; /* No FIFO */ + + /* map UART1 to GPIO pins */ + // GPFSEL1 register controls the function of GPIO pins + reg = *GPFSEL1; + reg &= ~((7<<12)|(7<<15)); /* address of gpio 14, 15 */ + reg |= (2<<12)|(2<<15); /* set to alt5 */ + + *GPFSEL1 = reg; + reg=150; + while ( reg-- ) + { + asm volatile("nop"); + } + // ensures that GPIO pins are not affected by internal resistors + *GPPUD = 0; /* Disable pull-up/down */ + reg=150; + while ( reg-- ) + { + asm volatile("nop"); + } + + *GPPUDCLK0 = (1<<14)|(1<<15); + reg=150; + while ( reg-- ) + { + asm volatile("nop"); + } + *GPPUDCLK0 = 0; /* flush GPIO setup */ + //Stabilizing the Signal to ensure Proper Configuration + reg=150; + while ( reg-- ) + { + asm volatile("nop"); + } + + // ensures that GPIO pins are returned to a neutral state + *GPPUDCLK0 = 0; /* flush GPIO setup */ + + *AUX_MU_CNTL = 3; // Enable the transmitter and receiver. + + //*((volatile unsigned int*)AUX_MU_IER) &= ~0x03; + +} + +/** + * Send a character + */ +void uart_send(unsigned int c) +{ + /* Wait until UART transmitter is ready to accept new data. */ + do { + + asm volatile("nop"); + + } while( ! ( *AUX_MU_LSR&0x20 )); + + /* write the character to the buffer */ + *AUX_MU_IO = c; + + // ensure proper line termination + if ( c == '\n' ) + { + do { + + asm volatile("nop"); + + } while( ! ( *AUX_MU_LSR&0x20 )); + + *AUX_MU_IO = '\r'; + } +} + + +/** + * Receive a character + */ +char uart_getc() { + + char r; + + /* wait until something is in the buffer */ + do{ + + asm volatile("nop"); + + } while ( ! ( *AUX_MU_LSR&0x01 ) ); + + /* read the data*/ + r = ( char )( *AUX_MU_IO ); + + /* convert carrige return to newline */ + //standardize newline characters across different systems. + return r == '\r' ? '\n' : r; +} + +/** + * Display a string + */ +void uart_puts(const char *s) +{ + while( *s ) + { + + uart_send(*s++); + + } +} + +char *get_string(void){ + int buffer_counter = 0; + char input_char; + static char buffer[TMP_BUFFER_LEN]; + strset(buffer, 0, TMP_BUFFER_LEN); + while (1) { + input_char = uart_getc(); + if (!(input_char < 128 && input_char >= 0)) { + uart_puts("Invalid character received\n"); + return NULL; + } else if (input_char == LINE_FEED || input_char == CRRIAGE_RETURN) { + uart_send(input_char); + buffer[buffer_counter] = '\0'; + return buffer; + }else { + uart_send(input_char); + + if (buffer_counter < TMP_BUFFER_LEN) { + buffer[buffer_counter] = input_char; + buffer_counter++; + } + else { + uart_puts("\nError: Input exceeded buffer length. Buffer reset.\n"); + buffer_counter = 0; + strset(buffer, 0, TMP_BUFFER_LEN); + + // New line head + uart_puts("# "); + } + } + } +} + +/** + * Display a binary value in hexadecimal + */ +void uart_hex(unsigned int d) { + unsigned int n; + int c; + 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?0x37:0x30; + uart_send(n); + } +} + +char read_buffer[BUFFER_SIZE]; +char write_buffer[BUFFER_SIZE]; + +int read_index_cur = 0; +int read_index_tail = 0; +int write_index_cur = 0; +int write_index_tail = 0; + +void initialize_async_buffers(void) { + strset(read_buffer, 0, BUFFER_SIZE); + strset(write_buffer, 0, BUFFER_SIZE); +} + +void uart_send_async(char c) { + //uart_puts("uart_send_async\n"); + + write_buffer[write_index_tail++] = c; + + if (write_index_tail >= BUFFER_SIZE) { + write_index_tail = 0; + } + + // Enable mini UART transmit interrupt to start sending the data + *((volatile unsigned int*)AUX_MU_IER) |= 0x02; +} + +char uart_getc_async(void) { + //*((volatile unsigned int*)AUX_MU_IER) |= (0x1); + //uart_puts("uart_getc_async\n"); + if(read_index_cur != read_index_tail){ + //uart_puts("test"); + char c = read_buffer[read_index_cur++]; + //uart_send(c); + if (read_index_cur >= BUFFER_SIZE) { + read_index_cur = 0; + } + + return c; + + } + else{ + return '!'; + } +} + +void uart_puts_async(const char *str) { + //uart_puts("uart_puts_async\n"); + while (*str) { + + if(*str == '\n'){ + write_buffer[write_index_tail++] = '\r'; + } + + + if (write_index_tail >= BUFFER_SIZE) { + write_index_tail = 0; + } + + write_buffer[write_index_tail++] = *str++; + + + } + // Enable mini UART transmit interrupt to start sending the data + *((volatile unsigned int*)AUX_MU_IER) |= 0x02; +} + +void get_string_async(char *buffer_async){ + //uart_puts("uart_string_async\n"); + int buffer_counter = 0; + char input_char; + + while(1){ + //uart_send(buffer_counter+'0'); + input_char = uart_getc_async(); + //uart_puts("in get\n"); + // Disable mini UART transmit interrupt + *((volatile unsigned int*)AUX_MU_IER) &= ~(0x2); + + if(input_char == '!'){ + //uart_puts("empty\n"); + continue; + } + //uart_puts("check input : "); + //uart_send(input_char); + //uart_puts("\n"); + // Get non ASCII code + if (input_char >= 128 || input_char < 0) { + //uart_puts("Invalid character received\n"); + continue; + } + if (input_char == CRRIAGE_RETURN) { + //uart_send_async(input_char); + buffer_async[buffer_counter] = '\0'; + //uart_puts_async("\n"); + return; + } + if (buffer_counter < TMP_BUFFER_LEN - 1) { + buffer_async[buffer_counter] = input_char; + buffer_counter++; + *((volatile unsigned int*)AUX_MU_IER) |= (0x1); + //uart_puts(buffer_async); + //uart_puts("\n"); + } else { + //uart_puts_async("\nError: Input exceeded buffer length. Buffer reset.\n"); + buffer_counter = 0; + strset(buffer_async, 0, TMP_BUFFER_LEN); + + // New line head + uart_puts_async("# "); + } + + } +} + +void uart_int(int num){ + char tmp[65]; + itoa(num,tmp,10); + uart_puts(tmp); +} + +void uart_hex_64(uint64_t d) { + 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(n); + } +} \ No newline at end of file diff --git a/demo/user_program/asm2img.sh b/demo/user_program/asm2img.sh new file mode 100755 index 000000000..f427cdc06 --- /dev/null +++ b/demo/user_program/asm2img.sh @@ -0,0 +1,3 @@ +aarch64-linux-gnu-as -o user_program.o user_program.S +aarch64-linux-gnu-ld -o user_program.elf user_program.o +aarch64-linux-gnu-objcopy -O binary user_program.elf -O binary ../rootfs/userprogram.img \ No newline at end of file diff --git a/demo/user_program/user_program.S b/demo/user_program/user_program.S new file mode 100755 index 000000000..87b4851f3 --- /dev/null +++ b/demo/user_program/user_program.S @@ -0,0 +1,11 @@ +.section ".text" +.global _start +_start: + mov x0, 0 +1: + add x0, x0, 1 + svc 0 + cmp x0, 5 + blt 1b +1: + b 1b \ No newline at end of file diff --git a/demo/user_program/user_program.elf b/demo/user_program/user_program.elf new file mode 100755 index 000000000..e506290ce Binary files /dev/null and b/demo/user_program/user_program.elf differ diff --git a/demo/user_program/user_program.o b/demo/user_program/user_program.o new file mode 100755 index 000000000..f84f74464 Binary files /dev/null and b/demo/user_program/user_program.o differ