diff --git a/README.org b/README.org index a77151714..cf4f47a15 100644 --- a/README.org +++ b/README.org @@ -1,4 +1,4 @@ -#+TITLE: Operating Systems Capstone 2023 +#+TITLE: Operating Systems Capstone 2024 #+OPTIONS: toc:nil This repository is used for homework submission. @@ -37,7 +37,7 @@ If you cannot find your branch, ask TAs for help. #+BEGIN_SRC shell git clone - cd osc2023 + cd osc2024 git checkout --track origin/ #+END_SRC diff --git a/lab2/.vscode/settings.json b/lab2/.vscode/settings.json new file mode 100644 index 000000000..1903fa635 --- /dev/null +++ b/lab2/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "files.associations": { + "cpio.h": "c", + "array": "c", + "string_view": "c", + "initializer_list": "c", + "utility": "c", + "reboot.h": "c", + "utils.h": "c", + "mailbox.h": "c" + } +} \ No newline at end of file diff --git a/lab2/bcm2710-rpi-3-b-plus.dtb b/lab2/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..c83b0817e Binary files /dev/null and b/lab2/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab2/bootloader/booting.S b/lab2/bootloader/booting.S new file mode 100644 index 000000000..7d65d428e --- /dev/null +++ b/lab2/bootloader/booting.S @@ -0,0 +1,27 @@ +.section ".text.boot" // Start a new section named ".text.boot" +.global _start // Declare _start symbol as global + +_start: // Start of the _start block + // read cpu id, stop slave cores + mrs x1, mpidr_el1 // Read Multiprocessor Affinity Register into x1 + and x1, x1, #3 // Mask the lower 2 bits (CPU core ID) from x1 + cbz x1, setting // If x1 is zero, jump to setting label + +halt: wfe // Wait for Event instruction + b halt // Branch (jump) to halt (infinite loop) + +setting: // Setting label + ldr x1, =_start // Load the address of _start into x1 + mov sp, x1 // Move the value of x1 into the Stack Pointer (sp) + ldr x1, =__bss_start // Load the address of __bss_start into x1 + ldr w2, =__bss_size // Load the value of __bss_size into w2 + +clear_bss: // Clear BSS segment loop label + cbz w2, kernel_main // If w2 (BSS size) is zero, jump to kernel_main + str xzr, [x1], #8 // Store zero (xzr) at the address pointed by x1, then increment x1 by 8 + sub w2, w2, #1 // Decrement w2 (BSS size) by 1 + cbnz w2, clear_bss // If w2 is not zero, jump back to clear_bss + +kernel_main: // Label for the start of kernel_main function + bl main // Branch with link (call) to main function + b halt // Branch to halt (infinite loop) diff --git a/lab2/bootloader/bootloader.c b/lab2/bootloader/bootloader.c new file mode 100644 index 000000000..b4813137a --- /dev/null +++ b/lab2/bootloader/bootloader.c @@ -0,0 +1,64 @@ +#include"header/bootloader.h" +#include"header/uart.h" +#include"header/utils.h" +// from linker script +extern char _start; +extern char _end; +void relocate(char *arg) +{ + unsigned long bootloader_size = (&_end - &_start); + char *oldbootloader = (char *)&_start; //0x80000 + char *newbootloader = (char *)0x60000; + + unsigned long bl_ptr = 0; + // copying + while (bootloader_size--) + { + newbootloader[bl_ptr] = oldbootloader[bl_ptr]; + ++bl_ptr; + } + // run kernel in 0x60000 + void (*run)(char *) = (void (*)(char *))newbootloader; + run(arg); +} +// can be verifying in gdb +void load_img(char *dtb_base) { + // kernel start + char *kernel = (char *)(0x80000); + int kn_ptr = 0; + + // size + int idx = 0; + char sz[50] = {}; + char c; + + // receiving str size + while(1) { + c = uart_get_char(); + // receive size end + if(c == '\n') { + sz[idx] = '\0'; + break; + } + sz[idx++] = c; + } + // get kernel image size + int size = atoi(sz); + uart_send_str(sz); + + // receive kernel img + while (size--) + kernel[kn_ptr++] = uart_get_img_char(); + // test message + uart_binary_to_hex((unsigned int) dtb_base); + uart_send_str("\nKernel received\n"); + int r = 1000; + while(r--){ + asm volatile("nop"); + } + // run kernel and pass dtb base + void (*run)(char *) = (void *)kernel; + // get dtb loading address + // run("0x60000"); + run(dtb_base); +} \ No newline at end of file diff --git a/lab2/bootloader/header/bootloader.h b/lab2/bootloader/header/bootloader.h new file mode 100644 index 000000000..3f3b59262 --- /dev/null +++ b/lab2/bootloader/header/bootloader.h @@ -0,0 +1,2 @@ +void load_img(); +void relocate(char *arg); \ No newline at end of file diff --git a/lab2/bootloader/header/reboot.h b/lab2/bootloader/header/reboot.h new file mode 100644 index 000000000..bf5420c1f --- /dev/null +++ b/lab2/bootloader/header/reboot.h @@ -0,0 +1,7 @@ +#ifndef _REBOOT_H_ +#define _REBOOT_H_ + +void set(long addr, unsigned int value); +void reset(int tick); +void cancel_reset(); +#endif \ No newline at end of file diff --git a/lab2/bootloader/header/shell.h b/lab2/bootloader/header/shell.h new file mode 100644 index 000000000..12a19e675 --- /dev/null +++ b/lab2/bootloader/header/shell.h @@ -0,0 +1,3 @@ +void ls(); +void cat(); +void shell(); \ No newline at end of file diff --git a/lab2/bootloader/header/uart.h b/lab2/bootloader/header/uart.h new file mode 100644 index 000000000..542a57c14 --- /dev/null +++ b/lab2/bootloader/header/uart.h @@ -0,0 +1,44 @@ +#ifndef _UART_H_ +#define _UART_H_ +#define MMIO_BASE 0x3f000000 + +#define GPFSEL0 ((volatile unsigned int *)(MMIO_BASE + 0x00200000)) +#define GPFSEL1 ((volatile unsigned int *)(MMIO_BASE + 0x00200004)) +#define GPFSEL2 ((volatile unsigned int *)(MMIO_BASE + 0x00200008)) +#define GPFSEL3 ((volatile unsigned int *)(MMIO_BASE + 0x0020000C)) +#define GPFSEL4 ((volatile unsigned int *)(MMIO_BASE + 0x00200010)) +#define GPFSEL5 ((volatile unsigned int *)(MMIO_BASE + 0x00200014)) +#define GPSET0 ((volatile unsigned int *)(MMIO_BASE + 0x0020001C)) +#define GPSET1 ((volatile unsigned int *)(MMIO_BASE + 0x00200020)) +#define GPCLR0 ((volatile unsigned int *)(MMIO_BASE + 0x00200028)) +#define GPLEV0 ((volatile unsigned int *)(MMIO_BASE + 0x00200034)) +#define GPLEV1 ((volatile unsigned int *)(MMIO_BASE + 0x00200038)) +#define GPEDS0 ((volatile unsigned int *)(MMIO_BASE + 0x00200040)) +#define GPEDS1 ((volatile unsigned int *)(MMIO_BASE + 0x00200044)) +#define GPHEN0 ((volatile unsigned int *)(MMIO_BASE + 0x00200064)) +#define GPHEN1 ((volatile unsigned int *)(MMIO_BASE + 0x00200068)) +#define GPPUD ((volatile unsigned int *)(MMIO_BASE + 0x00200094)) +#define GPPUDCLK0 ((volatile unsigned int *)(MMIO_BASE + 0x00200098)) +#define GPPUDCLK1 ((volatile unsigned int *)(MMIO_BASE + 0x0020009C)) + +#define AUX_ENABLE ((volatile unsigned int *)(MMIO_BASE + 0x00215004)) +#define AUX_MU_IO ((volatile unsigned int *)(MMIO_BASE + 0x00215040)) +#define AUX_MU_IER ((volatile unsigned int *)(MMIO_BASE + 0x00215044)) +#define AUX_MU_IIR ((volatile unsigned int *)(MMIO_BASE + 0x00215048)) +#define AUX_MU_LCR ((volatile unsigned int *)(MMIO_BASE + 0x0021504C)) +#define AUX_MU_MCR ((volatile unsigned int *)(MMIO_BASE + 0x00215050)) +#define AUX_MU_LSR ((volatile unsigned int *)(MMIO_BASE + 0x00215054)) +#define AUX_MU_MSR ((volatile unsigned int *)(MMIO_BASE + 0x00215058)) +#define AUX_MU_SCRATCH ((volatile unsigned int *)(MMIO_BASE + 0x0021505C)) +#define AUX_MU_CNTL ((volatile unsigned int *)(MMIO_BASE + 0x00215060)) +#define AUX_MU_STAT ((volatile unsigned int *)(MMIO_BASE + 0x00215064)) +#define AUX_MU_BAUD ((volatile unsigned int *)(MMIO_BASE + 0x00215068)) + +#endif + +void uart_init(); +void uart_send_char(unsigned int c); +char uart_get_char(); +void uart_send_str(char *s); +void uart_binary_to_hex(unsigned int d); +char uart_get_img_char(); \ No newline at end of file diff --git a/lab2/bootloader/header/utils.h b/lab2/bootloader/header/utils.h new file mode 100644 index 000000000..aaa489a29 --- /dev/null +++ b/lab2/bootloader/header/utils.h @@ -0,0 +1,2 @@ +int string_compare(char *a, char *b); +int atoi(char *str); diff --git a/lab2/bootloader/kernel8.elf b/lab2/bootloader/kernel8.elf new file mode 100755 index 000000000..37a073dcf Binary files /dev/null and b/lab2/bootloader/kernel8.elf differ diff --git a/lab2/bootloader/kernel8.img b/lab2/bootloader/kernel8.img new file mode 100755 index 000000000..e5e170a08 Binary files /dev/null and b/lab2/bootloader/kernel8.img differ diff --git a/lab2/bootloader/linker.ld b/lab2/bootloader/linker.ld new file mode 100644 index 000000000..958e7c546 --- /dev/null +++ b/lab2/bootloader/linker.ld @@ -0,0 +1,24 @@ +SECTIONS +{ + . = 0x80000; /* Set the memory address to 0x80000 (start point)*/ + + .text : { /* Define the .text section, which contains executable code*/ + KEEP(*(.text.boot)) /* Keep all .text.boot sections*/ + *(.text) /* Keep all other .text sections*/ + } + + .rodata : { *(.rodata) } /* Define the .rodata section, which contains read-only data*/ + + .data : { *(.data) } /* Define the .data section, which contains initialized data*/ + + .bss () : { /* Define the .bss section, which contains uninitialized data*/ + __bss_start = .; /* Define __bss_start symbol as the current memory address*/ + *(.bss) /* Keep all .bss sections*/ + *(COMMON) /* Keep all common symbols*/ + __bss_end = .; /* Define __bss_end symbol as the current memory address*/ + } + + _end = .; /* Define _end symbol as the current memory address*/ +} + +__bss_size = (__bss_end - __bss_start) >> 3; /* Calculate the size of the .bss section in bytes*/ diff --git a/lab2/bootloader/main.c b/lab2/bootloader/main.c new file mode 100644 index 000000000..5f1653f7d --- /dev/null +++ b/lab2/bootloader/main.c @@ -0,0 +1,20 @@ +#include"header/uart.h" +#include"header/bootloader.h" +#include"header/shell.h" +char *dtb_base; +int relocated = 1; +void main(char *arg) +{ + uart_init(); + + // register x0 + dtb_base = arg; + + // relocate copies bootloader program from 0x80000 to 0x60000 + if (relocated) { + relocated = 0; + relocate(arg); + } + uart_send_str("\x1b[2J\x1b[H"); + shell(dtb_base); +} \ No newline at end of file diff --git a/lab2/bootloader/makefile b/lab2/bootloader/makefile new file mode 100644 index 000000000..34df2ec5e --- /dev/null +++ b/lab2/bootloader/makefile @@ -0,0 +1,31 @@ +CFLAGS = -Wall -ffreestanding -nostdinc -nostdlib -nostartfiles -fno-stack-protector -g +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) + +ASMS = $(wildcard *.S) +ASM_OBJS = $(ASMS:.S=.o) + +all:: clean_img flash clean + +%.o: %.S + aarch64-linux-gnu-gcc $(CFLAGS) -c $< -o $@ + + +%.o: %.c + aarch64-linux-gnu-gcc $(CFLAGS) -c $< -o $@ + +flash: $(ASM_OBJS) $(OBJS) + aarch64-linux-gnu-ld $(ASM_OBJS) $(OBJS) -T linker.ld -o kernel8.elf + aarch64-linux-gnu-objcopy kernel8.elf -O binary kernel8.img +clean: + rm -f $(ASM_OBJS) $(OBJS) + +clean_img: + rm -f kernel8.elf + rm -f kernel8.img +test: + qemu-system-aarch64 -machine raspi3b -kernel kernel8.img -display none -serial null -serial stdio -initrd ../rootfs/initramfs.cpio +test_pty: + qemu-system-aarch64 -machine raspi3b -kernel kernel8.img -display none -serial null -serial pty +screen: + sudo screen /dev/ttyUSB0 115200 \ No newline at end of file diff --git a/lab2/bootloader/reboot.c b/lab2/bootloader/reboot.c new file mode 100644 index 000000000..089d71dcb --- /dev/null +++ b/lab2/bootloader/reboot.c @@ -0,0 +1,20 @@ +#include"header/reboot.h" + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +void reset(int tick) { // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick +} + +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} \ No newline at end of file diff --git a/lab2/bootloader/shell.c b/lab2/bootloader/shell.c new file mode 100644 index 000000000..036db19ba --- /dev/null +++ b/lab2/bootloader/shell.c @@ -0,0 +1,59 @@ +#include"header/shell.h" +#include"header/uart.h" +#include"header/utils.h" +#include"header/reboot.h" +#include"header/bootloader.h" + +void shell(char *dtb_base){ + char cmd[256]; + char *cur; + while (1) + { + char *s = "# "; + uart_send_str(s); + cur = cmd; + char receive; + while (1) + { + receive = uart_get_char(); + if(receive == '\n'){ + *cur = '\0'; + break; + } + else if(receive == 127){ + if(cur == cmd){ + *cur = '\0'; + continue; + } + *cur = '\0'; + cur--; + uart_send_str("\b \b"); + continue; + } + *cur = receive; + uart_send_char(receive); + cur++; + } + cur = cmd; + if(string_compare(cur,"help")){ + uart_send_str("\nhelp\t\t:print this help menu\r\n"); + uart_send_str("hello\t\t:print Hello World!\r\n"); + uart_send_str("load\t\t:load kernel image through uart\r\n"); + uart_send_str("reboot\t\t:reboot the device\r\n"); + } + else if(string_compare(cur,"hello")){ + uart_send_str("\nHello World!\n"); + } + else if(string_compare(cur,"load")){ + uart_send_str("\nload kernel...\n"); + load_img(dtb_base); + } + else if (string_compare(cur,"reboot")) { + uart_send_str("\nRebooting....\n"); + reset(1000); + + } + else + uart_send_str("\n"); + } +} \ No newline at end of file diff --git a/lab2/bootloader/uart.c b/lab2/bootloader/uart.c new file mode 100644 index 000000000..4d35998a6 --- /dev/null +++ b/lab2/bootloader/uart.c @@ -0,0 +1,74 @@ +#include"header/uart.h" + +void uart_init(){ + + *AUX_ENABLE |= 1; + *AUX_MU_CNTL = 0; + *AUX_MU_IER = 0; + *AUX_MU_LCR = 3; + *AUX_MU_MCR = 0; + *AUX_MU_BAUD = 270; + + register unsigned int r; + + //??? + r =* GPFSEL1; + r &= ~((7 << 12) | (7 << 15)); // gpio14, gpio15 innitial + 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_IIR = 6; + *AUX_MU_CNTL = 3; +} + +void uart_send_char(unsigned int c){ + do{asm volatile("nop");}while(!(*AUX_MU_LSR & 0x20)); // This bit is set if the transmit FIFO can accept at least one byte. + /* write the character to the buffer */ + *AUX_MU_IO = c; +} + +char uart_get_char(){ + char r; + /* wait until something is in the buffer */ + //bit 0 is set if the receive FIFO holds at least 1 symbol. + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01)); + /* read it and return */ + r=(char)(*AUX_MU_IO); + /* convert carriage return to newline */ + return r=='\r'?'\n':r; +} +char uart_get_img_char(){ + char r; + /* wait until something is in the buffer */ + //bit 0 is set if the receive FIFO holds at least 1 symbol. + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01)); + /* read it and return */ + r=(char)(*AUX_MU_IO); + return r; +} +void uart_send_str(char *s){ + while(*s) { + /* convert newline to carriage return + newline */ + if(*s=='\n') + uart_send_char('\r'); + uart_send_char(*s++); + } +} + +void uart_binary_to_hex(unsigned int d) { + unsigned int n; + int c; + uart_send_str("0x"); + for(c=28;c>=0;c-=4) { + // get highest tetrad + n=(d>>c)&0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n+=n>9?0x37:0x30; + uart_send_char(n); + } +} \ No newline at end of file diff --git a/lab2/bootloader/utils.c b/lab2/bootloader/utils.c new file mode 100644 index 000000000..0d398f6f5 --- /dev/null +++ b/lab2/bootloader/utils.c @@ -0,0 +1,34 @@ +#include"header/utils.h" +#include"header/uart.h" + +int string_compare(char* a, char* b) { + char *p1=a; + char *p2=b; + while(1){ + char c1 = *p1; + p1++; + char c2 = *p2; + p2++; + + if(c1==c2){ + if(c1 == '\0') return 1; + else continue; + } + else return 0; + + } +} + +int atoi(char *str) +{ + int res = 0; + + for (int i = 0; str[i] != '\0'; ++i) + { + if (str[i] > '9' || str[i] < '0') + return res; + res = res * 10 + str[i] - '0'; + } + + return res; +} diff --git a/lab2/config.txt b/lab2/config.txt new file mode 100644 index 000000000..8c6facb68 --- /dev/null +++ b/lab2/config.txt @@ -0,0 +1,4 @@ +kernel_address=0x60000 +kernel=bootloader.img +arm_64bit=1 +initramfs initramfs.cpio 0x20000000 \ No newline at end of file diff --git a/lab2/rootfs/file1.txt b/lab2/rootfs/file1.txt new file mode 100644 index 000000000..3677cc6cc --- /dev/null +++ b/lab2/rootfs/file1.txt @@ -0,0 +1,55 @@ + _oI=vo__ + ?/$="'" """^SATAN$~\ + .&?/' `""$$, + ,/?/' /-"^\. .-=~\T, + ,/?/' /SATAN| |\IS,&' |LT + `\?\\ ``\?\^I/HATE@:~:$=v\. `$k==v\.??\, `\d `\$$'9P'I-LOVE=SATAN\/$$~?$\ ,R/ + /$?~^'"""""`"\\&&< ?b "`~$P:c: /v==v,#::?<<&:'T| d$/' + [|:. ""=o/&. ,P o&Z'`'.##| |MH\|| ,$$' + `=:$H&=\. `"b?b. .&' 96*.-v.:?/`\==$&?$&*' + `^$?\. `*&*\\ ,P ?~-~' |$$S>' + `\7b ,T/\&&\. d? |T' + \/b .&J' `\> d' T, + &`L /|| ?| ?, + ||9 J\T H ?, + H|| ||/ || 6 6 6 9, + ||M PJ' || 6 6 6 `H + bT, ||T || 66 666 666 || + T/L H|| `b 6 6 6 6 6 6 M + &T, M| 9, 666 666 666 9 + `L9, M| `&. | + `?*,9|| `b d + `\?(|H. `b ?b + `*\ `&. `\. J*|b + `\o/\. `&. ,P 9/L + 9:&. `9\ ?? `H9. + *?9\ `b .&' |/| + `|`\. `L ./' `|H + d\/qZbo. M .,=' ,|T + ./~&$$?=??/' `"=H$| H .o='' J\| + ,*/'' `\? `' ./?ov=="*b9, ,$P + ,Td ,$$'`' ?|M ,$/ + J|| ,$?/ M|| ?$/ + M|| |>\. ._,~9$'' T|| d'M. + 9`| `Hi:R&:&&6&="' ./$J| `^"\Z\. + ||M `=Z\:"" H|T" `&H&>v_ + bT, .. v,?|\ M|| .:Z|&\. + ||H _DEATH~>TO9H| `?*\ ?$`#'H + 9ALL|1KIDS* .$/ `bZ&\ ,o\&KILL&/' + \?$.:?ooo/*""' `\$$b_ |\MAIM*:./' + `"""' `' `~?&qDESTROY#/' + "^~DIE/" + diff --git a/lab2/rootfs/file2.txt b/lab2/rootfs/file2.txt new file mode 100644 index 000000000..cfb787b3e --- /dev/null +++ b/lab2/rootfs/file2.txt @@ -0,0 +1,14 @@ +fasdfdsafsdafadsf +kernel_addressfasdfsdaf +kernel_addressfasdfsdafsadf +sdaf +sdafsad +fasdfdsafsdafadsfsadf +sdafhert +h +hbafs +gf +bootloaderhewr +hbafsabvfhwert +rwetr +gefgvgagretraegearsujew5y diff --git a/lab2/rootfs/initramfs.cpio b/lab2/rootfs/initramfs.cpio new file mode 100644 index 000000000..b0ae9915f Binary files /dev/null and b/lab2/rootfs/initramfs.cpio differ diff --git a/lab2/shell/cpio.c b/lab2/shell/cpio.c new file mode 100644 index 000000000..20055ca0e --- /dev/null +++ b/lab2/shell/cpio.c @@ -0,0 +1,125 @@ +#include"header/cpio.h" +#include"header/utils.h" +char *cpio_start; +char *cpio_end; +int cpio_newc_parse_header(struct cpio_newc_header *this_header_pointer, char **pathname, unsigned int *filesize, char **data, struct cpio_newc_header **next_header_pointer) +{ + // Ensure magic header 070701 + // new ascii format + if (strncmp(this_header_pointer->c_magic, CPIO_NEWC_HEADER_MAGIC, sizeof(this_header_pointer->c_magic)) != 0){ + return -1; + } + // transfer big endian 8 byte hex string to unsinged int + // data size + *filesize = hex_to_int(this_header_pointer->c_filesize, 8); + + // end of header is the pathname + // header | pathname str | data + *pathname = ((char *)this_header_pointer) + sizeof(struct cpio_newc_header); + // uart_send_str(pathname[0]); + // get file data, file data is just after pathname + // header | pathname str | data + // check picture on hackmd note + unsigned int pathname_length = hex_to_int(this_header_pointer->c_namesize, 8); + // get the offset to start of data + // | offset | data + unsigned int offset = pathname_length + sizeof(struct cpio_newc_header); + // pathname and data might be zero padding + // section % 4 ==0 + offset = offset % 4 == 0 ? offset : (offset + 4 - offset % 4); // padding + // header pointer + offset = start of data + // h| offset | data + *data = (char *)this_header_pointer + offset; + + // get next header pointer + if (*filesize == 0) + // hardlinked files handeld by setting filesize to zero + *next_header_pointer = (struct cpio_newc_header *)*data; + else + { + // data size + offset = *filesize; + // move pointer to the end of data + *next_header_pointer = (struct cpio_newc_header *)(*data + (offset % 4 == 0 ? offset : (offset + 4 - offset % 4))); + } + + // if filepath is TRAILER!!! means there is no more files. + // end of archieve + // empty filename : TRAILER!!! + if (strncmp(*pathname, "TRAILER!!!", sizeof("TRAILER!!!")) == 0) + *next_header_pointer = 0; + + return 0; +} +int ls(){ + // cpio_start = (char*)0x8000000 ; + // cpio_start = (char*)0x20000000; + char *filepath; + char *filedata; + unsigned int filesize; + // current pointer + struct cpio_newc_header *header_pointer = (struct cpio_newc_header *)cpio_start; + + // print every cpio pathname + while (header_pointer) + { + int error = cpio_newc_parse_header(header_pointer, &filepath, &filesize, &filedata, &header_pointer); + // if parse header error + if (error) + { + uart_send_str("error\n"); + break; + } + + // if this is not TRAILER!!! (last of file) + if (header_pointer != 0){ + uart_send_str(filepath); + uart_send_str("\n"); + } + } + return 0; +} +int cat(char *path){ + // cpio_start = (char*) 0x8000000; + // cpio_start = (char*)0x20000000; + char *filepath; + char *filedata; + unsigned int filesize; + // current header pointer, cpio start + struct cpio_newc_header *header_pointer = (struct cpio_newc_header *)cpio_start; + + while (header_pointer) + { + int error = cpio_newc_parse_header(header_pointer, &filepath, &filesize, &filedata, &header_pointer); + // if parse header error + if (error == -1) + { + uart_send_str("error \n"); + break; + } + // parse until filepath is same as cat input + // print the content of input file + if (string_compare(path, filepath)) + { + if(string_compare(filepath,".")){ + uart_send_str("cat: "); + uart_send_str(path); + uart_send_str("No such file or directory\r\n"); + break; + } + for (unsigned int i = 0; i < filesize; i++) + uart_send_char(filedata[i]); + uart_send_str("\n"); + break; + } + // end of cpio, cannot find input file + if (header_pointer == 0){ + uart_send_str("cat: \""); + uart_send_str(path); + uart_send_str("\" No such file or directory\r\n"); + break; + } + + } + return 0; +} \ No newline at end of file diff --git a/lab2/shell/dtb.c b/lab2/shell/dtb.c new file mode 100644 index 000000000..2f9f752df --- /dev/null +++ b/lab2/shell/dtb.c @@ -0,0 +1,109 @@ +#include"header/dtb.h" +#include"header/utils.h" +#include"header/uart.h" +extern char *cpio_start; +extern char *cpio_end; +char *dtb_base; +unsigned int endian_big2little(unsigned int x) { + return (x >> 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x << 24); +} +// a tree data structure which indicating what devices are on a computer system. +// only find out node of initramfs and get the address +void fdt_traverse(dtb_callback callback) +{ + struct fdt_header *header = (struct fdt_header *)dtb_base; + // fdt header magic 0xD00DFEED (big-endian) + if (endian_big2little(header->magic) != 0xD00DFEED) + { + uart_send_str("fdt_traverse: wrong magic in fdt_traverse\n"); + uart_send_str("expect: 0XD00DFEED, get: "); + uart_send_char(endian_big2little(header->magic)); + uart_send_str("\n"); + return; + } + + // length in bytes of structure block section of dtb + unsigned int struct_size = endian_big2little(header->size_dt_struct); + + // check hackmd notes about the picture of DTB structure + // header is address of fdt_header, so we need (char *) + // offset in bytes of the structure block from beginning of header + // to locate struct start + char *dt_struct_ptr = (char *)((char *)header + endian_big2little(header->off_dt_struct)); + // offset in bytes of strings block from beginning of header + // to locate string start + // fdt_prop use string_ptr + nameoff to get the pathname + char *dt_strings_ptr = (char *)((char *)header + endian_big2little(header->off_dt_strings)); + + // parse from struct begin to end + char *end = (char *)dt_struct_ptr + struct_size; + char *pointer = dt_struct_ptr; + + // according to lexical structure + while (pointer < end) + { + // lexical big-endian-32-bit integer + // all tokens shall be alligned on 32-bit boundary + unsigned int token_type = endian_big2little(*(unsigned int *)pointer); + pointer += 4; + + // lexical structure + switch (token_type) + { + // begin of node's representation + case FDT_BEGIN_NODE: + // move node's unit name + // string end \0 + pointer += strlen(pointer); + // node name is followed by zeroed padding bytes + // allign + pointer += (4 - (unsigned long long)pointer % 4); + break; + + // end of node's representation + case FDT_END_NODE: + break; + + case FDT_PROP: + + // len | name offset | address + // uint32_t + // length of prop values in byte + unsigned int len = endian_big2little(*(unsigned int *)pointer); + pointer += 4; + + // nameoff save offset of string blocks + // strings_ptr + nameoff get the name + char *name = (char *)dt_strings_ptr + endian_big2little(*(unsigned int *)pointer); + pointer += 4; + + // check node is initrd-start/end and set cpio_start/end address + callback(token_type, name, pointer, len); + // address, byte string of length len + pointer += len; + // followed by zeroed padding bytes + if ((unsigned long long)pointer % 4 != 0) + pointer += 4 - (unsigned long long)pointer % 4; // alignment 4 byte + break; + // ** cant skip + // ignore NOP + case FDT_NOP: + break; + // marks end of structures block + case FDT_END: + break; + default: + return; + } + } +} + +void initramfs_callback(unsigned int node_type, char *name, void *value, unsigned int name_size) +{ + if (string_compare(name, "linux,initrd-start")){ + cpio_start = (char *)(unsigned long long)endian_big2little(*(unsigned int *)value); + } + if (string_compare(name, "linux,initrd-end")){ + cpio_end = (char *)(unsigned long long)endian_big2little(*(unsigned int *)value); + } +} \ No newline at end of file diff --git a/lab2/shell/header/cpio.h b/lab2/shell/header/cpio.h new file mode 100644 index 000000000..21a46e1e3 --- /dev/null +++ b/lab2/shell/header/cpio.h @@ -0,0 +1,30 @@ +#ifndef CPIO_H +#define CPIO_H + +#include "uart.h" +#include "utils.h" + +#define CPIO_NEWC_HEADER_MAGIC "070701" // big endian + +struct cpio_newc_header +{ + char c_magic[6]; // Magic number identifying the CPIO archive format. Should be "070701" for newc format. + char c_ino[8]; // File inode number. + char c_mode[8]; // File mode (permissions and file type). + char c_uid[8]; // User ID of the file owner. + char c_gid[8]; // Group ID of the file owner. + char c_nlink[8]; // Number of hard links to the file. + char c_mtime[8]; // Modification time of the file (timestamp). + char c_filesize[8]; // Size of the file in bytes. + char c_devmajor[8]; // Major number of the device (for character or block special files). + char c_devminor[8]; // Minor number of the device. + char c_rdevmajor[8]; // Major number of the device for special files. + char c_rdevminor[8]; // Minor number of the device for special files. + char c_namesize[8]; // Size of the file name including null terminator. + char c_check[8]; // Checksum of the file header. +}; +void initramfs_callback(unsigned int node_type, char *name, void *value, unsigned int name_size); +int cpio_newc_parse_header(struct cpio_newc_header *this_header_pointer, char **pathname, unsigned int *filesize, char **data, struct cpio_newc_header **next_header_pointer); +int ls(); +int cat(char *path); +#endif \ No newline at end of file diff --git a/lab2/shell/header/dtb.h b/lab2/shell/header/dtb.h new file mode 100644 index 000000000..d5381a5cc --- /dev/null +++ b/lab2/shell/header/dtb.h @@ -0,0 +1,22 @@ +struct fdt_header { + unsigned int magic; + unsigned int totalsize; + unsigned int off_dt_struct; + unsigned int off_dt_strings; + unsigned int off_mem_rsvmap; + unsigned int version; + unsigned int last_comp_version; + unsigned int boot_cpuid_phys; + unsigned int size_dt_strings; + unsigned int size_dt_struct; +}; +#define FDT_BEGIN_NODE 0x1 /* Start node: full name */ +#define FDT_END_NODE 0x2 /* End node */ +#define FDT_PROP 0x3 /* Property: name off, size, content */ +#define FDT_NOP 0x4 /* nop */ +#define FDT_END 0x9 +typedef void (*dtb_callback)(unsigned int node_type, char *name, void *value, unsigned int name_size); + +unsigned int endian_big2little(unsigned int x); +void fdt_traverse(dtb_callback callback); +void initramfs_callback(unsigned int node_type, char *name, void *value, unsigned int name_size); \ No newline at end of file diff --git a/lab2/shell/header/mailbox.h b/lab2/shell/header/mailbox.h new file mode 100644 index 000000000..e7c131fc7 --- /dev/null +++ b/lab2/shell/header/mailbox.h @@ -0,0 +1,27 @@ +#ifndef _MAILBOX_H_ +#define _MAILBOX_H_ + +#define MMIO_BASE 0x3f000000 +#define MAILBOX_BASE MMIO_BASE + 0xb880 + +#define MAILBOX_READ (unsigned int*)(MAILBOX_BASE) +#define MAILBOX_STATUS (unsigned int*)(MAILBOX_BASE + 0x18) +#define MAILBOX_WRITE (unsigned int*)(MAILBOX_BASE + 0x20) + + +#define MAILBOX_EMPTY 0x40000000 +#define MAILBOX_FULL 0x80000000 + +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_MEMORY 0x00010005 +#define REQUEST_CODE 0x00000000 +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +void get_board_revision(); +void mailbox_call(unsigned int* mailbox); +void get_memory_info(); + +#endif \ No newline at end of file diff --git a/lab2/shell/header/malloc.h b/lab2/shell/header/malloc.h new file mode 100644 index 000000000..36c1b15a4 --- /dev/null +++ b/lab2/shell/header/malloc.h @@ -0,0 +1 @@ +void *simple_malloc(unsigned int size); \ No newline at end of file diff --git a/lab2/shell/header/reboot.h b/lab2/shell/header/reboot.h new file mode 100644 index 000000000..bf5420c1f --- /dev/null +++ b/lab2/shell/header/reboot.h @@ -0,0 +1,7 @@ +#ifndef _REBOOT_H_ +#define _REBOOT_H_ + +void set(long addr, unsigned int value); +void reset(int tick); +void cancel_reset(); +#endif \ No newline at end of file diff --git a/lab2/shell/header/shell.h b/lab2/shell/header/shell.h new file mode 100644 index 000000000..7ce4cee06 --- /dev/null +++ b/lab2/shell/header/shell.h @@ -0,0 +1 @@ +void shell(); \ No newline at end of file diff --git a/lab2/shell/header/uart.h b/lab2/shell/header/uart.h new file mode 100644 index 000000000..a3d45ed28 --- /dev/null +++ b/lab2/shell/header/uart.h @@ -0,0 +1,43 @@ +#ifndef _UART_H_ +#define _UART_H_ +#define MMIO_BASE 0x3f000000 + +#define GPFSEL0 ((volatile unsigned int *)(MMIO_BASE + 0x00200000)) +#define GPFSEL1 ((volatile unsigned int *)(MMIO_BASE + 0x00200004)) +#define GPFSEL2 ((volatile unsigned int *)(MMIO_BASE + 0x00200008)) +#define GPFSEL3 ((volatile unsigned int *)(MMIO_BASE + 0x0020000C)) +#define GPFSEL4 ((volatile unsigned int *)(MMIO_BASE + 0x00200010)) +#define GPFSEL5 ((volatile unsigned int *)(MMIO_BASE + 0x00200014)) +#define GPSET0 ((volatile unsigned int *)(MMIO_BASE + 0x0020001C)) +#define GPSET1 ((volatile unsigned int *)(MMIO_BASE + 0x00200020)) +#define GPCLR0 ((volatile unsigned int *)(MMIO_BASE + 0x00200028)) +#define GPLEV0 ((volatile unsigned int *)(MMIO_BASE + 0x00200034)) +#define GPLEV1 ((volatile unsigned int *)(MMIO_BASE + 0x00200038)) +#define GPEDS0 ((volatile unsigned int *)(MMIO_BASE + 0x00200040)) +#define GPEDS1 ((volatile unsigned int *)(MMIO_BASE + 0x00200044)) +#define GPHEN0 ((volatile unsigned int *)(MMIO_BASE + 0x00200064)) +#define GPHEN1 ((volatile unsigned int *)(MMIO_BASE + 0x00200068)) +#define GPPUD ((volatile unsigned int *)(MMIO_BASE + 0x00200094)) +#define GPPUDCLK0 ((volatile unsigned int *)(MMIO_BASE + 0x00200098)) +#define GPPUDCLK1 ((volatile unsigned int *)(MMIO_BASE + 0x0020009C)) + +#define AUX_ENABLE ((volatile unsigned int *)(MMIO_BASE + 0x00215004)) +#define AUX_MU_IO ((volatile unsigned int *)(MMIO_BASE + 0x00215040)) +#define AUX_MU_IER ((volatile unsigned int *)(MMIO_BASE + 0x00215044)) +#define AUX_MU_IIR ((volatile unsigned int *)(MMIO_BASE + 0x00215048)) +#define AUX_MU_LCR ((volatile unsigned int *)(MMIO_BASE + 0x0021504C)) +#define AUX_MU_MCR ((volatile unsigned int *)(MMIO_BASE + 0x00215050)) +#define AUX_MU_LSR ((volatile unsigned int *)(MMIO_BASE + 0x00215054)) +#define AUX_MU_MSR ((volatile unsigned int *)(MMIO_BASE + 0x00215058)) +#define AUX_MU_SCRATCH ((volatile unsigned int *)(MMIO_BASE + 0x0021505C)) +#define AUX_MU_CNTL ((volatile unsigned int *)(MMIO_BASE + 0x00215060)) +#define AUX_MU_STAT ((volatile unsigned int *)(MMIO_BASE + 0x00215064)) +#define AUX_MU_BAUD ((volatile unsigned int *)(MMIO_BASE + 0x00215068)) + +#endif + +void uart_init(); +void uart_send_char(unsigned int c); +char uart_get_char(); +void uart_send_str(char *s); +void uart_binary_to_hex(unsigned int d); diff --git a/lab2/shell/header/utils.h b/lab2/shell/header/utils.h new file mode 100644 index 000000000..f12bd534c --- /dev/null +++ b/lab2/shell/header/utils.h @@ -0,0 +1,9 @@ +int string_compare(char *a, char *b); +int strncmp(char *a, char *b, int cnt); +unsigned int hex_to_int(char *a, int size); +int isdigit(int c); +int toupper(int c); +int ishex(int c); +char* strtok(char* str, const char* delimiters); +char *strcpy(char *dest, const char *src); +unsigned int strlen(const char *s); \ No newline at end of file diff --git a/lab2/shell/kernel8.elf b/lab2/shell/kernel8.elf new file mode 100755 index 000000000..5cb232278 Binary files /dev/null and b/lab2/shell/kernel8.elf differ diff --git a/lab2/shell/linker.ld b/lab2/shell/linker.ld new file mode 100644 index 000000000..9bff61183 --- /dev/null +++ b/lab2/shell/linker.ld @@ -0,0 +1,24 @@ +SECTIONS +{ + . = 0x80000; /* Set the memory address to 0x80000 (start point)*/ + + .text : { /* Define the .text section, which contains executable code*/ + KEEP(*(.text.boot)) /* Keep all .text.boot sections*/ + *(.text) /* Keep all other .text sections*/ + } + + .rodata : { *(.rodata) } /* Define the .rodata section, which contains read-only data*/ + + .data : { *(.data) } /* Define the .data section, which contains initialized data*/ + + .bss () : { /* Define the .bss section, which contains uninitialized data*/ + __bss_start = .; /* Define __bss_start symbol as the current memory address*/ + *(.bss) /* Keep all .bss sections*/ + *(COMMON) /* Keep all common symbols*/ + __bss_end = .; /* Define __bss_end symbol as the current memory address*/ + } + __heap_start = .; + _end = .; /* Define _end symbol as the current memory address*/ +} + +__bss_size = (__bss_end - __bss_start) >> 3; /* Calculate the size of the .bss section in bytes*/ diff --git a/lab2/shell/mailbox.c b/lab2/shell/mailbox.c new file mode 100644 index 000000000..2ef732242 --- /dev/null +++ b/lab2/shell/mailbox.c @@ -0,0 +1,69 @@ +#include"header/mailbox.h" +#include"header/uart.h" + +void mailbox_call(unsigned int *mailbox){ + // Write the data (shifted into the upper 28 bits) combined with + // the channel (in the lower four bits) to the write register. + unsigned int r = (((unsigned long)mailbox) & ~0xf) | 8; //mail_ch_prop + // & ~0xf => only "and" upper 28 bit can be saved + // |8 => if upper 28 is 1 => save and ensure last 4 bit is 1 + // Check if Mailbox 0 status register’s full flag is set. + while (*MAILBOX_STATUS & MAILBOX_FULL) { + asm volatile("nop"); + }; + // If not, then you can write to Mailbox 1 Read/Write register. + *MAILBOX_WRITE = r; + while (1) { + // Check if Mailbox 0 status register’s empty flag is set. + while (*MAILBOX_STATUS & MAILBOX_EMPTY) { + asm volatile("nop"); + }; + // If not, then you can read from Mailbox 0 Read/Write register. + // Check if the value is the same as you wrote in step 1. + if (r == *MAILBOX_READ) + return; + } + +} + +void get_board_revision(){ + unsigned int mailbox[7]; + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = END_TAG; + + mailbox_call(mailbox); // message passing procedure call, you should implement it following the 6 steps provided above. + + //printf("0x%x\n", mailbox[5]); // it should be 0xa020d3 for rpi3 b+ + uart_send_str("0x"); + uart_binary_to_hex(mailbox[5]); + uart_send_str("\n"); +} + +void get_memory_info(){ + unsigned int mailbox[8]; + mailbox[0] = 8 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_ARM_MEMORY; // tag identifier + mailbox[3] = 8; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; // tag code + mailbox[5] = 0; // base address + mailbox[6] = 0; // size in bytes + mailbox[7] = END_TAG; // end tag + // tags end + mailbox_call(mailbox); + uart_send_str("ARM memory base address : "); + uart_binary_to_hex(mailbox[5]); + uart_send_str("\n"); + + uart_send_str("ARM memory size : "); + uart_binary_to_hex(mailbox[6]); + uart_send_str("\n"); +} diff --git a/lab2/shell/main.c b/lab2/shell/main.c new file mode 100644 index 000000000..591b14bed --- /dev/null +++ b/lab2/shell/main.c @@ -0,0 +1,18 @@ +#include "header/utils.h" +#include "header/uart.h" +#include "header/shell.h" +#include "header/reboot.h" +#include "header/mailbox.h" +#include "header/cpio.h" +#include "header/dtb.h" +extern char *dtb_base; +int main(char *arg){ + uart_init(); + dtb_base = arg; + fdt_traverse(initramfs_callback); + uart_send_str("\x1b[2J\x1b[H"); + char *s = "Type in `help` to get instruction menu!\n"; + uart_send_str(s); + shell(); + return 0; +} \ No newline at end of file diff --git a/lab2/shell/makefile b/lab2/shell/makefile new file mode 100644 index 000000000..8f955a0c3 --- /dev/null +++ b/lab2/shell/makefile @@ -0,0 +1,29 @@ +CFLAGS = -Wall -ffreestanding -nostdinc -nostdlib -nostartfiles -fno-stack-protector -g +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) + +ASMS = $(wildcard *.S) +ASM_OBJS = $(ASMS:.S=.o) + +all:: clean_img flash clean + +%.o: %.S + aarch64-linux-gnu-gcc $(CFLAGS) -c $< -o $@ + + +%.o: %.c + aarch64-linux-gnu-gcc $(CFLAGS) -c $< -o $@ + +flash: $(ASM_OBJS) $(OBJS) + aarch64-linux-gnu-ld $(ASM_OBJS) $(OBJS) -T linker.ld -o kernel8.elf + aarch64-linux-gnu-objcopy -O binary kernel8.elf shell.img +clean: + rm -f $(ASM_OBJS) $(OBJS) + +clean_img: + rm -f kernel8.elf + rm -f shell.img +test: + qemu-system-aarch64 -machine raspi3b -kernel shell.img -display none -serial null -serial stdio -initrd ../rootfs/initramfs.cpio -dtb ../bcm2710-rpi-3-b-plus.dtb +screen: + sudo screen /dev/ttyUSB0 115200 \ No newline at end of file diff --git a/lab2/shell/malloc.c b/lab2/shell/malloc.c new file mode 100644 index 000000000..346a6b55a --- /dev/null +++ b/lab2/shell/malloc.c @@ -0,0 +1,6 @@ +#include"header/malloc.h" +extern __heap_start; +char *top = &__heap_start; +void* simple_malloc(unsigned int size) { + return top += size; +} \ No newline at end of file diff --git a/lab2/shell/reboot.c b/lab2/shell/reboot.c new file mode 100644 index 000000000..089d71dcb --- /dev/null +++ b/lab2/shell/reboot.c @@ -0,0 +1,20 @@ +#include"header/reboot.h" + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +void reset(int tick) { // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick +} + +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} \ No newline at end of file diff --git a/lab2/shell/shell.c b/lab2/shell/shell.c new file mode 100644 index 000000000..e749a28ff --- /dev/null +++ b/lab2/shell/shell.c @@ -0,0 +1,91 @@ +#include"header/shell.h" +#include"header/uart.h" +#include"header/utils.h" +#include"header/reboot.h" +#include"header/mailbox.h" +#include"header/cpio.h" +#include"header/malloc.h" +void shell(){ + char cmd[256]; + char *cur; + while (1) + { + char *s = "# "; + uart_send_str(s); + cur = cmd; + char receive; + while (1) + { + receive = uart_get_char(); + if(receive == '\n'){ + *cur = '\0'; + break; + } + else if(receive == 127){ + if(cur == cmd){ + *cur = '\0'; + continue; + } + *cur = '\0'; + cur--; + uart_send_str("\b \b"); + continue; + } + *cur = receive; + uart_send_char(receive); + cur++; + } + char arg[20][20]; + char *tk = strtok(cmd," "); + for(int i = 0; tk != 0;i++){ + strcpy(arg[i],tk); + tk = strtok(0," "); + } + if(string_compare(arg[0],"help")){ + uart_send_str("\nhelp\t\t:print this help menu\r\n"); + uart_send_str("hello\t\t:print Hello World!\r\n"); + uart_send_str("info\t\t:Get the hardware's information\r\n"); + uart_send_str("ls\t\t:list files in directory\r\n"); + uart_send_str("cat\t\t:cat\r\n"); + uart_send_str("clear\t\t:clear terminal\r\n"); + uart_send_str("reboot\t\t:reboot the device\r\n"); + uart_send_str("malloc\t\t:alloc string\r\n"); + } + else if(string_compare(arg[0],"hello")){ + uart_send_str("\nHello World!\n"); + } + else if(string_compare(arg[0],"info")){ + uart_send_str("\nInfo:\n"); + uart_send_str("Board Vision: "); + get_board_revision(); + get_memory_info(); + + } + else if(string_compare(arg[0],"clear")){ + uart_send_str("\x1b[2J\x1b[H"); + } + else if(string_compare(arg[0],"ls")){ + uart_send_str("\n"); + ls("."); + } + else if(string_compare(arg[0],"cat")){ + uart_send_str("\n"); + cat(arg[1]); + } + else if (string_compare(arg[0],"reboot")) { + uart_send_str("\nRebooting....\n"); + reset(1000); + } + else if (string_compare(arg[0],"malloc")){ + uart_send_str("\n"); + unsigned int size = (strlen(arg[1]) + 31) >> 5 << 5; + char *string = simple_malloc(size); + strcpy(string,arg[1]); + uart_send_str(string); + uart_send_str("\n"); + } + else + uart_send_str("\n"); + } + +} \ No newline at end of file diff --git a/lab2/shell/shell.img b/lab2/shell/shell.img new file mode 100755 index 000000000..e865ab037 Binary files /dev/null and b/lab2/shell/shell.img differ diff --git a/lab2/shell/shell_init.S b/lab2/shell/shell_init.S new file mode 100644 index 000000000..7d65d428e --- /dev/null +++ b/lab2/shell/shell_init.S @@ -0,0 +1,27 @@ +.section ".text.boot" // Start a new section named ".text.boot" +.global _start // Declare _start symbol as global + +_start: // Start of the _start block + // read cpu id, stop slave cores + mrs x1, mpidr_el1 // Read Multiprocessor Affinity Register into x1 + and x1, x1, #3 // Mask the lower 2 bits (CPU core ID) from x1 + cbz x1, setting // If x1 is zero, jump to setting label + +halt: wfe // Wait for Event instruction + b halt // Branch (jump) to halt (infinite loop) + +setting: // Setting label + ldr x1, =_start // Load the address of _start into x1 + mov sp, x1 // Move the value of x1 into the Stack Pointer (sp) + ldr x1, =__bss_start // Load the address of __bss_start into x1 + ldr w2, =__bss_size // Load the value of __bss_size into w2 + +clear_bss: // Clear BSS segment loop label + cbz w2, kernel_main // If w2 (BSS size) is zero, jump to kernel_main + str xzr, [x1], #8 // Store zero (xzr) at the address pointed by x1, then increment x1 by 8 + sub w2, w2, #1 // Decrement w2 (BSS size) by 1 + cbnz w2, clear_bss // If w2 is not zero, jump back to clear_bss + +kernel_main: // Label for the start of kernel_main function + bl main // Branch with link (call) to main function + b halt // Branch to halt (infinite loop) diff --git a/lab2/shell/uart.c b/lab2/shell/uart.c new file mode 100644 index 000000000..cf4ec1b6c --- /dev/null +++ b/lab2/shell/uart.c @@ -0,0 +1,66 @@ +#include"header/uart.h" + +void uart_init(){ + + *AUX_ENABLE |= 1; + *AUX_MU_CNTL = 0; + *AUX_MU_IER = 0; + *AUX_MU_LCR = 3; + *AUX_MU_MCR = 0; + *AUX_MU_BAUD = 270; + + register unsigned int r; + + //??? + r =* GPFSEL1; + r &= ~((7 << 12) | (7 << 15)); // gpio14, gpio15 innitial + 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_IIR = 6; + *AUX_MU_CNTL = 3; +} + +void uart_send_char(unsigned int c){ + do{asm volatile("nop");}while(!(*AUX_MU_LSR & 0x20)); // This bit is set if the transmit FIFO can accept at least one byte. + /* write the character to the buffer */ + *AUX_MU_IO = c; +} + +char uart_get_char(){ + char r; + /* wait until something is in the buffer */ + //bit 0 is set if the receive FIFO holds at least 1 symbol. + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01)); + /* read it and return */ + r=(char)(*AUX_MU_IO); + /* convert carriage return to newline */ + return r=='\r'?'\n':r; +} + +void uart_send_str(char *s){ + while(*s) { + /* convert newline to carriage return + newline */ + if(*s=='\n') + uart_send_char('\r'); + uart_send_char(*s++); + } +} + +void uart_binary_to_hex(unsigned int d) { + unsigned int n; + int c; + uart_send_str("0x"); + for(c=28;c>=0;c-=4) { + // get highest tetrad + n=(d>>c)&0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n+=n>9?0x37:0x30; + uart_send_char(n); + } +} \ No newline at end of file diff --git a/lab2/shell/utils.c b/lab2/shell/utils.c new file mode 100644 index 000000000..4e04a6b84 --- /dev/null +++ b/lab2/shell/utils.c @@ -0,0 +1,95 @@ +#include"header/utils.h" +#include"header/uart.h" + +int string_compare(char *s1,char *s2) { + while (*s1 && *s2 && (*s1 == *s2)) { + s1++; + s2++; + } + return !(*s1 - *s2); +} + +int strncmp(char *s1, char *s2, int n) { + while (n-- && *s1 && (*s1 == *s2)) { + s1++; + s2++; + } + if (n == (int) -1) { + return 0; + } + return *(const unsigned char *) s1 - *(const unsigned char *) s2; +} +int isdigit(int c){ + return c >= '0' && c <= '9'; +} +int toupper(int c){ + if (c >= 'a' && c <= 'z') { + return c - 'a' + 'A'; + } else { + return c; + } +} + +int ishex(int c){ + return isdigit(c) || (toupper(c) >= 'A' && toupper(c) <= 'F'); +} + +unsigned int hex_to_int(char *a, int size){ + unsigned int result = 0; + + for (int i = 0; i < size; i++) { + char c = a[i]; + if (ishex(c)) { + int val = isdigit(c) ? c - '0' : toupper(c) - 'A' + 10; + result = (result << 4) + val; + } + } + + return result; +} + +char* strtok(char* str, const char* delimiters) { + static char* buffer = 0; + if (str != 0) { + buffer = str; + } + if (buffer == 0) { + return 0; + } + char* start = buffer; + while (*buffer != '\0') { + const char* delim = delimiters; + while (*delim != '\0') { + if (*buffer == *delim) { + *buffer = '\0'; + buffer++; + if (start != buffer) { + return start; + } else { + start++; + break; + } + } + delim++; + } + if (*delim == '\0') { + buffer++; + } + } + if (start == buffer) { + return 0; + } else { + return start; + } +} +char *strcpy(char *dest, const char *src) { + char *ret = dest; + while ((*dest++ = *src++)); + return ret; +} + +unsigned int strlen(const char *s) { + int len = 0; + while (*s++) len++; + return len; +} \ No newline at end of file diff --git a/lab2/writer.py b/lab2/writer.py new file mode 100644 index 000000000..738cc1871 --- /dev/null +++ b/lab2/writer.py @@ -0,0 +1,25 @@ +import serial +import os +import time + + +tty = serial.Serial("/dev/ttyUSB0", 115200, timeout=0.5) +# acquire the file size +file_stats = os.stat("./shell/shell.img") +# issue request and tell the size of img to rec +tty.write(str(file_stats.st_size).encode('utf-8')) +# size sended +# python3 .encode() +tty.write(str("\n").encode('utf-8')) +time.sleep(0.0005) +# send img byte-by-byte +# delay to ensure no loss +# uart is low speed interface +# if sleep too short e.g: 0.0001, it may loss +with open("./shell/shell.img", "rb") as fp: + byte = fp.read(1) + while byte: + tty.write(byte) + byte = fp.read(1) + # delay enough time to ensure no loss + time.sleep(0.0005) \ No newline at end of file