diff --git a/Dockerfile b/Dockerfile index 743cbf69c..6a5ece06b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update # Install QEMU for emulation RUN apt-get install -y \ qemu-system-arm \ - gdb \ + gdb-multiarch \ sudo # Install the AArch64 cross-compiler toolchain @@ -30,6 +30,11 @@ RUN apt-get install -y \ # make gcc alia to aarch64-linux-gnu-gcc RUN echo "alias gcc='aarch64-linux-gnu-gcc'" >> ~/.bashrc +# install python dependicies +RUN apt install -y python3-pip + +RUN pip install pyserial + # clean up package caches RUN rm -rf /var/lib/apt/lists/* diff --git a/lab_2/README.md b/lab_2/README.md index cdb3a5992..30115f485 100644 --- a/lab_2/README.md +++ b/lab_2/README.md @@ -1,34 +1,14 @@ -Tutorial 03 - UART1, Auxilary mini UART -======================================= - -It is time for the famous Hello World example. We're going to write on the UART1 first, as it's easier to program -as it has a fixed clocked frequency. - -NOTE: qemu does not redirect UART1 to terminal by default, only UART0, so you have to use `-serial null -serial stdio`. - -Gpio.h ------- - -We have a new header file. This defines the base MMIO address, and the GPIO controller's addresses. This file -going to be very popular, as many devices need it. - -Uart.h, uart.c --------------- - -A very minimal implementation. - -`uart_init()` initializes the device and maps it to the GPIO ports. - -`uart_send(c)` sends a character over the serial line. - -`uart_getc()` receives a character. The carrige return character (13) will be converted into a newline character (10). - -`uart_puts(s)` prints out a string. On newline, a carrige return character will also be sent (13 + 10). - -Main ----- - -First, we have to call the uart initialization code. Then, it'll return "Hello World!". If you've purchased an USB -serial cable, you should see it on minicom's screen. After that every character typed in minicom will be -echoed back. If you haven't turned off local echo, that means you'll see every pressed key twice. - +1. python UART transfer data loss +- AUX_MU_LSR_REG bit 1: This bit is set if there was a receiver overrun. That is: +one or more characters arrived whilst the receive +FIFO was full. The newly arrived charters have been +discarded. This bit is cleared each time this register is +read. To do a non-destructive read of this overrun bit +use the Mini Uart Extra Status register. +[reference: P15](https://cs140e.sergio.bz/docs/BCM2837-ARM-Peripherals.pdf) + +2. init UART register to avoid garbage pending +3. link loader can arrange the .text section freely + - why align +4. wze is for halting CPU that is not id 0 +5. \ No newline at end of file diff --git a/lab_2/bootloader/Makefile b/lab_2/bootloader/Makefile index 87d5b39d0..2a00a5890 100644 --- a/lab_2/bootloader/Makefile +++ b/lab_2/bootloader/Makefile @@ -46,7 +46,14 @@ clean: rm kernel8.elf *.o >/dev/null 2>/dev/null || true run: - qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial pty -display none -d in_asm + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -initrd initramfs.cpio -serial pty -display none -dtb bcm2710-rpi-3-b-plus.dtb + +run_asm: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -initrd initramfs.cpio -serial pty -display none -dtb bcm2710-rpi-3-b-plus.dtb -d in_asm + + +run_stdio: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -initrd initramfs.cpio -serial stdio -display none -dtb bcm2710-rpi-3-b-plus.dtb debug: qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -s -S diff --git a/lab_2/bootloader/bcm2710-rpi-3-b-plus.dtb b/lab_2/bootloader/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..a219bf3d5 Binary files /dev/null and b/lab_2/bootloader/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab_2/bootloader/device_tree.c b/lab_2/bootloader/device_tree.c new file mode 100644 index 000000000..6370eb7b7 --- /dev/null +++ b/lab_2/bootloader/device_tree.c @@ -0,0 +1,74 @@ +#include "include/device_tree.h" +#include "include/uart.h" +// #include +// #include + +device_tree_header myHeader; + +void header_parser(uintptr_t dtb_address){ + uint32_t* start; + //uint32_t* dtb = mock_load_file(); + uint32_t* dtb = dtb_address; + start = dtb; + // __builtin_bswap32() is a GCC built-in function to convert to the system's endianness.(RPi uses little-endian) + myHeader.magic = __builtin_bswap32(*dtb++); + if ((myHeader.magic - 0xd00dfeed) != 0) { + uart_puts("DTB magic number doesn't match!\r\n"); + return 1; + } + myHeader.totalsize = __builtin_bswap32(*dtb++); + myHeader.off_dt_struct = __builtin_bswap32(*dtb++); + myHeader.off_dt_strings = __builtin_bswap32(*dtb++); + myHeader.off_mem_rsvmap = __builtin_bswap32(*dtb++); + myHeader.version = __builtin_bswap32(*dtb++); + myHeader.last_comp_version = __builtin_bswap32(*dtb++); + myHeader.boot_cpuid_phys = __builtin_bswap32(*dtb++); + myHeader.size_dt_strings = __builtin_bswap32(*dtb++); + myHeader.size_dt_struct = __builtin_bswap32(*dtb++); + + // jump to structure + uint32_t* structure_ptr = (uint32_t *)(start + myHeader.off_dt_struct); + while(1){ + uint32_t token = __builtin_bswap32(*structure_ptr++); + if(token == FDT_BEGIN_NODE){ + uart_puts("Start\n"); + } + } + + //The node’s name as a null-terminated string + + + +} + +// unsigned long* mock_load_file() { +// FILE *file = fopen("bcm2710-rpi-3-b-plus.dtb", "rb"); +// if (!file) { +// perror("Failed to open file"); +// return 1; +// } + +// // Get the size of the file +// fseek(file, 0, SEEK_END); +// long fileSize = ftell(file); +// rewind(file); + +// // Allocate memory to hold the entire file +// unsigned char *buffer = (unsigned char *)malloc(fileSize); +// if (!buffer) { +// perror("Failed to allocate memory"); +// fclose(file); +// return 1; +// } + +// // Read the entire file into the buffer +// size_t bytesRead = fread(buffer, 1, fileSize, file); +// if (bytesRead != fileSize) { +// perror("Failed to read file"); +// free(buffer); +// fclose(file); +// return 1; +// } + +// return (unsigned long*)buffer; +// } \ No newline at end of file diff --git a/lab_2/bootloader/include/device_tree.h b/lab_2/bootloader/include/device_tree.h new file mode 100644 index 000000000..6846d0cba --- /dev/null +++ b/lab_2/bootloader/include/device_tree.h @@ -0,0 +1,34 @@ +#include "stdint.h" + + +typedef struct fdt_header { + // 0xd00dfeed (big-endian) + uint32_t magic; + uint32_t totalsize; + // offsets of each block from start + uint32_t off_dt_struct; + uint32_t off_dt_strings; + uint32_t off_mem_rsvmap; + + uint32_t version; + uint32_t last_comp_version; + // physical ID of the system’s boot CPU + uint32_t boot_cpuid_phys; + uint32_t size_dt_strings; + uint32_t size_dt_struct; +} device_tree_header; + +#define ALIGN_MEMORY_BLOCK 8 + +/* All tokens shall be aligned on a 32-bit boundary */ +#define ALIGN_STRUCT_BLOCK 4 + +/* tokens used for structure block */ +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + + +void header_parser(); diff --git a/lab_2/bootloader/include/stdint.h b/lab_2/bootloader/include/stdint.h new file mode 100644 index 000000000..3ddcc9b17 --- /dev/null +++ b/lab_2/bootloader/include/stdint.h @@ -0,0 +1,9 @@ + +typedef unsigned int uint16_t; + +typedef unsigned long uint32_t; + +typedef unsigned long long uint64_t; +typedef unsigned long uintptr_t; +typedef float float32; +typedef double float64; \ No newline at end of file diff --git a/lab_2/bootloader/initramfs.cpio b/lab_2/bootloader/initramfs.cpio new file mode 100644 index 000000000..e9c1dda97 Binary files /dev/null and b/lab_2/bootloader/initramfs.cpio differ diff --git a/lab_2/bootloader/kernel_uploader.py b/lab_2/bootloader/kernel_uploader.py index 339093955..5f93a1747 100644 --- a/lab_2/bootloader/kernel_uploader.py +++ b/lab_2/bootloader/kernel_uploader.py @@ -2,8 +2,13 @@ import os import os.path import sys +import time -port = '/dev/pts/3' + +print("please enter the serial port: ", end="") +port = input() +port = "/dev/"+port +# port = '/dev/pts/1' s = serial.Serial(port, baudrate=115200) def read_line(s): @@ -18,24 +23,47 @@ def read_line(s): return received_string size = os.stat("../shell/shell_kernel.img").st_size +print(size) +# size = os.stat("./kernel8.img").st_size + size_bytes = size.to_bytes(4,"little") +print(f"size from python: {hex(size)}") s.write(size_bytes) +time.sleep(1) # get response of correctness of bytes size sent -received_size = read_line(s) -print(received_size) +while s.in_waiting > 0: + received_content = read_line(s) + print(received_content) + +with open("../shell/shell_kernel.img", "rb") as f: + sent_size = 0 # Initialize size counter -with open("../shell/shell_kernel.img","rb") as f: - s.write(f.read()) + byte = f.read(1) # Read the first byte + while byte: + s.write(byte) # Send the byte over serial + # s.flush() # Flush the output buffer + sent_size += 1 # Increment size counter + byte = f.read(1) # Read the next byte + + +assert sent_size == size +print("kernel sent successfully.") # get response of whether kernel is loaded successfully or not -received_content = read_line(s) -print(received_content) +time.sleep(1) while(True): while s.in_waiting > 0: received_content = read_line(s) print(received_content) + print("#", end=" ") inp = input() + if(inp == ""): + continue + inp += "\n" bytes_to_send = inp.encode('utf-8') s.write(bytes_to_send) - print(received_content) \ No newline at end of file + #while s.in_waiting > 0: + # received_content = read_line(s) + # print(received_content) + time.sleep(1) \ No newline at end of file diff --git a/lab_2/bootloader/link.ld b/lab_2/bootloader/link.ld index 9d5029b23..5d4536049 100644 --- a/lab_2/bootloader/link.ld +++ b/lab_2/bootloader/link.ld @@ -22,13 +22,24 @@ * DEALINGS IN THE SOFTWARE. * */ - SECTIONS { . = 0x60000; PROVIDE(_head = .); - .text : { KEEP(*(.text.boot)) *(.text .text.*) } - .rodata : { *(.rodata .rodata.*) } + .relocate : { + KEEP(*(.text.relocate)) + } + . = ALIGN(4096); + + .imgLoader : { + KEEP(*(.text.load_img)) + } + . = ALIGN(4096); + .text : { + KEEP(*(.text.boot)) + *(.text) + } + . = ALIGN(4096); PROVIDE(_data = .); .data : { *(.data .data.*) } .bss : { diff --git a/lab_2/bootloader/main.c b/lab_2/bootloader/main.c index c2c550fed..e8be04b8c 100644 --- a/lab_2/bootloader/main.c +++ b/lab_2/bootloader/main.c @@ -26,6 +26,8 @@ #include "include/uart.h" #include "include/utils.h" #include "include/mbox.h" +#include "include/stdint.h" +#include "include/device_tree.h" void load_img(){ unsigned int size = 0; @@ -35,27 +37,24 @@ void load_img(){ size_buffer[i] = uart_getc(); uart_puts("size-check correct\n"); + uart_puts("Kernel size received: "); + uart_hex(size); + uart_puts("\n"); + char *kernel = (char *) 0x80000; while(size--) *kernel++ = uart_getc(); uart_puts("kernel-loaded\n"); - - asm volatile( - "mov x30, 0x80000;" - "ret;" - ); + return; } -void main(int argc, char* argv[]){ - asm volatile( - "mov x10, x0" - ); +void relocator(uintptr_t dtb_address){ uart_init(); + // header_parser(dtb_address); load_img(); asm volatile( "mov x30, 0x80000;" - "mov x0, x10;" "ret;" ); } diff --git a/lab_2/bootloader/reader.py b/lab_2/bootloader/reader.py new file mode 100644 index 000000000..19a5e759a --- /dev/null +++ b/lab_2/bootloader/reader.py @@ -0,0 +1,9 @@ +with open("./bcm2710-rpi-3-b-plus.dtb", "rb") as f: + data = f.read() +# Filter out the 0x00 bytes +filtered_data = bytes(b for b in data if b != 0x00) + +# Print the filtered binary data +print(filtered_data) + +#print(data) \ No newline at end of file diff --git a/lab_2/bootloader/start.S b/lab_2/bootloader/start.S index ecef527bb..b086305c4 100644 --- a/lab_2/bootloader/start.S +++ b/lab_2/bootloader/start.S @@ -1,31 +1,43 @@ -.section ".text.boot" - -.global _start - -_start: +.section ".text.relocate" +.global _relocate +_relocate: // relocate our code from load address to link address ldr x1, =0x80000; // src address - ldr x2, =_head // target address + ldr x2, =0x60000; // target address ldr w3, =__loader_size 1: ldr x4, [x1], #8 str x4, [x2], #8 sub w3, w3, #1 cbnz w3, 1b - // set top of stack just before our code (stack grows to a lower address per AAPCS64) ldr x1, =_start mov sp, x1 // clear bss ldr x1, =__bss_start ldr w2, =__bss_size -3: cbz w2, 4f +2: cbz w2, 3f str xzr, [x1], #8 sub w2, w2, #1 - cbnz w2, 3b + cbnz w2, 2b + + +3: // Device tree address has been moved from x0 to x10 within the bootloader. + mov x0, x10 + bl relocator-0x20000 + b _start + + +.section ".text.boot" + +.global _start + +_start: + // jump to main function in C + bl 0x80000 + // halt this core if return +1: + wfe + b 1b - // jump to relocated C code, should not return -4: bl main-0x20000 - // for failsafe, halt this core too - b =0x80000 \ No newline at end of file diff --git a/lab_2/bootloader/uart.c b/lab_2/bootloader/uart.c index 489c6608a..998d1509a 100644 --- a/lab_2/bootloader/uart.c +++ b/lab_2/bootloader/uart.c @@ -68,6 +68,12 @@ void uart_init() r=150; while(r--) { asm volatile("nop"); } *GPPUDCLK0 = 0; // flush GPIO setup *AUX_MU_CNTL = 3; // enable Tx, Rx + /*EXTRA: Read from AUX_MU_IO until AUX_MU_LSR indicates no more data*/ + while (*AUX_MU_LSR & 0x01) { + // Read and discard the data + volatile unsigned int data = *AUX_MU_IO; + (void)data; // Prevent unused variable warning + } } /** diff --git a/lab_2/shell/Makefile b/lab_2/shell/Makefile index 3c685e120..ed9e406a1 100644 --- a/lab_2/shell/Makefile +++ b/lab_2/shell/Makefile @@ -46,7 +46,7 @@ clean: rm kernel8.elf *.o >/dev/null 2>/dev/null || true run: - qemu-system-aarch64 -M raspi3b -kernel shell_kernel.img -initrd initramfs.cpio -serial null -serial stdio -display none + qemu-system-aarch64 -M raspi3b -kernel shell_kernel.img -initrd initramfs.cpio -serial null -serial stdio -display none -d in_asm debug: qemu-system-aarch64 -M raspi3b -kernel shell_kernel.img -initrd initramfs.cpio -serial null -serial stdio -display none -s -S diff --git a/lab_2/shell/cpio.c b/lab_2/shell/cpio.c index 77a9f6f10..3fdbd10c2 100644 --- a/lab_2/shell/cpio.c +++ b/lab_2/shell/cpio.c @@ -6,7 +6,6 @@ char* cpio_addr = (char *)0x8000000;; void cpio_ls(){ char* addr = (char*) cpio_addr; - uart_puts((char *)(addr+sizeof(struct cpio_header))); while(strcmp((char *)(addr+sizeof(struct cpio_header)),"TRAILER!!!") != 0){ struct cpio_header* header = (struct cpio_header*) addr; unsigned long filename_size = utils_atoi(header->c_namesize,(int)sizeof(header->c_namesize)); @@ -26,11 +25,11 @@ void cpio_cat(char *filename){ struct cpio_header *header = (struct cpio_header *)target; unsigned long pathname_size = utils_atoi(header->c_namesize,(int)sizeof(header->c_namesize)); unsigned long file_size = utils_atoi(header->c_filesize,(int)sizeof(header->c_filesize)); + //The header is followed by the pathname of the entry, then is content of file unsigned long headerPathname_size = sizeof(struct cpio_header) + pathname_size; utils_align(&headerPathname_size,4); utils_align(&file_size,4); - char *file_content = target + headerPathname_size; for (unsigned int i = 0; i < file_size; i++) { @@ -47,6 +46,7 @@ void cpio_cat(char *filename){ char *findFile(char *name){ char *addr = (char *)cpio_addr; while (strcmp((char *)(addr + sizeof(struct cpio_header)), "TRAILER!!!") != 0){ + //The header is followed by the pathname of the entry if ((strcmp((char *)(addr + sizeof(struct cpio_header)), name) == 0)){ return addr; } diff --git a/lab_2/shell/main.c b/lab_2/shell/main.c index 60860d053..65e22a961 100644 --- a/lab_2/shell/main.c +++ b/lab_2/shell/main.c @@ -22,7 +22,7 @@ * DEALINGS IN THE SOFTWARE. * */ -#define MAX_BUFFER 10 +#define MAX_BUFFER 50 #include "include/uart.h" #include "include/utils.h" #include "include/mbox.h" @@ -30,13 +30,77 @@ void main(int argc, char* argv[]){ - uart_init(); - cpio_ls(); - cpio_cat("hello2.txt"); - cpio_ls(); - cpio_cat("hello.txt"); - int* data = (int *)simple_malloc((unsigned long) sizeof(int)*8); - int* b = (int *)simple_malloc((unsigned long) sizeof(int)*8); - uart_puts("exit normally"); + unsigned int* a = (unsigned int*) simple_malloc(4); + *a = 32; + unsigned int* b = (unsigned int*) simple_malloc(4); + *b = 70; + uart_puts("a = 0x"); + uart_hex(*a); + uart_puts("\nb = 0x"); + uart_hex(*b); + uart_send('\n'); + while(1){ + char command[MAX_BUFFER]; + char c = '\0'; + int length=0; + for(int i=0; i\t: print the content of file in root filesystem\n"); + uart_puts("hello\t: print hello world!\n"); + uart_puts("reboot\t: reboot the device\n"); + } + else if(strcmp(command, "hello") == 0){ + uart_puts("Hello World!\n"); + } + else if(strcmp(command, "ls") == 0){ + cpio_ls(); + } + else if(strcmp(command, "reboot") == 0){ + reset(); + } + // command with arguments + else{ + char arguments[3][MAX_BUFFER]; + // initialize + for(int i=0;i<3;i++){ + for(int j=0;j SIMPLE_MALLOC_BUFFER_SIZE) { //Not enough space left diff --git a/lab_3/Makefile b/lab_3/Makefile new file mode 100644 index 000000000..015d9ea3d --- /dev/null +++ b/lab_3/Makefile @@ -0,0 +1,52 @@ +# +# Copyright (C) 2018 bzt (bztsrc@github) +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# + +GCC = "aarch64-linux-gnu-gcc" +LD = "aarch64-linux-gnu-ld" +OBJCPY = "aarch64-linux-gnu-objcopy" +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) +CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles +BOOTLOADER_BIN = kernel8.img +all: clean kernel8.img + +start.o: start.S + $(GCC) $(CFLAGS) -c start.S -o start.o + +%.o: %.c + $(GCC) $(CFLAGS) -c $< -o $@ -g + +kernel8.img: start.o $(OBJS) + $(LD) -nostdlib -nostartfiles start.o $(OBJS) -T link.ld -o kernel8.elf + $(OBJCPY) -O binary kernel8.elf kernel8.img + +clean: + rm kernel8.elf *.o >/dev/null 2>/dev/null || true + +run: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -d in_asm + +debug: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -s -S diff --git a/lab_3/Makefile.gcc b/lab_3/Makefile.gcc new file mode 100644 index 000000000..77366f3cf --- /dev/null +++ b/lab_3/Makefile.gcc @@ -0,0 +1,52 @@ +# +# Copyright (C) 2018 bzt (bztsrc@github) +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# + +GCC = "aarch64-linux-gnu-gcc" +LD = "aarch64-linux-gnu-ld" +OBJCPY = "aarch64-linux-gnu-objcopy" +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) +CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles + +all: clean kernel8.img + +start.o: start.S + $(GCC) $(CFLAGS) -c start.S -o start.o + +%.o: %.c + $(GCC) $(CFLAGS) -c $< -o $@ -g + +kernel8.img: start.o $(OBJS) + $(LD) -nostdlib -nostartfiles start.o $(OBJS) -T link.ld -o kernel8.elf + $(OBJCPY) -O binary kernel8.elf kernel8.img + +clean: + rm kernel8.elf *.o >/dev/null 2>/dev/null || true + +run: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none + +debug: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -s -S diff --git a/lab_3/README.md b/lab_3/README.md new file mode 100644 index 000000000..ff2c23e3f --- /dev/null +++ b/lab_3/README.md @@ -0,0 +1,6 @@ +1. python UART transfer data loss +2. init UART register to avoid garbage pending +3. link loader can arrange the .text section freely + - why align +4. wze is for halting CPU that is not id 0 +5. \ No newline at end of file diff --git a/lab_3/bootloader/Makefile b/lab_3/bootloader/Makefile new file mode 100644 index 000000000..2a00a5890 --- /dev/null +++ b/lab_3/bootloader/Makefile @@ -0,0 +1,59 @@ +# +# Copyright (C) 2018 bzt (bztsrc@github) +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# + +GCC = "aarch64-linux-gnu-gcc" +LD = "aarch64-linux-gnu-ld" +OBJCPY = "aarch64-linux-gnu-objcopy" +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) +CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles +BOOTLOADER_BIN = kernel8.img +all: clean kernel8.img + +start.o: start.S + $(GCC) $(CFLAGS) -c start.S -o start.o + +%.o: %.c + $(GCC) $(CFLAGS) -c $< -o $@ -g + +kernel8.img: start.o $(OBJS) + $(LD) -nostdlib -nostartfiles start.o $(OBJS) -T link.ld -o kernel8.elf + $(OBJCPY) -O binary kernel8.elf kernel8.img + +clean: + rm kernel8.elf *.o >/dev/null 2>/dev/null || true + +run: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -initrd initramfs.cpio -serial pty -display none -dtb bcm2710-rpi-3-b-plus.dtb + +run_asm: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -initrd initramfs.cpio -serial pty -display none -dtb bcm2710-rpi-3-b-plus.dtb -d in_asm + + +run_stdio: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -initrd initramfs.cpio -serial stdio -display none -dtb bcm2710-rpi-3-b-plus.dtb + +debug: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -s -S diff --git a/lab_3/bootloader/bcm2710-rpi-3-b-plus.dtb b/lab_3/bootloader/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..a219bf3d5 Binary files /dev/null and b/lab_3/bootloader/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab_3/bootloader/device_tree.c b/lab_3/bootloader/device_tree.c new file mode 100644 index 000000000..6370eb7b7 --- /dev/null +++ b/lab_3/bootloader/device_tree.c @@ -0,0 +1,74 @@ +#include "include/device_tree.h" +#include "include/uart.h" +// #include +// #include + +device_tree_header myHeader; + +void header_parser(uintptr_t dtb_address){ + uint32_t* start; + //uint32_t* dtb = mock_load_file(); + uint32_t* dtb = dtb_address; + start = dtb; + // __builtin_bswap32() is a GCC built-in function to convert to the system's endianness.(RPi uses little-endian) + myHeader.magic = __builtin_bswap32(*dtb++); + if ((myHeader.magic - 0xd00dfeed) != 0) { + uart_puts("DTB magic number doesn't match!\r\n"); + return 1; + } + myHeader.totalsize = __builtin_bswap32(*dtb++); + myHeader.off_dt_struct = __builtin_bswap32(*dtb++); + myHeader.off_dt_strings = __builtin_bswap32(*dtb++); + myHeader.off_mem_rsvmap = __builtin_bswap32(*dtb++); + myHeader.version = __builtin_bswap32(*dtb++); + myHeader.last_comp_version = __builtin_bswap32(*dtb++); + myHeader.boot_cpuid_phys = __builtin_bswap32(*dtb++); + myHeader.size_dt_strings = __builtin_bswap32(*dtb++); + myHeader.size_dt_struct = __builtin_bswap32(*dtb++); + + // jump to structure + uint32_t* structure_ptr = (uint32_t *)(start + myHeader.off_dt_struct); + while(1){ + uint32_t token = __builtin_bswap32(*structure_ptr++); + if(token == FDT_BEGIN_NODE){ + uart_puts("Start\n"); + } + } + + //The node’s name as a null-terminated string + + + +} + +// unsigned long* mock_load_file() { +// FILE *file = fopen("bcm2710-rpi-3-b-plus.dtb", "rb"); +// if (!file) { +// perror("Failed to open file"); +// return 1; +// } + +// // Get the size of the file +// fseek(file, 0, SEEK_END); +// long fileSize = ftell(file); +// rewind(file); + +// // Allocate memory to hold the entire file +// unsigned char *buffer = (unsigned char *)malloc(fileSize); +// if (!buffer) { +// perror("Failed to allocate memory"); +// fclose(file); +// return 1; +// } + +// // Read the entire file into the buffer +// size_t bytesRead = fread(buffer, 1, fileSize, file); +// if (bytesRead != fileSize) { +// perror("Failed to read file"); +// free(buffer); +// fclose(file); +// return 1; +// } + +// return (unsigned long*)buffer; +// } \ No newline at end of file diff --git a/lab_3/bootloader/include/device_tree.h b/lab_3/bootloader/include/device_tree.h new file mode 100644 index 000000000..6846d0cba --- /dev/null +++ b/lab_3/bootloader/include/device_tree.h @@ -0,0 +1,34 @@ +#include "stdint.h" + + +typedef struct fdt_header { + // 0xd00dfeed (big-endian) + uint32_t magic; + uint32_t totalsize; + // offsets of each block from start + uint32_t off_dt_struct; + uint32_t off_dt_strings; + uint32_t off_mem_rsvmap; + + uint32_t version; + uint32_t last_comp_version; + // physical ID of the system’s boot CPU + uint32_t boot_cpuid_phys; + uint32_t size_dt_strings; + uint32_t size_dt_struct; +} device_tree_header; + +#define ALIGN_MEMORY_BLOCK 8 + +/* All tokens shall be aligned on a 32-bit boundary */ +#define ALIGN_STRUCT_BLOCK 4 + +/* tokens used for structure block */ +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + + +void header_parser(); diff --git a/lab_3/bootloader/include/gpio.h b/lab_3/bootloader/include/gpio.h new file mode 100644 index 000000000..52fa671d0 --- /dev/null +++ b/lab_3/bootloader/include/gpio.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#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)) diff --git a/lab_3/bootloader/include/mbox.h b/lab_3/bootloader/include/mbox.h new file mode 100644 index 000000000..e0e2e41f1 --- /dev/null +++ b/lab_3/bootloader/include/mbox.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +/* a properly aligned buffer */ +extern volatile unsigned int mbox[36]; + +#define MBOX_REQUEST 0 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define MBOX_TAG_GETSERIAL 0x10004 +#define MBOX_TAG_REVISION 0x00010002 +#define MBOX_TAG_MEMORY 0x00010005 +#define MBOX_TAG_LAST 0 + +int mbox_call(unsigned char ch); diff --git a/lab_3/bootloader/include/stdint.h b/lab_3/bootloader/include/stdint.h new file mode 100644 index 000000000..3ddcc9b17 --- /dev/null +++ b/lab_3/bootloader/include/stdint.h @@ -0,0 +1,9 @@ + +typedef unsigned int uint16_t; + +typedef unsigned long uint32_t; + +typedef unsigned long long uint64_t; +typedef unsigned long uintptr_t; +typedef float float32; +typedef double float64; \ No newline at end of file diff --git a/lab_3/bootloader/include/uart.h b/lab_3/bootloader/include/uart.h new file mode 100644 index 000000000..245c358c8 --- /dev/null +++ b/lab_3/bootloader/include/uart.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +void uart_init(); +void uart_send(unsigned int c); +char uart_getc(); +void uart_puts(char *s); +void uart_hex(unsigned int d); \ No newline at end of file diff --git a/lab_3/bootloader/include/utils.h b/lab_3/bootloader/include/utils.h new file mode 100644 index 000000000..b993a5b68 --- /dev/null +++ b/lab_3/bootloader/include/utils.h @@ -0,0 +1,4 @@ +void set(long addr, unsigned int value); +void reset(); +int strcmp(char* a, char* b); +void cancel_reset(); \ No newline at end of file diff --git a/lab_3/bootloader/initramfs.cpio b/lab_3/bootloader/initramfs.cpio new file mode 100644 index 000000000..e9c1dda97 Binary files /dev/null and b/lab_3/bootloader/initramfs.cpio differ diff --git a/lab_3/bootloader/kernel_uploader.py b/lab_3/bootloader/kernel_uploader.py new file mode 100644 index 000000000..66e2575a0 --- /dev/null +++ b/lab_3/bootloader/kernel_uploader.py @@ -0,0 +1,92 @@ +import serial +import os +import os.path +import sys +import time +import signal + + +def tstp_handler(signum, frame): + print("SIGTSTP received (Ctrl+Z), enter your command now:") + inp = input() + inp += "\n" + bytes_to_send = inp.encode('utf-8') + s.write(bytes_to_send) + + +def cont_handler(signum, frame): + print("SIGCONT received, resuming normal operation.") + + + +print("please enter the serial port: ", end="") +port = input() +port = "/dev/"+port +# port = '/dev/pts/1' +s = serial.Serial(port, baudrate=115200) + +def read_line(s): + received_string = "" + while True: + c = s.read().decode() + if c=="\r": + continue + if c=="\n": + break + received_string += c + return received_string + +size = os.stat("../shell/shell_kernel.img").st_size +print(size) +# size = os.stat("./kernel8.img").st_size + +size_bytes = size.to_bytes(4,"little") +print(f"size from python: {hex(size)}") +s.write(size_bytes) +p = s + +time.sleep(1) +# get response of correctness of bytes size sent +while s.in_waiting > 0: + received_content = read_line(s) + print(received_content) + +with open("../shell/shell_kernel.img", "rb") as f: + sent_size = 0 # Initialize size counter + + byte = f.read(1) # Read the first byte + while byte: + s.write(byte) # Send the byte over serial + # s.flush() # Flush the output buffer + sent_size += 1 # Increment size counter + byte = f.read(1) # Read the next byte + + +assert sent_size == size +print("kernel sent successfully.") +# Register signal handlers +signal.signal(signal.SIGTSTP, tstp_handler) +signal.signal(signal.SIGCONT, cont_handler) + +# Run a loop to keep the program alive and responsive to signals +while True: + received_content = read_line(s) + print(received_content) + +# # get response of whether kernel is loaded successfully or not +# time.sleep(1) +# while(True): +# while s.in_waiting > 0: +# received_content = read_line(s) +# print(received_content) +# print("#", end=" ") +# inp = input() +# if(inp == ""): +# continue +# inp += "\n" +# bytes_to_send = inp.encode('utf-8') +# s.write(bytes_to_send) +# #while s.in_waiting > 0: +# # received_content = read_line(s) +# # print(received_content) +# time.sleep(1) \ No newline at end of file diff --git a/lab_3/bootloader/link.ld b/lab_3/bootloader/link.ld new file mode 100644 index 000000000..5d4536049 --- /dev/null +++ b/lab_3/bootloader/link.ld @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +SECTIONS +{ + . = 0x60000; + PROVIDE(_head = .); + .relocate : { + KEEP(*(.text.relocate)) + } + . = ALIGN(4096); + + .imgLoader : { + KEEP(*(.text.load_img)) + } + . = ALIGN(4096); + .text : { + KEEP(*(.text.boot)) + *(.text) + } + . = ALIGN(4096); + PROVIDE(_data = .); + .data : { *(.data .data.*) } + .bss : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; +} +__bss_size = (__bss_end - __bss_start)>>3; +__loader_size = (_end - _head)>>3; \ No newline at end of file diff --git a/lab_3/bootloader/main.c b/lab_3/bootloader/main.c new file mode 100644 index 000000000..e8be04b8c --- /dev/null +++ b/lab_3/bootloader/main.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +#define MAX_BUFFER 10 +#include "include/uart.h" +#include "include/utils.h" +#include "include/mbox.h" +#include "include/stdint.h" +#include "include/device_tree.h" + +void load_img(){ + unsigned int size = 0; + unsigned char *size_buffer = (unsigned char *) &size; + uart_puts("enter kernel size now:"); + for(int i=0; i<4; i++) + size_buffer[i] = uart_getc(); + uart_puts("size-check correct\n"); + + uart_puts("Kernel size received: "); + uart_hex(size); + uart_puts("\n"); + + char *kernel = (char *) 0x80000; + while(size--) *kernel++ = uart_getc(); + + uart_puts("kernel-loaded\n"); + return; + +} + +void relocator(uintptr_t dtb_address){ + uart_init(); + // header_parser(dtb_address); + load_img(); + asm volatile( + "mov x30, 0x80000;" + "ret;" + ); +} diff --git a/lab_3/bootloader/mbox.c b/lab_3/bootloader/mbox.c new file mode 100644 index 000000000..b5b47c2f2 --- /dev/null +++ b/lab_3/bootloader/mbox.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "include/gpio.h" + +/* mailbox message buffer +* The buffer itself is 16-byte aligned as only the upper 28 bits of the address can be passed via the mailbox. +*/ +volatile unsigned int __attribute__((aligned(16))) mbox[36]; + +#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880) +#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0)) +#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10)) +#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14)) +#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18)) +#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C)) +#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20)) +#define MBOX_RESPONSE 0x80000000 +#define MBOX_FULL 0x80000000 +#define MBOX_EMPTY 0x40000000 + +/** + * Make a mailbox call. Returns 0 on failure, non-zero on success + */ +int mbox_call(unsigned char ch) +{ + unsigned int r = (((unsigned int)((unsigned long)&mbox)&~0xF) | (ch&0xF)); + /* wait until we can write to the mailbox */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL); + /* write the address of our message to the mailbox with channel identifier */ + *MBOX_WRITE = r; + /* now wait for the response */ + while(1) { + /* is there a response? */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY); + /* is it a response to our message? */ + if(r == *MBOX_READ) + /* is it a valid successful response? */ + return mbox[1]==MBOX_RESPONSE; + } + return 0; +} diff --git a/lab_3/bootloader/reader.py b/lab_3/bootloader/reader.py new file mode 100644 index 000000000..19a5e759a --- /dev/null +++ b/lab_3/bootloader/reader.py @@ -0,0 +1,9 @@ +with open("./bcm2710-rpi-3-b-plus.dtb", "rb") as f: + data = f.read() +# Filter out the 0x00 bytes +filtered_data = bytes(b for b in data if b != 0x00) + +# Print the filtered binary data +print(filtered_data) + +#print(data) \ No newline at end of file diff --git a/lab_3/bootloader/start.S b/lab_3/bootloader/start.S new file mode 100644 index 000000000..b086305c4 --- /dev/null +++ b/lab_3/bootloader/start.S @@ -0,0 +1,43 @@ +.section ".text.relocate" +.global _relocate + +_relocate: + // relocate our code from load address to link address + ldr x1, =0x80000; // src address + ldr x2, =0x60000; // target address + ldr w3, =__loader_size +1: ldr x4, [x1], #8 + str x4, [x2], #8 + sub w3, w3, #1 + cbnz w3, 1b + + ldr x1, =_start + mov sp, x1 + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size +2: cbz w2, 3f + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, 2b + + +3: // Device tree address has been moved from x0 to x10 within the bootloader. + mov x0, x10 + bl relocator-0x20000 + b _start + + +.section ".text.boot" + +.global _start + +_start: + // jump to main function in C + bl 0x80000 + // halt this core if return +1: + wfe + b 1b + diff --git a/lab_3/bootloader/uart.c b/lab_3/bootloader/uart.c new file mode 100644 index 000000000..5e63f2d3a --- /dev/null +++ b/lab_3/bootloader/uart.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "include/gpio.h" + +/** Auxilary mini UART registers + * Address & Description refer: https://cs140e.sergio.bz/docs/BCM2837-ARM-Peripherals.pdf Page.8 + */ + +#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() +{ + register unsigned int r; + + /* initialize UART */ + *AUX_ENABLE |=1; // enable UART1, AUX mini uart + *AUX_MU_CNTL = 0; + *AUX_MU_LCR = 3; // 8 bits + *AUX_MU_MCR = 0; + *AUX_MU_IER = 0; + *AUX_MU_IIR = 0xc6; // disable interrupts + *AUX_MU_BAUD = 270; // 115200 baud + /* map UART1 to GPIO pins */ + r=*GPFSEL1; + r&=~((7<<12)|(7<<15)); // gpio14, gpio15 + r|=(2<<12)|(2<<15); // alt5 + *GPFSEL1 = r; + *GPPUD = 0; // enable pins 14 and 15 + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = (1<<14)|(1<<15); + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = 0; // flush GPIO setup + *AUX_MU_CNTL = 3; // enable Tx, Rx + /*EXTRA: Read from AUX_MU_IO until AUX_MU_LSR indicates no more data*/ + while (*AUX_MU_LSR & 0x01) { + // Read and discard the data + volatile unsigned int data = *AUX_MU_IO; + (void)data; // Prevent unused variable warning + } +} + +void uart_enable_interrupt(){ + // enable tx rx interrupt in uart + *AUX_MU_IER |= 0x02; + *IRQS1 |= 1 << 29; +} + + +/** + * Send a character + */ +void uart_send(unsigned int c) { + /* wait until we can send */ + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); + /* write the character to the buffer */ + *AUX_MU_IO=c; +} + +/** + * 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 it and return */ + r=(char)(*AUX_MU_IO); + /* convert carriage return to newline */ + return r=='\r'?'\n':r; +} + +/** + * Display a string + */ +void uart_puts(char *s) { + while(*s) { + /* convert newline to carriage return + newline */ + if(*s=='\n') + uart_send('\r'); + 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); + } +} \ No newline at end of file diff --git a/lab_3/bootloader/utils.c b/lab_3/bootloader/utils.c new file mode 100644 index 000000000..d31e58159 --- /dev/null +++ b/lab_3/bootloader/utils.c @@ -0,0 +1,61 @@ +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +/** + * compare two string, given s1 and s2 + * return 0 if the both string are equal; + * return -1 if s1 is less than s2; + * return 1 if s1 is greater than s2 + */ +int strcmp(char* a, char* b){ + int value = 0; + while(*a != '\0' && *b != '\0'){ + if(*a < *b){ + return -1; + } + else if(*a > *b){ + return 1; + } + else{ + a++; + b++; + } + } + if(*a == '\0'){ + value++; + } + if(*b == '\0'){ + value--; + } + return value; +} + +/** + * set up given value to given address + */ +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + + +/** + * reboot respberry pi + * if tick=0, reboot instantly; + * otherwise, wait for tick seconds to reboot + */ +void reset(int tick) { // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + if(tick != 0){ + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick + } +} + +/** + * clear reboot register + */ +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} \ No newline at end of file diff --git a/lab_3/config.txt b/lab_3/config.txt new file mode 100644 index 000000000..7e9ff304c --- /dev/null +++ b/lab_3/config.txt @@ -0,0 +1,2 @@ +initramfs initramfs.cpio 0x80000000 +kernel=bootloader.img \ No newline at end of file diff --git a/lab_3/rootfs/hello.txt b/lab_3/rootfs/hello.txt new file mode 100644 index 000000000..ca9e3b5cc --- /dev/null +++ b/lab_3/rootfs/hello.txt @@ -0,0 +1 @@ +this is a example file. diff --git a/lab_3/rootfs/hello2.txt b/lab_3/rootfs/hello2.txt new file mode 100644 index 000000000..d90bb747c --- /dev/null +++ b/lab_3/rootfs/hello2.txt @@ -0,0 +1 @@ +this is another example file. diff --git a/lab_3/rootfs/link.ld b/lab_3/rootfs/link.ld new file mode 100644 index 000000000..bd0d89847 --- /dev/null +++ b/lab_3/rootfs/link.ld @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +SECTIONS +{ + . = 0x30000; + PROVIDE(_head = .); + .text : { KEEP(*(.text.boot)) *(.text .text.*) } + .rodata : { *(.rodata .rodata.*) } + PROVIDE(_data = .); + .data : { *(.data .data.*) } + .bss : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; +} +__bss_size = (__bss_end - __bss_start)>>3; +__loader_size = (_end - _head)>>3; \ No newline at end of file diff --git a/lab_3/rootfs/makefile b/lab_3/rootfs/makefile new file mode 100644 index 000000000..1f075562f --- /dev/null +++ b/lab_3/rootfs/makefile @@ -0,0 +1,36 @@ +# +# Copyright (C) 2018 bzt (bztsrc@github) +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# + +GCC = "aarch64-linux-gnu-gcc" +LD = "aarch64-linux-gnu-ld" +OBJCPY = "aarch64-linux-gnu-objcopy" +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.S=.o) +CFLAGS = -Wall -O0 -ffreestanding -nostdinc -nostdlib -nostartfiles +BOOTLOADER_BIN = kernel8.img +all: user_program.S + "aarch64-linux-gnu-gcc" -Wall -O0 -ffreestanding -nostdinc -nostdlib -nostartfiles -c user_program.S -o user_program.o + "aarch64-linux-gnu-ld" -nostdlib -nostartfiles user_program.o -T link.ld -o user_program.elf + "aarch64-linux-gnu-objcopy" -O binary user_program.elf user_program.img diff --git a/lab_3/rootfs/user_program b/lab_3/rootfs/user_program new file mode 100755 index 000000000..e235f8e5d Binary files /dev/null and b/lab_3/rootfs/user_program differ diff --git a/lab_3/rootfs/user_program.S b/lab_3/rootfs/user_program.S new file mode 100644 index 000000000..4d2ef454d --- /dev/null +++ b/lab_3/rootfs/user_program.S @@ -0,0 +1,13 @@ +.section ".text" +.global _start +_start: + mov x0, 0 +1: + add x0, x0, 1 + svc 0 + cmp x0, 5 + blt 1b + ret; +1: + b 1b + \ No newline at end of file diff --git a/lab_3/rootfs/user_program.elf b/lab_3/rootfs/user_program.elf new file mode 100755 index 000000000..977a8eef5 Binary files /dev/null and b/lab_3/rootfs/user_program.elf differ diff --git a/lab_3/rootfs/user_program.img b/lab_3/rootfs/user_program.img new file mode 100755 index 000000000..1adf648a4 Binary files /dev/null and b/lab_3/rootfs/user_program.img differ diff --git a/lab_3/shell/Makefile b/lab_3/shell/Makefile new file mode 100644 index 000000000..2befc4866 --- /dev/null +++ b/lab_3/shell/Makefile @@ -0,0 +1,61 @@ +# +# Copyright (C) 2018 bzt (bztsrc@github) +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# + +GCC = "aarch64-linux-gnu-gcc" +LD = "aarch64-linux-gnu-ld" +OBJCPY = "aarch64-linux-gnu-objcopy" +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) +CFLAGS = -Wall -O0 -ffreestanding -nostdinc -nostdlib -nostartfiles -w +BOOTLOADER_BIN = kernel8.img +all: clean kernel8.img + +# start.o: start.S +# $(GCC) $(CFLAGS) -c start.S -o start.o + +%.o: %.S + $(GCC) $(CFLAGS) -c $< -o $@ -g + "aarch64-linux-gnu-gcc" -Wall -O0 -ffreestanding -nostdinc -nostdlib -nostartfiles -c exception_vector.S -o exception_vector.o -g + "aarch64-linux-gnu-gcc" -Wall -O0 -ffreestanding -nostdinc -nostdlib -nostartfiles -c interrupts.S -o interrupts.o -g + +%.o: %.c + $(GCC) $(CFLAGS) -c $< -o $@ -g + + +kernel8.img: start.o $(OBJS) + $(LD) -nostdlib -nostartfiles start.o $(OBJS) exception_vector.o interrupts.o -T link.ld -o kernel8.elf + $(OBJCPY) -O binary kernel8.elf shell_kernel.img + +clean: + rm kernel8.elf *.o >/dev/null 2>/dev/null || true + +run_asm: + qemu-system-aarch64 -M raspi3b -kernel shell_kernel.img -initrd initramfs.cpio -serial null -serial stdio -display none -d in_asm + +run: + qemu-system-aarch64 -M raspi3b -kernel shell_kernel.img -initrd initramfs.cpio -serial null -serial stdio -display none + +debug: + qemu-system-aarch64 -M raspi3b -kernel shell_kernel.img -initrd initramfs.cpio -serial null -serial stdio -display none -s -S diff --git a/lab_3/shell/cpio.c b/lab_3/shell/cpio.c new file mode 100644 index 000000000..53f870e6a --- /dev/null +++ b/lab_3/shell/cpio.c @@ -0,0 +1,102 @@ +#include "include/cpio.h" +#include "include/uart.h" +#include "include/stdint.h" +#include "include/utils.h" + +char* cpio_addr = (char *)0x8000000;; + +void cpio_ls(){ + char* addr = (char*) cpio_addr; + uart_puts((char *)(addr+sizeof(struct cpio_header))); + while(strcmp((char *)(addr+sizeof(struct cpio_header)),"TRAILER!!!") != 0){ + struct cpio_header* header = (struct cpio_header*) addr; + unsigned long filename_size = utils_atoi(header->c_namesize,(int)sizeof(header->c_namesize)); + unsigned long headerPathname_size = sizeof(struct cpio_header) + filename_size; + unsigned long file_size = utils_atoi(header->c_filesize,(int)sizeof(header->c_filesize)); + utils_align(&headerPathname_size,4); + utils_align(&file_size,4); + uart_puts(addr+sizeof(struct cpio_header)); + uart_puts("\n"); + addr += (headerPathname_size + file_size); + } +} + +void cpio_exec(char *filename){ + char *target = findFile(filename); + if (target){ + struct cpio_header *header = (struct cpio_header *)target; + unsigned long pathname_size = utils_atoi(header->c_namesize,(int)sizeof(header->c_namesize)); + unsigned long file_size = utils_atoi(header->c_filesize,(int)sizeof(header->c_filesize)); + unsigned long headerPathname_size = sizeof(struct cpio_header) + pathname_size; + + utils_align(&headerPathname_size,4); + utils_align(&file_size,4); + char *file_content = target + headerPathname_size; + + char *program_ptr = (char *) 0x30000; // load the user program into 0x30000 + char* start_point = (char*) 0x30000; + char* stack_pointer = (char *) (0x30000 + 0x3000); // Stack pointer for the user program, base address+0x3000 + for (unsigned int i = 0; i < file_size; i++){ + *program_ptr ++ = *file_content++; + } + asm volatile( + // 0x3c0 + "mov x0, 0x3c0;\n\t" + "msr spsr_el1, x0;\n\t" + // start address of user program + "mov x1, 0x30000;\n\t" + "msr elr_el1, x1;\n\t" + // sp for user program + "mov x2, %0;\n\t" + "msr sp_el0, x2;\n\t" + "eret;" + : // No output operands + : "r" (start_point), "r" (stack_pointer) + : "x0", "x1", "x2" // tell compiler x0~x2 has been used + ); + } + uart_puts("completed.\n"); +} + + + +void cpio_cat(char *filename){ + char *target = findFile(filename); + if (target){ + struct cpio_header *header = (struct cpio_header *)target; + unsigned long pathname_size = utils_atoi(header->c_namesize,(int)sizeof(header->c_namesize)); + unsigned long file_size = utils_atoi(header->c_filesize,(int)sizeof(header->c_filesize)); + unsigned long headerPathname_size = sizeof(struct cpio_header) + pathname_size; + + utils_align(&headerPathname_size,4); + utils_align(&file_size,4); + char *file_content = target + headerPathname_size; + for (unsigned int i = 0; i < file_size; i++) + { + uart_send(file_content[i]); + } + uart_puts("\n"); + } + else + { + uart_puts("Not found the file\n"); + } +} + +char *findFile(char *name){ + char *addr = (char *)cpio_addr; + while (strcmp((char *)(addr + sizeof(struct cpio_header)), "TRAILER!!!") != 0){ + if ((strcmp((char *)(addr + sizeof(struct cpio_header)), name) == 0)){ + return addr; + } + struct cpio_header* header = (struct cpio_header *)addr; + unsigned long pathname_size = utils_atoi(header->c_namesize,(int)sizeof(header->c_namesize));; + unsigned long file_size = utils_atoi(header->c_filesize,(int)sizeof(header->c_filesize)); + unsigned long headerPathname_size = sizeof(struct cpio_header) + pathname_size; + + utils_align(&headerPathname_size,4); + utils_align(&file_size,4); + addr += (headerPathname_size + file_size); + } + return 0; +} \ No newline at end of file diff --git a/lab_3/shell/exception_vector.S b/lab_3/shell/exception_vector.S new file mode 100644 index 000000000..6e5ea29a7 --- /dev/null +++ b/lab_3/shell/exception_vector.S @@ -0,0 +1,102 @@ +.align 11 // vector table should be aligned to 0x800 +.global exception_vector_table + +exception_vector_table: + b exception_handler // branch to a handler function. +.align 7 // entry size is 0x80, .align will pad 0 + b exception_handler +.align 7 + b exception_handler // reserved for FIQ(Fast Interrupt) +.align 7 + b exception_handler // reserved for SError +.align 7 + + b interrupt_handler // synchronous: caused by current excution instr. +.align 7 + b interrupt_handler +.align 7 + b interrupt_handler +.align 7 + b interrupt_handler +.align 7 + + b exception_handler // time interrupt +.align 7 + b exception_handler +.align 7 + b exception_handler +.align 7 + b exception_handler + + b exception_handler +.align 7 + b exception_handler +.align 7 + b exception_handler +.align 7 + b exception_handler +.align 7 + + + +.global set_exception_vector_table +set_exception_vector_table: + adr x4, exception_vector_table + msr vbar_el1, x4 + ret + +// 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] +.endm + + +// load general registers from stack + +.macro load_all + ldp x0, x1, [sp, 16*16] + msr spsr_el1, x0 + msr elr_el1, x1 + ldp x0, x1, [sp, 16*0] + ldp x2, x3, [sp, 16*1] + ldp x4, x5, [sp, 16*2] + ldp x6, x7, [sp, 16*3] + ldp x8, x9, [sp, 16*4] + ldp x10, x11, [sp, 16*5] + ldp x12, x13, [sp, 16*6] + ldp x14, x15, [sp, 16*7] + ldp x16, x17, [sp, 16*8] + ldp x18, x19, [sp, 16*9] + ldp x20, x21, [sp, 16*10] + ldp x22, x23, [sp, 16*11] + ldp x24, x25, [sp, 16*12] + ldp x26, x27, [sp, 16*13] + ldp x28, x29, [sp, 16*14] + ldr x30, [sp, 16*15] + add sp, sp, 32*9 +.endm + +exception_handler: + save_all + bl exception_entry + load_all + eret \ No newline at end of file diff --git a/lab_3/shell/exceptions.c b/lab_3/shell/exceptions.c new file mode 100644 index 000000000..60434e8c2 --- /dev/null +++ b/lab_3/shell/exceptions.c @@ -0,0 +1,25 @@ +#include "include/uart.h" + +int exception_entry(){ + uart_puts("exception entry!\n"); + + unsigned long long spsr_el1, elr_el1, esr_el1; + + asm volatile( + "mrs %0, spsr_el1;" + "mrs %1, elr_el1;" + "mrs %2, esr_el1;" + : "=r" (spsr_el1), "=r" (elr_el1), "=r" (esr_el1) + ); + uart_puts("spsr_el1: "); + uart_hex(spsr_el1); + uart_send('\n'); + uart_puts("elr_el1: "); + uart_hex(elr_el1); + uart_send('\n'); + uart_puts("esr_el1: "); + uart_hex(esr_el1); + uart_send('\n'); + + return 0; +} \ No newline at end of file diff --git a/lab_3/shell/include/cpio.h b/lab_3/shell/include/cpio.h new file mode 100644 index 000000000..52c6da00e --- /dev/null +++ b/lab_3/shell/include/cpio.h @@ -0,0 +1,21 @@ +struct cpio_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(); +void cpio_cat(char *filename); +void cpio_exec(char* filename); +char *findFile(char *name); \ No newline at end of file diff --git a/lab_3/shell/include/gpio.h b/lab_3/shell/include/gpio.h new file mode 100644 index 000000000..52fa671d0 --- /dev/null +++ b/lab_3/shell/include/gpio.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#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)) diff --git a/lab_3/shell/include/interrupt.h b/lab_3/shell/include/interrupt.h new file mode 100644 index 000000000..470f6847d --- /dev/null +++ b/lab_3/shell/include/interrupt.h @@ -0,0 +1,34 @@ +#define BASE_INTERRUPT_REGISTER 0x7E00B000 +#ifndef NULL + #define NULL 0 +#endif +#define CORE0_TIMER_IRQ_CTRL 0x40000040 + +#define IRQ_BASIC_PENDING ((volatile unsigned int*)(BASE_INTERRUPT_REGISTER+0x00000200)) +#define IRQ_PENDING_1 ((volatile unsigned int*)(BASE_INTERRUPT_REGISTER+0x00000204)) +#define IRQ_PENDING_2 ((volatile unsigned int*)(BASE_INTERRUPT_REGISTER+0x00000208)) +#define FIQ_CONTROL ((volatile unsigned int*)(BASE_INTERRUPT_REGISTER+0x0000020C)) +#define ENABLE_IRQS_1 ((volatile unsigned int*)(BASE_INTERRUPT_REGISTER+0x00000210)) +#define ENABLE_IRQS_2 ((volatile unsigned int*)(BASE_INTERRUPT_REGISTER+0x00000214)) +#define ENABLE_BASIC_IRQS ((volatile unsigned int*)(BASE_INTERRUPT_REGISTER+0x00000218)) +#define DISABLE_IRQS_1 ((volatile unsigned int*)(BASE_INTERRUPT_REGISTER+0x0000021C)) +#define DISABLE_IRQS_2 ((volatile unsigned int*)(BASE_INTERRUPT_REGISTER+0x00000220)) +#define DISABLE_BASIC_IRQS ((volatile unsigned int*)(BASE_INTERRUPT_REGISTER+0x00000224)) + +typedef struct Timer{ + unsigned long long trigger_tick; + void* callback_function; + void* argument; + struct Timer* next; +}Timer; + +int print_boot_timer(); +void interrupt_entry(); +unsigned long long get_current_tick(); +void disable_timer_interrupt(); +void enable_timer_interrupt(); +void print_time_out(int delay); +void set_time_out(char* message, unsigned long long seconds); +void core_timer_init(); +void _set_time_out(void (*callback_func)(void *), char* message, unsigned long long delay); +void print_time(); \ No newline at end of file diff --git a/lab_3/shell/include/mbox.h b/lab_3/shell/include/mbox.h new file mode 100644 index 000000000..e0e2e41f1 --- /dev/null +++ b/lab_3/shell/include/mbox.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +/* a properly aligned buffer */ +extern volatile unsigned int mbox[36]; + +#define MBOX_REQUEST 0 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define MBOX_TAG_GETSERIAL 0x10004 +#define MBOX_TAG_REVISION 0x00010002 +#define MBOX_TAG_MEMORY 0x00010005 +#define MBOX_TAG_LAST 0 + +int mbox_call(unsigned char ch); diff --git a/lab_3/shell/include/stdint.h b/lab_3/shell/include/stdint.h new file mode 100644 index 000000000..3ddcc9b17 --- /dev/null +++ b/lab_3/shell/include/stdint.h @@ -0,0 +1,9 @@ + +typedef unsigned int uint16_t; + +typedef unsigned long uint32_t; + +typedef unsigned long long uint64_t; +typedef unsigned long uintptr_t; +typedef float float32; +typedef double float64; \ No newline at end of file diff --git a/lab_3/shell/include/uart.h b/lab_3/shell/include/uart.h new file mode 100644 index 000000000..e2751a08a --- /dev/null +++ b/lab_3/shell/include/uart.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "gpio.h" + +#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)) + +void uart_init(); +void uart_send(unsigned int c); +char uart_getc(); +void uart_puts(char *s); +void uart_hex(unsigned int d); +void uart_read_handler(); +void uart_write_handler(); +void uart_enable_interrupt(); +void demo_async_uart(); \ No newline at end of file diff --git a/lab_3/shell/include/utils.h b/lab_3/shell/include/utils.h new file mode 100644 index 000000000..8f28d9205 --- /dev/null +++ b/lab_3/shell/include/utils.h @@ -0,0 +1,7 @@ +void set(long addr, unsigned int value); +void reset(); +int strcmp(char* a, char* b); +void cancel_reset(); +void utils_align(void *size, unsigned int s); +unsigned long utils_atoi(const char *s, int char_size); +void* simple_malloc(unsigned long size); \ No newline at end of file diff --git a/lab_3/shell/initramfs.cpio b/lab_3/shell/initramfs.cpio new file mode 100644 index 000000000..0b64417cc Binary files /dev/null and b/lab_3/shell/initramfs.cpio differ diff --git a/lab_3/shell/interrupt.c b/lab_3/shell/interrupt.c new file mode 100644 index 000000000..b9bb4c0d0 --- /dev/null +++ b/lab_3/shell/interrupt.c @@ -0,0 +1,146 @@ +#include "include/interrupt.h" +#include "include/uart.h" +#include "include/utils.h" + +#define CORE0_INTERRUPT_SOURCE ((volatile unsigned int*)(0x40000060)) + +struct Timer* timer_queue_head = NULL; + +int print_boot_timer(){ + uart_puts("Interrupt occurs!\n"); + unsigned long long freq, ticks, next_tick; + asm volatile( + "mrs %0, cntfrq_el0;" + "mrs %1, cntpct_el0;" + : "=r" (freq), "=r" (ticks) + ); + // set up the next timer - basic + // asm volatile ( + // "msr cntp_tval_el0, %0" + // : + // : "r" (freq * 2) + // ); + + // set up next timer - advanced (with timer queue) + timer_queue_head = timer_queue_head->next; + if(timer_queue_head != NULL){ + next_tick = timer_queue_head->trigger_tick; + uart_hex(next_tick); + uart_puts("\t"); + uart_hex(ticks); + asm volatile ( + "msr cntp_tval_el0, %0" + : + : "r" (next_tick - ticks) + ); + } + else{ + // no more queued core time interrupt, disable the interrupt src + disable_timer_interrupt(); + } + unsigned int time = (unsigned int)(ticks/freq); + uart_puts("\n"); + uart_hex(time); + uart_puts(" seconds elapsed\n"); + return 0; +} + + +void interrupt_entry(){ + //asm volatile("msr DAIFSet, 0xf"); + // int irq_pending1 = *IRQ_PENDING_1; + int core0_irq = *CORE0_INTERRUPT_SOURCE; + int iir = *AUX_MU_IIR; + if (core0_irq & (1 << 1)){ + print_boot_timer(); + } + else{ + // P13, Receiver holds valid byte + if ((iir & 0x06) == 0x04){ + uart_read_handler(); + } + // P13, Transmit holding register empty + //else if((iir & 0x06) == 0x02){ + else{ + uart_write_handler(); + } + } + return; +} + + +unsigned long long get_current_tick(){ + unsigned long long cntpct_el0 = 0; + asm volatile("mrs %0, cntpct_el0" : "=r"(cntpct_el0)); + return cntpct_el0; +} + +void disable_timer_interrupt(){ + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x0); +} + +void enable_timer_interrupt(){ + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x2); +} + +void print_time_out(int delay){ + uart_puts("Timer interrupt occured at 0x"); + uart_hex(delay); + uart_puts(" seconds"); + // remove timer head + timer_queue_head = timer_queue_head->next; +} + +void set_time_out(char* message, unsigned long long seconds){ + _set_time_out(print_time_out, message, seconds); +} + +void core_timer_init(){ + core_timer_enable(); + disable_timer_interrupt(); +} + +void print_time(){ + struct Timer* cur = timer_queue_head; + while(cur != NULL){ + uart_puts(""); + uart_hex(cur->trigger_tick); + uart_puts("\n"); + cur = cur->next; + } +} + +void _set_time_out(void (*callback_func)(void *), char* message, unsigned long long delay){ + Timer *new_timer = (Timer *)simple_malloc(sizeof(Timer)); + unsigned long long freq; + asm volatile("mrs %0, cntfrq_el0" : "=r"(freq)); + unsigned long long delay_tick = delay*(freq); + new_timer->callback_function = callback_func; + new_timer->trigger_tick = delay_tick+get_current_tick(); + new_timer->next = NULL; + uart_puts("\n"); + uart_hex(new_timer->trigger_tick); + if(timer_queue_head == NULL || new_timer->trigger_ticktrigger_tick){ + new_timer->next = timer_queue_head; + timer_queue_head = new_timer; + enable_timer_interrupt(); + asm volatile ( + "msr cntp_tval_el0, %0" + : + : "r" (timer_queue_head->trigger_tick) + ); + uart_puts("\nset next interrupt time to 0x"); + uart_hex(timer_queue_head->trigger_tick); + uart_puts(", current tick = 0x"); + uart_hex(get_current_tick()); + uart_puts("\n"); + return; + } + struct Timer *iter = timer_queue_head; + while(iter->next != NULL && iter->next->trigger_tick <= new_timer->trigger_tick){ + iter = iter->next; + } + new_timer->next = iter->next; + iter->next = new_timer; + return; +} \ No newline at end of file diff --git a/lab_3/shell/interrupts.S b/lab_3/shell/interrupts.S new file mode 100644 index 000000000..4495af92a --- /dev/null +++ b/lab_3/shell/interrupts.S @@ -0,0 +1,72 @@ +#define CORE0_TIMER_IRQ_CTRL 0x40000040 + +// 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] +.endm + + +// load general registers from stack + +.macro load_all + ldp x0, x1, [sp, 16*16] + msr spsr_el1, x0 + msr elr_el1, x1 + ldp x0, x1, [sp, 16*0] + ldp x2, x3, [sp, 16*1] + ldp x4, x5, [sp, 16*2] + ldp x6, x7, [sp, 16*3] + ldp x8, x9, [sp, 16*4] + ldp x10, x11, [sp, 16*5] + ldp x12, x13, [sp, 16*6] + ldp x14, x15, [sp, 16*7] + ldp x16, x17, [sp, 16*8] + ldp x18, x19, [sp, 16*9] + ldp x20, x21, [sp, 16*10] + ldp x22, x23, [sp, 16*11] + ldp x24, x25, [sp, 16*12] + ldp x26, x27, [sp, 16*13] + ldp x28, x29, [sp, 16*14] + ldr x30, [sp, 16*15] + add sp, sp, 32*9 +.endm + + +.global core_timer_enable +core_timer_enable: + mov x0, 1 + msr cntp_ctl_el0, x0 // enable + mrs x0, cntfrq_el0 + mrs x1, cntpct_el0 // get current timer + add x0, x1, x0 // next exception = 1 second later + msr cntp_tval_el0, x0 // set expired time + mov x0, 0 + ldr x1, =CORE0_TIMER_IRQ_CTRL + str w0, [x1] // unmask timer interrupt + ret + +.global interrupt_handler +interrupt_handler: + save_all + bl interrupt_entry + load_all + eret diff --git a/lab_3/shell/link.ld b/lab_3/shell/link.ld new file mode 100644 index 000000000..5f7bbdf2b --- /dev/null +++ b/lab_3/shell/link.ld @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +SECTIONS +{ + . = 0x80000; + PROVIDE(_head = .); + .text : { KEEP(*(.text.boot)) *(.text .text.*) } + .rodata : { *(.rodata .rodata.*) } + PROVIDE(_data = .); + .data : { *(.data .data.*) } + .bss : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; +} +__bss_size = (__bss_end - __bss_start)>>3; +__loader_size = (_end - _head)>>3; \ No newline at end of file diff --git a/lab_3/shell/main.c b/lab_3/shell/main.c new file mode 100644 index 000000000..8818c1e11 --- /dev/null +++ b/lab_3/shell/main.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +#define MAX_BUFFER 50 +#include "include/uart.h" +#include "include/utils.h" +#include "include/mbox.h" +#include "include/cpio.h" +#include "include/interrupt.h" + + +extern void set_exception_vector_table(); +extern void core_timer_enable(); + + + +void main(int argc, char* argv[]){ + uart_init(); + set_exception_vector_table(); + // default: disabled, need to set interrupt ticks immediately if enable + core_timer_init(); + + // show el + unsigned long el; + asm volatile ("mrs %0, CurrentEL" : "=r" (el)); + el = el >> 2; // CurrentEL的值在高两位 + + // print current exception level + uart_puts("Booted! Current EL: "); + uart_send('0' + el); + uart_puts("\n"); + //cpio_exec("user_program.img"); + core_timer_enable(); + set_time_out("", 10); + set_time_out("", 1); + set_time_out("", 7); + + while(1){ + char command[MAX_BUFFER]; + char c = '\0'; + int length=0; + for(int i=0; i\t: print the content of file in initfs\n"); + uart_puts("hello\t: print hello world!\n"); + uart_puts("exec: execute user program in initfs"); + uart_puts("async_uart: switch to async uart mode (currently for demo only)"); + uart_puts("reboot\t: reboot the device\n"); + } + else if(strcmp(command, "hello") == 0){ + uart_puts("Hello World!\n"); + } + else if(strcmp(command, "ls") == 0){ + cpio_ls(); + } + else if(strcmp(command, "async_uart") == 0){ + demo_async_uart(); + } + else if(strcmp(command, "reboot") == 0){ + reset(); + } + else if(strcmp(command, "exec") == 0){ + uart_puts("executing...\n"); + // execute a dedicated user program + cpio_exec("user_program.img"); + } + // command with arguments + else{ + char arguments[3][MAX_BUFFER]; + // initialize + for(int i=0;i<3;i++){ + for(int j=0;j 0, stop +1: wfe + b 1b + + +2: // cpu id == 0 + + // el2 to el1 + bl from_el2_to_el1 + + // set top of stack just before our code (stack grows to a lower address per AAPCS64) + ldr x1, =_start + mov sp, x1 + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size +3: cbz w2, 4f + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, 3b + + // jump to C code, should not return +4: bl main + // for failsafe, halt this core too + b 1b + +from_el2_to_el1: + mov x0, (1 << 31) // EL1 uses aarch64 + // move system register to register (write x0 into hcr_el2) + msr hcr_el2, x0 + mov x0, 0x345 // 3c5 EL1h (SPSel = 1) with interrupt disabled, 345 enable interrupt + msr spsr_el2, x0 + msr elr_el2, lr + eret // return to EL1 diff --git a/lab_3/shell/uart.c b/lab_3/shell/uart.c new file mode 100644 index 000000000..dee6592ce --- /dev/null +++ b/lab_3/shell/uart.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "include/gpio.h" +#include "include/uart.h" +/** Auxilary mini UART registers + * Address & Description refer: https://cs140e.sergio.bz/docs/BCM2837-ARM-Peripherals.pdf Page.8 + */ + + +/* + The definition below is for async uart IO +*/ + +#define BUFFER_SIZE 1024 +#define IRQS1 ((volatile unsigned int *)(0x3f00b210)) +char uart_read_buffer[BUFFER_SIZE]; +unsigned int read_idx = 0; + +char uart_write_buffer[BUFFER_SIZE]; +unsigned int write_idx = 0; +unsigned int write_cur = 0; +int async; + + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init() +{ + register unsigned int r; + + /* initialize UART */ + *AUX_ENABLE |=1; // enable UART1, AUX mini uart + *AUX_MU_CNTL = 0; + *AUX_MU_LCR = 3; // 8 bits + *AUX_MU_MCR = 0; + *AUX_MU_IER = 0; + *AUX_MU_IIR = 0xc6; // disable interrupts + *AUX_MU_BAUD = 270; // 115200 baud + /* map UART1 to GPIO pins */ + r=*GPFSEL1; + r&=~((7<<12)|(7<<15)); // gpio14, gpio15 + r|=(2<<12)|(2<<15); // alt5 + *GPFSEL1 = r; + *GPPUD = 0; // enable pins 14 and 15 + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = (1<<14)|(1<<15); + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = 0; // flush GPIO setup + *AUX_MU_CNTL = 3; // enable Tx, Rx +} + +/** + * Send a character + */ +void uart_send(unsigned int c) { + /* This bit is set if the transmit FIFO can accept at least one byte*/ + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); + /* write the character to the buffer */ + *AUX_MU_IO=c; +} + +/** + * 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 it and return */ + r=(char)(*AUX_MU_IO); + /* convert carriage return to newline */ + return r=='\r'?'\n':r; +} + +/** + * Display a string + */ +void uart_puts(char *s) { + while(*s) { + /* convert newline to carriage return + newline */ + if(*s=='\n') + uart_send('\r'); + 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); + } +} + +void uart_enable_interrupt(){ + *AUX_MU_IER |= 0x02; + *IRQS1 |= 1 << 29; +} + +void uart_load_buffer(){ + while(write_cur < write_idx){ + uart_send(uart_write_buffer[write_cur]); + } +} + +void demo_async_uart(){ + uart_puts("turning to async mode...\n"); + uart_enable_interrupt(); + while(1){ + asm volatile("nop"); + } +} + +void uart_read_handler() { + char ch = (char)(*AUX_MU_IO); + uart_read_buffer[write_idx] = ch; + write_idx++; + uart_write_buffer[write_idx] = ch; + read_idx++; + write_idx++; + if(ch == '\r'){ + uart_puts(uart_write_buffer); + } +} + +void uart_write_handler(){ + if(write_cur < write_idx){ + *AUX_MU_IO=uart_read_buffer[write_cur]; + write_cur++; + } +} \ No newline at end of file diff --git a/lab_3/shell/utils.c b/lab_3/shell/utils.c new file mode 100644 index 000000000..79223d30c --- /dev/null +++ b/lab_3/shell/utils.c @@ -0,0 +1,105 @@ +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 +#define SIMPLE_MALLOC_BUFFER_SIZE 8192 + +unsigned long utils_atoi(const char *s, int char_size) { + unsigned long num = 0; + for (int i = 0; i < char_size; i++) { + num = num * 16; + if (*s >= '0' && *s <= '9') { + num += (*s - '0'); + } else if (*s >= 'A' && *s <= 'F') { + num += (*s - 'A' + 10); + } else if (*s >= 'a' && *s <= 'f') { + num += (*s - 'a' + 10); + } + s++; + } + return num; +} + + + + +/** + * compare two string, given s1 and s2 + * return 0 if the both string are equal; + * return -1 if s1 is less than s2; + * return 1 if s1 is greater than s2 + */ +int strcmp(char* a, char* b){ + int value = 0; + while(*a != '\0' && *b != '\0'){ + if(*a < *b){ + return -1; + } + else if(*a > *b){ + return 1; + } + else{ + a++; + b++; + } + } + if(*a == '\0'){ + value++; + } + if(*b == '\0'){ + value--; + } + return value; +} + +/** + * set up given value to given address + */ +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + + +void utils_align(void *size, unsigned int s) { + unsigned long* x = (unsigned long*) size; + unsigned long mask = s-1; + *x = ((*x) + mask) & (~mask); +} + +/** + * reboot respberry pi + * if tick=0, reboot instantly; + * otherwise, wait for tick seconds to reboot + */ +void reset(int tick) { // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + if(tick != 0){ + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick + } +} + +/** + * clear reboot register + */ +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} + + +static unsigned char simple_malloc_buffer[SIMPLE_MALLOC_BUFFER_SIZE]; +static unsigned long simple_malloc_offset = 0; + +void* simple_malloc(unsigned long size){ + //align to 8 bytes + utils_align(&size,8); + + if(simple_malloc_offset + size > SIMPLE_MALLOC_BUFFER_SIZE) { + //Not enough space left + return (void*) 0; + } + void* allocated = (void *)&simple_malloc_buffer[simple_malloc_offset]; + simple_malloc_offset += size; + + return allocated; +} \ No newline at end of file diff --git a/lab_4/Makefile b/lab_4/Makefile new file mode 100644 index 000000000..015d9ea3d --- /dev/null +++ b/lab_4/Makefile @@ -0,0 +1,52 @@ +# +# Copyright (C) 2018 bzt (bztsrc@github) +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# + +GCC = "aarch64-linux-gnu-gcc" +LD = "aarch64-linux-gnu-ld" +OBJCPY = "aarch64-linux-gnu-objcopy" +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) +CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles +BOOTLOADER_BIN = kernel8.img +all: clean kernel8.img + +start.o: start.S + $(GCC) $(CFLAGS) -c start.S -o start.o + +%.o: %.c + $(GCC) $(CFLAGS) -c $< -o $@ -g + +kernel8.img: start.o $(OBJS) + $(LD) -nostdlib -nostartfiles start.o $(OBJS) -T link.ld -o kernel8.elf + $(OBJCPY) -O binary kernel8.elf kernel8.img + +clean: + rm kernel8.elf *.o >/dev/null 2>/dev/null || true + +run: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -d in_asm + +debug: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -s -S diff --git a/lab_4/Makefile.gcc b/lab_4/Makefile.gcc new file mode 100644 index 000000000..77366f3cf --- /dev/null +++ b/lab_4/Makefile.gcc @@ -0,0 +1,52 @@ +# +# Copyright (C) 2018 bzt (bztsrc@github) +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# + +GCC = "aarch64-linux-gnu-gcc" +LD = "aarch64-linux-gnu-ld" +OBJCPY = "aarch64-linux-gnu-objcopy" +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) +CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles + +all: clean kernel8.img + +start.o: start.S + $(GCC) $(CFLAGS) -c start.S -o start.o + +%.o: %.c + $(GCC) $(CFLAGS) -c $< -o $@ -g + +kernel8.img: start.o $(OBJS) + $(LD) -nostdlib -nostartfiles start.o $(OBJS) -T link.ld -o kernel8.elf + $(OBJCPY) -O binary kernel8.elf kernel8.img + +clean: + rm kernel8.elf *.o >/dev/null 2>/dev/null || true + +run: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none + +debug: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -s -S diff --git a/lab_4/README.md b/lab_4/README.md new file mode 100644 index 000000000..ff2c23e3f --- /dev/null +++ b/lab_4/README.md @@ -0,0 +1,6 @@ +1. python UART transfer data loss +2. init UART register to avoid garbage pending +3. link loader can arrange the .text section freely + - why align +4. wze is for halting CPU that is not id 0 +5. \ No newline at end of file diff --git a/lab_4/bootloader/Makefile b/lab_4/bootloader/Makefile new file mode 100644 index 000000000..2a00a5890 --- /dev/null +++ b/lab_4/bootloader/Makefile @@ -0,0 +1,59 @@ +# +# Copyright (C) 2018 bzt (bztsrc@github) +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# + +GCC = "aarch64-linux-gnu-gcc" +LD = "aarch64-linux-gnu-ld" +OBJCPY = "aarch64-linux-gnu-objcopy" +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) +CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles +BOOTLOADER_BIN = kernel8.img +all: clean kernel8.img + +start.o: start.S + $(GCC) $(CFLAGS) -c start.S -o start.o + +%.o: %.c + $(GCC) $(CFLAGS) -c $< -o $@ -g + +kernel8.img: start.o $(OBJS) + $(LD) -nostdlib -nostartfiles start.o $(OBJS) -T link.ld -o kernel8.elf + $(OBJCPY) -O binary kernel8.elf kernel8.img + +clean: + rm kernel8.elf *.o >/dev/null 2>/dev/null || true + +run: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -initrd initramfs.cpio -serial pty -display none -dtb bcm2710-rpi-3-b-plus.dtb + +run_asm: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -initrd initramfs.cpio -serial pty -display none -dtb bcm2710-rpi-3-b-plus.dtb -d in_asm + + +run_stdio: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -initrd initramfs.cpio -serial stdio -display none -dtb bcm2710-rpi-3-b-plus.dtb + +debug: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -s -S diff --git a/lab_4/bootloader/bcm2710-rpi-3-b-plus.dtb b/lab_4/bootloader/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..a219bf3d5 Binary files /dev/null and b/lab_4/bootloader/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab_4/bootloader/device_tree.c b/lab_4/bootloader/device_tree.c new file mode 100644 index 000000000..6370eb7b7 --- /dev/null +++ b/lab_4/bootloader/device_tree.c @@ -0,0 +1,74 @@ +#include "include/device_tree.h" +#include "include/uart.h" +// #include +// #include + +device_tree_header myHeader; + +void header_parser(uintptr_t dtb_address){ + uint32_t* start; + //uint32_t* dtb = mock_load_file(); + uint32_t* dtb = dtb_address; + start = dtb; + // __builtin_bswap32() is a GCC built-in function to convert to the system's endianness.(RPi uses little-endian) + myHeader.magic = __builtin_bswap32(*dtb++); + if ((myHeader.magic - 0xd00dfeed) != 0) { + uart_puts("DTB magic number doesn't match!\r\n"); + return 1; + } + myHeader.totalsize = __builtin_bswap32(*dtb++); + myHeader.off_dt_struct = __builtin_bswap32(*dtb++); + myHeader.off_dt_strings = __builtin_bswap32(*dtb++); + myHeader.off_mem_rsvmap = __builtin_bswap32(*dtb++); + myHeader.version = __builtin_bswap32(*dtb++); + myHeader.last_comp_version = __builtin_bswap32(*dtb++); + myHeader.boot_cpuid_phys = __builtin_bswap32(*dtb++); + myHeader.size_dt_strings = __builtin_bswap32(*dtb++); + myHeader.size_dt_struct = __builtin_bswap32(*dtb++); + + // jump to structure + uint32_t* structure_ptr = (uint32_t *)(start + myHeader.off_dt_struct); + while(1){ + uint32_t token = __builtin_bswap32(*structure_ptr++); + if(token == FDT_BEGIN_NODE){ + uart_puts("Start\n"); + } + } + + //The node’s name as a null-terminated string + + + +} + +// unsigned long* mock_load_file() { +// FILE *file = fopen("bcm2710-rpi-3-b-plus.dtb", "rb"); +// if (!file) { +// perror("Failed to open file"); +// return 1; +// } + +// // Get the size of the file +// fseek(file, 0, SEEK_END); +// long fileSize = ftell(file); +// rewind(file); + +// // Allocate memory to hold the entire file +// unsigned char *buffer = (unsigned char *)malloc(fileSize); +// if (!buffer) { +// perror("Failed to allocate memory"); +// fclose(file); +// return 1; +// } + +// // Read the entire file into the buffer +// size_t bytesRead = fread(buffer, 1, fileSize, file); +// if (bytesRead != fileSize) { +// perror("Failed to read file"); +// free(buffer); +// fclose(file); +// return 1; +// } + +// return (unsigned long*)buffer; +// } \ No newline at end of file diff --git a/lab_4/bootloader/include/device_tree.h b/lab_4/bootloader/include/device_tree.h new file mode 100644 index 000000000..6846d0cba --- /dev/null +++ b/lab_4/bootloader/include/device_tree.h @@ -0,0 +1,34 @@ +#include "stdint.h" + + +typedef struct fdt_header { + // 0xd00dfeed (big-endian) + uint32_t magic; + uint32_t totalsize; + // offsets of each block from start + uint32_t off_dt_struct; + uint32_t off_dt_strings; + uint32_t off_mem_rsvmap; + + uint32_t version; + uint32_t last_comp_version; + // physical ID of the system’s boot CPU + uint32_t boot_cpuid_phys; + uint32_t size_dt_strings; + uint32_t size_dt_struct; +} device_tree_header; + +#define ALIGN_MEMORY_BLOCK 8 + +/* All tokens shall be aligned on a 32-bit boundary */ +#define ALIGN_STRUCT_BLOCK 4 + +/* tokens used for structure block */ +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + + +void header_parser(); diff --git a/lab_4/bootloader/include/gpio.h b/lab_4/bootloader/include/gpio.h new file mode 100644 index 000000000..52fa671d0 --- /dev/null +++ b/lab_4/bootloader/include/gpio.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#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)) diff --git a/lab_4/bootloader/include/mbox.h b/lab_4/bootloader/include/mbox.h new file mode 100644 index 000000000..e0e2e41f1 --- /dev/null +++ b/lab_4/bootloader/include/mbox.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +/* a properly aligned buffer */ +extern volatile unsigned int mbox[36]; + +#define MBOX_REQUEST 0 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define MBOX_TAG_GETSERIAL 0x10004 +#define MBOX_TAG_REVISION 0x00010002 +#define MBOX_TAG_MEMORY 0x00010005 +#define MBOX_TAG_LAST 0 + +int mbox_call(unsigned char ch); diff --git a/lab_4/bootloader/include/stdint.h b/lab_4/bootloader/include/stdint.h new file mode 100644 index 000000000..3ddcc9b17 --- /dev/null +++ b/lab_4/bootloader/include/stdint.h @@ -0,0 +1,9 @@ + +typedef unsigned int uint16_t; + +typedef unsigned long uint32_t; + +typedef unsigned long long uint64_t; +typedef unsigned long uintptr_t; +typedef float float32; +typedef double float64; \ No newline at end of file diff --git a/lab_4/bootloader/include/uart.h b/lab_4/bootloader/include/uart.h new file mode 100644 index 000000000..245c358c8 --- /dev/null +++ b/lab_4/bootloader/include/uart.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +void uart_init(); +void uart_send(unsigned int c); +char uart_getc(); +void uart_puts(char *s); +void uart_hex(unsigned int d); \ No newline at end of file diff --git a/lab_4/bootloader/include/utils.h b/lab_4/bootloader/include/utils.h new file mode 100644 index 000000000..b993a5b68 --- /dev/null +++ b/lab_4/bootloader/include/utils.h @@ -0,0 +1,4 @@ +void set(long addr, unsigned int value); +void reset(); +int strcmp(char* a, char* b); +void cancel_reset(); \ No newline at end of file diff --git a/lab_4/bootloader/initramfs.cpio b/lab_4/bootloader/initramfs.cpio new file mode 100644 index 000000000..e9c1dda97 Binary files /dev/null and b/lab_4/bootloader/initramfs.cpio differ diff --git a/lab_4/bootloader/kernel_uploader.py b/lab_4/bootloader/kernel_uploader.py new file mode 100644 index 000000000..ab8def68f --- /dev/null +++ b/lab_4/bootloader/kernel_uploader.py @@ -0,0 +1,94 @@ +import serial +import os +import os.path +import sys +import time +import signal + + +def tstp_handler(signum, frame): + print("SIGTSTP received (Ctrl+Z), enter your command now:") + inp = input() + inp += "\n" + bytes_to_send = inp.encode('utf-8') + s.write(bytes_to_send) + + +def cont_handler(signum, frame): + print("SIGCONT received, resuming normal operation.") + + + +print("please enter the serial port: ", end="") +port = input() +port = "/dev/"+port +# port = '/dev/pts/1' +s = serial.Serial(port, baudrate=115200) + +def read_line(s): + received_string = "" + while True: + c = s.read().decode() + if c=="\r": + continue + if c=="\n": + break + received_string += c + return received_string + +size = os.stat("/home/laxiflora/Desktop/osc2024/lab_4/shell/shell_kernel.img").st_size +print(size) +# size = os.stat("./kernel8.img").st_size + +size_bytes = size.to_bytes(4,"little") +print(f"size from python: {hex(size)}") +s.write(size_bytes) +p = s + +time.sleep(1) +# get response of correctness of bytes size sent +while s.in_waiting > 0: + received_content = read_line(s) + print(received_content) + +with open("/home/laxiflora/Desktop/osc2024/lab_4/shell/shell_kernel.img", "rb") as f: + sent_size = 0 # Initialize size counter + + byte = f.read(1) # Read the first byte + while byte: + s.write(byte) # Send the byte over serial + # s.flush() # Flush the output buffer + sent_size += 1 # Increment size counter + byte = f.read(1) # Read the next byte + + +assert sent_size == size +print("kernel sent successfully.") +# Register signal handlers +signal.signal(signal.SIGTSTP, tstp_handler) +signal.signal(signal.SIGCONT, cont_handler) + +print(f"Process ID: {os.getpid()}") + +# Run a loop to keep the program alive and responsive to signals +while True: + received_content = read_line(s) + print(received_content) + +# # get response of whether kernel is loaded successfully or not +# time.sleep(1) +# while(True): +# while s.in_waiting > 0: +# received_content = read_line(s) +# print(received_content) +# print("#", end=" ") +# inp = input() +# if(inp == ""): +# continue +# inp += "\n" +# bytes_to_send = inp.encode('utf-8') +# s.write(bytes_to_send) +# #while s.in_waiting > 0: +# # received_content = read_line(s) +# # print(received_content) +# time.sleep(1) \ No newline at end of file diff --git a/lab_4/bootloader/link.ld b/lab_4/bootloader/link.ld new file mode 100644 index 000000000..5d4536049 --- /dev/null +++ b/lab_4/bootloader/link.ld @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +SECTIONS +{ + . = 0x60000; + PROVIDE(_head = .); + .relocate : { + KEEP(*(.text.relocate)) + } + . = ALIGN(4096); + + .imgLoader : { + KEEP(*(.text.load_img)) + } + . = ALIGN(4096); + .text : { + KEEP(*(.text.boot)) + *(.text) + } + . = ALIGN(4096); + PROVIDE(_data = .); + .data : { *(.data .data.*) } + .bss : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; +} +__bss_size = (__bss_end - __bss_start)>>3; +__loader_size = (_end - _head)>>3; \ No newline at end of file diff --git a/lab_4/bootloader/main.c b/lab_4/bootloader/main.c new file mode 100644 index 000000000..e8be04b8c --- /dev/null +++ b/lab_4/bootloader/main.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +#define MAX_BUFFER 10 +#include "include/uart.h" +#include "include/utils.h" +#include "include/mbox.h" +#include "include/stdint.h" +#include "include/device_tree.h" + +void load_img(){ + unsigned int size = 0; + unsigned char *size_buffer = (unsigned char *) &size; + uart_puts("enter kernel size now:"); + for(int i=0; i<4; i++) + size_buffer[i] = uart_getc(); + uart_puts("size-check correct\n"); + + uart_puts("Kernel size received: "); + uart_hex(size); + uart_puts("\n"); + + char *kernel = (char *) 0x80000; + while(size--) *kernel++ = uart_getc(); + + uart_puts("kernel-loaded\n"); + return; + +} + +void relocator(uintptr_t dtb_address){ + uart_init(); + // header_parser(dtb_address); + load_img(); + asm volatile( + "mov x30, 0x80000;" + "ret;" + ); +} diff --git a/lab_4/bootloader/mbox.c b/lab_4/bootloader/mbox.c new file mode 100644 index 000000000..b5b47c2f2 --- /dev/null +++ b/lab_4/bootloader/mbox.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "include/gpio.h" + +/* mailbox message buffer +* The buffer itself is 16-byte aligned as only the upper 28 bits of the address can be passed via the mailbox. +*/ +volatile unsigned int __attribute__((aligned(16))) mbox[36]; + +#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880) +#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0)) +#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10)) +#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14)) +#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18)) +#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C)) +#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20)) +#define MBOX_RESPONSE 0x80000000 +#define MBOX_FULL 0x80000000 +#define MBOX_EMPTY 0x40000000 + +/** + * Make a mailbox call. Returns 0 on failure, non-zero on success + */ +int mbox_call(unsigned char ch) +{ + unsigned int r = (((unsigned int)((unsigned long)&mbox)&~0xF) | (ch&0xF)); + /* wait until we can write to the mailbox */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL); + /* write the address of our message to the mailbox with channel identifier */ + *MBOX_WRITE = r; + /* now wait for the response */ + while(1) { + /* is there a response? */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY); + /* is it a response to our message? */ + if(r == *MBOX_READ) + /* is it a valid successful response? */ + return mbox[1]==MBOX_RESPONSE; + } + return 0; +} diff --git a/lab_4/bootloader/reader.py b/lab_4/bootloader/reader.py new file mode 100644 index 000000000..19a5e759a --- /dev/null +++ b/lab_4/bootloader/reader.py @@ -0,0 +1,9 @@ +with open("./bcm2710-rpi-3-b-plus.dtb", "rb") as f: + data = f.read() +# Filter out the 0x00 bytes +filtered_data = bytes(b for b in data if b != 0x00) + +# Print the filtered binary data +print(filtered_data) + +#print(data) \ No newline at end of file diff --git a/lab_4/bootloader/start.S b/lab_4/bootloader/start.S new file mode 100644 index 000000000..b086305c4 --- /dev/null +++ b/lab_4/bootloader/start.S @@ -0,0 +1,43 @@ +.section ".text.relocate" +.global _relocate + +_relocate: + // relocate our code from load address to link address + ldr x1, =0x80000; // src address + ldr x2, =0x60000; // target address + ldr w3, =__loader_size +1: ldr x4, [x1], #8 + str x4, [x2], #8 + sub w3, w3, #1 + cbnz w3, 1b + + ldr x1, =_start + mov sp, x1 + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size +2: cbz w2, 3f + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, 2b + + +3: // Device tree address has been moved from x0 to x10 within the bootloader. + mov x0, x10 + bl relocator-0x20000 + b _start + + +.section ".text.boot" + +.global _start + +_start: + // jump to main function in C + bl 0x80000 + // halt this core if return +1: + wfe + b 1b + diff --git a/lab_4/bootloader/uart.c b/lab_4/bootloader/uart.c new file mode 100644 index 000000000..5e63f2d3a --- /dev/null +++ b/lab_4/bootloader/uart.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "include/gpio.h" + +/** Auxilary mini UART registers + * Address & Description refer: https://cs140e.sergio.bz/docs/BCM2837-ARM-Peripherals.pdf Page.8 + */ + +#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() +{ + register unsigned int r; + + /* initialize UART */ + *AUX_ENABLE |=1; // enable UART1, AUX mini uart + *AUX_MU_CNTL = 0; + *AUX_MU_LCR = 3; // 8 bits + *AUX_MU_MCR = 0; + *AUX_MU_IER = 0; + *AUX_MU_IIR = 0xc6; // disable interrupts + *AUX_MU_BAUD = 270; // 115200 baud + /* map UART1 to GPIO pins */ + r=*GPFSEL1; + r&=~((7<<12)|(7<<15)); // gpio14, gpio15 + r|=(2<<12)|(2<<15); // alt5 + *GPFSEL1 = r; + *GPPUD = 0; // enable pins 14 and 15 + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = (1<<14)|(1<<15); + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = 0; // flush GPIO setup + *AUX_MU_CNTL = 3; // enable Tx, Rx + /*EXTRA: Read from AUX_MU_IO until AUX_MU_LSR indicates no more data*/ + while (*AUX_MU_LSR & 0x01) { + // Read and discard the data + volatile unsigned int data = *AUX_MU_IO; + (void)data; // Prevent unused variable warning + } +} + +void uart_enable_interrupt(){ + // enable tx rx interrupt in uart + *AUX_MU_IER |= 0x02; + *IRQS1 |= 1 << 29; +} + + +/** + * Send a character + */ +void uart_send(unsigned int c) { + /* wait until we can send */ + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); + /* write the character to the buffer */ + *AUX_MU_IO=c; +} + +/** + * 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 it and return */ + r=(char)(*AUX_MU_IO); + /* convert carriage return to newline */ + return r=='\r'?'\n':r; +} + +/** + * Display a string + */ +void uart_puts(char *s) { + while(*s) { + /* convert newline to carriage return + newline */ + if(*s=='\n') + uart_send('\r'); + 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); + } +} \ No newline at end of file diff --git a/lab_4/bootloader/utils.c b/lab_4/bootloader/utils.c new file mode 100644 index 000000000..d31e58159 --- /dev/null +++ b/lab_4/bootloader/utils.c @@ -0,0 +1,61 @@ +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +/** + * compare two string, given s1 and s2 + * return 0 if the both string are equal; + * return -1 if s1 is less than s2; + * return 1 if s1 is greater than s2 + */ +int strcmp(char* a, char* b){ + int value = 0; + while(*a != '\0' && *b != '\0'){ + if(*a < *b){ + return -1; + } + else if(*a > *b){ + return 1; + } + else{ + a++; + b++; + } + } + if(*a == '\0'){ + value++; + } + if(*b == '\0'){ + value--; + } + return value; +} + +/** + * set up given value to given address + */ +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + + +/** + * reboot respberry pi + * if tick=0, reboot instantly; + * otherwise, wait for tick seconds to reboot + */ +void reset(int tick) { // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + if(tick != 0){ + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick + } +} + +/** + * clear reboot register + */ +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} \ No newline at end of file diff --git a/lab_4/config.txt b/lab_4/config.txt new file mode 100644 index 000000000..7e9ff304c --- /dev/null +++ b/lab_4/config.txt @@ -0,0 +1,2 @@ +initramfs initramfs.cpio 0x80000000 +kernel=bootloader.img \ No newline at end of file diff --git a/lab_4/rootfs/hello.txt b/lab_4/rootfs/hello.txt new file mode 100644 index 000000000..ca9e3b5cc --- /dev/null +++ b/lab_4/rootfs/hello.txt @@ -0,0 +1 @@ +this is a example file. diff --git a/lab_4/rootfs/hello2.txt b/lab_4/rootfs/hello2.txt new file mode 100644 index 000000000..d90bb747c --- /dev/null +++ b/lab_4/rootfs/hello2.txt @@ -0,0 +1 @@ +this is another example file. diff --git a/lab_4/rootfs/link.ld b/lab_4/rootfs/link.ld new file mode 100644 index 000000000..bd0d89847 --- /dev/null +++ b/lab_4/rootfs/link.ld @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +SECTIONS +{ + . = 0x30000; + PROVIDE(_head = .); + .text : { KEEP(*(.text.boot)) *(.text .text.*) } + .rodata : { *(.rodata .rodata.*) } + PROVIDE(_data = .); + .data : { *(.data .data.*) } + .bss : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; +} +__bss_size = (__bss_end - __bss_start)>>3; +__loader_size = (_end - _head)>>3; \ No newline at end of file diff --git a/lab_4/rootfs/makefile b/lab_4/rootfs/makefile new file mode 100644 index 000000000..1f075562f --- /dev/null +++ b/lab_4/rootfs/makefile @@ -0,0 +1,36 @@ +# +# Copyright (C) 2018 bzt (bztsrc@github) +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# + +GCC = "aarch64-linux-gnu-gcc" +LD = "aarch64-linux-gnu-ld" +OBJCPY = "aarch64-linux-gnu-objcopy" +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.S=.o) +CFLAGS = -Wall -O0 -ffreestanding -nostdinc -nostdlib -nostartfiles +BOOTLOADER_BIN = kernel8.img +all: user_program.S + "aarch64-linux-gnu-gcc" -Wall -O0 -ffreestanding -nostdinc -nostdlib -nostartfiles -c user_program.S -o user_program.o + "aarch64-linux-gnu-ld" -nostdlib -nostartfiles user_program.o -T link.ld -o user_program.elf + "aarch64-linux-gnu-objcopy" -O binary user_program.elf user_program.img diff --git a/lab_4/rootfs/user_program b/lab_4/rootfs/user_program new file mode 100755 index 000000000..e235f8e5d Binary files /dev/null and b/lab_4/rootfs/user_program differ diff --git a/lab_4/rootfs/user_program.S b/lab_4/rootfs/user_program.S new file mode 100644 index 000000000..4d2ef454d --- /dev/null +++ b/lab_4/rootfs/user_program.S @@ -0,0 +1,13 @@ +.section ".text" +.global _start +_start: + mov x0, 0 +1: + add x0, x0, 1 + svc 0 + cmp x0, 5 + blt 1b + ret; +1: + b 1b + \ No newline at end of file diff --git a/lab_4/rootfs/user_program.elf b/lab_4/rootfs/user_program.elf new file mode 100755 index 000000000..977a8eef5 Binary files /dev/null and b/lab_4/rootfs/user_program.elf differ diff --git a/lab_4/rootfs/user_program.img b/lab_4/rootfs/user_program.img new file mode 100755 index 000000000..1adf648a4 Binary files /dev/null and b/lab_4/rootfs/user_program.img differ diff --git a/lab_4/shell/Makefile b/lab_4/shell/Makefile new file mode 100644 index 000000000..ecd9c6b2d --- /dev/null +++ b/lab_4/shell/Makefile @@ -0,0 +1,61 @@ +# +# Copyright (C) 2018 bzt (bztsrc@github) +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# + +GCC = "aarch64-linux-gnu-gcc" +LD = "aarch64-linux-gnu-ld" +OBJCPY = "aarch64-linux-gnu-objcopy" +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) +CFLAGS = -Wall -O0 -ffreestanding -nostdinc -nostdlib -nostartfiles +BOOTLOADER_BIN = kernel8.img +all: clean kernel8.img + +# start.o: start.S +# $(GCC) $(CFLAGS) -c start.S -o start.o + +%.o: %.S + $(GCC) $(CFLAGS) -c $< -o $@ -g + "aarch64-linux-gnu-gcc" -Wall -w -O0 -ffreestanding -nostdinc -nostdlib -nostartfiles -c exception_vector.S -o exception_vector.o -g + "aarch64-linux-gnu-gcc" -Wall -w -O0 -ffreestanding -nostdinc -nostdlib -nostartfiles -c interrupts.S -o interrupts.o -g + +%.o: %.c + $(GCC) $(CFLAGS) -c $< -w -o $@ -g + + +kernel8.img: start.o $(OBJS) + $(LD) -nostdlib -nostartfiles start.o $(OBJS) exception_vector.o interrupts.o -T link.ld -o kernel8.elf + $(OBJCPY) -O binary kernel8.elf shell_kernel.img + +clean: + rm kernel8.elf *.o >/dev/null 2>/dev/null || true + +run_asm: + qemu-system-aarch64 -M raspi3b -kernel shell_kernel.img -initrd initramfs.cpio -serial null -serial stdio -display none -d in_asm + +run: + qemu-system-aarch64 -M raspi3b -kernel shell_kernel.img -initrd initramfs.cpio -serial null -serial stdio -display none + +debug: + qemu-system-aarch64 -M raspi3b -kernel shell_kernel.img -initrd initramfs.cpio -serial null -serial stdio -display none -s -S diff --git a/lab_4/shell/cpio.c b/lab_4/shell/cpio.c new file mode 100644 index 000000000..99ee37706 --- /dev/null +++ b/lab_4/shell/cpio.c @@ -0,0 +1,102 @@ +#include "include/cpio.h" +#include "include/uart.h" +#include "include/stdint.h" +#include "include/utils.h" + +char* cpio_addr = (char *)0x8000000; + +void cpio_ls(){ + char* addr = (char*) cpio_addr; + uart_puts((char *)(addr+sizeof(struct cpio_header))); + while(strcmp((char *)(addr+sizeof(struct cpio_header)),"TRAILER!!!") != 0){ + struct cpio_header* header = (struct cpio_header*) addr; + unsigned long filename_size = utils_atoi(header->c_namesize,(int)sizeof(header->c_namesize)); + unsigned long headerPathname_size = sizeof(struct cpio_header) + filename_size; + unsigned long file_size = utils_atoi(header->c_filesize,(int)sizeof(header->c_filesize)); + utils_align(&headerPathname_size,4); + utils_align(&file_size,4); + uart_puts(addr+sizeof(struct cpio_header)); + uart_puts("\n"); + addr += (headerPathname_size + file_size); + } +} + +void cpio_exec(char *filename){ + char *target = findFile(filename); + if (target){ + struct cpio_header *header = (struct cpio_header *)target; + unsigned long pathname_size = utils_atoi(header->c_namesize,(int)sizeof(header->c_namesize)); + unsigned long file_size = utils_atoi(header->c_filesize,(int)sizeof(header->c_filesize)); + unsigned long headerPathname_size = sizeof(struct cpio_header) + pathname_size; + + utils_align(&headerPathname_size,4); + utils_align(&file_size,4); + char *file_content = target + headerPathname_size; + + char *program_ptr = (char *) 0x30000; // load the user program into 0x30000 + char* start_point = (char*) 0x30000; + char* stack_pointer = (char *) (0x30000 + 0x3000); // Stack pointer for the user program, base address+0x3000 + for (unsigned int i = 0; i < file_size; i++){ + *program_ptr ++ = *file_content++; + } + asm volatile( + // 0x3c0 + "mov x0, 0x3c0;\n\t" + "msr spsr_el1, x0;\n\t" + // start address of user program + "mov x1, 0x30000;\n\t" + "msr elr_el1, x1;\n\t" + // sp for user program + "mov x2, %0;\n\t" + "msr sp_el0, x2;\n\t" + "eret;" + : // No output operands + : "r" (start_point), "r" (stack_pointer) + : "x0", "x1", "x2" // tell compiler x0~x2 has been used + ); + } + uart_puts("completed.\n"); +} + + + +void cpio_cat(char *filename){ + char *target = findFile(filename); + if (target){ + struct cpio_header *header = (struct cpio_header *)target; + unsigned long pathname_size = utils_atoi(header->c_namesize,(int)sizeof(header->c_namesize)); + unsigned long file_size = utils_atoi(header->c_filesize,(int)sizeof(header->c_filesize)); + unsigned long headerPathname_size = sizeof(struct cpio_header) + pathname_size; + + utils_align(&headerPathname_size,4); + utils_align(&file_size,4); + char *file_content = target + headerPathname_size; + for (unsigned int i = 0; i < file_size; i++) + { + uart_send(file_content[i]); + } + uart_puts("\n"); + } + else + { + uart_puts("Not found the file\n"); + } +} + +char *findFile(char *name){ + char *addr = (char *)cpio_addr; + while (strcmp((char *)(addr + sizeof(struct cpio_header)), "TRAILER!!!") != 0){ + if ((strcmp((char *)(addr + sizeof(struct cpio_header)), name) == 0)){ + return addr; + } + struct cpio_header* header = (struct cpio_header *)addr; + unsigned long pathname_size = utils_atoi(header->c_namesize,(int)sizeof(header->c_namesize));; + unsigned long file_size = utils_atoi(header->c_filesize,(int)sizeof(header->c_filesize)); + unsigned long headerPathname_size = sizeof(struct cpio_header) + pathname_size; + + utils_align(&headerPathname_size,4); + utils_align(&file_size,4); + addr += (headerPathname_size + file_size); + } + return 0; +} \ No newline at end of file diff --git a/lab_4/shell/dynamic_allocator.c b/lab_4/shell/dynamic_allocator.c new file mode 100644 index 000000000..be3cc282d --- /dev/null +++ b/lab_4/shell/dynamic_allocator.c @@ -0,0 +1,149 @@ +#include "include/dynamic_allocator.h" +#include "include/page_allocator.h" + +// #define POOL {4, 8, 16, 32, 64, 128, 256, 512, 1024} +// #define PARTITION {4, 2, 2, 2, 2, 2, 2, 2, 2} +// #define POOL_SIZE 8 +// // max pages allowed to be partitioned +// #define MAX_PAGE 64 + +// typedef struct Page{ +// void* prefix; +// // the occupied section of each partition size in page +// int usage[POOL_SIZE]; +// } + +// typedef struct DynamicAllocator{ +// int chunk_option[POOL_SIZE]; +// int partition[POOL_SIZE]; +// int allocated_page_num; +// Page allocated_page_info[MAX_PAGE]; + +// }DynamicAllocator; + + +struct DynamicAllocator dynamic_allocator; + + +void init_dynamic_allocator(){ + int pool[] = POOL; + int part[] = PARTITION; + dynamic_allocator.allocated_page_num = 0; + for(int i=0;i>3; +__loader_size = (_end - _head)>>3; \ No newline at end of file diff --git a/lab_4/shell/main.c b/lab_4/shell/main.c new file mode 100644 index 000000000..fa769248d --- /dev/null +++ b/lab_4/shell/main.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +#define MAX_BUFFER 50 +#include "include/uart.h" +#include "include/utils.h" +#include "include/mbox.h" +#include "include/cpio.h" +#include "include/page_allocator.h" +#include "include/dynamic_allocator.h" + +extern void set_exception_vector_table(); +extern void core_timer_enable(); + + + +void main(int argc, char* argv[]){ + // init uart + uart_init(); + init_simple_malloc(); + // init exception table and interrupt (lab3) + set_exception_vector_table(); + // show el + unsigned long el; + asm volatile ("mrs %0, CurrentEL" : "=r" (el)); + el = el >> 2; // CurrentEL的值在高两位 + + // print current exception level + uart_puts("Booted! Current EL: "); + uart_send('0' + el); + uart_puts("\n"); + // init memory (lab4) + init_buddy_system(); + uart_puts("Booted! Current EL: "); + uart_send('0' + el); + uart_puts("\n"); + init_dynamic_allocator(); + + // char* my_array = malloc_page(1); + // char* my_variablwe = (char*)malloc(1023); + // char* my_varieable = (char*)malloc(1023); + // char* wmy_variable = (char*)malloc(1023); + // char* my_vrariable = (char*)malloc(1023); + // char* my_variatble = (char*)malloc(1023); + // free(my_variablwe); + // my_variablwe = (char*)malloc(7642); + // free(my_variablwe); + // my_variablwe = (char*)malloc(1023); + // free(my_variablwe); + // my_variablwe = (char*)malloc(1023); + // free(my_variablwe); + // free(my_variatble); + + char* my_array = malloc_page(3); + char* my_array2 = malloc_page(3); + char* my_array3 = malloc_page(3); + char* my_array4 = malloc_page(3); + char* my_array5 = malloc_page(3); + char* my_array6 = malloc_page(3); + while(1){ + char command[MAX_BUFFER]; + char c = '\0'; + int length=0; + for(int i=0; i\t: print the content of file in initfs\n"); + uart_puts("hello\t: print hello world!\n"); + uart_puts("exec: execute user program in initfs\n"); + uart_puts("async_uart: switch to async uart mode (currently for demo only)\n"); + uart_puts("malloc \t: malloc memory of size \n"); + uart_puts("free\t: free all malloced page memory (for demo, the memory alloced in simple malloc will not be freed)\n"); + uart_puts("reboot\t: reboot the device\n"); + } + else if(strcmp(command, "hello") == 0){ + uart_puts("Hello World!\n"); + } + else if(strcmp(command, "free") == 0){ + free_page(my_array); + free_page(my_array2); + free_page(my_array3); + free_page(my_array4); + free_page(my_array5); + + my_array = malloc_page(3); + my_array2 = malloc_page(3); + my_array3 = malloc_page(3); + my_array4 = malloc_page(3); + my_array5 = malloc_page(3); + } + else if(strcmp(command, "ls") == 0){ + cpio_ls(); + } + else if(strcmp(command, "async_uart") == 0){ + demo_async_uart(); + } + else if(strcmp(command, "reboot") == 0){ + reset(); + } + else if(strcmp(command, "exec") == 0){ + uart_puts("executing...\n"); + // execute a dedicated user program + cpio_exec("user_program.img"); + } + // command with arguments + else{ + char arguments[3][MAX_BUFFER]; + // initialize + for(int i=0;i<3;i++){ + for(int j=0;jroot; + target->root = target->root->next; + return to_ret; +} + +void init_order_list(){ + int current_order = MAX_ORDER-1; + int current_page_start = 0; + // advanced: handle cases that some pages are reserved + while((HEAP_START_ADDRESS+(PAGE_SIZE*current_page_start)) < HEAP_END_ADDRESS){ + int continuous_block = 0; + while(continuous_block < _pow(2, MAX_ORDER) && current_page_start+continuous_blockaddress = (unsigned char*) HEAP_START_ADDRESS+(PAGE_SIZE*current_page_start); + new_node->page_index = current_page_start; + list_push_back(new_node, order); + + uart_puts("[Init] grouping block at address 0x"); + uart_hex(new_node->address); + uart_puts(" with 0x"); + uart_hex((unsigned int)allocated_size/PAGE_SIZE); + uart_puts(" pages and start at index "); + uart_hex((unsigned int)new_node->page_index); + uart_puts(" in The Array"); + uart_puts("\n"); + current_page_start = current_page_start +continuous_block; + current_page_start++; + } + + // assume all pages are available at beginnig, greedly allocate pages in max order size + // while(current_order >= 0){ + // while((current_page_index+_pow(2, current_order)-1) < AVAILABLE_PAGE_NUM){ + // unsigned int allocated_size = _pow(2, current_order)*PAGE_SIZE; + // // record the grouped block at The Array + // the_array[current_page_index].block_size = _pow(2, current_order); + // // malloc a struct node to record the meta data of this block + // Node* new_node = simple_malloc(sizeof(Node)); + // // push into order list + // new_node->address = (unsigned char*) HEAP_START_ADDRESS+(PAGE_SIZE*current_page_index); + // new_node->page_index = current_page_index; + // list_push_back(new_node, current_order); + + // uart_puts("[Init] grouping block at address 0x"); + // uart_hex(new_node->address); + // uart_puts(" with 0x"); + // uart_hex((unsigned int)allocated_size/PAGE_SIZE); + // uart_puts(" pages and start at index "); + // uart_hex((unsigned int)new_node->page_index); + // uart_puts(" in The Array"); + // uart_puts("\n"); + + // current_page_index = current_page_index+_pow(2, current_order)+1; + // } + // current_order--; + // } + +} + +void print_order_list(OrderList* list){ + Node* cur = list->root; + uart_puts("address : \n"); + while(cur != NULL){ + uart_hex(cur->address); + uart_puts("\n"); + cur = cur->next; + } +} + +void init_buddy_system(){ + // initialize The Array + for(int i=0;iroot != NULL; +} + +Node* get_buddy(OrderList* target, int target_page_index){ + Node* cur = target->root; + Node* prev = NULL; + while(cur != NULL){ + if(cur->page_index == target_page_index){ + if(prev != NULL){ + prev->next = cur->next; + } + // root is the buddy + else{ + target->root = target->root->next; + } + cur->next = NULL; + return cur; + } + prev = cur; + cur = cur->next; + } + uart_puts("[Assertion Error] buddy not found\n"); + print_order_list(target); + return NULL; +} + +void free_page(void* to_free){ + int page_index = ((unsigned int)to_free-HEAP_START_ADDRESS)/PAGE_SIZE; + int free_block_size = the_array[page_index].block_size; + int do_merge = 0; + if(the_array[page_index].available != OCCUPIED){ + uart_puts("[Assertion Error] releasing free page head\n"); + } + the_array[page_index].available = FREE; + int next_block_index = page_index+free_block_size+1; + uart_puts("[Free] block that contains "); + // block size starts from zero, thus need to +1 + uart_hex(free_block_size+1); + uart_puts(" pages started from address 0x"); + uart_hex((unsigned int)to_free); + uart_puts(" to address 0x"); + uart_hex((unsigned int)to_free+(free_block_size*PAGE_SIZE)); + uart_puts(" with index starts from "); + uart_hex(page_index); + uart_puts("\n"); + + if(the_array[next_block_index].available == FREE){ + // debug: print the address of next page of freed block + // uart_puts("Accessing location: 0x"); + // uart_hex((unsigned int)HEAP_START_ADDRESS+(PAGE_SIZE*next_block_index)); + // uart_puts("\n"); + + // same size, can merge + if(the_array[next_block_index].block_size == free_block_size && the_array[next_block_index].available==FREE){ + int order =0, block_size = free_block_size; + // get sqrt(2) of block_size to obtain order + while(block_size > 0){ + order++; + block_size/=2; + } + print_order_list(&order_list[order]); + Node* buddy = get_buddy(&order_list[order], next_block_index); + if(buddy != NULL){ + Node* new_node = simple_malloc(sizeof(Node)); + // push into order list + new_node->address = (unsigned char*) to_free; + new_node->page_index = page_index; + the_array[page_index].block_size = _pow(2, order+1); + the_array[next_block_index].available = FREE; + the_array[next_block_index].block_size = FREE; + list_push_back(new_node, order+1); + uart_puts("[Merge] block that contains "); + uart_hex(free_block_size); + uart_puts(" pages started from address 0x"); + uart_hex((unsigned int)to_free); + uart_puts(" to address 0x"); + uart_hex((unsigned int)HEAP_START_ADDRESS+(PAGE_SIZE*(next_block_index+free_block_size))); + uart_puts("\n"); + do_merge = 1; + } + } + } + if(!do_merge){ + Node* new_node = simple_malloc(sizeof(Node)); + new_node->address = (unsigned char*) to_free; + new_node->page_index = page_index; + int order =0, block_size = free_block_size; + // get sqrt(2) of block_size to obtain order + while(block_size > 0){ + order++; + block_size/=2; + } + list_push_back(new_node, order); + } + +} + +unsigned char* malloc_page(int request_page_num){ + //determine the minimum list order that this request needs + int current_order = 0; + int cut_freg = 0; + // start from allocating the smallest block until is can satisfy needs + //print_order_list(&order_list[2]); + while(current_order _pow(2, current_order)){ + current_order++; + } + else{ + if(check_list_has_element(&order_list[current_order])){ + struct Node* allocated_address = list_pop(&order_list[current_order]); + // mark the block as OCCUPIED + the_array[(unsigned int)allocated_address->page_index].available = OCCUPIED; + // the block_size start from zero, thus we need to -1 + the_array[(unsigned int)allocated_address->page_index].block_size = _pow(2, current_order)-1; + // print the log + uart_puts("[Malloc] block that contains "); + uart_hex(_pow(2, current_order)); + uart_puts(" pages started from address 0x"); + uart_hex((unsigned int)allocated_address->address); + uart_puts(" to address 0x"); + uart_hex((unsigned int)((allocated_address->address)+(_pow(2, current_order)-1)*PAGE_SIZE)); + uart_puts(" with index starts from "); + uart_hex((unsigned int)allocated_address->page_index); + uart_puts("\n"); + int cutter_count = 1; + while(cut_freg > 0){ + // mid address is the starting address of last page that BEEN malloced + int mid_page_index = allocated_address->page_index+(_pow(2, current_order-cutter_count))-1; + // end address is the starting address of last page in this block + unsigned char* end_address = mid_page_index+_pow(2, current_order-cutter_count); + Node* new_node = simple_malloc(sizeof(Node)); + // push into order list + new_node->address = (unsigned char*) HEAP_START_ADDRESS+(PAGE_SIZE*(mid_page_index+1)); + new_node->page_index = mid_page_index+1; + the_array[new_node->page_index].block_size = _pow(2, current_order-cutter_count)-1; + uart_puts("[Release redundant memory] block that contains "); + uart_hex(_pow(2, current_order-cutter_count)); + uart_puts(" pages started from address 0x"); + uart_hex(new_node->address); + uart_puts(" to address 0x"); + uart_hex(new_node->address+((the_array[new_node->page_index].block_size)*PAGE_SIZE)); + uart_puts(" is freed \n"); + list_push_back(new_node, current_order-cutter_count); + cut_freg--; + cutter_count++; + } + if(cutter_count>1){ + the_array[(unsigned int)allocated_address->page_index].block_size = _pow(2, current_order-(cutter_count-1))-1; + } + + return allocated_address->address; + } + else{ + cut_freg++; // we may allocate more then 2 times more memory than needed + current_order++; + } + } + } + uart_puts("[Warning] malloc failed, returning 0x00\n"); + return 0x0; +} + + + +void list_push_back(Node* to_push, int order){ + OrderList* target_list = &(order_list[order]); + if(target_list->root == NULL){ + target_list->root = to_push; + } + else{ + Node* current = target_list->root; + while(current->next != NULL){ + current = current->next; + } + current->next = to_push; + } + //print_order_list(target_list); +} + +void init_reserve_memory(){ + // Spin tables for multicore boot (0x0000 - 0x1000) + memory_reserve(0x00000000, 0x00001000); + // initramfs, allocate 4 pages + memory_reserve(0x8000000, 0x8000000 + 0x4000); + // kernel image + memory_reserve(&_head, &_end); +} + + +void memory_reserve(unsigned int start, unsigned int end){ + start = start-(start % PAGE_SIZE); + end = end % PAGE_SIZE ? end + PAGE_SIZE - (end % PAGE_SIZE) : end; + + uart_puts("[Reserve] Memory Reserve: Start from adress 0x"); + uart_hex(start); + uart_puts(" to 0x"); + uart_hex(end); + uart_puts("\n"); + + int start_index = (int)((start-HEAP_START_ADDRESS)/PAGE_SIZE); + // assume end_index do not exceed limit + int end_index = (end-HEAP_START_ADDRESS)/PAGE_SIZE; + for(int i=start_index;i 0, stop +1: wfe + b 1b + + +2: // cpu id == 0 + + // el2 to el1 + bl from_el2_to_el1 + + // set top of stack just before our code (stack grows to a lower address per AAPCS64) + ldr x1, =_start + mov sp, x1 + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size +3: cbz w2, 4f + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, 3b + + // jump to C code, should not return +4: bl main + // for failsafe, halt this core too + b 1b + +from_el2_to_el1: + mov x0, (1 << 31) // EL1 uses aarch64 + // move system register to register (write x0 into hcr_el2) + msr hcr_el2, x0 + mov x0, 0x3c5 // 3c5 EL1h (SPSel = 1) with interrupt disabled, 345 enable interrupt + msr spsr_el2, x0 + msr elr_el2, lr + eret // return to EL1 diff --git a/lab_4/shell/uart.c b/lab_4/shell/uart.c new file mode 100644 index 000000000..dee6592ce --- /dev/null +++ b/lab_4/shell/uart.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "include/gpio.h" +#include "include/uart.h" +/** Auxilary mini UART registers + * Address & Description refer: https://cs140e.sergio.bz/docs/BCM2837-ARM-Peripherals.pdf Page.8 + */ + + +/* + The definition below is for async uart IO +*/ + +#define BUFFER_SIZE 1024 +#define IRQS1 ((volatile unsigned int *)(0x3f00b210)) +char uart_read_buffer[BUFFER_SIZE]; +unsigned int read_idx = 0; + +char uart_write_buffer[BUFFER_SIZE]; +unsigned int write_idx = 0; +unsigned int write_cur = 0; +int async; + + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init() +{ + register unsigned int r; + + /* initialize UART */ + *AUX_ENABLE |=1; // enable UART1, AUX mini uart + *AUX_MU_CNTL = 0; + *AUX_MU_LCR = 3; // 8 bits + *AUX_MU_MCR = 0; + *AUX_MU_IER = 0; + *AUX_MU_IIR = 0xc6; // disable interrupts + *AUX_MU_BAUD = 270; // 115200 baud + /* map UART1 to GPIO pins */ + r=*GPFSEL1; + r&=~((7<<12)|(7<<15)); // gpio14, gpio15 + r|=(2<<12)|(2<<15); // alt5 + *GPFSEL1 = r; + *GPPUD = 0; // enable pins 14 and 15 + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = (1<<14)|(1<<15); + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = 0; // flush GPIO setup + *AUX_MU_CNTL = 3; // enable Tx, Rx +} + +/** + * Send a character + */ +void uart_send(unsigned int c) { + /* This bit is set if the transmit FIFO can accept at least one byte*/ + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); + /* write the character to the buffer */ + *AUX_MU_IO=c; +} + +/** + * 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 it and return */ + r=(char)(*AUX_MU_IO); + /* convert carriage return to newline */ + return r=='\r'?'\n':r; +} + +/** + * Display a string + */ +void uart_puts(char *s) { + while(*s) { + /* convert newline to carriage return + newline */ + if(*s=='\n') + uart_send('\r'); + 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); + } +} + +void uart_enable_interrupt(){ + *AUX_MU_IER |= 0x02; + *IRQS1 |= 1 << 29; +} + +void uart_load_buffer(){ + while(write_cur < write_idx){ + uart_send(uart_write_buffer[write_cur]); + } +} + +void demo_async_uart(){ + uart_puts("turning to async mode...\n"); + uart_enable_interrupt(); + while(1){ + asm volatile("nop"); + } +} + +void uart_read_handler() { + char ch = (char)(*AUX_MU_IO); + uart_read_buffer[write_idx] = ch; + write_idx++; + uart_write_buffer[write_idx] = ch; + read_idx++; + write_idx++; + if(ch == '\r'){ + uart_puts(uart_write_buffer); + } +} + +void uart_write_handler(){ + if(write_cur < write_idx){ + *AUX_MU_IO=uart_read_buffer[write_cur]; + write_cur++; + } +} \ No newline at end of file diff --git a/lab_4/shell/utils.c b/lab_4/shell/utils.c new file mode 100644 index 000000000..bb2cb26c9 --- /dev/null +++ b/lab_4/shell/utils.c @@ -0,0 +1,118 @@ +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 +#define SIMPLE_MALLOC_BUFFER_SIZE 8192 + +unsigned long utils_atoi(const char *s, int char_size) { + unsigned long num = 0; + for (int i = 0; i < char_size; i++) { + num = num * 16; + if (*s >= '0' && *s <= '9') { + num += (*s - '0'); + } else if (*s >= 'A' && *s <= 'F') { + num += (*s - 'A' + 10); + } else if (*s >= 'a' && *s <= 'f') { + num += (*s - 'a' + 10); + } + s++; + } + return num; +} + +int _pow(int base, int exp){ + + int ret = 1; + for(int i=0;i *b){ + return 1; + } + else{ + a++; + b++; + } + } + if(*a == '\0'){ + value++; + } + if(*b == '\0'){ + value--; + } + return value; +} + +/** + * set up given value to given address + */ +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + + +void utils_align(void *size, unsigned int s) { + unsigned long* x = (unsigned long*) size; + unsigned long mask = s-1; + *x = ((*x) + mask) & (~mask); +} + +/** + * reboot respberry pi + * if tick=0, reboot instantly; + * otherwise, wait for tick seconds to reboot + */ +void reset(int tick) { // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + if(tick != 0){ + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick + } +} + +/** + * clear reboot register + */ +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} + + +static unsigned char simple_malloc_buffer[SIMPLE_MALLOC_BUFFER_SIZE]; +static unsigned long simple_malloc_offset = 0; + +void init_simple_malloc(){ + for(int i=0;i SIMPLE_MALLOC_BUFFER_SIZE) { + //Not enough space left + return (void*) 0; + } + void* allocated = (void *)&simple_malloc_buffer[simple_malloc_offset]; + simple_malloc_offset += size; + + return allocated; +} \ No newline at end of file diff --git a/lab_5/Makefile b/lab_5/Makefile new file mode 100644 index 000000000..015d9ea3d --- /dev/null +++ b/lab_5/Makefile @@ -0,0 +1,52 @@ +# +# Copyright (C) 2018 bzt (bztsrc@github) +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# + +GCC = "aarch64-linux-gnu-gcc" +LD = "aarch64-linux-gnu-ld" +OBJCPY = "aarch64-linux-gnu-objcopy" +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) +CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles +BOOTLOADER_BIN = kernel8.img +all: clean kernel8.img + +start.o: start.S + $(GCC) $(CFLAGS) -c start.S -o start.o + +%.o: %.c + $(GCC) $(CFLAGS) -c $< -o $@ -g + +kernel8.img: start.o $(OBJS) + $(LD) -nostdlib -nostartfiles start.o $(OBJS) -T link.ld -o kernel8.elf + $(OBJCPY) -O binary kernel8.elf kernel8.img + +clean: + rm kernel8.elf *.o >/dev/null 2>/dev/null || true + +run: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -d in_asm + +debug: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -s -S diff --git a/lab_5/Makefile.gcc b/lab_5/Makefile.gcc new file mode 100644 index 000000000..77366f3cf --- /dev/null +++ b/lab_5/Makefile.gcc @@ -0,0 +1,52 @@ +# +# Copyright (C) 2018 bzt (bztsrc@github) +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# + +GCC = "aarch64-linux-gnu-gcc" +LD = "aarch64-linux-gnu-ld" +OBJCPY = "aarch64-linux-gnu-objcopy" +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) +CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles + +all: clean kernel8.img + +start.o: start.S + $(GCC) $(CFLAGS) -c start.S -o start.o + +%.o: %.c + $(GCC) $(CFLAGS) -c $< -o $@ -g + +kernel8.img: start.o $(OBJS) + $(LD) -nostdlib -nostartfiles start.o $(OBJS) -T link.ld -o kernel8.elf + $(OBJCPY) -O binary kernel8.elf kernel8.img + +clean: + rm kernel8.elf *.o >/dev/null 2>/dev/null || true + +run: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none + +debug: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -s -S diff --git a/lab_5/README.md b/lab_5/README.md new file mode 100644 index 000000000..ff2c23e3f --- /dev/null +++ b/lab_5/README.md @@ -0,0 +1,6 @@ +1. python UART transfer data loss +2. init UART register to avoid garbage pending +3. link loader can arrange the .text section freely + - why align +4. wze is for halting CPU that is not id 0 +5. \ No newline at end of file diff --git a/lab_5/bootloader/Makefile b/lab_5/bootloader/Makefile new file mode 100644 index 000000000..2a00a5890 --- /dev/null +++ b/lab_5/bootloader/Makefile @@ -0,0 +1,59 @@ +# +# Copyright (C) 2018 bzt (bztsrc@github) +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# + +GCC = "aarch64-linux-gnu-gcc" +LD = "aarch64-linux-gnu-ld" +OBJCPY = "aarch64-linux-gnu-objcopy" +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) +CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles +BOOTLOADER_BIN = kernel8.img +all: clean kernel8.img + +start.o: start.S + $(GCC) $(CFLAGS) -c start.S -o start.o + +%.o: %.c + $(GCC) $(CFLAGS) -c $< -o $@ -g + +kernel8.img: start.o $(OBJS) + $(LD) -nostdlib -nostartfiles start.o $(OBJS) -T link.ld -o kernel8.elf + $(OBJCPY) -O binary kernel8.elf kernel8.img + +clean: + rm kernel8.elf *.o >/dev/null 2>/dev/null || true + +run: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -initrd initramfs.cpio -serial pty -display none -dtb bcm2710-rpi-3-b-plus.dtb + +run_asm: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -initrd initramfs.cpio -serial pty -display none -dtb bcm2710-rpi-3-b-plus.dtb -d in_asm + + +run_stdio: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -initrd initramfs.cpio -serial stdio -display none -dtb bcm2710-rpi-3-b-plus.dtb + +debug: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -s -S diff --git a/lab_5/bootloader/bcm2710-rpi-3-b-plus.dtb b/lab_5/bootloader/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..a219bf3d5 Binary files /dev/null and b/lab_5/bootloader/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab_5/bootloader/device_tree.c b/lab_5/bootloader/device_tree.c new file mode 100644 index 000000000..6370eb7b7 --- /dev/null +++ b/lab_5/bootloader/device_tree.c @@ -0,0 +1,74 @@ +#include "include/device_tree.h" +#include "include/uart.h" +// #include +// #include + +device_tree_header myHeader; + +void header_parser(uintptr_t dtb_address){ + uint32_t* start; + //uint32_t* dtb = mock_load_file(); + uint32_t* dtb = dtb_address; + start = dtb; + // __builtin_bswap32() is a GCC built-in function to convert to the system's endianness.(RPi uses little-endian) + myHeader.magic = __builtin_bswap32(*dtb++); + if ((myHeader.magic - 0xd00dfeed) != 0) { + uart_puts("DTB magic number doesn't match!\r\n"); + return 1; + } + myHeader.totalsize = __builtin_bswap32(*dtb++); + myHeader.off_dt_struct = __builtin_bswap32(*dtb++); + myHeader.off_dt_strings = __builtin_bswap32(*dtb++); + myHeader.off_mem_rsvmap = __builtin_bswap32(*dtb++); + myHeader.version = __builtin_bswap32(*dtb++); + myHeader.last_comp_version = __builtin_bswap32(*dtb++); + myHeader.boot_cpuid_phys = __builtin_bswap32(*dtb++); + myHeader.size_dt_strings = __builtin_bswap32(*dtb++); + myHeader.size_dt_struct = __builtin_bswap32(*dtb++); + + // jump to structure + uint32_t* structure_ptr = (uint32_t *)(start + myHeader.off_dt_struct); + while(1){ + uint32_t token = __builtin_bswap32(*structure_ptr++); + if(token == FDT_BEGIN_NODE){ + uart_puts("Start\n"); + } + } + + //The node’s name as a null-terminated string + + + +} + +// unsigned long* mock_load_file() { +// FILE *file = fopen("bcm2710-rpi-3-b-plus.dtb", "rb"); +// if (!file) { +// perror("Failed to open file"); +// return 1; +// } + +// // Get the size of the file +// fseek(file, 0, SEEK_END); +// long fileSize = ftell(file); +// rewind(file); + +// // Allocate memory to hold the entire file +// unsigned char *buffer = (unsigned char *)malloc(fileSize); +// if (!buffer) { +// perror("Failed to allocate memory"); +// fclose(file); +// return 1; +// } + +// // Read the entire file into the buffer +// size_t bytesRead = fread(buffer, 1, fileSize, file); +// if (bytesRead != fileSize) { +// perror("Failed to read file"); +// free(buffer); +// fclose(file); +// return 1; +// } + +// return (unsigned long*)buffer; +// } \ No newline at end of file diff --git a/lab_5/bootloader/include/device_tree.h b/lab_5/bootloader/include/device_tree.h new file mode 100644 index 000000000..6846d0cba --- /dev/null +++ b/lab_5/bootloader/include/device_tree.h @@ -0,0 +1,34 @@ +#include "stdint.h" + + +typedef struct fdt_header { + // 0xd00dfeed (big-endian) + uint32_t magic; + uint32_t totalsize; + // offsets of each block from start + uint32_t off_dt_struct; + uint32_t off_dt_strings; + uint32_t off_mem_rsvmap; + + uint32_t version; + uint32_t last_comp_version; + // physical ID of the system’s boot CPU + uint32_t boot_cpuid_phys; + uint32_t size_dt_strings; + uint32_t size_dt_struct; +} device_tree_header; + +#define ALIGN_MEMORY_BLOCK 8 + +/* All tokens shall be aligned on a 32-bit boundary */ +#define ALIGN_STRUCT_BLOCK 4 + +/* tokens used for structure block */ +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + + +void header_parser(); diff --git a/lab_5/bootloader/include/gpio.h b/lab_5/bootloader/include/gpio.h new file mode 100644 index 000000000..52fa671d0 --- /dev/null +++ b/lab_5/bootloader/include/gpio.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#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)) diff --git a/lab_5/bootloader/include/mbox.h b/lab_5/bootloader/include/mbox.h new file mode 100644 index 000000000..e0e2e41f1 --- /dev/null +++ b/lab_5/bootloader/include/mbox.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +/* a properly aligned buffer */ +extern volatile unsigned int mbox[36]; + +#define MBOX_REQUEST 0 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define MBOX_TAG_GETSERIAL 0x10004 +#define MBOX_TAG_REVISION 0x00010002 +#define MBOX_TAG_MEMORY 0x00010005 +#define MBOX_TAG_LAST 0 + +int mbox_call(unsigned char ch); diff --git a/lab_5/bootloader/include/stdint.h b/lab_5/bootloader/include/stdint.h new file mode 100644 index 000000000..3ddcc9b17 --- /dev/null +++ b/lab_5/bootloader/include/stdint.h @@ -0,0 +1,9 @@ + +typedef unsigned int uint16_t; + +typedef unsigned long uint32_t; + +typedef unsigned long long uint64_t; +typedef unsigned long uintptr_t; +typedef float float32; +typedef double float64; \ No newline at end of file diff --git a/lab_5/bootloader/include/uart.h b/lab_5/bootloader/include/uart.h new file mode 100644 index 000000000..245c358c8 --- /dev/null +++ b/lab_5/bootloader/include/uart.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +void uart_init(); +void uart_send(unsigned int c); +char uart_getc(); +void uart_puts(char *s); +void uart_hex(unsigned int d); \ No newline at end of file diff --git a/lab_5/bootloader/include/utils.h b/lab_5/bootloader/include/utils.h new file mode 100644 index 000000000..b993a5b68 --- /dev/null +++ b/lab_5/bootloader/include/utils.h @@ -0,0 +1,4 @@ +void set(long addr, unsigned int value); +void reset(); +int strcmp(char* a, char* b); +void cancel_reset(); \ No newline at end of file diff --git a/lab_5/bootloader/initramfs.cpio b/lab_5/bootloader/initramfs.cpio new file mode 100644 index 000000000..e9c1dda97 Binary files /dev/null and b/lab_5/bootloader/initramfs.cpio differ diff --git a/lab_5/bootloader/kernel_uploader.py b/lab_5/bootloader/kernel_uploader.py new file mode 100644 index 000000000..ab8def68f --- /dev/null +++ b/lab_5/bootloader/kernel_uploader.py @@ -0,0 +1,94 @@ +import serial +import os +import os.path +import sys +import time +import signal + + +def tstp_handler(signum, frame): + print("SIGTSTP received (Ctrl+Z), enter your command now:") + inp = input() + inp += "\n" + bytes_to_send = inp.encode('utf-8') + s.write(bytes_to_send) + + +def cont_handler(signum, frame): + print("SIGCONT received, resuming normal operation.") + + + +print("please enter the serial port: ", end="") +port = input() +port = "/dev/"+port +# port = '/dev/pts/1' +s = serial.Serial(port, baudrate=115200) + +def read_line(s): + received_string = "" + while True: + c = s.read().decode() + if c=="\r": + continue + if c=="\n": + break + received_string += c + return received_string + +size = os.stat("/home/laxiflora/Desktop/osc2024/lab_4/shell/shell_kernel.img").st_size +print(size) +# size = os.stat("./kernel8.img").st_size + +size_bytes = size.to_bytes(4,"little") +print(f"size from python: {hex(size)}") +s.write(size_bytes) +p = s + +time.sleep(1) +# get response of correctness of bytes size sent +while s.in_waiting > 0: + received_content = read_line(s) + print(received_content) + +with open("/home/laxiflora/Desktop/osc2024/lab_4/shell/shell_kernel.img", "rb") as f: + sent_size = 0 # Initialize size counter + + byte = f.read(1) # Read the first byte + while byte: + s.write(byte) # Send the byte over serial + # s.flush() # Flush the output buffer + sent_size += 1 # Increment size counter + byte = f.read(1) # Read the next byte + + +assert sent_size == size +print("kernel sent successfully.") +# Register signal handlers +signal.signal(signal.SIGTSTP, tstp_handler) +signal.signal(signal.SIGCONT, cont_handler) + +print(f"Process ID: {os.getpid()}") + +# Run a loop to keep the program alive and responsive to signals +while True: + received_content = read_line(s) + print(received_content) + +# # get response of whether kernel is loaded successfully or not +# time.sleep(1) +# while(True): +# while s.in_waiting > 0: +# received_content = read_line(s) +# print(received_content) +# print("#", end=" ") +# inp = input() +# if(inp == ""): +# continue +# inp += "\n" +# bytes_to_send = inp.encode('utf-8') +# s.write(bytes_to_send) +# #while s.in_waiting > 0: +# # received_content = read_line(s) +# # print(received_content) +# time.sleep(1) \ No newline at end of file diff --git a/lab_5/bootloader/link.ld b/lab_5/bootloader/link.ld new file mode 100644 index 000000000..5d4536049 --- /dev/null +++ b/lab_5/bootloader/link.ld @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +SECTIONS +{ + . = 0x60000; + PROVIDE(_head = .); + .relocate : { + KEEP(*(.text.relocate)) + } + . = ALIGN(4096); + + .imgLoader : { + KEEP(*(.text.load_img)) + } + . = ALIGN(4096); + .text : { + KEEP(*(.text.boot)) + *(.text) + } + . = ALIGN(4096); + PROVIDE(_data = .); + .data : { *(.data .data.*) } + .bss : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; +} +__bss_size = (__bss_end - __bss_start)>>3; +__loader_size = (_end - _head)>>3; \ No newline at end of file diff --git a/lab_5/bootloader/main.c b/lab_5/bootloader/main.c new file mode 100644 index 000000000..e8be04b8c --- /dev/null +++ b/lab_5/bootloader/main.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +#define MAX_BUFFER 10 +#include "include/uart.h" +#include "include/utils.h" +#include "include/mbox.h" +#include "include/stdint.h" +#include "include/device_tree.h" + +void load_img(){ + unsigned int size = 0; + unsigned char *size_buffer = (unsigned char *) &size; + uart_puts("enter kernel size now:"); + for(int i=0; i<4; i++) + size_buffer[i] = uart_getc(); + uart_puts("size-check correct\n"); + + uart_puts("Kernel size received: "); + uart_hex(size); + uart_puts("\n"); + + char *kernel = (char *) 0x80000; + while(size--) *kernel++ = uart_getc(); + + uart_puts("kernel-loaded\n"); + return; + +} + +void relocator(uintptr_t dtb_address){ + uart_init(); + // header_parser(dtb_address); + load_img(); + asm volatile( + "mov x30, 0x80000;" + "ret;" + ); +} diff --git a/lab_5/bootloader/mbox.c b/lab_5/bootloader/mbox.c new file mode 100644 index 000000000..b5b47c2f2 --- /dev/null +++ b/lab_5/bootloader/mbox.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "include/gpio.h" + +/* mailbox message buffer +* The buffer itself is 16-byte aligned as only the upper 28 bits of the address can be passed via the mailbox. +*/ +volatile unsigned int __attribute__((aligned(16))) mbox[36]; + +#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880) +#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0)) +#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10)) +#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14)) +#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18)) +#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C)) +#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20)) +#define MBOX_RESPONSE 0x80000000 +#define MBOX_FULL 0x80000000 +#define MBOX_EMPTY 0x40000000 + +/** + * Make a mailbox call. Returns 0 on failure, non-zero on success + */ +int mbox_call(unsigned char ch) +{ + unsigned int r = (((unsigned int)((unsigned long)&mbox)&~0xF) | (ch&0xF)); + /* wait until we can write to the mailbox */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL); + /* write the address of our message to the mailbox with channel identifier */ + *MBOX_WRITE = r; + /* now wait for the response */ + while(1) { + /* is there a response? */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY); + /* is it a response to our message? */ + if(r == *MBOX_READ) + /* is it a valid successful response? */ + return mbox[1]==MBOX_RESPONSE; + } + return 0; +} diff --git a/lab_5/bootloader/reader.py b/lab_5/bootloader/reader.py new file mode 100644 index 000000000..19a5e759a --- /dev/null +++ b/lab_5/bootloader/reader.py @@ -0,0 +1,9 @@ +with open("./bcm2710-rpi-3-b-plus.dtb", "rb") as f: + data = f.read() +# Filter out the 0x00 bytes +filtered_data = bytes(b for b in data if b != 0x00) + +# Print the filtered binary data +print(filtered_data) + +#print(data) \ No newline at end of file diff --git a/lab_5/bootloader/start.S b/lab_5/bootloader/start.S new file mode 100644 index 000000000..b086305c4 --- /dev/null +++ b/lab_5/bootloader/start.S @@ -0,0 +1,43 @@ +.section ".text.relocate" +.global _relocate + +_relocate: + // relocate our code from load address to link address + ldr x1, =0x80000; // src address + ldr x2, =0x60000; // target address + ldr w3, =__loader_size +1: ldr x4, [x1], #8 + str x4, [x2], #8 + sub w3, w3, #1 + cbnz w3, 1b + + ldr x1, =_start + mov sp, x1 + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size +2: cbz w2, 3f + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, 2b + + +3: // Device tree address has been moved from x0 to x10 within the bootloader. + mov x0, x10 + bl relocator-0x20000 + b _start + + +.section ".text.boot" + +.global _start + +_start: + // jump to main function in C + bl 0x80000 + // halt this core if return +1: + wfe + b 1b + diff --git a/lab_5/bootloader/uart.c b/lab_5/bootloader/uart.c new file mode 100644 index 000000000..5e63f2d3a --- /dev/null +++ b/lab_5/bootloader/uart.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "include/gpio.h" + +/** Auxilary mini UART registers + * Address & Description refer: https://cs140e.sergio.bz/docs/BCM2837-ARM-Peripherals.pdf Page.8 + */ + +#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() +{ + register unsigned int r; + + /* initialize UART */ + *AUX_ENABLE |=1; // enable UART1, AUX mini uart + *AUX_MU_CNTL = 0; + *AUX_MU_LCR = 3; // 8 bits + *AUX_MU_MCR = 0; + *AUX_MU_IER = 0; + *AUX_MU_IIR = 0xc6; // disable interrupts + *AUX_MU_BAUD = 270; // 115200 baud + /* map UART1 to GPIO pins */ + r=*GPFSEL1; + r&=~((7<<12)|(7<<15)); // gpio14, gpio15 + r|=(2<<12)|(2<<15); // alt5 + *GPFSEL1 = r; + *GPPUD = 0; // enable pins 14 and 15 + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = (1<<14)|(1<<15); + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = 0; // flush GPIO setup + *AUX_MU_CNTL = 3; // enable Tx, Rx + /*EXTRA: Read from AUX_MU_IO until AUX_MU_LSR indicates no more data*/ + while (*AUX_MU_LSR & 0x01) { + // Read and discard the data + volatile unsigned int data = *AUX_MU_IO; + (void)data; // Prevent unused variable warning + } +} + +void uart_enable_interrupt(){ + // enable tx rx interrupt in uart + *AUX_MU_IER |= 0x02; + *IRQS1 |= 1 << 29; +} + + +/** + * Send a character + */ +void uart_send(unsigned int c) { + /* wait until we can send */ + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); + /* write the character to the buffer */ + *AUX_MU_IO=c; +} + +/** + * 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 it and return */ + r=(char)(*AUX_MU_IO); + /* convert carriage return to newline */ + return r=='\r'?'\n':r; +} + +/** + * Display a string + */ +void uart_puts(char *s) { + while(*s) { + /* convert newline to carriage return + newline */ + if(*s=='\n') + uart_send('\r'); + 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); + } +} \ No newline at end of file diff --git a/lab_5/bootloader/utils.c b/lab_5/bootloader/utils.c new file mode 100644 index 000000000..d31e58159 --- /dev/null +++ b/lab_5/bootloader/utils.c @@ -0,0 +1,61 @@ +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +/** + * compare two string, given s1 and s2 + * return 0 if the both string are equal; + * return -1 if s1 is less than s2; + * return 1 if s1 is greater than s2 + */ +int strcmp(char* a, char* b){ + int value = 0; + while(*a != '\0' && *b != '\0'){ + if(*a < *b){ + return -1; + } + else if(*a > *b){ + return 1; + } + else{ + a++; + b++; + } + } + if(*a == '\0'){ + value++; + } + if(*b == '\0'){ + value--; + } + return value; +} + +/** + * set up given value to given address + */ +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + + +/** + * reboot respberry pi + * if tick=0, reboot instantly; + * otherwise, wait for tick seconds to reboot + */ +void reset(int tick) { // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + if(tick != 0){ + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick + } +} + +/** + * clear reboot register + */ +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} \ No newline at end of file diff --git a/lab_5/config.txt b/lab_5/config.txt new file mode 100644 index 000000000..7e9ff304c --- /dev/null +++ b/lab_5/config.txt @@ -0,0 +1,2 @@ +initramfs initramfs.cpio 0x80000000 +kernel=bootloader.img \ No newline at end of file diff --git a/lab_5/rootfs/hello.txt b/lab_5/rootfs/hello.txt new file mode 100644 index 000000000..ca9e3b5cc --- /dev/null +++ b/lab_5/rootfs/hello.txt @@ -0,0 +1 @@ +this is a example file. diff --git a/lab_5/rootfs/hello2.txt b/lab_5/rootfs/hello2.txt new file mode 100644 index 000000000..d90bb747c --- /dev/null +++ b/lab_5/rootfs/hello2.txt @@ -0,0 +1 @@ +this is another example file. diff --git a/lab_5/rootfs/link.ld b/lab_5/rootfs/link.ld new file mode 100644 index 000000000..bd0d89847 --- /dev/null +++ b/lab_5/rootfs/link.ld @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +SECTIONS +{ + . = 0x30000; + PROVIDE(_head = .); + .text : { KEEP(*(.text.boot)) *(.text .text.*) } + .rodata : { *(.rodata .rodata.*) } + PROVIDE(_data = .); + .data : { *(.data .data.*) } + .bss : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; +} +__bss_size = (__bss_end - __bss_start)>>3; +__loader_size = (_end - _head)>>3; \ No newline at end of file diff --git a/lab_5/rootfs/makefile b/lab_5/rootfs/makefile new file mode 100644 index 000000000..1f075562f --- /dev/null +++ b/lab_5/rootfs/makefile @@ -0,0 +1,36 @@ +# +# Copyright (C) 2018 bzt (bztsrc@github) +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# + +GCC = "aarch64-linux-gnu-gcc" +LD = "aarch64-linux-gnu-ld" +OBJCPY = "aarch64-linux-gnu-objcopy" +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.S=.o) +CFLAGS = -Wall -O0 -ffreestanding -nostdinc -nostdlib -nostartfiles +BOOTLOADER_BIN = kernel8.img +all: user_program.S + "aarch64-linux-gnu-gcc" -Wall -O0 -ffreestanding -nostdinc -nostdlib -nostartfiles -c user_program.S -o user_program.o + "aarch64-linux-gnu-ld" -nostdlib -nostartfiles user_program.o -T link.ld -o user_program.elf + "aarch64-linux-gnu-objcopy" -O binary user_program.elf user_program.img diff --git a/lab_5/rootfs/user_program b/lab_5/rootfs/user_program new file mode 100755 index 000000000..e235f8e5d Binary files /dev/null and b/lab_5/rootfs/user_program differ diff --git a/lab_5/rootfs/user_program.S b/lab_5/rootfs/user_program.S new file mode 100644 index 000000000..4d2ef454d --- /dev/null +++ b/lab_5/rootfs/user_program.S @@ -0,0 +1,13 @@ +.section ".text" +.global _start +_start: + mov x0, 0 +1: + add x0, x0, 1 + svc 0 + cmp x0, 5 + blt 1b + ret; +1: + b 1b + \ No newline at end of file diff --git a/lab_5/rootfs/user_program.elf b/lab_5/rootfs/user_program.elf new file mode 100755 index 000000000..977a8eef5 Binary files /dev/null and b/lab_5/rootfs/user_program.elf differ diff --git a/lab_5/rootfs/user_program.img b/lab_5/rootfs/user_program.img new file mode 100755 index 000000000..1adf648a4 Binary files /dev/null and b/lab_5/rootfs/user_program.img differ diff --git a/lab_5/shell/Makefile b/lab_5/shell/Makefile new file mode 100644 index 000000000..69b1bd455 --- /dev/null +++ b/lab_5/shell/Makefile @@ -0,0 +1,62 @@ +# +# Copyright (C) 2018 bzt (bztsrc@github) +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# + +GCC = "aarch64-linux-gnu-gcc" +LD = "aarch64-linux-gnu-ld" +OBJCPY = "aarch64-linux-gnu-objcopy" +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) +CFLAGS = -Wall -O0 -ffreestanding -nostdinc -nostdlib -nostartfiles +BOOTLOADER_BIN = kernel8.img +all: clean kernel8.img + +# start.o: start.S +# $(GCC) $(CFLAGS) -c start.S -o start.o + +%.o: %.S + $(GCC) $(CFLAGS) -c $< -o $@ -g + "aarch64-linux-gnu-gcc" -Wall -w -O0 -ffreestanding -nostdinc -nostdlib -nostartfiles -c exception_vector.S -o exception_vector.o -g + "aarch64-linux-gnu-gcc" -Wall -w -O0 -ffreestanding -nostdinc -nostdlib -nostartfiles -c interrupts.S -o interrupts.o -g + "aarch64-linux-gnu-gcc" -Wall -w -O0 -ffreestanding -nostdinc -nostdlib -nostartfiles -c _thread.S -o _thread.o -g + +%.o: %.c + $(GCC) $(CFLAGS) -c $< -w -o $@ -g + + +kernel8.img: start.o $(OBJS) + $(LD) -nostdlib -nostartfiles start.o $(OBJS) exception_vector.o interrupts.o _thread.o -T link.ld -o kernel8.elf + $(OBJCPY) -O binary kernel8.elf shell_kernel.img + +clean: + rm kernel8.elf *.o >/dev/null 2>/dev/null || true + +run_asm: + qemu-system-aarch64 -M raspi3b -kernel shell_kernel.img -initrd initramfs.cpio -serial null -serial stdio -display none -d in_asm + +run: + qemu-system-aarch64 -M raspi3b -kernel shell_kernel.img -initrd initramfs.cpio -serial null -serial stdio -display none + +debug: + qemu-system-aarch64 -M raspi3b -kernel shell_kernel.img -initrd initramfs.cpio -serial null -serial stdio -display none -s -S diff --git a/lab_5/shell/_thread.S b/lab_5/shell/_thread.S new file mode 100644 index 000000000..514958efa --- /dev/null +++ b/lab_5/shell/_thread.S @@ -0,0 +1,26 @@ +.global switch_to +switch_to: + stp x19, x20, [x0, 16 * 0] + stp x21, x22, [x0, 16 * 1] + stp x23, x24, [x0, 16 * 2] + stp x25, x26, [x0, 16 * 3] + stp x27, x28, [x0, 16 * 4] + stp fp, lr, [x0, 16 * 5] + mov x9, sp + str x9, [x0, 16 * 6] + + ldp x19, x20, [x1, 16 * 0] + ldp x21, x22, [x1, 16 * 1] + ldp x23, x24, [x1, 16 * 2] + ldp x25, x26, [x1, 16 * 3] + ldp x27, x28, [x1, 16 * 4] + ldp fp, lr, [x1, 16 * 5] + ldr x9, [x1, 16 * 6] + mov sp, x9 + msr tpidr_el1, x1 + ret + +.global get_current +get_current: + mrs x0, tpidr_el1 + ret \ No newline at end of file diff --git a/lab_5/shell/cpio.c b/lab_5/shell/cpio.c new file mode 100644 index 000000000..99ee37706 --- /dev/null +++ b/lab_5/shell/cpio.c @@ -0,0 +1,102 @@ +#include "include/cpio.h" +#include "include/uart.h" +#include "include/stdint.h" +#include "include/utils.h" + +char* cpio_addr = (char *)0x8000000; + +void cpio_ls(){ + char* addr = (char*) cpio_addr; + uart_puts((char *)(addr+sizeof(struct cpio_header))); + while(strcmp((char *)(addr+sizeof(struct cpio_header)),"TRAILER!!!") != 0){ + struct cpio_header* header = (struct cpio_header*) addr; + unsigned long filename_size = utils_atoi(header->c_namesize,(int)sizeof(header->c_namesize)); + unsigned long headerPathname_size = sizeof(struct cpio_header) + filename_size; + unsigned long file_size = utils_atoi(header->c_filesize,(int)sizeof(header->c_filesize)); + utils_align(&headerPathname_size,4); + utils_align(&file_size,4); + uart_puts(addr+sizeof(struct cpio_header)); + uart_puts("\n"); + addr += (headerPathname_size + file_size); + } +} + +void cpio_exec(char *filename){ + char *target = findFile(filename); + if (target){ + struct cpio_header *header = (struct cpio_header *)target; + unsigned long pathname_size = utils_atoi(header->c_namesize,(int)sizeof(header->c_namesize)); + unsigned long file_size = utils_atoi(header->c_filesize,(int)sizeof(header->c_filesize)); + unsigned long headerPathname_size = sizeof(struct cpio_header) + pathname_size; + + utils_align(&headerPathname_size,4); + utils_align(&file_size,4); + char *file_content = target + headerPathname_size; + + char *program_ptr = (char *) 0x30000; // load the user program into 0x30000 + char* start_point = (char*) 0x30000; + char* stack_pointer = (char *) (0x30000 + 0x3000); // Stack pointer for the user program, base address+0x3000 + for (unsigned int i = 0; i < file_size; i++){ + *program_ptr ++ = *file_content++; + } + asm volatile( + // 0x3c0 + "mov x0, 0x3c0;\n\t" + "msr spsr_el1, x0;\n\t" + // start address of user program + "mov x1, 0x30000;\n\t" + "msr elr_el1, x1;\n\t" + // sp for user program + "mov x2, %0;\n\t" + "msr sp_el0, x2;\n\t" + "eret;" + : // No output operands + : "r" (start_point), "r" (stack_pointer) + : "x0", "x1", "x2" // tell compiler x0~x2 has been used + ); + } + uart_puts("completed.\n"); +} + + + +void cpio_cat(char *filename){ + char *target = findFile(filename); + if (target){ + struct cpio_header *header = (struct cpio_header *)target; + unsigned long pathname_size = utils_atoi(header->c_namesize,(int)sizeof(header->c_namesize)); + unsigned long file_size = utils_atoi(header->c_filesize,(int)sizeof(header->c_filesize)); + unsigned long headerPathname_size = sizeof(struct cpio_header) + pathname_size; + + utils_align(&headerPathname_size,4); + utils_align(&file_size,4); + char *file_content = target + headerPathname_size; + for (unsigned int i = 0; i < file_size; i++) + { + uart_send(file_content[i]); + } + uart_puts("\n"); + } + else + { + uart_puts("Not found the file\n"); + } +} + +char *findFile(char *name){ + char *addr = (char *)cpio_addr; + while (strcmp((char *)(addr + sizeof(struct cpio_header)), "TRAILER!!!") != 0){ + if ((strcmp((char *)(addr + sizeof(struct cpio_header)), name) == 0)){ + return addr; + } + struct cpio_header* header = (struct cpio_header *)addr; + unsigned long pathname_size = utils_atoi(header->c_namesize,(int)sizeof(header->c_namesize));; + unsigned long file_size = utils_atoi(header->c_filesize,(int)sizeof(header->c_filesize)); + unsigned long headerPathname_size = sizeof(struct cpio_header) + pathname_size; + + utils_align(&headerPathname_size,4); + utils_align(&file_size,4); + addr += (headerPathname_size + file_size); + } + return 0; +} \ No newline at end of file diff --git a/lab_5/shell/dynamic_allocator.c b/lab_5/shell/dynamic_allocator.c new file mode 100644 index 000000000..be3cc282d --- /dev/null +++ b/lab_5/shell/dynamic_allocator.c @@ -0,0 +1,149 @@ +#include "include/dynamic_allocator.h" +#include "include/page_allocator.h" + +// #define POOL {4, 8, 16, 32, 64, 128, 256, 512, 1024} +// #define PARTITION {4, 2, 2, 2, 2, 2, 2, 2, 2} +// #define POOL_SIZE 8 +// // max pages allowed to be partitioned +// #define MAX_PAGE 64 + +// typedef struct Page{ +// void* prefix; +// // the occupied section of each partition size in page +// int usage[POOL_SIZE]; +// } + +// typedef struct DynamicAllocator{ +// int chunk_option[POOL_SIZE]; +// int partition[POOL_SIZE]; +// int allocated_page_num; +// Page allocated_page_info[MAX_PAGE]; + +// }DynamicAllocator; + + +struct DynamicAllocator dynamic_allocator; + + +void init_dynamic_allocator(){ + int pool[] = POOL; + int part[] = PARTITION; + dynamic_allocator.allocated_page_num = 0; + for(int i=0;i>3; +__loader_size = (_end - _head)>>3; \ No newline at end of file diff --git a/lab_5/shell/main.c b/lab_5/shell/main.c new file mode 100644 index 000000000..2089a2f63 --- /dev/null +++ b/lab_5/shell/main.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +#define MAX_BUFFER 50 +#include "include/uart.h" +#include "include/utils.h" +#include "include/mbox.h" +#include "include/cpio.h" +#include "include/page_allocator.h" +#include "include/dynamic_allocator.h" +#include "include/thread.h" + +extern void set_exception_vector_table(); +extern void core_timer_enable(); + + + +void main(int argc, char* argv[]){ + // init uart + uart_init(); + init_simple_malloc(); + // init exception table and interrupt (lab3) + set_exception_vector_table(); + // init memory (lab4) + init_buddy_system(); + init_dynamic_allocator(); + init_thread(); + while(1){ + char command[MAX_BUFFER]; + char c = '\0'; + int length=0; + for(int i=0; i\t: print the content of file in initfs\n"); + uart_puts("hello\t: print hello world!\n"); + uart_puts("exec: execute user program in initfs\n"); + uart_puts("async_uart: switch to async uart mode (currently for demo only)\n"); + uart_puts("malloc \t: malloc memory of size \n"); + uart_puts("free\t: free all malloced page memory (for demo, the memory alloced in simple malloc will not be freed)\n"); + uart_puts("reboot\t: reboot the device\n"); + } + else if(strcmp(command, "hello") == 0){ + uart_puts("Hello World!\n"); + } + else if(strcmp(command, "free") == 0){ + // demo lab4 + // free_page(my_array); + // free_page(my_array2); + // free_page(my_array3); + // free_page(my_array4); + // free_page(my_array5); + + // my_array = malloc_page(3); + // my_array2 = malloc_page(3); + // my_array3 = malloc_page(3); + // my_array4 = malloc_page(3); + // my_array5 = malloc_page(3); + } + else if(strcmp(command, "idle") == 0){ + // demo lab 5-1 + for(int i = 0; i < 5; ++i) { // N should > 2 + creat_thread(foo); + } + idle(); + } + else if(strcmp(command, "ls") == 0){ + cpio_ls(); + } + else if(strcmp(command, "async_uart") == 0){ + demo_async_uart(); + } + else if(strcmp(command, "reboot") == 0){ + reset(); + } + else if(strcmp(command, "exec") == 0){ + uart_puts("executing...\n"); + // execute a dedicated user program + cpio_exec("user_program.img"); + } + // command with arguments + else{ + char arguments[3][MAX_BUFFER]; + // initialize + for(int i=0;i<3;i++){ + for(int j=0;jroot; + target->root = target->root->next; + return to_ret; +} + +void init_order_list(){ + int current_order = MAX_ORDER-1; + int current_page_start = 0; + // advanced: handle cases that some pages are reserved + while((HEAP_START_ADDRESS+(PAGE_SIZE*current_page_start)) < HEAP_END_ADDRESS){ + int continuous_block = 0; + while(continuous_block < _pow(2, MAX_ORDER) && current_page_start+continuous_blockaddress = (unsigned char*) HEAP_START_ADDRESS+(PAGE_SIZE*current_page_start); + new_node->page_index = current_page_start; + list_push_back(new_node, order); + + uart_puts("[Init] grouping block at address 0x"); + uart_hex(new_node->address); + uart_puts(" with 0x"); + uart_hex((unsigned int)allocated_size/PAGE_SIZE); + uart_puts(" pages and start at index "); + uart_hex((unsigned int)new_node->page_index); + uart_puts(" in The Array"); + uart_puts("\n"); + current_page_start = current_page_start +continuous_block; + current_page_start++; + } + + // assume all pages are available at beginnig, greedly allocate pages in max order size + // while(current_order >= 0){ + // while((current_page_index+_pow(2, current_order)-1) < AVAILABLE_PAGE_NUM){ + // unsigned int allocated_size = _pow(2, current_order)*PAGE_SIZE; + // // record the grouped block at The Array + // the_array[current_page_index].block_size = _pow(2, current_order); + // // malloc a struct node to record the meta data of this block + // Node* new_node = simple_malloc(sizeof(Node)); + // // push into order list + // new_node->address = (unsigned char*) HEAP_START_ADDRESS+(PAGE_SIZE*current_page_index); + // new_node->page_index = current_page_index; + // list_push_back(new_node, current_order); + + // uart_puts("[Init] grouping block at address 0x"); + // uart_hex(new_node->address); + // uart_puts(" with 0x"); + // uart_hex((unsigned int)allocated_size/PAGE_SIZE); + // uart_puts(" pages and start at index "); + // uart_hex((unsigned int)new_node->page_index); + // uart_puts(" in The Array"); + // uart_puts("\n"); + + // current_page_index = current_page_index+_pow(2, current_order)+1; + // } + // current_order--; + // } + +} + +void print_order_list(OrderList* list){ + Node* cur = list->root; + uart_puts("address : \n"); + while(cur != NULL){ + uart_hex(cur->address); + uart_puts("\n"); + cur = cur->next; + } +} + +void init_buddy_system(){ + // initialize The Array + for(int i=0;iroot != NULL; +} + +Node* get_buddy(OrderList* target, int target_page_index){ + Node* cur = target->root; + Node* prev = NULL; + while(cur != NULL){ + if(cur->page_index == target_page_index){ + if(prev != NULL){ + prev->next = cur->next; + } + // root is the buddy + else{ + target->root = target->root->next; + } + cur->next = NULL; + return cur; + } + prev = cur; + cur = cur->next; + } + uart_puts("[Assertion Error] buddy not found\n"); + print_order_list(target); + return NULL; +} + +void free_page(void* to_free){ + int page_index = ((unsigned int)to_free-HEAP_START_ADDRESS)/PAGE_SIZE; + int free_block_size = the_array[page_index].block_size; + int do_merge = 0; + if(the_array[page_index].available != OCCUPIED){ + uart_puts("[Assertion Error] releasing free page head\n"); + } + the_array[page_index].available = FREE; + int next_block_index = page_index+free_block_size+1; + uart_puts("[Free] block that contains "); + // block size starts from zero, thus need to +1 + uart_hex(free_block_size+1); + uart_puts(" pages started from address 0x"); + uart_hex((unsigned int)to_free); + uart_puts(" to address 0x"); + uart_hex((unsigned int)to_free+(free_block_size*PAGE_SIZE)); + uart_puts(" with index starts from "); + uart_hex(page_index); + uart_puts("\n"); + + if(the_array[next_block_index].available == FREE){ + // debug: print the address of next page of freed block + // uart_puts("Accessing location: 0x"); + // uart_hex((unsigned int)HEAP_START_ADDRESS+(PAGE_SIZE*next_block_index)); + // uart_puts("\n"); + + // same size, can merge + if(the_array[next_block_index].block_size == free_block_size && the_array[next_block_index].available==FREE){ + int order =0, block_size = free_block_size; + // get sqrt(2) of block_size to obtain order + while(block_size > 0){ + order++; + block_size/=2; + } + print_order_list(&order_list[order]); + Node* buddy = get_buddy(&order_list[order], next_block_index); + if(buddy != NULL){ + Node* new_node = simple_malloc(sizeof(Node)); + // push into order list + new_node->address = (unsigned char*) to_free; + new_node->page_index = page_index; + the_array[page_index].block_size = _pow(2, order+1); + the_array[next_block_index].available = FREE; + the_array[next_block_index].block_size = FREE; + list_push_back(new_node, order+1); + uart_puts("[Merge] block that contains "); + uart_hex(free_block_size); + uart_puts(" pages started from address 0x"); + uart_hex((unsigned int)to_free); + uart_puts(" to address 0x"); + uart_hex((unsigned int)HEAP_START_ADDRESS+(PAGE_SIZE*(next_block_index+free_block_size))); + uart_puts("\n"); + do_merge = 1; + } + } + } + if(!do_merge){ + Node* new_node = simple_malloc(sizeof(Node)); + new_node->address = (unsigned char*) to_free; + new_node->page_index = page_index; + int order =0, block_size = free_block_size; + // get sqrt(2) of block_size to obtain order + while(block_size > 0){ + order++; + block_size/=2; + } + list_push_back(new_node, order); + } + +} + +unsigned char* malloc_page(int request_page_num){ + //determine the minimum list order that this request needs + int current_order = 0; + int cut_freg = 0; + // start from allocating the smallest block until is can satisfy needs + //print_order_list(&order_list[2]); + while(current_order _pow(2, current_order)){ + current_order++; + } + else{ + if(check_list_has_element(&order_list[current_order])){ + struct Node* allocated_address = list_pop(&order_list[current_order]); + // mark the block as OCCUPIED + the_array[(unsigned int)allocated_address->page_index].available = OCCUPIED; + // the block_size start from zero, thus we need to -1 + the_array[(unsigned int)allocated_address->page_index].block_size = _pow(2, current_order)-1; + // print the log + uart_puts("[Malloc] block that contains "); + uart_hex(_pow(2, current_order)); + uart_puts(" pages started from address 0x"); + uart_hex((unsigned int)allocated_address->address); + uart_puts(" to address 0x"); + uart_hex((unsigned int)((allocated_address->address)+(_pow(2, current_order)-1)*PAGE_SIZE)); + uart_puts(" with index starts from "); + uart_hex((unsigned int)allocated_address->page_index); + uart_puts("\n"); + int cutter_count = 1; + while(cut_freg > 0){ + // mid address is the starting address of last page that BEEN malloced + int mid_page_index = allocated_address->page_index+(_pow(2, current_order-cutter_count))-1; + // end address is the starting address of last page in this block + unsigned char* end_address = mid_page_index+_pow(2, current_order-cutter_count); + Node* new_node = simple_malloc(sizeof(Node)); + // push into order list + new_node->address = (unsigned char*) HEAP_START_ADDRESS+(PAGE_SIZE*(mid_page_index+1)); + new_node->page_index = mid_page_index+1; + the_array[new_node->page_index].block_size = _pow(2, current_order-cutter_count)-1; + uart_puts("[Release redundant memory] block that contains "); + uart_hex(_pow(2, current_order-cutter_count)); + uart_puts(" pages started from address 0x"); + uart_hex(new_node->address); + uart_puts(" to address 0x"); + uart_hex(new_node->address+((the_array[new_node->page_index].block_size)*PAGE_SIZE)); + uart_puts(" is freed \n"); + list_push_back(new_node, current_order-cutter_count); + cut_freg--; + cutter_count++; + } + if(cutter_count>1){ + the_array[(unsigned int)allocated_address->page_index].block_size = _pow(2, current_order-(cutter_count-1))-1; + } + + return allocated_address->address; + } + else{ + cut_freg++; // we may allocate more then 2 times more memory than needed + current_order++; + } + } + } + uart_puts("[Warning] malloc failed, returning 0x00\n"); + return 0x0; +} + + + +void list_push_back(Node* to_push, int order){ + OrderList* target_list = &(order_list[order]); + if(target_list->root == NULL){ + target_list->root = to_push; + } + else{ + Node* current = target_list->root; + while(current->next != NULL){ + current = current->next; + } + current->next = to_push; + } + //print_order_list(target_list); +} + +void init_reserve_memory(){ + // Spin tables for multicore boot (0x0000 - 0x1000) + memory_reserve(0x00000000, 0x00001000); + // initramfs, allocate 4 pages + memory_reserve(0x8000000, 0x8000000 + 0x4000); + // kernel image + memory_reserve(&_head, &_end); +} + + +void memory_reserve(unsigned int start, unsigned int end){ + start = start-(start % PAGE_SIZE); + end = end % PAGE_SIZE ? end + PAGE_SIZE - (end % PAGE_SIZE) : end; + + uart_puts("[Reserve] Memory Reserve: Start from adress 0x"); + uart_hex(start); + uart_puts(" to 0x"); + uart_hex(end); + uart_puts("\n"); + + int start_index = (int)((start-HEAP_START_ADDRESS)/PAGE_SIZE); + // assume end_index do not exceed limit + int end_index = (end-HEAP_START_ADDRESS)/PAGE_SIZE; + for(int i=start_index;i 0, stop +1: wfe + b 1b + + +2: // cpu id == 0 + + // el2 to el1 + bl from_el2_to_el1 + + // set top of stack just before our code (stack grows to a lower address per AAPCS64) + ldr x1, =_start + mov sp, x1 + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size +3: cbz w2, 4f + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, 3b + + // jump to C code, should not return +4: bl main + // for failsafe, halt this core too + b 1b + +from_el2_to_el1: + mov x0, (1 << 31) // EL1 uses aarch64 + // move system register to register (write x0 into hcr_el2) + msr hcr_el2, x0 + mov x0, 0x3c5 // 3c5 EL1h (SPSel = 1) with interrupt disabled, 345 enable interrupt + msr spsr_el2, x0 + msr elr_el2, lr + eret // return to EL1 diff --git a/lab_5/shell/thread.c b/lab_5/shell/thread.c new file mode 100644 index 000000000..289691e58 --- /dev/null +++ b/lab_5/shell/thread.c @@ -0,0 +1,152 @@ +#include "include/thread.h" +#include "include/dynamic_allocator.h" +#include "include/page_allocator.h" + +ThreadQueue thread_queue; + +void init_thread(){ + // create idle thread + for(int i=0;iavailable = EXIT; + schedule(); +} + +void schedule(){ + int id = get_id_from_struct_thread(get_current()); + // find next READY thread start from schedule caller id + for(int i=1; i< MAX_THREAD; i++){ + int next = (id+i)%MAX_THREAD; + // skip idle thread(id = 0) + if(next == 0){ + continue; + } + else if(thread_queue.queue[next].available == READY){ + thread_queue.current_routine = next; + context_switch(id, next); + return; + } + } + context_switch(id, 0); + return; +} + + +/* Do context switch. */ +void context_switch(int prev_id, int next_id){ + // uart_puts("[Context switch] Switch from thread id 0x"); + // uart_hex(prev_id); + // uart_puts(" to thread id 0x"); + // uart_hex(next_id); + // uart_puts("\n"); + switch_to(&thread_queue.queue[prev_id], &thread_queue.queue[next_id]); +} + +int get_id_from_struct_thread(struct Thread* cur){ + // find the id of current thread + for(int i=0;i=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); + } +} + +void uart_enable_interrupt(){ + *AUX_MU_IER |= 0x02; + *IRQS1 |= 1 << 29; +} + +void uart_load_buffer(){ + while(write_cur < write_idx){ + uart_send(uart_write_buffer[write_cur]); + } +} + +void demo_async_uart(){ + uart_puts("turning to async mode...\n"); + uart_enable_interrupt(); + while(1){ + asm volatile("nop"); + } +} + +void uart_read_handler() { + char ch = (char)(*AUX_MU_IO); + uart_read_buffer[write_idx] = ch; + write_idx++; + uart_write_buffer[write_idx] = ch; + read_idx++; + write_idx++; + if(ch == '\r'){ + uart_puts(uart_write_buffer); + } +} + +void uart_write_handler(){ + if(write_cur < write_idx){ + *AUX_MU_IO=uart_read_buffer[write_cur]; + write_cur++; + } +} \ No newline at end of file diff --git a/lab_5/shell/utils.c b/lab_5/shell/utils.c new file mode 100644 index 000000000..2516fd43e --- /dev/null +++ b/lab_5/shell/utils.c @@ -0,0 +1,119 @@ +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 +#define SIMPLE_MALLOC_BUFFER_SIZE 8192 + +unsigned long utils_atoi(const char *s, int char_size) { + unsigned long num = 0; + for (int i = 0; i < char_size; i++) { + num = num * 16; + if (*s >= '0' && *s <= '9') { + num += (*s - '0'); + } else if (*s >= 'A' && *s <= 'F') { + num += (*s - 'A' + 10); + } else if (*s >= 'a' && *s <= 'f') { + num += (*s - 'a' + 10); + } + s++; + } + return num; +} + + +int _pow(int base, int exp){ + + int ret = 1; + for(int i=0;i *b){ + return 1; + } + else{ + a++; + b++; + } + } + if(*a == '\0'){ + value++; + } + if(*b == '\0'){ + value--; + } + return value; +} + +/** + * set up given value to given address + */ +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + + +void utils_align(void *size, unsigned int s) { + unsigned long* x = (unsigned long*) size; + unsigned long mask = s-1; + *x = ((*x) + mask) & (~mask); +} + +/** + * reboot respberry pi + * if tick=0, reboot instantly; + * otherwise, wait for tick seconds to reboot + */ +void reset(int tick) { // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + if(tick != 0){ + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick + } +} + +/** + * clear reboot register + */ +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} + + +static unsigned char simple_malloc_buffer[SIMPLE_MALLOC_BUFFER_SIZE]; +static unsigned long simple_malloc_offset = 0; + +void init_simple_malloc(){ + for(int i=0;i SIMPLE_MALLOC_BUFFER_SIZE) { + //Not enough space left + return (void*) 0; + } + void* allocated = (void *)&simple_malloc_buffer[simple_malloc_offset]; + simple_malloc_offset += size; + + return allocated; +} \ No newline at end of file