From 361488c60943664d1039d20cf45caa66388856c4 Mon Sep 17 00:00:00 2001 From: kyle Date: Thu, 28 Mar 2024 17:12:51 +0800 Subject: [PATCH 1/4] updata lab2 --- lab2/.vscode/settings.json | 12 +++ lab2/bcm2710-rpi-3-b-plus.dtb | Bin 0 -> 34228 bytes lab2/bootloader/booting.S | 27 ++++++ lab2/bootloader/bootloader.c | 64 ++++++++++++++ lab2/bootloader/header/bootloader.h | 2 + lab2/bootloader/header/reboot.h | 7 ++ lab2/bootloader/header/shell.h | 3 + lab2/bootloader/header/uart.h | 44 ++++++++++ lab2/bootloader/header/utils.h | 2 + lab2/bootloader/linker.ld | 24 ++++++ lab2/bootloader/main.c | 20 +++++ lab2/bootloader/makefile | 31 +++++++ lab2/bootloader/reboot.c | 20 +++++ lab2/bootloader/shell.c | 59 +++++++++++++ lab2/bootloader/uart.c | 74 ++++++++++++++++ lab2/bootloader/utils.c | 34 ++++++++ lab2/config.txt | 4 + lab2/rootfs/file1.txt | 55 ++++++++++++ lab2/rootfs/file2.txt | 14 ++++ lab2/rootfs/initramfs.cpio | Bin 0 -> 4608 bytes lab2/shell/cpio.c | 125 ++++++++++++++++++++++++++++ lab2/shell/dtb.c | 109 ++++++++++++++++++++++++ lab2/shell/header/cpio.h | 30 +++++++ lab2/shell/header/dtb.h | 22 +++++ lab2/shell/header/mailbox.h | 27 ++++++ lab2/shell/header/malloc.h | 1 + lab2/shell/header/reboot.h | 7 ++ lab2/shell/header/shell.h | 1 + lab2/shell/header/uart.h | 43 ++++++++++ lab2/shell/header/utils.h | 9 ++ lab2/shell/linker.ld | 24 ++++++ lab2/shell/mailbox.c | 69 +++++++++++++++ lab2/shell/main.c | 18 ++++ lab2/shell/makefile | 29 +++++++ lab2/shell/malloc.c | 6 ++ lab2/shell/reboot.c | 20 +++++ lab2/shell/shell.c | 91 ++++++++++++++++++++ lab2/shell/shell_init.S | 27 ++++++ lab2/shell/uart.c | 66 +++++++++++++++ lab2/shell/utils.c | 95 +++++++++++++++++++++ lab2/writer.py | 25 ++++++ osc2024 | 1 + 42 files changed, 1341 insertions(+) create mode 100644 lab2/.vscode/settings.json create mode 100644 lab2/bcm2710-rpi-3-b-plus.dtb create mode 100644 lab2/bootloader/booting.S create mode 100644 lab2/bootloader/bootloader.c create mode 100644 lab2/bootloader/header/bootloader.h create mode 100644 lab2/bootloader/header/reboot.h create mode 100644 lab2/bootloader/header/shell.h create mode 100644 lab2/bootloader/header/uart.h create mode 100644 lab2/bootloader/header/utils.h create mode 100644 lab2/bootloader/linker.ld create mode 100644 lab2/bootloader/main.c create mode 100644 lab2/bootloader/makefile create mode 100644 lab2/bootloader/reboot.c create mode 100644 lab2/bootloader/shell.c create mode 100644 lab2/bootloader/uart.c create mode 100644 lab2/bootloader/utils.c create mode 100644 lab2/config.txt create mode 100644 lab2/rootfs/file1.txt create mode 100644 lab2/rootfs/file2.txt create mode 100644 lab2/rootfs/initramfs.cpio create mode 100644 lab2/shell/cpio.c create mode 100644 lab2/shell/dtb.c create mode 100644 lab2/shell/header/cpio.h create mode 100644 lab2/shell/header/dtb.h create mode 100644 lab2/shell/header/mailbox.h create mode 100644 lab2/shell/header/malloc.h create mode 100644 lab2/shell/header/reboot.h create mode 100644 lab2/shell/header/shell.h create mode 100644 lab2/shell/header/uart.h create mode 100644 lab2/shell/header/utils.h create mode 100644 lab2/shell/linker.ld create mode 100644 lab2/shell/mailbox.c create mode 100644 lab2/shell/main.c create mode 100644 lab2/shell/makefile create mode 100644 lab2/shell/malloc.c create mode 100644 lab2/shell/reboot.c create mode 100644 lab2/shell/shell.c create mode 100644 lab2/shell/shell_init.S create mode 100644 lab2/shell/uart.c create mode 100644 lab2/shell/utils.c create mode 100644 lab2/writer.py create mode 160000 osc2024 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 0000000000000000000000000000000000000000..c83b0817e2eb5295a3dfe6aafe3aa55d93e9785d GIT binary patch literal 34228 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 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 0000000000000000000000000000000000000000..b0ae9915f7651f2bf44f7ab09fbe00481ffe0f80 GIT binary patch literal 4608 zcmd5=ZExE)5bkIH3P$0mLePtowoWBPVcpt=?Aomn3j>yMHm%7{x)u{^XU+x?`t3VP zq9jXBn|&LDh;Mh#9q*1u(%p;hMfa>LOaJ8yS-m_P4rJYZF?@Yccf04kUiZcM;B`Kp zO=h2>e_o9ow#o_n8AvPSoe$o>-x;T|NH(KdRkc~qsz(Y!|=-AC(C8$X-tSZ*w=IoAx+a3^M2U>h*S17W}8q) zKNQ0?4P)~u?50yOJC?R!HXzxSpR(`?{B>^RWNHh9#O3rC3z?MuNCCSh9K>=)NApuy z3di*Q^=SBU@R`{^z%UI;n`5O4a$d7=`FmBlJ5EXIa@jyo!xiFD^%&+!R znl3Ma05epjnkdJ(!2%OjN-&;#7oxRFL7^z>sQ}WVn3hEZQ@yI@ghtTQG|zE#1!tRy zW$hDY&c=FBf&^kx@^P+fLB?4QWewBfR7x=kQE29jS`eJR@A*0sLQ0c`Puxm7*$+55 z7=STBy%R8rIU|K;Jj&1|KNQzdOQlp=r7EDQ5!t4$)mH3bk02EMrt|_QW0sUQHk>Sm z0fSQDt+0>_9nP5dJa>+5I=CmjE?B4x1_YelFeQz%iyXlW6H4k}>^bu++nRe;>RXzw zo3l*NbX;nc^&zAUWhg465TTff%O&WMEDO~*AyejMo9Bv+<|fGkQA}z|DJ-QJC`s93 zgV-ChC#kpP0Yo~)8 zOw)x9*-q2A#uy=&s1=49Pw~wA-9yeEM46|aM=vjlr-#ykF_v-utMJr1G9$qT@Dqm| zj=@aspM>1#T(?h81rpPM$&dtHJBa%p4v1fxL_%>bqIHkMke$26?HRVUw>|1`=KGjX zObq3AzQC1bGZ=#y%5Ab=1PVlFYNbWW5s(C~6avu5u#>b!F+&IJqm+x)UQyFoEy5Z< zLd>ZEY$5}Jv#X5ou{766_k>RrzEe+TG~YXFu2$2-^Fj!>m>jdPMi$iCjb;M@sVpjl zQ=_bF(}QvKpOLtSNgHM? zmZ)L6brVSH+G=XdMKf;dAp?>=7eQmAeh-93Z4d)|q6t!1cii{0$3`J^_l;?)x zYT*_Wu!UV`azvSI-t}7QxJ*ITYI(f#zDGor7SLZ(;(IE&Zum4 zf#jkQ{Ur!AV&;6iiK>%U&gI)Hqq0r77Zk-5&C?6Ar<1~Mhx%0BIJxErxE9JPE!c^# zmnaC0S!-RU;YbPyA0>>J3~-@L;Hc1ysM;2i%EYsVyWqa3*ju$c6LL&iq>r4$#BgpM zlyP$tl(QzLRnnT)$Y=|sJ}a&YPuWW|b#dJkVFeQF(`MMXyfP*aK6}^1Bcw;*O;M^O zJ%GoGj4w2}=rmzezRZ}of5SXYs{!QAK!gW_oCM@*-+Jogi4)m!bM8$lj%|Ya+H-K* zyAelj>q0<;EC<7W7^GL>CpS>*sA&gjsUd@6eyX=4+U-v!;!Iw73@{3=990L4ZiqrN z6GlFaCKFQKtSd@JFA{~r|j@Ic^@9J0Yx=(pmpZ8z)-2B1(_HFTS{!j1f^Xy%{ zS?%IYyjyK{@oKY*cbm?a_4d#8*X1gXx9i<5o0oHsjqg_RrjrrK5A-@M$dcr4y}j?; zb?zb{?A&fTQIgz$O;+)Gd$)er=HshqzqxymgxiPp{kC(v-rVkQSGQZ}tk$>d)pqyS qAM1x#|8#1+^ literal 0 HcmV?d00001 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/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_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 diff --git a/osc2024 b/osc2024 new file mode 160000 index 000000000..8066f1e38 --- /dev/null +++ b/osc2024 @@ -0,0 +1 @@ +Subproject commit 8066f1e38955111256bfadbf4f747c612270dba9 From 95ed9850b1a315d20065d91f39d4513bf18eb6be Mon Sep 17 00:00:00 2001 From: Shukkai Date: Thu, 28 Mar 2024 17:26:43 +0800 Subject: [PATCH 2/4] update lab2 --- osc2024 | 1 - 1 file changed, 1 deletion(-) delete mode 160000 osc2024 diff --git a/osc2024 b/osc2024 deleted file mode 160000 index 8066f1e38..000000000 --- a/osc2024 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8066f1e38955111256bfadbf4f747c612270dba9 From 750924af7b438a309e0cc0b5982d73ceeed92cc3 Mon Sep 17 00:00:00 2001 From: Shukkai Date: Thu, 28 Mar 2024 17:27:26 +0800 Subject: [PATCH 3/4] update lab2 --- lab2/.vscode/settings.json | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 lab2/.vscode/settings.json diff --git a/lab2/.vscode/settings.json b/lab2/.vscode/settings.json deleted file mode 100644 index 1903fa635..000000000 --- a/lab2/.vscode/settings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "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 From 99670545dd9c25e0c41752f53d376e96ed26f0bd Mon Sep 17 00:00:00 2001 From: Shukkai Date: Thu, 25 Apr 2024 18:21:25 +0800 Subject: [PATCH 4/4] lab3 updated --- lab3/.vscode/settings.json | 6 + lab3/bcm2710-rpi-3-b-plus.dtb | Bin 0 -> 34228 bytes lab3/bootloader/booting.S | 27 ++++ lab3/bootloader/bootloader.c | 64 +++++++++ lab3/bootloader/header/bootloader.h | 2 + lab3/bootloader/header/reboot.h | 7 + lab3/bootloader/header/shell.h | 3 + lab3/bootloader/header/uart.h | 44 ++++++ lab3/bootloader/header/utils.h | 2 + lab3/bootloader/linker.ld | 24 ++++ lab3/bootloader/main.c | 20 +++ lab3/bootloader/makefile | 31 +++++ lab3/bootloader/reboot.c | 20 +++ lab3/bootloader/shell.c | 59 ++++++++ lab3/bootloader/uart.c | 74 ++++++++++ lab3/bootloader/utils.c | 34 +++++ lab3/config.txt | 4 + lab3/rootfs/file1.txt | 55 ++++++++ lab3/rootfs/file2.txt | 14 ++ lab3/rootfs/initramfs.cpio | Bin 0 -> 5120 bytes lab3/shell/cpio.c | 156 +++++++++++++++++++++ lab3/shell/dtb.c | 109 +++++++++++++++ lab3/shell/exec.c | 36 +++++ lab3/shell/header/cpio.h | 31 +++++ lab3/shell/header/dtb.h | 22 +++ lab3/shell/header/exec.h | 5 + lab3/shell/header/irq.h | 11 ++ lab3/shell/header/list.h | 122 ++++++++++++++++ lab3/shell/header/mailbox.h | 27 ++++ lab3/shell/header/malloc.h | 4 + lab3/shell/header/reboot.h | 7 + lab3/shell/header/shell.h | 2 + lab3/shell/header/task.h | 26 ++++ lab3/shell/header/timer.h | 31 +++++ lab3/shell/header/uart.h | 73 ++++++++++ lab3/shell/header/utils.h | 10 ++ lab3/shell/irq.c | 135 ++++++++++++++++++ lab3/shell/linker.ld | 24 ++++ lab3/shell/mailbox.c | 69 ++++++++++ lab3/shell/main.c | 48 +++++++ lab3/shell/makefile | 32 +++++ lab3/shell/malloc.c | 11 ++ lab3/shell/reboot.c | 20 +++ lab3/shell/shell.c | 149 ++++++++++++++++++++ lab3/shell/shell_init.S | 158 +++++++++++++++++++++ lab3/shell/task.c | 87 ++++++++++++ lab3/shell/timer.c | 114 +++++++++++++++ lab3/shell/uart.c | 207 ++++++++++++++++++++++++++++ lab3/shell/utils.c | 116 ++++++++++++++++ lab3/user program/linker.ld | 16 +++ lab3/user program/makefile | 13 ++ lab3/user program/testing | 7 + lab3/user program/testing.S | 14 ++ lab3/writer.py | 25 ++++ 54 files changed, 2407 insertions(+) create mode 100644 lab3/.vscode/settings.json create mode 100644 lab3/bcm2710-rpi-3-b-plus.dtb create mode 100644 lab3/bootloader/booting.S create mode 100644 lab3/bootloader/bootloader.c create mode 100644 lab3/bootloader/header/bootloader.h create mode 100644 lab3/bootloader/header/reboot.h create mode 100644 lab3/bootloader/header/shell.h create mode 100644 lab3/bootloader/header/uart.h create mode 100644 lab3/bootloader/header/utils.h create mode 100644 lab3/bootloader/linker.ld create mode 100644 lab3/bootloader/main.c create mode 100644 lab3/bootloader/makefile create mode 100644 lab3/bootloader/reboot.c create mode 100644 lab3/bootloader/shell.c create mode 100644 lab3/bootloader/uart.c create mode 100644 lab3/bootloader/utils.c create mode 100644 lab3/config.txt create mode 100644 lab3/rootfs/file1.txt create mode 100644 lab3/rootfs/file2.txt create mode 100644 lab3/rootfs/initramfs.cpio create mode 100644 lab3/shell/cpio.c create mode 100644 lab3/shell/dtb.c create mode 100644 lab3/shell/exec.c create mode 100644 lab3/shell/header/cpio.h create mode 100644 lab3/shell/header/dtb.h create mode 100644 lab3/shell/header/exec.h create mode 100644 lab3/shell/header/irq.h create mode 100644 lab3/shell/header/list.h create mode 100644 lab3/shell/header/mailbox.h create mode 100644 lab3/shell/header/malloc.h create mode 100644 lab3/shell/header/reboot.h create mode 100644 lab3/shell/header/shell.h create mode 100644 lab3/shell/header/task.h create mode 100644 lab3/shell/header/timer.h create mode 100644 lab3/shell/header/uart.h create mode 100644 lab3/shell/header/utils.h create mode 100644 lab3/shell/irq.c create mode 100644 lab3/shell/linker.ld create mode 100644 lab3/shell/mailbox.c create mode 100644 lab3/shell/main.c create mode 100644 lab3/shell/makefile create mode 100644 lab3/shell/malloc.c create mode 100644 lab3/shell/reboot.c create mode 100644 lab3/shell/shell.c create mode 100644 lab3/shell/shell_init.S create mode 100644 lab3/shell/task.c create mode 100644 lab3/shell/timer.c create mode 100644 lab3/shell/uart.c create mode 100644 lab3/shell/utils.c create mode 100644 lab3/user program/linker.ld create mode 100644 lab3/user program/makefile create mode 100644 lab3/user program/testing create mode 100644 lab3/user program/testing.S create mode 100644 lab3/writer.py diff --git a/lab3/.vscode/settings.json b/lab3/.vscode/settings.json new file mode 100644 index 000000000..c4d142e9b --- /dev/null +++ b/lab3/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "files.associations": { + "cpio.h": "c", + "uart.h": "c" + } +} \ No newline at end of file diff --git a/lab3/bcm2710-rpi-3-b-plus.dtb b/lab3/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 0000000000000000000000000000000000000000..c83b0817e2eb5295a3dfe6aafe3aa55d93e9785d GIT binary patch literal 34228 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 3; /* Calculate the size of the .bss section in bytes*/ diff --git a/lab3/bootloader/main.c b/lab3/bootloader/main.c new file mode 100644 index 000000000..5f1653f7d --- /dev/null +++ b/lab3/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/lab3/bootloader/makefile b/lab3/bootloader/makefile new file mode 100644 index 000000000..34df2ec5e --- /dev/null +++ b/lab3/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/lab3/bootloader/reboot.c b/lab3/bootloader/reboot.c new file mode 100644 index 000000000..089d71dcb --- /dev/null +++ b/lab3/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/lab3/bootloader/shell.c b/lab3/bootloader/shell.c new file mode 100644 index 000000000..036db19ba --- /dev/null +++ b/lab3/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/lab3/bootloader/uart.c b/lab3/bootloader/uart.c new file mode 100644 index 000000000..4d35998a6 --- /dev/null +++ b/lab3/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/lab3/bootloader/utils.c b/lab3/bootloader/utils.c new file mode 100644 index 000000000..0d398f6f5 --- /dev/null +++ b/lab3/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/lab3/config.txt b/lab3/config.txt new file mode 100644 index 000000000..8c6facb68 --- /dev/null +++ b/lab3/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/lab3/rootfs/file1.txt b/lab3/rootfs/file1.txt new file mode 100644 index 000000000..3677cc6cc --- /dev/null +++ b/lab3/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/lab3/rootfs/file2.txt b/lab3/rootfs/file2.txt new file mode 100644 index 000000000..cfb787b3e --- /dev/null +++ b/lab3/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/lab3/rootfs/initramfs.cpio b/lab3/rootfs/initramfs.cpio new file mode 100644 index 0000000000000000000000000000000000000000..de645099bdcc722cc87d98824e1d93267eede8b0 GIT binary patch literal 5120 zcmeHL-EP}96wZKM`MURG6pktc{n%-0M?z%QU0lei-5QB7U>RrAp6w)SSD|+1Yye^G z74{r^n_(}qC+H3(QIaL6$^FJ4q)49gogW?^lCHPvt$L#lrS;tXMz%+d?x}3+&$`E3 zZM}ZjY&Ker*0XrHP$hKr!@|(kXEtH)fixxW=(r=Pj_;S(h~+iiR)W?@<}$G)kfv#) zi%!^igE#DP%r>EpzAc7p8ph^h*i9#Ab}VhgY(TOtf5XB@@E5s}6RRx{5+{T2EM!vp zkOFo=IEdwp_AU;<6prbu^IrGO=?$|Vz%UI;%eJR|P16yd>WpDb$U{J8I4k*Z8x?Wl z@jyo!X_?60wXXJ9x-Kb!05{|%pUB3z!2%O3B^Y0LEm5&jP$-IeAb>P2rezVqR4;Ei zp;PE-n&&vWg0s!YvepqZhi7__fdrzT@o}zeLCl#A#UG}{sgz<8qR`ACwIDcs-}7}O zgp?)=@4LBnvLA4=H2`CRdi&rKb4XIn_%ueB{7_s+nM$ejN?t%yV``haRVk#JVL-syB~#KkYb6L~7*SFL zV^5i9+17<;ZG219b#oXC8k}WX#eE2ALph4dC`4$+#K{=+h{maEoR9(Y;?2`$y$h4X zfhhU~r4*J@43wm7)N_JP*nQz`JnXL%qd9&Dn~w}T{TE*!oFx$*lys6{l3%%ov#En$ z_f9YNElN(P=M57vTpL*cBOS7xrg4oiLQYU63^l&NL+?iqIcpGQ9(W!-IU$}N$_1QZ z8Ry>%PuUSW2{wQqIb?ebW|H-Z$feG8``|zzF$kCpNzk>1xbNYB_?b&26xXJ-xZ*Hm zCrjft4cl7V9(6eLeM~4OhFW$$!ntQ-7=svU*?Js^W>{^DCmLQ zGDe)O%NV@6Uz8HimTiGpqK4@fT_C9o))bi2&skXy8Ibg;2ud6Eb0BnD1wn9*!Xa8l zQG2DL$eAH_p-63_?A%aX72I?Jwy^8;cPJCjyIw^dmnq0XE01>`xc6Uh3|irOl6yJFG!0i%BL4(PiF(S z9qLngh>=MloCkq9}3<`Qq4JSMu$9+<4@> zy8iN|q=)j*JAdn4eHg#17n9X&F-qAwc3r!k0%7fHQJY55?fYmln=h~DcgtjaGF>mO?!ZhpJ0 zUCkF)>#NDt5;~Ll)qJvC{qocN?)h)E!fzvq`Jb)h-)ufhv3pYawjQ2$dj0PC{{DXa M^T_|zf6@d00=d6VF8}}l literal 0 HcmV?d00001 diff --git a/lab3/shell/cpio.c b/lab3/shell/cpio.c new file mode 100644 index 000000000..06a9aa5cd --- /dev/null +++ b/lab3/shell/cpio.c @@ -0,0 +1,156 @@ +#include"header/cpio.h" +#include"header/utils.h" +#include"header/exec.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(){ + 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\r\n"); + break; + } + + // if this is not TRAILER!!! (last of file) + if (header_pointer != 0){ + uart_send_str(filepath); + uart_send_str("\r\n"); + } + } + return 0; +} +int cat(char *path){ + 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 \r\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("\r\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; +} +int execfile(char *thefilepath) +{ + char* filepath; + char* filedata; + unsigned int filesize; + 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) + { + uart_send_str("error"); + break; + } + // traverse until find the filepath + // program start address is data + // header | pathname str | data + if(string_compare(thefilepath,filepath)) + { + exec(filedata); + break; + } + //if is TRAILER (last of file) + if (header_pointer == 0) + { + uart_send_str("execfile: "); + uart_send_str(thefilepath); + uart_send_str(": No such file or directory\r\n"); + return -1; + } + } + return 0; +} \ No newline at end of file diff --git a/lab3/shell/dtb.c b/lab3/shell/dtb.c new file mode 100644 index 000000000..2f9f752df --- /dev/null +++ b/lab3/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/lab3/shell/exec.c b/lab3/shell/exec.c new file mode 100644 index 000000000..787bd9875 --- /dev/null +++ b/lab3/shell/exec.c @@ -0,0 +1,36 @@ +#include"header/exec.h" +#include"header/malloc.h" + +void exec(char *testing){ + // allocate space for executing the input program + char *ustack = simple_malloc(2000); + // goto el0 to run program + + //uses the msr (Move to System Register) instruction to set the + //SPSR_EL1 (Saved Program Status Register at Exception Level 1) to the value of xzr (zero register). + //This effectively clears the SPSR_EL1, resetting any flags (like condition flags or interrupt masks) it holds. + // spsr_el1 + // 0~3 bit 0b0000 : el0t , jump to el0 and use el0 stack + // 6~9 bit 0b0000 : turn on every interrupt + asm volatile("msr spsr_el1, xzr\n\t"); + //writes the value in the variable testing to the ELR_EL1 (Exception Link Register at Exception Level 1) register. + //The ELR_EL1 holds the return address for exceptions, typically used when returning from an exception back to the + //main execution flow. + //The value in testing is expected to be a memory address + //where execution should resume upon executing the eret instruction later. + // elr_el1 set program start address + asm volatile("msr elr_el1, %0\n\t" + ::"r"(testing)); + //sets the SP_EL0 (Stack Pointer for Exception Level 0, set at top) register to the address ustack + 2000. + //This setup is preparing the stack pointer for use in EL0, usually after an exception return. + //The +2000 likely ensures that there's adequate space allocated in the stack + //to handle whatever process will run at EL0, avoiding stack overflow. + asm volatile("msr sp_el0, %0\n\t":: + "r"(ustack + 2000)); + //return from an exception. This instruction uses the value of ELR_EL1 to set the program counter + // and SPSR_EL1 to restore previously saved processor state. + //Essentially, this transfers control to the address specified in ELR_EL1, effectively resuming execution at the point + //decided by earlier instructions. + asm volatile("eret\n\t" ); + //stack will keep growing +} diff --git a/lab3/shell/header/cpio.h b/lab3/shell/header/cpio.h new file mode 100644 index 000000000..870e00ac5 --- /dev/null +++ b/lab3/shell/header/cpio.h @@ -0,0 +1,31 @@ +#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); +int execfile(char *thefilepath); +#endif \ No newline at end of file diff --git a/lab3/shell/header/dtb.h b/lab3/shell/header/dtb.h new file mode 100644 index 000000000..d5381a5cc --- /dev/null +++ b/lab3/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/lab3/shell/header/exec.h b/lab3/shell/header/exec.h new file mode 100644 index 000000000..d9c2d7abe --- /dev/null +++ b/lab3/shell/header/exec.h @@ -0,0 +1,5 @@ +#ifndef _EXCEPTION_H_ +#define _EXCEPTION_H_ + +void exec(char *testing); +#endif \ No newline at end of file diff --git a/lab3/shell/header/irq.h b/lab3/shell/header/irq.h new file mode 100644 index 000000000..0123d2f98 --- /dev/null +++ b/lab3/shell/header/irq.h @@ -0,0 +1,11 @@ +#ifndef IRQ_H +#define IRQ_H +#include "mailbox.h" +#define IRQ_PENDING_1 ((volatile unsigned int *)(MMIO_BASE + 0xB204)) +#define CORE0_INTERRUPT_SOURCE ((volatile unsigned int *)(0x40000060)) + +void except_handler_c(); +void irq_except_handler_c(); +void enable_interrupt(); +void disable_interrupt(); +#endif \ No newline at end of file diff --git a/lab3/shell/header/list.h b/lab3/shell/header/list.h new file mode 100644 index 000000000..3f3b45b37 --- /dev/null +++ b/lab3/shell/header/list.h @@ -0,0 +1,122 @@ +#ifndef _LIST_H_ +#define _LIST_H_ + +/* + * Circular doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + * + * https://github.com/torvalds/linux/blob/master/include/linux/list. + * https://elixir.bootlin.com/linux/latest/source/scripts/kconfig/list.h#L24 + */ + +typedef struct list_head { + struct list_head *next, *prev; +}list_head_t; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +/** + * INIT_LIST_HEAD - Initialize a list_head structure + * @list: list_head structure to be initialized. + * + * Initializes the list_head to point to itself. If it is a list header, + * the result is an empty list. + */ +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +static inline void __list_add(struct list_head *node, + struct list_head *prev, + struct list_head *next) +{ + next->prev = node; + node->next = next; + node->prev = prev; + prev->next = node; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *node, struct list_head *head) +{ + __list_add(node, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *node, struct list_head *head) +{ + __list_add(node, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +static inline void list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + + +/** + * list_is_head - tests whether @list is the list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_head(const struct list_head *list, const struct list_head *head) +{ + return list == head; +} + + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next) + +#endif \ No newline at end of file diff --git a/lab3/shell/header/mailbox.h b/lab3/shell/header/mailbox.h new file mode 100644 index 000000000..e7c131fc7 --- /dev/null +++ b/lab3/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/lab3/shell/header/malloc.h b/lab3/shell/header/malloc.h new file mode 100644 index 000000000..3f1fc6492 --- /dev/null +++ b/lab3/shell/header/malloc.h @@ -0,0 +1,4 @@ +#ifndef _MALLOC_H_ +#define _MALLO_H_ +void *simple_malloc(unsigned long size); +#endif \ No newline at end of file diff --git a/lab3/shell/header/reboot.h b/lab3/shell/header/reboot.h new file mode 100644 index 000000000..bf5420c1f --- /dev/null +++ b/lab3/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/lab3/shell/header/shell.h b/lab3/shell/header/shell.h new file mode 100644 index 000000000..44d095662 --- /dev/null +++ b/lab3/shell/header/shell.h @@ -0,0 +1,2 @@ +void shell(); +void choose_opt(char *cmd); \ No newline at end of file diff --git a/lab3/shell/header/task.h b/lab3/shell/header/task.h new file mode 100644 index 000000000..22c440a09 --- /dev/null +++ b/lab3/shell/header/task.h @@ -0,0 +1,26 @@ +#ifndef _TASK_H_ +#define _TASK_H_ + +#include "irq.h" +#include "list.h" +#include "timer.h" +#include "uart.h" + + +typedef struct task +{ + // struct list_head listhead; + struct task *next; + struct task *prev; + int priority; // store priority (smaller number is more preemptive) + void *task_function; // task function pointer +} task; +void irqtask_list_init(); +void add_task(void *task_function, int priority); +void run_task(); + +void high_prio(); +void low_prio(); +void test_preempt(); + +#endif \ No newline at end of file diff --git a/lab3/shell/header/timer.h b/lab3/shell/header/timer.h new file mode 100644 index 000000000..a27cdaab1 --- /dev/null +++ b/lab3/shell/header/timer.h @@ -0,0 +1,31 @@ +#ifndef TIMER_H +#define TIMER_H +#define CORE0_TIMER_IRQ_CTRL 0x40000040 +#define STR(x) #x //it converts the macro argument x into a string literal after macro replacement +#define XSTR(x) STR(x) + +#include "list.h" + + +typedef struct timer { + // struct list_head listhead; + struct timer *prev; + struct timer *next; + unsigned long long interrupt_time; //store as tick time after cpu start + void* callback; // interrupt -> timer_callback -> callback(args) + char* args; // need to free the string by event callback function +} timer; + +void core_timer_interrupt_enable(); +void core_timer_interrupt_disable(); +void set_core_timer_interrupt(unsigned long long sec); +void core_timer_interrupt_disable_alternative(); + +void timer_list_init(); +void add_timer(void* callback, unsigned long long timeout, char* args); +void poptimer(); +void core_timer_handler(); + +unsigned long long get_tick_plus_s(unsigned long long second); + +#endif \ No newline at end of file diff --git a/lab3/shell/header/uart.h b/lab3/shell/header/uart.h new file mode 100644 index 000000000..177737a6a --- /dev/null +++ b/lab3/shell/header/uart.h @@ -0,0 +1,73 @@ +#ifndef _UART_H_ +#define _UART_H_ +#include "mailbox.h" + +#define GPIO_BASE (MMIO_BASE + 0x200000) + +// ref: https://cs140e.sergio.bz/docs/BCM2837-ARM-Peripherals.pdf (p. 90) + +#define GPFSEL0 ((volatile unsigned int *)(GPIO_BASE + 0x00)) +#define GPFSEL1 ((volatile unsigned int *)(GPIO_BASE + 0x04)) +#define GPFSEL2 ((volatile unsigned int *)(GPIO_BASE + 0x08)) +#define GPFSEL3 ((volatile unsigned int *)(GPIO_BASE + 0x0C)) +#define GPFSEL4 ((volatile unsigned int *)(GPIO_BASE + 0x10)) +#define GPFSEL5 ((volatile unsigned int *)(GPIO_BASE + 0x14)) +// 0x18 reserved +#define GPSET0 ((volatile unsigned int *)(GPIO_BASE + 0x1C)) +#define GPSET1 ((volatile unsigned int *)(GPIO_BASE + 0x20)) +// 0x24 reserved +#define GPCLR0 ((volatile unsigned int *)(GPIO_BASE + 0x28)) +#define GPCLR1 ((volatile unsigned int *)(GPIO_BASE + 0x2C)) +// 0x30 reserved +#define GPLEV0 ((volatile unsigned int *)(GPIO_BASE + 0x34)) +#define GPLEV1 ((volatile unsigned int *)(GPIO_BASE + 0x38)) +// 0x3C reserved +#define GPEDS0 ((volatile unsigned int *)(GPIO_BASE + 0x40)) +#define GPEDS1 ((volatile unsigned int *)(GPIO_BASE + 0x44)) +// 0x48 reserved +#define GPREN0 ((volatile unsigned int *)(GPIO_BASE + 0x4C)) +#define GPREN1 ((volatile unsigned int *)(GPIO_BASE + 0x50)) +// 0x54 reserved +#define GPFEN0 ((volatile unsigned int *)(GPIO_BASE + 0x58)) +#define GPFEN1 ((volatile unsigned int *)(GPIO_BASE + 0x5C)) +// 0x60 reserved +#define GPHEN0 ((volatile unsigned int *)(GPIO_BASE + 0x64)) +#define GPHEN1 ((volatile unsigned int *)(GPIO_BASE + 0x68)) +// 0x6C reserved +#define GPLEN0 ((volatile unsigned int *)(GPIO_BASE + 0x70)) +#define GPLEN1 ((volatile unsigned int *)(GPIO_BASE + 0x74)) +// 0x78 reserved +#define GPAREN0 ((volatile unsigned int *)(GPIO_BASE + 0x7C)) +#define GPAREN1 ((volatile unsigned int *)(GPIO_BASE + 0x80)) +// 0x84 reserved +#define GPAFEN0 ((volatile unsigned int *)(GPIO_BASE + 0x88)) +#define GPAFEN1 ((volatile unsigned int *)(GPIO_BASE + 0x8C)) +// 0x90 reserved +#define GPPUD ((volatile unsigned int *)(GPIO_BASE + 0x94)) +#define GPPUDCLK0 ((volatile unsigned int *)(GPIO_BASE + 0x98)) +#define GPPUDCLK1 ((volatile unsigned int *)(GPIO_BASE + 0x9C)) +// 0xA0 reserved +// 0xB0 reserved + +void uart_init(); // initialize the device and maps it to the GPIO ports +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); + +void uart_interrupt_enable(); +void uart_interrupt_disable(); +void uart_rx_interrupt_enable(); +void uart_rx_interrupt_disable(); +void uart_tx_interrupt_enable(); +void uart_tx_interrupt_disable(); + +void uart_tx_handler(); +void uart_rx_handler(); + +void uart_async_putc(char c); +void uart_async_puts(char *s); +char uart_async_getc(); +void uart_clear_buffers(); + +#endif \ No newline at end of file diff --git a/lab3/shell/header/utils.h b/lab3/shell/header/utils.h new file mode 100644 index 000000000..fc4f1e171 --- /dev/null +++ b/lab3/shell/header/utils.h @@ -0,0 +1,10 @@ +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); +unsigned int atoi(char* str); \ No newline at end of file diff --git a/lab3/shell/irq.c b/lab3/shell/irq.c new file mode 100644 index 000000000..6482bc337 --- /dev/null +++ b/lab3/shell/irq.c @@ -0,0 +1,135 @@ +#include"header/irq.h" +#include"header/uart.h" +#include"header/shell.h" +#include "header/timer.h" +#include "header/uart.h" +#include "header/task.h" +#define CORE0_TIMER_IRQ_CTRL_ ((volatile unsigned int *)(0x40000040)) +#define AUX_MU_IIR ((volatile unsigned int *)(0x3F215048)) + +void enable_interrupt() { + asm volatile("msr DAIFClr, 0xf"); + //DAIFClr: This is the name of the register being targeted for modification. In ARM architectures, + //DAIF stands for "Disable Asynchronous Interrupts Flag". + //The Clr suffix likely indicates that the instruction is clearing specific bits in this register. + //0xf: This is the value being written to the DAIF register. In binary, 0xf is 1111, + //meaning all four exception mask bits (Debug, SError, IRQ, and FIQ) are being cleared. + //By clearing these bits, interrupts and exceptions of all types are allowed to be taken. +} + +void disable_interrupt() { + asm volatile("msr DAIFSet, 0xf"); + //set bits 0xf +} + +void except_handler_c(unsigned int x0) { + uart_send_str("In Exception handle\n"); + // Set all bits in the DAIF (Disable Asynchronous Interrupts Flags) register to 1, effectively masking all interrupts and exceptions + asm volatile("msr DAIFSet, 0xf"); + + // Declare and initialize a variable to store the value of SPSR_EL1 (Saved Program Status Register for Exception Level 1) + unsigned long long spsr_el1 = 0; + + // Read the value of SPSR_EL1 into the variable spsr_el1 + asm volatile("mrs %0, spsr_el1":"=r"(spsr_el1)); + + // Transmit the value of SPSR_EL1 over UART + uart_send_str("spsr_el1: "); + uart_binary_to_hex(spsr_el1); + uart_send_str("\r\n"); + + // Declare and initialize a variable to store the value of ELR_EL1 (Exception Link Register for Exception Level 1) + unsigned long long elr_el1 = 0; + + // Read the value of ELR_EL1 into the variable elr_el1 + asm volatile("mrs %0, elr_el1":"=r"(elr_el1)); + + // Transmit the value of ELR_EL1 over UART + uart_send_str("elr_el1: "); + uart_binary_to_hex(elr_el1); + uart_send_str("\r\n"); + + // Declare and initialize a variable to store the value of ESR_EL1 (Exception Syndrome Register for Exception Level 1) + unsigned long long esr_el1 = 0; + + // Read the value of ESR_EL1 into the variable esr_el1 + asm volatile("mrs %0, esr_el1":"=r"(esr_el1)); + + // Transmit the value of ESR_EL1 over UART + uart_binary_to_hex(esr_el1); + uart_send_str("\r\n"); + + // Extract and transmit the value of EC (Exception Class) from ESR_EL1 over UART + unsigned ec = (esr_el1 >> 26) & 0x3F; // Extract the EC field from bits 32 to 26 in ESR_EL1 + uart_send_str("ec: "); + uart_binary_to_hex(ec); + uart_send_str("\n"); + + // Clear all bits in the DAIF register, allowing interrupts and exceptions to be taken again + asm volatile("msr DAIFClr, 0xf"); + + while (1) { + + } +} + +void irq_except_handler_c() { + // part 2 + // asm volatile("msr DAIFSet, 0xf"); + // uart_send_str("In timer interruption\n"); + // unsigned long long cntpct_el0 = 0;//The register count secs with frequency + // asm volatile("mrs %0,cntpct_el0":"=r"(cntpct_el0)); + // unsigned long long cntfrq_el0 = 0;//The base frequency + // asm volatile("mrs %0,cntfrq_el0":"=r"(cntfrq_el0)); + // unsigned long long sec = cntpct_el0 / cntfrq_el0; + // uart_send_str("sec:");//except_handler_c + // uart_binary_to_hex(sec); + // uart_send_str("\n"); + // unsigned long long wait = cntfrq_el0 * 2;// wait 2 seconds + // asm volatile ("msr cntp_tval_el0, %0"::"r"(wait));//set new timer + // asm volatile("msr DAIFClr, 0xf"); + + // part3 + // from aux && from GPU0 -> uart exception + // if(*IRQ_PENDING_1 & (1<<29) &&*CORE0_INTERRUPT_SOURCE & (1 << 8)) + // { + // if (*AUX_MU_IIR & 0x4) { + // uart_rx_interrupt_disable(); + // uart_rx_handler(); + // // uart_puts("pop task1\n"); + // } + // if (*AUX_MU_IIR & 0x2) { + // uart_tx_interrupt_disable(); + // // pop_task(); + // uart_tx_handler(); + // } + // } + // else if (*CORE0_INTERRUPT_SOURCE & (1 << 1)) { + // core_timer_interrupt_disable(); + // *CORE0_TIMER_IRQ_CTRL_ = 0; + // core_timer_handler(); + // core_timer_interrupt_enable(); + // } + + //final + // see p13 + if(*IRQ_PENDING_1 & (1<<29) && *CORE0_INTERRUPT_SOURCE & (1 << 8)) + { + if (*AUX_MU_IIR & 0x4) { + uart_rx_interrupt_disable(); + add_task(uart_rx_handler, 2); + run_task(); + } + if (*AUX_MU_IIR & 0x2) { + uart_tx_interrupt_disable(); + add_task(uart_tx_handler, 1); + run_task(); + } + } + else if (*CORE0_INTERRUPT_SOURCE & (1 << 1)) { + core_timer_interrupt_disable(); + add_task(core_timer_handler, 0); + run_task(); + core_timer_interrupt_enable(); + } +} diff --git a/lab3/shell/linker.ld b/lab3/shell/linker.ld new file mode 100644 index 000000000..9bff61183 --- /dev/null +++ b/lab3/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/lab3/shell/mailbox.c b/lab3/shell/mailbox.c new file mode 100644 index 000000000..2ef732242 --- /dev/null +++ b/lab3/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/lab3/shell/main.c b/lab3/shell/main.c new file mode 100644 index 000000000..0189224db --- /dev/null +++ b/lab3/shell/main.c @@ -0,0 +1,48 @@ +#include "header/utils.h" +#include "header/uart.h" +#include "header/shell.h" +#include "header/cpio.h" +#include "header/dtb.h" +#include "header/uart.h" +#include "header/timer.h" +#include "header/task.h" +extern char *dtb_base; +int main(char *arg){ + register unsigned long long x21 asm("x21"); + // pass by x21 reg + dtb_base = (char*)x21; + + // // print addresses + // unsigned long el = 0; + // asm volatile ("mrs %0, CurrentEL":"=r"(el)); + // uart_send_str("Current exception level: "); + // uart_binary_to_hex(el>>2); // CurrentEL store el level at [3:2] + // uart_send_str("\n"); + // asm volatile("mov %0, sp"::"r"(el)); + // uart_send_str("Current stack pointer address: "); + // uart_binary_to_hex(el); + // uart_send_str("\n"); + + // fdt init + fdt_traverse(initramfs_callback); + uart_init(); + irqtask_list_init(); + timer_list_init(); + + uart_send_str("\x1b[2J\x1b[H"); + + // init interrupt + // enable_timer(); + uart_interrupt_enable(); + asm volatile("msr DAIFClr, 0xf"); + core_timer_interrupt_enable(); + core_timer_interrupt_disable_alternative(); + + + + char *s = "Type in `help` to get instruction menu!\r\n"; + uart_send_str(s); + + shell(); + return 0; +} \ No newline at end of file diff --git a/lab3/shell/makefile b/lab3/shell/makefile new file mode 100644 index 000000000..e3b1a1901 --- /dev/null +++ b/lab3/shell/makefile @@ -0,0 +1,32 @@ +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) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +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) $(DEP_FILES) + +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/lab3/shell/malloc.c b/lab3/shell/malloc.c new file mode 100644 index 000000000..2f1e2586d --- /dev/null +++ b/lab3/shell/malloc.c @@ -0,0 +1,11 @@ +#include"header/malloc.h" +extern char __heap_start; +char *top = &__heap_start; +void* simple_malloc(unsigned long size) { + char* r = top + 0x10; + // size paddling to multiple of 0x10 + size = 0x10 + size - size % 0x10; + *(unsigned long*)(r - 0x8) = size; + top += size; + return r; +} \ No newline at end of file diff --git a/lab3/shell/reboot.c b/lab3/shell/reboot.c new file mode 100644 index 000000000..089d71dcb --- /dev/null +++ b/lab3/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/lab3/shell/shell.c b/lab3/shell/shell.c new file mode 100644 index 000000000..f330bdac2 --- /dev/null +++ b/lab3/shell/shell.c @@ -0,0 +1,149 @@ +#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" +#include"header/timer.h" +#include"header/task.h" +void shell(){ + while (1) + { + char cmd[20]; + for(int i = 0;i < 20; i++){ + cmd[20] = '\0'; + } + char *cur; + 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; + } + else{ + *cur = receive; + uart_send_char(receive); + cur++; + } + } + choose_opt(cmd); + } +} +void choose_opt(char *cmd){ + char arg[20][20]; + for(int i = 0;i < 20;i++){ + for(int j = 0;j < 20;j++){ + arg[i][j] = '\0'; + } + } + char *tk = strtok(cmd," "); + int i = 0; + for(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 [dir]\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"); + uart_send_str("async\t\t:asynchronous uart I/O\r\n"); + uart_send_str("timeout\t\t:timeout [message] [seconds]\r\n"); + uart_send_str("preemtion\t\t: preemtion testing\r\n"); + } + else if(string_compare(arg[0],"hello")){ + uart_send_str("\r\nHello World!\r\n"); + } + else if(string_compare(arg[0],"info")){ + uart_send_str("\r\nInfo:\r\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("\r\n"); + ls("."); + } + else if(string_compare(arg[0],"cat")){ + uart_send_str("\r\n"); + cat(arg[1]); + } + else if (string_compare(arg[0],"reboot")) { + uart_send_str("\r\nRebooting....\r\n"); + reset(1000); + } + else if (string_compare(arg[0],"malloc")){ + uart_send_str("\r\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("\r\n"); + } + else if (string_compare(arg[0],"exec")){ + uart_send_str("\r\nexecute file: "); + uart_send_str(arg[1]); + uart_send_str("...\r\n"); + execfile(arg[1]); + } + else if (string_compare(arg[0], "async")){ + uart_send_str("\r\nasync begin....\r\n"); + char c = 0; + uart_clear_buffers(); + while (1) { + c = uart_async_getc(); + if (c == 13 || c == 10) { + break; + } + + uart_async_putc(c); + } + uart_send_str("\r\n"); + } + else if(string_compare(arg[0], "timeout")){ + if(i != 3){ + uart_send_str("\r\nusage\t:timeout [message] [seconds]\r\n"); + } + else + { + core_timer_interrupt_enable(); + unsigned long long cntpct = 0, cntfrq = 0; + asm volatile("mrs %0, cntpct_el0\n\t" : "=r"(cntpct)); + asm volatile("mrs %0, cntfrq_el0\n\t" : "=r"(cntfrq)); + // add_timer(uart_send_str, atoi(arg[2])*cntfrq + cntpct, arg[1]); + add_timer(uart_send_str, atoi(arg[2]), arg[1]); + } + uart_send_str("\r\n"); + } + else if (string_compare(arg[0], "preempt")){ + uart_async_puts("\r\npreemption testing....\r\n"); + test_preempt(); + uart_async_puts("\r\n"); + } + else + uart_send_str("\r\n"); +} diff --git a/lab3/shell/shell_init.S b/lab3/shell/shell_init.S new file mode 100644 index 000000000..927033e40 --- /dev/null +++ b/lab3/shell/shell_init.S @@ -0,0 +1,158 @@ +.section ".text" + +.global _start + +_start: + mrs x1, mpidr_el1 // read the MPIDR_EL1 register; mrs = move from system register + and x1, x1, #0x3 + cbz x1, cpu0 // cbz = compare and branch if zero; if x0 is zero, branch to cpu0 + +halt: + wfe // wait for event + b halt + +cpu0: + mov x21, x0 + bl from_el2_to_el1 + bl set_exception_vector_table + + ldr x1, =_start // load the address of _start into x0 + mov sp, x1 // set the stack pointer to the address of _start + ldr x1, =__bss_start // load the address of __bss_start into x0 + ldr w2, =__bss_size + +clear_bss: + cbz w2, kernel_main + str xzr, [x1], #8 // store zero to the address in x0, then increment x0 by 8 + sub w2, w2, #1 + cbnz w2, clear_bss + +kernel_main: + bl main // jump to C code + b halt + +from_el2_to_el1: + mov x0, (1 << 31) + msr hcr_el2, x0 + mov x0, 0x3c5 + msr spsr_el2, x0 + msr elr_el2, lr + eret +// 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] + // for nested interrupt + mrs x0, spsr_el1 + str x0, [sp, 16 * 16] + mrs x0, elr_el1 + str x0, [sp, 16 * 17] + ldp x0, x1, [sp, 16 * 0] // restore x0, x1 +.endm + +// load general registers from stack +.macro load_all + ldp x0, x1, [sp ,16 * 0] + ldp x2, x3, [sp ,16 * 1] + ldp x4, x5, [sp ,16 * 2] + ldp x6, x7, [sp ,16 * 3] + ldp x8, x9, [sp ,16 * 4] + ldp x10, x11, [sp ,16 * 5] + ldp x12, x13, [sp ,16 * 6] + ldp x14, x15, [sp ,16 * 7] + ldp x16, x17, [sp ,16 * 8] + ldp x18, x19, [sp ,16 * 9] + ldp x20, x21, [sp ,16 * 10] + ldp x22, x23, [sp ,16 * 11] + ldp x24, x25, [sp ,16 * 12] + ldp x26, x27, [sp ,16 * 13] + ldp x28, x29, [sp ,16 * 14] + ldr x30, [sp, 16 * 15] + // for nested interrupt + ldr x0, [sp, 16 * 16] + msr spsr_el1, x0 + ldr x0, [sp, 16 * 17] + msr elr_el1, x0 + ldp x0, x1, [sp, 16 * 0] // restore x0, x1 + + add sp, sp, 32 * 9 // nested loop got one more item to save + + +.endm + +exception_handler: + save_all + bl except_handler_c + load_all + eret + +invalid_handler: + save_all + //bl except_handler_c + load_all + eret + +irq_exception_handler: + save_all + bl irq_except_handler_c + load_all + eret + +.align 11 // vector table should be aligned to 0x800, to a 2^11 = 2048-byte boundary. +.global exception_vector_table +exception_vector_table: + b invalid_handler // branch to a handler function. + .align 7 // entry size is 0x80, .align will pad 0, 2^7 = 128-byte boundary. + b invalid_handler + .align 7 + b invalid_handler + .align 7 + b invalid_handler + .align 7 + + b invalid_handler + .align 7 + b irq_exception_handler + .align 7 + b invalid_handler + .align 7 + b invalid_handler + .align 7 + + b exception_handler + .align 7 + b irq_exception_handler + .align 7 + b invalid_handler + .align 7 + b invalid_handler + .align 7 + + b invalid_handler + .align 7 + b invalid_handler + .align 7 + b invalid_handler + .align 7 + b invalid_handler + .align 7 + +set_exception_vector_table: + adr x0, exception_vector_table + msr vbar_el1, x0 + ret \ No newline at end of file diff --git a/lab3/shell/task.c b/lab3/shell/task.c new file mode 100644 index 000000000..9a0120da5 --- /dev/null +++ b/lab3/shell/task.c @@ -0,0 +1,87 @@ +#include "header/task.h" +#include "header/list.h" +#include "header/malloc.h" +#include "header/uart.h" + +int curr_task_priority = 100; +task *task_list = 0; + +void irqtask_list_init(){ + task_list = 0; +} +void add_task(void *task_function, int priority){ + asm volatile("msr DAIFSet, 0xf"); + // make new node + task *cur = simple_malloc(sizeof(task)); + cur -> task_function = task_function; + cur -> priority = priority; + + // enqueue + asm volatile("msr DAIFSet, 0xf"); + // insert if task list is empty + if(task_list == 0 || cur->priority < task_list -> priority){ + cur -> next = task_list; + cur -> prev = 0; + if(task_list == 0){ + task_list -> prev = cur; + } + task_list = cur; + } + // find place to insert + else{ + task *node = task_list; + while (node -> next != 0 && node -> next -> priority <= cur ->priority) { + node = node -> next; + } + cur -> prev = node; + cur -> next = node -> next; + if(node -> next != 0){ + node -> next -> prev = cur; + } + node -> next = cur; + } + asm volatile("msr DAIFClr, 0xf"); + asm volatile("msr DAIFClr, 0xf"); +} + +void run_task(){ + asm volatile("msr DAIFClr, 0xf"); + while (task_list) { + asm volatile("msr DAIFSet, 0xf"); + task *tar = task_list; + if(curr_task_priority <= tar->priority){ + asm volatile("msr DAIFClr, 0xf"); + break; + } + // moving + task_list = task_list->next; + // removing prev task as it will be exec + if(task_list) + task_list -> prev = 0; + int prev_prio = curr_task_priority; + curr_task_priority = tar->priority; + // exec task + asm volatile("msr DAIFClr, 0xf"); + ((void (*)())tar->task_function)(); + asm volatile("msr DAIFSet, 0xf"); + + curr_task_priority = prev_prio; + asm volatile("msr DAIFClr, 0xf"); + } + +} + +void high_prio(){ + uart_async_puts("\r\nhigh priority testing\r\n"); + for(int i = 0;i<10000;i++); + uart_async_puts("high priority end\r\n"); +} +void low_prio(){ + uart_async_puts("\r\nlow priority testing\r\n"); + for(int i = 0;i<10000;i++); + uart_async_puts("low priority end\r\n"); +} +void test_preempt(){ + add_task(low_prio, 9); + add_task(high_prio, 0); +} diff --git a/lab3/shell/timer.c b/lab3/shell/timer.c new file mode 100644 index 000000000..d7be97771 --- /dev/null +++ b/lab3/shell/timer.c @@ -0,0 +1,114 @@ +#include"header/timer.h" +#include "header/malloc.h" +#include "header/utils.h" + +// struct list_head* timer_event_list; // first head has nothing, store timer_event_t after it +timer *timer_list = 0; + +void core_timer_interrupt_enable(){ + asm volatile("mov x1, 1\n\t");//The purpose of this instruction depends on the context of the program. Typically, it's used to prepare data or a control signal for subsequent operations. + asm volatile("msr cntp_ctl_el0, x1\n\t");//This register often controls various aspects of the timer in ARM architectures, such as enabling or disabling it. + asm volatile("mov x2, 2\n\t");// prepares a value for subsequent operations. + asm volatile("ldr x1, =" XSTR(CORE0_TIMER_IRQ_CTRL) "\n\t");//memory-mapped control register related to the timer's interrupt control. + asm volatile("str w2, [x1]\n\t");//The value in register w2 (lower 32 bits of x2) is stored into the memory location pointed to by x1. This effectively writes the value 2 to the memory-mapped control register represented by CORE0_TIMER_IRQ_CTRL. +} +void core_timer_interrupt_disable(){ + asm volatile("mov x2, 0\n\t");//The purpose of this operation depends on the context of the program. Register x2 may be used as a general-purpose register to hold data or addresses. + asm volatile("ldr x1, =" XSTR(CORE0_TIMER_IRQ_CTRL) "\n\t");// ads the address of a symbol named CORE0_TIMER_IRQ_CTRL into register x1. The symbol likely represents the memory-mapped control register related to the timer's interrupt control. The = operator with ldr instruction is typically used to load an address directly into a register. + asm volatile("str w2, [x1]\n\t");//tored into the memory location pointed to by x1. This effectively writes the value 0 to the memory-mapped control register represented by CORE0_TIMER_IRQ_CTRL +} +void core_timer_interrupt_disable_alternative() { + unsigned long long sec = 0xFFFFFFFFFFFFFFFF; + // unsigned long long sec = 10000; + asm volatile("msr cntp_cval_el0, %0" ::"r"(sec)); +} + +unsigned long long get_tick_plus_s(unsigned long long second){ + unsigned long long cntpct_el0=0; + __asm__ __volatile__("mrs %0, cntpct_el0\n\t": "=r"(cntpct_el0)); // tick auchor + unsigned long long cntfrq_el0=0; + __asm__ __volatile__("mrs %0, cntfrq_el0\n\t": "=r"(cntfrq_el0)); // tick frequency + return (cntpct_el0 + cntfrq_el0*second); +} +void set_core_timer_interrupt(unsigned long long sec){ + + //part 2 + // core_timer_interrupt_disable_alternative(); + + //part 4 + __asm__ __volatile__( + "mrs x1, cntfrq_el0\n\t" // cntfrq_el0 -> frequency of the timer + "mul x1, x1, %0\n\t" // cntpct_el0 = cntfrq_el0 * seconds: relative timer to cntfrq_el0 + "msr cntp_tval_el0, x1\n\t" // Set expired time to cntp_tval_el0, which stores time value of EL1 physical timer. + :"=r" (sec)); +} + +void timer_list_init(){ + // INIT_LIST_HEAD(timer_event_list); + timer_list = 0; +} + +void add_timer(void* callback, unsigned long long timeout, char* args){ + // create timer node + timer* event = simple_malloc(sizeof(timer)); + // storing + event->args = simple_malloc(strlen(args)+1); + strcpy(event -> args,args); + event->interrupt_time = timeout; + event->callback = callback; + // add the event into timer_list (sorted) + timer* cur = timer_list; + asm volatile("msr DAIFSet, 0xf"); + // insert while list empty or the smallest + if(timer_list == 0 || timer_list->interrupt_time > event->interrupt_time){ + event -> next = timer_list; + event -> prev = 0; + if(timer_list != 0){ + timer_list -> prev = event; + } + timer_list = event; + set_core_timer_interrupt(timer_list->interrupt_time); + } + else { + while (cur->next != 0 && cur->next->interrupt_time < event->interrupt_time) { + cur = cur->next; + } + event->next = cur -> next; + event->prev = cur; + if(cur->next != 0){ + cur->next->prev = event; + } + cur->next = event; + } + asm volatile("msr DAIFClr, 0xf"); +} + +void poptimer(){ + asm volatile("msr DAIFSet, 0xf"); + while (timer_list) { + timer *cur = timer_list; + ((void (*)())cur->callback)(cur->args); + timer_list = timer_list->next; + cur = timer_list; + timer_list -> prev = 0; + if(timer_list == 0) + { + core_timer_interrupt_disable_alternative();// disable timer interrupt (set a very big value) + } + else + { + set_core_timer_interrupt(cur->interrupt_time); + } + } + asm volatile("msr DAIFClr, 0xf"); +} + +void core_timer_handler(){ + if (timer_list == 0) + { + core_timer_interrupt_disable_alternative(); // disable timer interrupt (set a very big value) + return; + } + poptimer(); // do callback and set new interrupt + +} \ No newline at end of file diff --git a/lab3/shell/uart.c b/lab3/shell/uart.c new file mode 100644 index 000000000..eb87c3451 --- /dev/null +++ b/lab3/shell/uart.c @@ -0,0 +1,207 @@ +#include "header/uart.h" + +/* + * Auxilary mini UART registers + * ref: https://cs140e.sergio.bz/docs/BCM2837-ARM-Peripherals.pdf (p. 8) + */ +#define AUX_BASE (MMIO_BASE + 0x215000) +#define AUX_ENABLE ((volatile unsigned int *)(AUX_BASE + 0x04)) +#define AUX_MU_IO ((volatile unsigned int *)(AUX_BASE + 0x40)) // for io data +#define AUX_MU_IER ((volatile unsigned int *)(AUX_BASE + 0x44)) +#define AUX_MU_IIR ((volatile unsigned int *)(AUX_BASE + 0x48)) // for interrupt identify +#define AUX_MU_LCR ((volatile unsigned int *)(AUX_BASE + 0x4C)) +#define AUX_MU_MCR ((volatile unsigned int *)(AUX_BASE + 0x50)) +#define AUX_MU_LSR ((volatile unsigned int *)(AUX_BASE + 0x54)) +#define AUX_MU_MSR ((volatile unsigned int *)(AUX_BASE + 0x58)) +#define AUX_MU_SCRATCH ((volatile unsigned int *)(AUX_BASE + 0x5C)) +#define AUX_MU_CNTL ((volatile unsigned int *)(AUX_BASE + 0x60)) +#define AUX_MU_STAT ((volatile unsigned int *)(AUX_BASE + 0x64)) +#define AUX_MU_BAUD ((volatile unsigned int *)(AUX_BASE + 0x68)) + +//p112 +#define ENABLE_IRQS_1 ((volatile unsigned int *)(MMIO_BASE + 0xB210)) +#define DISABLE_IRQS_1 ((volatile unsigned int *)(MMIO_BASE + 0xB21C)) +#define BUFFER_SIZE 1024 +char uart_tx_buffer[BUFFER_SIZE]; +char uart_rx_buffer[BUFFER_SIZE]; +unsigned int uart_tx_buffer_head = 0; +unsigned int uart_tx_buffer_tail = 1; +unsigned int uart_rx_buffer_head = 0; +unsigned int uart_rx_buffer_tail = 1; + +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; + *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 +} + +void uart_send_char(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; +} + +char uart_get_char() +{ + 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 carrige return to newline */ + return r == '\r' ? '\n' : r; +} + +void uart_send_str(char *s) +{ + while (*s) { + /* convert newline to carrige return + newline */ + if (*s == '\n') { + uart_send_char('\r'); + } + uart_send_char(*s++); + } +} + +void uart_binary_to_hex(unsigned int d) +{ + uart_send_str("0x"); + unsigned int n; + for (int c = 28; c >= 0; c -= 4) { + n = (d >> c) & 0xF; + n += n > 9 ? 0x57 : 0x30; + uart_send_char(n); + } + uart_send_str("\n"); +} + + +void uart_interrupt_enable() +{ + // ref: https://cs140e.sergio.bz/docs/BCM2837-ARM-Peripherals.pdf (p. 12) + *AUX_MU_IER |= 0x1; // enable rx interrupt + *AUX_MU_IER |= 0x2; // enable tx interrupt + *ENABLE_IRQS_1 |= 1 << 29; // enable mini uart interrupt +} + +void uart_interrupt_disable() +{ + *AUX_MU_IER &= ~0x1; // disable rx interrupt + *AUX_MU_IER &= ~0x2; // disable tx interrupt + *ENABLE_IRQS_1 &= ~(1 << 29); // disable mini uart interrupt +} + +void uart_rx_interrupt_enable() { *AUX_MU_IER |= 0x1; } + +void uart_rx_interrupt_disable() { *AUX_MU_IER &= ~0x1; } + +void uart_tx_interrupt_enable() { *AUX_MU_IER |= 0x2; } + +void uart_tx_interrupt_disable() { *AUX_MU_IER &= ~0x2; } + +void uart_rx_handler() +{ + if ((uart_rx_buffer_head + 1) % BUFFER_SIZE == uart_rx_buffer_tail) { // checks if the next position in the receive buffer (uart_rx_buffer_head + 1) would overlap with the current tail of the buffer (uart_rx_buffer_tail). + uart_rx_interrupt_disable(); // disable read interrupt + return; + } + + uart_rx_buffer[uart_rx_buffer_head] = (char)(*AUX_MU_IO); // receive data, reads a character from the UART receive register (*AUX_MU_IO) and stores it in the receive buffer at the current head position (uart_rx_buffer[uart_rx_buffer_head]). + uart_rx_buffer_head = (uart_rx_buffer_head + 1) % BUFFER_SIZE; //Update Buffer Head Pointer: (uart_rx_buffer_head + 1) % BUFFER_SIZE ensures that the head pointer wraps around to the beginning of the buffer if it reaches the end (BUFFER_SIZE) to implement a circular buffer. +} + +void uart_tx_handler() +{ + if (uart_tx_buffer_head == uart_tx_buffer_tail) { // check buffer is empty or not, if empty nothing to write + uart_tx_interrupt_disable(); // disable write interrupt + return; + } + + asm volatile("msr DAIFSet, 0xf"); + uart_send_char(uart_tx_buffer[uart_tx_buffer_tail]); // send last character of writing buffer + uart_tx_buffer_tail = (uart_tx_buffer_tail + 1) % BUFFER_SIZE; // ensures that the tail pointer wraps around to the beginning of the buffer if it reaches the end (BUFFER_SIZE) to implement a circular buffer. + asm volatile("msr DAIFClr, 0xf"); + uart_tx_interrupt_enable(); +} + +void uart_async_puts(char *s) +{ + while ((uart_tx_buffer_head + 1) % BUFFER_SIZE == uart_tx_buffer_tail) + uart_tx_interrupt_enable(); + + asm volatile("msr DAIFSet, 0xf"); + while (*s) { + uart_tx_buffer[uart_tx_buffer_head++] = *s++; + uart_tx_buffer_head %= BUFFER_SIZE; + } + asm volatile("msr DAIFClr, 0xf"); + + uart_tx_interrupt_enable(); +} + +void uart_async_putc(char c) +{ + while ((uart_tx_buffer_head + 1) % BUFFER_SIZE == uart_tx_buffer_tail) // check list is full or not by comparing head+1 & tail + uart_tx_interrupt_enable(); // if not enable writing interrupt to enable writing handler start writing interrupt + // below is + asm volatile("msr DAIFSet, 0xf"); + uart_tx_buffer[uart_tx_buffer_head++] = c; // store c at current head position and increase one for next position + uart_tx_buffer_head %= BUFFER_SIZE; // avoid index out of range + asm volatile("msr DAIFClr, 0xf"); + + uart_tx_interrupt_enable(); +} + +char uart_async_getc() +{ + while ((uart_rx_buffer_tail == uart_rx_buffer_head)) // check if reading buffer is empty + uart_rx_interrupt_enable(); // if empty enable reading handler to start reading + + asm volatile("msr DAIFSet, 0xf"); + char c = uart_rx_buffer[uart_rx_buffer_tail]; // get a byte from rx buffer + uart_rx_buffer_tail = (uart_rx_buffer_tail + 1) % BUFFER_SIZE; // avoid index out of range + asm volatile("msr DAIFClr, 0xf"); + + return c; +} + +void uart_clear_buffers() +{ + for (int i = 0; i < BUFFER_SIZE; i++) { + uart_rx_buffer[i] = '\0'; + uart_tx_buffer[i] = '\0'; + } +} \ No newline at end of file diff --git a/lab3/shell/utils.c b/lab3/shell/utils.c new file mode 100644 index 000000000..534e2218c --- /dev/null +++ b/lab3/shell/utils.c @@ -0,0 +1,116 @@ +#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) { + const char *sc; + for (sc = s; *sc != '\0'; ++sc) + ; + return sc - s; +} + +unsigned int atoi(char* str) +{ + // Initialize result + unsigned int res = 0; + + // Iterate through all characters + // of input string and update result + // take ASCII character of corresponding digit and + // subtract the code from '0' to get numerical + // value and multiply res by 10 to shuffle + // digits left to update running total + for (int i = 0; str[i] != '\0'; ++i) + { + if(str[i] > '9' || str[i] < '0')return res; + res = res * 10 + str[i] - '0'; + } + // return result. + return res; +} \ No newline at end of file diff --git a/lab3/user program/linker.ld b/lab3/user program/linker.ld new file mode 100644 index 000000000..47697d773 --- /dev/null +++ b/lab3/user program/linker.ld @@ -0,0 +1,16 @@ +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*/ + + _end = .; /* Define _end symbol as the current memory address*/ +} + diff --git a/lab3/user program/makefile b/lab3/user program/makefile new file mode 100644 index 000000000..2354f0fb7 --- /dev/null +++ b/lab3/user program/makefile @@ -0,0 +1,13 @@ +all: one.img + +one.o: testing.S + aarch64-linux-gnu-gcc -c testing.S -o one.o + +one.img: one.o + aarch64-linux-gnu-ld one.o -T linker.ld -o one.elf + aarch64-linux-gnu-objcopy -O binary one.elf one.img + +clean: + rm one.o one.elf > /dev/null 2>/dev/null || true +cimg: + rm one.img \ No newline at end of file diff --git a/lab3/user program/testing b/lab3/user program/testing new file mode 100644 index 000000000..ffa21c03a --- /dev/null +++ b/lab3/user program/testing @@ -0,0 +1,7 @@ +.section ".text" +.global _start +_start: + svc 0x1337 +1: + nop + b 1b \ No newline at end of file diff --git a/lab3/user program/testing.S b/lab3/user program/testing.S new file mode 100644 index 000000000..66db5a6e8 --- /dev/null +++ b/lab3/user program/testing.S @@ -0,0 +1,14 @@ +.section ".text" // Directs the assembler to place the following code in the ".text" section +.global _start // Makes _start globally accessible, typically the entry point in bare-metal programming +_start: // Label marking the start of the executable code + + mov x0, 0 // Initializes register x0 to 0; x0 will be used as a loop counter + +1: // Label "1" marks the beginning of the first loop + add x0, x0, 1 // Increments the value in x0 by 1 + svc 0 // Performs a supervisor call with immediate value 0 (used here for demonstration) + cmp x0, 5 // Compares the value in x0 to 5 + blt 1b // Branches back to label "1" if x0 is less than 5, continuing the loop + +1: // Another label "1", re-used for clarity, marking the start of an infinite loop + b 1b // Unconditionally branches to itself, creating an infinite loop diff --git a/lab3/writer.py b/lab3/writer.py new file mode 100644 index 000000000..738cc1871 --- /dev/null +++ b/lab3/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