diff --git a/Lab8/archive/app4/app4.c b/Lab8/archive/app4/app4.c new file mode 100644 index 000000000..0657704af --- /dev/null +++ b/Lab8/archive/app4/app4.c @@ -0,0 +1,15 @@ +#include "inc/syscall.h" + +int main(int argc,char** argv){ + int fd=open(argv[1],0); + char name[100]; + int size; + while(1){ + size=read(fd,name,100); + name[size]=0; + if(size==0)break; + uart_printf("Name: %s, Size: %d\n",name,size); + } + + exit(); +} \ No newline at end of file diff --git a/Lab8/archive/app4/inc/printf.c b/Lab8/archive/app4/inc/printf.c new file mode 100644 index 000000000..b37854c5f --- /dev/null +++ b/Lab8/archive/app4/inc/printf.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +/** + * minimal sprintf implementation + */ +unsigned int vsprintf(char *dst, char* fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig=dst, tmpstr[19]; + + // failsafes + if(dst==(void*)0 || fmt==(void*)0) { + return 0; + } + + // main loop + arg = 0; + while(*fmt) { + // argument access + if(*fmt=='%') { + fmt++; + // literal % + if(*fmt=='%') { + goto put; + } + len=0; + // size modifier + while(*fmt>='0' && *fmt<='9') { + len *= 10; + len += *fmt-'0'; + fmt++; + } + // skip long modifier + if(*fmt=='l') { + fmt++; + } + // character + if(*fmt=='c') { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } else + // decimal number + if(*fmt=='d') { + arg = __builtin_va_arg(args, int); + // check input + sign=0; + if((int)arg<0) { + arg*=-1; + sign++; + } + if(arg>99999999999999999L) { + arg=99999999999999999L; + } + // convert to string + i=18; + tmpstr[i]=0; + do { + tmpstr[--i]='0'+(arg%10); + arg/=10; + } while(arg!=0 && i>0); + if(sign) { + tmpstr[--i]='-'; + } + // padding, only space + if(len>0 && len<18) { + while(i>18-len) { + tmpstr[--i]=' '; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // hex number + if(*fmt=='x') { + arg = __builtin_va_arg(args, long int); + // convert to string + i=16; + tmpstr[i]=0; + do { + char n=arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i]=n+(n>9?0x37:0x30); + arg>>=4; + } while(arg!=0 && i>0); + // padding, only leading zeros + if(len>0 && len<=16) { + while(i>16-len) { + tmpstr[--i]='0'; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // string + if(*fmt=='s') { + p = __builtin_va_arg(args, char*); +copystring: if(p==(void*)0) { + p="(null)"; + } + while(*p) { + *dst++ = *p++; + } + } + } else { +put: *dst++ = *fmt; + } + fmt++; + } + *dst=0; + // number of bytes written + return dst-orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char* fmt, ...) +{ + //__builtin_va_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst,fmt,args); +} \ No newline at end of file diff --git a/Lab8/archive/app4/inc/printf.h b/Lab8/archive/app4/inc/printf.h new file mode 100644 index 000000000..101e564e3 --- /dev/null +++ b/Lab8/archive/app4/inc/printf.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); \ No newline at end of file diff --git a/Lab8/archive/app4/inc/syscall.c b/Lab8/archive/app4/inc/syscall.c new file mode 100644 index 000000000..13e7370c9 --- /dev/null +++ b/Lab8/archive/app4/inc/syscall.c @@ -0,0 +1,103 @@ +#include "syscall.h" +#include "printf.h" + +void delay(int cnt){ + while(cnt>0)cnt--; +} + +int getpid(){ + long ret; + asm volatile("\ + svc 1\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} + +int uart_read(char* buf,int size){ + long ret; + asm volatile("\ + svc 2\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} + +int uart_write(char* buf,int size){ + long ret; + asm volatile("\ + svc 3\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} + +unsigned int uart_printf(char* fmt,...){ + char dst[100]; + //__builtin_va_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args,fmt); + unsigned int ret=vsprintf(dst,fmt,args); + uart_write(dst,ret); + return ret; +} + +int exec(char* name,char** argv){ + long ret; + asm volatile("\ + svc 4\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} + +void exit(){ + asm volatile("svc 5\n"::); + while(1){} +} + +int fork(){ + long ret; + asm volatile("\ + svc 6\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} + +int open(const char *pathname,int flags){ + long ret; + asm volatile("\ + svc 7\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} + +int close(int fd){ + long ret; + asm volatile("\ + svc 8\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} + +int write(int fd,const void *buf,int count){ + long ret; + asm volatile("\ + svc 9\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} + +int read(int fd,void *buf,int count){ + long ret; + asm volatile("\ + svc 10\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} \ No newline at end of file diff --git a/Lab8/archive/app4/inc/syscall.h b/Lab8/archive/app4/inc/syscall.h new file mode 100644 index 000000000..33031b0f3 --- /dev/null +++ b/Lab8/archive/app4/inc/syscall.h @@ -0,0 +1,14 @@ +#define O_CREAT 2 + +void delay(int cnt); +int getpid(); +int uart_read(char* buf,int size); +int uart_write(char* buf,int size); +unsigned int uart_printf(char* fmt,...); +int exec(char* name,char** argv); +void exit(); +int fork(); +int open(const char *pathname,int flags); +int close(int fd); +int write(int fd,const void *buf,int count); +int read(int fd,void *buf,int count); \ No newline at end of file diff --git a/Lab8/archive/app4/linker.ld b/Lab8/archive/app4/linker.ld new file mode 100644 index 000000000..284d50338 --- /dev/null +++ b/Lab8/archive/app4/linker.ld @@ -0,0 +1,16 @@ +SECTIONS +{ + . = 0x70000; + __prog_start = .; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } +} +__bss_size = (__bss_end - __bss_start)>>3; diff --git a/Lab8/archive/app4/makefile b/Lab8/archive/app4/makefile new file mode 100644 index 000000000..175e8e4be --- /dev/null +++ b/Lab8/archive/app4/makefile @@ -0,0 +1,25 @@ +.PHONY:all clean +APP:=app4 +LINKER:=linker.ld +CFLAGS:=-nostdinc -nostdlib -nostartfiles +LIBS:=$(wildcard inc/*.c) +OBJS:=$(APP).o $(LIBS:.c=.o) + +all: + make $(APP) + cp $(APP) ../rootfs/$(APP) + cd ..&&make + +$(APP):$(OBJS) + aarch64-linux-gnu-ld -T $(LINKER) -o tmp.elf $(OBJS) + aarch64-linux-gnu-objcopy -O binary tmp.elf $@ + rm tmp.elf + +%.o:%.c + aarch64-linux-gnu-gcc $(CFLAGS) -c $< -o $@ + aarch64-linux-gnu-gcc $(CFLAGS) -S $< + +clean: + -rm $(APP) + -rm $(OBJS) + -rm *.s diff --git a/Lab8/archive/app5/app5.c b/Lab8/archive/app5/app5.c new file mode 100644 index 000000000..7d65d4319 --- /dev/null +++ b/Lab8/archive/app5/app5.c @@ -0,0 +1,22 @@ +#include "inc/syscall.h" + +int main(int argc,char** argv){ + char buffer[101]; + + int fd=open(argv[1],0); + uart_printf("read somthing from %s(fd %d):\n",argv[1],fd); + while(1){ + int ret=read(fd,buffer,100); + if(ret==0)break; + buffer[ret]=0; + uart_printf("%s",buffer); + } + close(fd); + + fd=open(argv[1],0); + uart_printf("\nwrite somthing to %s(fd %d):\n",argv[1],fd); + int len=uart_read(buffer,100); + write(fd,buffer,len); + + exit(); +} diff --git a/Lab8/archive/app5/inc/printf.c b/Lab8/archive/app5/inc/printf.c new file mode 100644 index 000000000..b37854c5f --- /dev/null +++ b/Lab8/archive/app5/inc/printf.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +/** + * minimal sprintf implementation + */ +unsigned int vsprintf(char *dst, char* fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig=dst, tmpstr[19]; + + // failsafes + if(dst==(void*)0 || fmt==(void*)0) { + return 0; + } + + // main loop + arg = 0; + while(*fmt) { + // argument access + if(*fmt=='%') { + fmt++; + // literal % + if(*fmt=='%') { + goto put; + } + len=0; + // size modifier + while(*fmt>='0' && *fmt<='9') { + len *= 10; + len += *fmt-'0'; + fmt++; + } + // skip long modifier + if(*fmt=='l') { + fmt++; + } + // character + if(*fmt=='c') { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } else + // decimal number + if(*fmt=='d') { + arg = __builtin_va_arg(args, int); + // check input + sign=0; + if((int)arg<0) { + arg*=-1; + sign++; + } + if(arg>99999999999999999L) { + arg=99999999999999999L; + } + // convert to string + i=18; + tmpstr[i]=0; + do { + tmpstr[--i]='0'+(arg%10); + arg/=10; + } while(arg!=0 && i>0); + if(sign) { + tmpstr[--i]='-'; + } + // padding, only space + if(len>0 && len<18) { + while(i>18-len) { + tmpstr[--i]=' '; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // hex number + if(*fmt=='x') { + arg = __builtin_va_arg(args, long int); + // convert to string + i=16; + tmpstr[i]=0; + do { + char n=arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i]=n+(n>9?0x37:0x30); + arg>>=4; + } while(arg!=0 && i>0); + // padding, only leading zeros + if(len>0 && len<=16) { + while(i>16-len) { + tmpstr[--i]='0'; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // string + if(*fmt=='s') { + p = __builtin_va_arg(args, char*); +copystring: if(p==(void*)0) { + p="(null)"; + } + while(*p) { + *dst++ = *p++; + } + } + } else { +put: *dst++ = *fmt; + } + fmt++; + } + *dst=0; + // number of bytes written + return dst-orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char* fmt, ...) +{ + //__builtin_va_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst,fmt,args); +} \ No newline at end of file diff --git a/Lab8/archive/app5/inc/printf.h b/Lab8/archive/app5/inc/printf.h new file mode 100644 index 000000000..101e564e3 --- /dev/null +++ b/Lab8/archive/app5/inc/printf.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); \ No newline at end of file diff --git a/Lab8/archive/app5/inc/syscall.c b/Lab8/archive/app5/inc/syscall.c new file mode 100644 index 000000000..13e7370c9 --- /dev/null +++ b/Lab8/archive/app5/inc/syscall.c @@ -0,0 +1,103 @@ +#include "syscall.h" +#include "printf.h" + +void delay(int cnt){ + while(cnt>0)cnt--; +} + +int getpid(){ + long ret; + asm volatile("\ + svc 1\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} + +int uart_read(char* buf,int size){ + long ret; + asm volatile("\ + svc 2\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} + +int uart_write(char* buf,int size){ + long ret; + asm volatile("\ + svc 3\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} + +unsigned int uart_printf(char* fmt,...){ + char dst[100]; + //__builtin_va_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args,fmt); + unsigned int ret=vsprintf(dst,fmt,args); + uart_write(dst,ret); + return ret; +} + +int exec(char* name,char** argv){ + long ret; + asm volatile("\ + svc 4\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} + +void exit(){ + asm volatile("svc 5\n"::); + while(1){} +} + +int fork(){ + long ret; + asm volatile("\ + svc 6\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} + +int open(const char *pathname,int flags){ + long ret; + asm volatile("\ + svc 7\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} + +int close(int fd){ + long ret; + asm volatile("\ + svc 8\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} + +int write(int fd,const void *buf,int count){ + long ret; + asm volatile("\ + svc 9\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} + +int read(int fd,void *buf,int count){ + long ret; + asm volatile("\ + svc 10\n\ + mov %0, x0\n\ + ":"=r"(ret):); + return ret; +} \ No newline at end of file diff --git a/Lab8/archive/app5/inc/syscall.h b/Lab8/archive/app5/inc/syscall.h new file mode 100644 index 000000000..33031b0f3 --- /dev/null +++ b/Lab8/archive/app5/inc/syscall.h @@ -0,0 +1,14 @@ +#define O_CREAT 2 + +void delay(int cnt); +int getpid(); +int uart_read(char* buf,int size); +int uart_write(char* buf,int size); +unsigned int uart_printf(char* fmt,...); +int exec(char* name,char** argv); +void exit(); +int fork(); +int open(const char *pathname,int flags); +int close(int fd); +int write(int fd,const void *buf,int count); +int read(int fd,void *buf,int count); \ No newline at end of file diff --git a/Lab8/archive/app5/linker.ld b/Lab8/archive/app5/linker.ld new file mode 100644 index 000000000..284d50338 --- /dev/null +++ b/Lab8/archive/app5/linker.ld @@ -0,0 +1,16 @@ +SECTIONS +{ + . = 0x70000; + __prog_start = .; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } +} +__bss_size = (__bss_end - __bss_start)>>3; diff --git a/Lab8/archive/app5/makefile b/Lab8/archive/app5/makefile new file mode 100644 index 000000000..0651627c4 --- /dev/null +++ b/Lab8/archive/app5/makefile @@ -0,0 +1,25 @@ +.PHONY:all clean +APP:=app5 +LINKER:=linker.ld +CFLAGS:=-nostdinc -nostdlib -nostartfiles +LIBS:=$(wildcard inc/*.c) +OBJS:=$(APP).o $(LIBS:.c=.o) + +all: + make $(APP) + cp $(APP) ../rootfs/$(APP) + cd ..&&make + +$(APP):$(OBJS) + aarch64-linux-gnu-ld -T $(LINKER) -o tmp.elf $(OBJS) + aarch64-linux-gnu-objcopy -O binary tmp.elf $@ + rm tmp.elf + +%.o:%.c + aarch64-linux-gnu-gcc $(CFLAGS) -c $< -o $@ + aarch64-linux-gnu-gcc $(CFLAGS) -S $< + +clean: + -rm $(APP) + -rm $(OBJS) + -rm *.s diff --git a/Lab8/archive/initramfs.cpio b/Lab8/archive/initramfs.cpio new file mode 100644 index 000000000..4f6c6aac2 Binary files /dev/null and b/Lab8/archive/initramfs.cpio differ diff --git a/Lab8/inc/allocator.c b/Lab8/inc/allocator.c new file mode 100644 index 000000000..cc85d8ff4 --- /dev/null +++ b/Lab8/inc/allocator.c @@ -0,0 +1,262 @@ +#include "allocator.h" +#include "mmio.h" +#include "error.h" +#define debug 0 +#if debug +#include "uart.h" +#endif + +#define A_BASE (KVA+0x10000000) +#define A_SIZE 0x10000000 +#define F_SIZE (1<<12) +#define F_NUM (A_SIZE/F_SIZE) +#define TLEVEL 20 +//A_SIZE=0.2G + +typedef struct{ + int beg,end; + int data[F_NUM+1];//+1 for end +}List; + +int listInsert(List* l,int v){ + int ret=l->end; + l->data[ret]=v; + l->end=(l->end+1)%(F_NUM+1); + return ret;//insert position +} + +int listGet(List* l,int i){ + if((l->beg<=l->end&&(ibeg||i>=l->end))|| + (l->beg>l->end&&(i>=l->end||ibeg)))ERROR("index out of bound!"); + int ret=l->data[i]; + l->data[i]=l->data[l->beg]; + l->beg=(l->beg+1)%(F_NUM+1); + return ret;//item value +} + +static List lists[TLEVEL]; +static int frame_table[F_NUM*2];//record position of list +static unsigned long i2addr[F_NUM*2]; +static int addr2i[F_NUM]; + +int __lg(int v){ + int ret=-1; + while(v){ + ++ret; + v>>=1; + } + return ret; +} + +unsigned long __toAddr(int i){//id!=0 + int root=31; + while(1){ + if(i&(1<=0){ + if(i&(1< (0x%x)\n",i,ret); + #endif + + return ret; +} + +int toIndex(unsigned long addr){ + int ret=addr2i[(addr-A_BASE)/F_SIZE]; + + #if debug + uart_printf("(0x%x) => [0x%x]\n",addr,ret); + #endif + + return ret; +} + +void reclaimFrame(int i){ + #if debug + uart_printf("[0x%x] has been freed.\n",i); + #endif + + int p=i; + int level=__lg(p); + while(frame_table[p^1]>=0){ + //beg will be moved in listGet(), + //so it need to update its bucket position + int beg_id=lists[level].data[lists[level].beg]; + frame_table[beg_id]=frame_table[p^1]; + + listGet(&lists[level],frame_table[p^1]); + frame_table[p^1]=-1; + + #if debug + uart_printf("-[0x%x]&[0x%x] is merged to [0x%x].\n",p,p^1,p/2); + #endif + + p=p/2; + --level; + } + + frame_table[p]=listInsert(&lists[level],p); +} + +int getFrame(int i,int tar_size,int cur_size){ + int level=__lg(i); + while(1){ + if(cur_size==F_SIZE||tar_size*2>cur_size)return i; + frame_table[i*2+1]=listInsert(&lists[level+1],i*2+1); + + i*=2; + cur_size/=2; + level++; + + #if debug + uart_printf("-[0x%x] is partitioned to [0x%x]&[0x%x].\n",i/2,i,i^1); + #endif + } +} + +int findFrame(int tar_size){ + for(int i=TLEVEL-1;i>=0;--i){ + int cur_size=A_SIZE>>i; + int beg=lists[i].beg; + int end=lists[i].end; + if(cur_size>=F_SIZE&&cur_size>=tar_size&&beg!=end){ + int ret=listGet(&lists[i],beg); + if(frame_table[ret]==-1)ERROR("the frame is being used!"); + frame_table[ret]=-1; + + ret=getFrame(ret,tar_size,cur_size); + i2addr[ret]=__toAddr(ret); + addr2i[(i2addr[ret]-A_BASE)/F_SIZE]=ret; + + #if debug + uart_printf("[0x%x] has been allocated.\n",ret); + #endif + + return ret; + } + } + + #if debug + uart_printf("Can't find a proper space.\n"); + #endif + return 0; +} + +void* falloc(int size){//raspi 3 b+ have 1G RAM + return (void*)toAddr(findFrame(size)); +} + +void ffree(unsigned long addr){ + reclaimFrame(toIndex(addr)); +} + +/*------------------------------------------*/ + +typedef struct _Pool{ + int size; + struct _Pool* next; + long mask[4]; +}Pool; + +int reclaimChunk(Pool* pool,unsigned long addr){ + unsigned long tmp=(unsigned long)pool; + if(addr>=tmp&&addrsize; + pool->mask[index/64]^=1<<(index%64); + + #if debug + uart_printf("(0x%x) has been freed.\n",addr); + #endif + + return 1; + } + return 0; +} + +void* findChunk(Pool* pool){ + for(int i=0;i<4;++i){ + long mask=pool->mask[i]; + long lowbit=mask&-mask; + if(lowbit){//exist space + long offset=0; + for(int j=0;((1<size <= F_SIZE){//not exeed current frame + pool->mask[i]^=1<size; + + #if debug + uart_printf("(0x%x) has been allocated.\n",ret); + #endif + + return (void*)ret; + }else{ + break; + } + } + } + + //no space + if(!pool->next){ + Pool* tmp=(Pool*)falloc(F_SIZE); + tmp->size=pool->size; + tmp->next=0; + for(int i=0;i<4;++i){ + tmp->mask[i]=-1; + } + pool->next=tmp; + } + return findChunk(pool->next); +} + +Pool* pools[4];//16, 32, 48, ... + +void* dalloc(int size){ + for(int i=0;i<4;++i){ + if(size<=pools[i]->size){ + return findChunk(pools[i]); + } + } + return falloc(size); +} + +void dfree(unsigned long addr){ + if((addr-A_BASE)%F_SIZE){ + reclaimChunk((Pool*)(addr-(addr-A_BASE)%F_SIZE),addr); + }else{ + ffree(addr); + } +} + +/*------------------------------------------*/ + +void allocator_init(){ + frame_table[0]=-1; + frame_table[1]=listInsert(&lists[0],1); + for(int i=2;isize=chunk_size[i]; + pools[i]->next=0; + for(int j=0;j<4;++j){ + pools[i]->mask[j]=-1; + } + } +} \ No newline at end of file diff --git a/Lab8/inc/allocator.h b/Lab8/inc/allocator.h new file mode 100644 index 000000000..a9d26f4e3 --- /dev/null +++ b/Lab8/inc/allocator.h @@ -0,0 +1,5 @@ +void* falloc(int size); +void ffree(unsigned long addr); +void* dalloc(int size); +void dfree(unsigned long addr); +void allocator_init(); \ No newline at end of file diff --git a/Lab8/inc/config.txt b/Lab8/inc/config.txt new file mode 100644 index 000000000..10286b5bb --- /dev/null +++ b/Lab8/inc/config.txt @@ -0,0 +1 @@ +initramfs initramfs.cpio 0x8000000 diff --git a/Lab8/inc/cpio.c b/Lab8/inc/cpio.c new file mode 100644 index 000000000..a37a539e5 --- /dev/null +++ b/Lab8/inc/cpio.c @@ -0,0 +1,290 @@ +#include "cpio.h" +#include "uart.h" + +typedef struct{//cpio_newc_header + char c_magic[6]; + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[8]; + char c_filesize[8]; + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; + char c_check[8]; +}cpio_header; + +#define CPIO_BASE ((cpio_header*)0x8000000) + +unsigned long strToU(char* str){ + unsigned long ret=0; + for(int i=0;i<8;++i){ + if(str[i]>='0'&&str[i]<='9'){ + ret=ret*16+str[i]-'0'; + }else if(str[i]>='a'&&str[i]<='f'){ + ret=ret*16+str[i]-'a'+10; + }else if(str[i]>='A'&&str[i]<='F'){ + ret=ret*16+str[i]-'A'+10; + } + } + return ret; +} + +cpio_header* dumpEntry(cpio_header* addr){ + unsigned long psize=strToU(addr->c_namesize),dsize=strToU(addr->c_filesize); + if((sizeof(cpio_header)+psize)&3)psize+=4-((sizeof(cpio_header)+psize)&3); + if(dsize&3)dsize+=4-(dsize&3); + + char* path=(char*)(addr+1); + char* data=path+psize; + if(strcmp(path,"TRAILER!!!")==0)return 0; + + uart_printf("Path: %s\n",path); + uart_printf("---Data---\n"); + for(int i=0;ic_namesize),dsize=strToU(addr->c_filesize); + if((sizeof(cpio_header)+psize)&3)psize+=4-((sizeof(cpio_header)+psize)&3); + if(dsize&3)dsize+=4-(dsize&3); + + char* path=(char*)(addr+1); + char* data=path+psize; + if(strcmp(path,"TRAILER!!!")==0)break; + if(strcmp(path,target)==0)return addr; + addr=(cpio_header*)(data+dsize); + } + return 0; +} + +cpio_header* getBase(){ + unsigned long addr=0; + char c; + uart_puts("Please enter archive load address (Hex): ");//qemu: 0x8000000 + do{ + c=uart_getc(); + if(c>='0'&&c<='9'){ + addr=addr*16+c-'0'; + }else if(c>='a'&&c<='f'){ + addr=addr*16+c-'a'+10; + }else if(c>='A'&&c<='F'){ + addr=addr*16+c-'A'+10; + } + }while(c!='\n'); + uart_printf("0x%x\n",addr); + return (cpio_header*)addr; +} + +void getName(char* target){ + uart_puts("Please enter file name: "); + int cnt=0; + while(1){ + target[cnt++]=uart_getc(); + uart_send(target[cnt-1]); + if(target[cnt-1]=='\n')break; + } + target[--cnt]=0; +} + +void dumpArchive(){ + //cpio_header* addr=(cpio_header*)getBase(); + cpio_header* addr=CPIO_BASE; + char target[100];getName(target); + cpio_header* ret=findEntry(addr,target); + if(ret)dumpEntry(ret); +} + +void* fbaseGet(){ + return (void*)CPIO_BASE; +} + +char* fdataGet(void* _addr,unsigned long* size){ + cpio_header* addr=(cpio_header*)_addr; + unsigned long psize=strToU(addr->c_namesize),dsize=strToU(addr->c_filesize); + *size=dsize; + if((sizeof(cpio_header)+psize)&3)psize+=4-((sizeof(cpio_header)+psize)&3); + if(dsize&3)dsize+=4-(dsize&3); + + char* path=(char*)(addr+1); + char* data=path+psize; + + return data; +} + +int fmodeGet(void* _addr){ + cpio_header* addr=(cpio_header*)_addr; + unsigned long tmp=strToU(addr->c_mode)>>12; + if(tmp==4){ + return 1;//dir + }else if(tmp==8){ + return 2;//file + } + return -1; +} + +char* fnameGet(void* _addr,unsigned long* size){ + cpio_header* addr=(cpio_header*)_addr; + unsigned long psize=strToU(addr->c_namesize),dsize=strToU(addr->c_filesize); + *size=psize; + if((sizeof(cpio_header)+psize)&3)psize+=4-((sizeof(cpio_header)+psize)&3); + if(dsize&3)dsize+=4-(dsize&3); + + char* path=(char*)(addr+1); + char* data=path+psize; + + return path; +} + +void* nextfGet(void* _addr){ + cpio_header* addr=(cpio_header*)_addr; + unsigned long psize=strToU(addr->c_namesize),dsize=strToU(addr->c_filesize); + if((sizeof(cpio_header)+psize)&3)psize+=4-((sizeof(cpio_header)+psize)&3); + if(dsize&3)dsize+=4-(dsize&3); + + char* path=(char*)(addr+1); + char* data=path+psize; + + if(strcmp(path,"TRAILER!!!")==0)return 0; + addr=(cpio_header*)(data+dsize); + return addr; +} + +void fDump(){ + void* addr=CPIO_BASE; + while(addr){ + unsigned long tmp; + char* str=fnameGet(addr,&tmp); + uart_printf("%d, %s\n",tmp,str); + addr=nextfGet(addr); + } +} + +void loadApp(char* path,unsigned long a_addr,unsigned long a_size){ + cpio_header* ret=findEntry(CPIO_BASE,path); + if(!ret){ + uart_puts("App not found!\n"); + return; + } + unsigned long psize=strToU(ret->c_namesize); + if((sizeof(cpio_header)+psize)&3)psize+=4-((sizeof(cpio_header)+psize)&3); + unsigned char* data=(unsigned char*)(ret+1)+psize; + + unsigned char* target=(unsigned char*)a_addr; + while(a_size--){ + *target=*data; + target++; + data++; + } + + uart_puts("loading...\n"); + + //change exception level + //asm volatile("mov x0, 0x3c0 \n");//disable interrupt + asm volatile("mov x0, 0x340 \n");//enable interrupt + asm volatile("msr spsr_el1, x0 \n"); + asm volatile("msr elr_el1, %0 \n"::"r"(a_addr)); + asm volatile("msr sp_el0, %0 \n"::"r"(a_addr)); + //asm volatile("mov x0, #(3 << 20) \n"); + //asm volatile("msr cpacr_el0, x0 \n"); + + asm volatile("eret \n"); +} + +unsigned long argvPut(char** argv,unsigned long ret){ + int cnt1=0,cnt2=0; + for(int i=0;;++i){ + cnt1++;//with null + if(!argv[i])break; + + for(int j=0;;++j){ + cnt2++;//with null + if(!argv[i][j])break; + } + } + + int sum=8+8+8*cnt1+cnt2; + ret=(ret-sum); + //alignment + ret=ret-(ret&15); + + char* tmp=(char*)ret; + *(unsigned long*)tmp=cnt1-1; + tmp+=8; + *(unsigned long*)tmp=(unsigned long)(tmp+8); + tmp+=8; + char* buffer=tmp+8*cnt1; + for(int i=0;ic_filesize); + unsigned long psize=strToU(ret->c_namesize); + if((sizeof(cpio_header)+psize)&3)psize+=4-((sizeof(cpio_header)+psize)&3); + unsigned char* data=(unsigned char*)(ret+1)+psize; + + *task_a_addr=a_addr; + *task_a_size=a_size; + + unsigned char* target=(unsigned char*)a_addr; + while(a_size--){ + *target=*data; + target++; + data++; + } + + uart_puts("loading...\n"); + + unsigned long sp_addr=argvPut(argv,a_addr); + /* + uart_printf("%d\n",*(unsigned long*)sp_addr); + char** tmp=*(char***)(sp_addr+8); + uart_printf("%x %x\n",tmp,tmp[0]); + for(int i=0;;++i){ + if(!tmp[i])break; + uart_printf("%d %s\n",i,tmp[i]); + } + while(1){} + */ + + //change exception level + asm volatile("mov x0, 0x340 \n");//enable interrupt + asm volatile("msr spsr_el1, x0 \n"); + asm volatile("msr elr_el1, %0 \n"::"r"(a_addr)); + asm volatile("msr sp_el0, %0 \n"::"r"(sp_addr)); + + asm volatile("mrs x3, sp_el0 \n"::); + asm volatile("ldr x0, [x3, 0] \n"::); + asm volatile("ldr x1, [x3, 8] \n"::); + + asm volatile("eret \n"); +} \ No newline at end of file diff --git a/Lab8/inc/cpio.h b/Lab8/inc/cpio.h new file mode 100644 index 000000000..148be3775 --- /dev/null +++ b/Lab8/inc/cpio.h @@ -0,0 +1,9 @@ +void dumpArchive(); +void* fbaseGet(); +int fmodeGet(void* _addr); +char* fdataGet(void* _addr,unsigned long* size); +char* fnameGet(void* _addr,unsigned long* size); +void* nextfGet(void* _addr); +void fDump(); +void loadApp(char* path,unsigned long a_addr,unsigned long a_size); +void loadApp_with_argv(char* path,unsigned long a_addr,char** argv,unsigned long* task_a_addr,unsigned long* task_a_size); \ No newline at end of file diff --git a/Lab8/inc/error.c b/Lab8/inc/error.c new file mode 100644 index 000000000..823f1c99e --- /dev/null +++ b/Lab8/inc/error.c @@ -0,0 +1,7 @@ +#include "error.h" +#include "uart.h" + +void ERROR(char* str){ + uart_printf("%s\n",str); + while(1){} +} \ No newline at end of file diff --git a/Lab8/inc/error.h b/Lab8/inc/error.h new file mode 100644 index 000000000..42e1b4a65 --- /dev/null +++ b/Lab8/inc/error.h @@ -0,0 +1 @@ +void ERROR(char* str); \ No newline at end of file diff --git a/Lab8/inc/exception.c b/Lab8/inc/exception.c new file mode 100644 index 000000000..2dfe3735c --- /dev/null +++ b/Lab8/inc/exception.c @@ -0,0 +1,135 @@ +#include "inc/uart.h" +#include "inc/thread.h" + +void dumpState(){ + unsigned long esr,elr,spsr; + asm volatile("mrs %0, esr_el1 \n":"=r"(esr):); + asm volatile("mrs %0, elr_el1 \n":"=r"(elr):); + asm volatile("mrs %0, spsr_el1 \n":"=r"(spsr):); + + uart_printf("--------------------\n"); + uart_printf("SPSR: 0x%x\n",spsr); + uart_printf("ELR: 0x%x\n",elr); + uart_printf("ESR: 0x%x\n",esr); + uart_printf("--------------------\n"); + //uart_printf("Exception Return Address: 0x%x\n",elr); + //uart_printf("Exception Class: 0x%x\n",(esr>>26)&0x3f);//0x15 for svc inst + //uart_printf("Instruction Specific Syndrome: 0x%x\n",esr&0x1ffffff);//issued imm value for svc inst +} + +void x0Set(unsigned long v){ + unsigned long* task; + asm volatile("mrs %0, tpidr_el1 \n":"=r"(task):); + task[16]=v; +} + +void exception_handler(){ + asm volatile("\ + str x0,[sp,-8]\n\ + str x1,[sp,-16]\n\ + str x2,[sp,-24]\n\ + "::); + unsigned long x0,x1,x2; + asm volatile("\ + ldr %0,[sp,-8]\n\ + ldr %1,[sp,-16]\n\ + ldr %2,[sp,-24]\n\ + ":"=r"(x0),"=r"(x1),"=r"(x2):); + + unsigned long esr,svc; + asm volatile("mrs %0, esr_el1 \n":"=r"(esr):); + if(((esr>>26)&0x3f)==0x15){ + svc=esr&0x1ffffff; + if(svc==0){ + dumpState(); + return; + }else if(svc==1){//getpid + unsigned long ret=tidGet(); + + x0Set(ret); + return; + }else if(svc==2){//uart_read + unsigned long ret=uart_gets((char*)x0,(int)x1,1); + + x0Set(ret); + return; + }else if(svc==3){//uart_write + uart_puts((char*)x0); + + x0Set(x1); + return; + }else if(svc==4){//exec + exec((char*)x0,(char**)x1); + + x0Set(0); + return; + }else if(svc==5){//exit + exit(); + + while(1){} + return; + }else if(svc==6){//fork + unsigned long ret=fork(); + + x0Set(ret); + return; + }else if(svc==7){//open + unsigned long ret=sys_open((const char*)x0,(int)x1); + + x0Set(ret); + return; + }else if(svc==8){//close + unsigned long ret=sys_close((int)x0); + + x0Set(ret); + return; + }else if(svc==9){//write + unsigned long ret=sys_write((int)x0,(const void*)x1,(int)x2); + + x0Set(ret); + return; + }else if(svc==10){//read + unsigned long ret=sys_read((int)x0,(void*)x1,(int)x2); + + x0Set(ret); + return; + }else{ + uart_printf("TODO\n"); + return; + } + }else if(((esr>>26)&0x3f)==0x24){ + unsigned long far; + asm volatile("mrs %0, far_el1\n":"=r"(far):); + uart_printf("[Data Abort] pid: %d, far_el1: %x\n",tidGet(),far); + exit(); + }else{ + uart_printf("unknown esr_el1...\n"); + while(1){} + } +} + +void interrupt_handler(){ + /* + asm volatile("mrs x0, cntfrq_el0 \n"); + asm volatile("add x0, x0, x0 \n"); + asm volatile("msr cntp_tval_el0, x0 \n"); + unsigned long cntpct,cntfrq,tmp; + asm volatile("mrs %0, cntpct_el0 \n":"=r"(cntpct):); + asm volatile("mrs %0, cntfrq_el0 \n":"=r"(cntfrq):); + + tmp=cntpct*10/cntfrq; + uart_printf("--------------------\n"); + uart_printf("Time Elapsed: %d.%ds\n",tmp/10,tmp%10); + uart_printf("--------------------\n"); + */ + asm volatile("mrs x0, cntfrq_el0 \n"); + asm volatile("asr x0, x0, 7 \n");// 1/128 second + asm volatile("msr cntp_tval_el0, x0 \n"); + threadSchedule(); +} + +void error_handler(){ + dumpState(); + uart_printf("unknown exception...\n"); + while(1){} +} \ No newline at end of file diff --git a/Lab8/inc/fat.c b/Lab8/inc/fat.c new file mode 100644 index 000000000..6620ecf6f --- /dev/null +++ b/Lab8/inc/fat.c @@ -0,0 +1,379 @@ +#include "sd.h" +#include "allocator.h" +#include "uart.h" +#include "error.h" +#include "vfs.h" + +/* +Note: https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system +*/ + +typedef struct{ + unsigned int partition_beg; + unsigned int sector_num,sector_size; + unsigned int table_beg,table_num,table_size; + unsigned int data_beg; + unsigned int* table; + unsigned int* dirty; +}MetaData; + +typedef struct{ + unsigned char name1[8]; + unsigned char name2[3]; + unsigned char attr; + unsigned char other1[8]; + unsigned short id1; + unsigned char other2[4]; + unsigned short id2; + unsigned int len; +}Dentry; + +typedef struct{ + vnode* parent; + unsigned char name[13]; + unsigned char type;//dir:1, file:0 + unsigned int id; + void* cache; + unsigned int capacity; + unsigned int len; + unsigned int dirty; +}Content; + +static MetaData metadata; + +void parseDentry(Dentry* dentry,vnode* node,vnode* parent,int display){ + //name + unsigned char name[13]; + int cnt=0; + for(int i=0;i<8;++i){ + if(dentry->name1[i]==' ')break; + name[cnt++]=dentry->name1[i]; + } + int flag=1; + for(int i=0;i<3;++i){ + if(dentry->name2[i]==' ')break; + if(flag){ + name[cnt++]='.'; + flag=0; + } + name[cnt++]=dentry->name2[i]; + } + name[cnt++]=0; + + //id + unsigned int id; + id=dentry->id1; + id=(id<<16)+dentry->id2; + + //len + unsigned int len=dentry->len; + + //type + unsigned int type=(dentry->attr&0x10)>0; + + if(display) + uart_printf("Parent: %s, File: %s, firstSector: %d, Bytes: %d, Directory: %d\n",((Content*)(parent->internal))->name,name,id,len,type); + + node->mnt=parent->mnt; + node->v_ops=parent->v_ops; + node->f_ops=parent->f_ops; + node->internal=(void*)dalloc(sizeof(Content)); + Content* content=(Content*)(node->internal); + content->parent=parent; + for(int i=0;i<13;++i)content->name[i]=name[i]; + content->type=type; + content->id=id; + content->cache=0; + content->len=len; +} + +unsigned int getChainLen(unsigned int id){ + int ret=1; + while(1){ + id=metadata.table[id]; + if(id>=2&&id<=0xFFFFFEF){ + ret++; + }else if(id>=0xFFFFFF8&&id<=0xFFFFFFF){ + break; + }else{ + ERROR("invalid table entry!"); + } + } + return ret; +} + +unsigned int getChain(unsigned int id,unsigned char** buf){ + unsigned int len=getChainLen(id)*512; + *buf=(unsigned char*)falloc(len); + for(int i=0;inode; + Content* content=(Content*)(node->internal); + vnode* parent=content->parent; + if(content->type==1)ERROR("TODO"); + if(content->cache==0||content->dirty==0)return; + content->dirty=0; + + {//update table + int old_blks=getChainLen(content->id); + int cur_blks=content->len/512; + if(content->len%512)cur_blks++; + if(old_blks>cur_blks)ERROR("old_blks>cur_blks"); + int tail=content->id; + while(metadata.table[tail]<0xFFFFFF8)tail=metadata.table[tail]; + for(int i=0;old_blkscache); + int cur=content->id; + for(int i=0;ilen;i+=512){ + if(cur<2||cur>0xFFFFFEF)ERROR("wrong table id!"); + writeblock(metadata.data_beg+cur,data); + data+=512; + cur=metadata.table[cur]; + } + } + {//update parent + int pos=-1; + vnode** childs=(vnode**)(((Content*)(parent->internal))->cache); + int child_num=((Content*)(parent->internal))->len; + for(int i=0;iinternal); + if(strcmp(content->name,child_content->name)==0){ + pos=i; + break; + } + } + if(pos==-1)ERROR("sync a unknown file!"); + int dirsize=512/32; + int cur=((Content*)(parent->internal))->id; + for(int i=0;ilen=content->len; + writeblock(metadata.data_beg+cur,buf); + ffree((unsigned long)buf); + } +} + +void initCache(Content* content){ + unsigned char* buf; + unsigned int len=getChain(content->id,&buf); + content->cache=buf; + content->capacity=len; + content->dirty=0; +} + +int writeFAT(file* f,const void* buf,unsigned long len){ + vnode* node=f->node; + Content* content=(Content*)(node->internal); + if(content->type!=0)ERROR("invalid file type!"); + if(content->cache==0)initCache(content); + + char* cache=(char*)(content->cache); + if(f->f_pos+len > content->capacity){ + char* new_cache=(char*)falloc((f->f_pos+len)*2); + for(int i=0;ilen;++i)new_cache[i]=cache[i]; + content->capacity=(f->f_pos+len)*2; + content->cache=new_cache; + ffree((unsigned long)cache); + cache=new_cache; + } + + const char* buffer=(const char*)buf; + for(int i=0;if_pos]=buffer[i]; + f->f_pos++; + } + + if(content->len < f->f_pos){ + content->len=f->f_pos; + } + content->dirty=1; + + return len; +} + +int readFAT(file* f,void* buf,unsigned long len){ + vnode* node=f->node; + Content* content=(Content*)(node->internal); + if(content->type!=0)ERROR("invalid file type!"); + if(content->cache==0)initCache(content); + + char* cache=(char*)(content->cache); + char* buffer=(char*)buf; + int ret=0; + for(int i=f->f_pos;ilen;++i){ + if(retf_pos+=ret; + return ret; +} + +int createFAT(vnode* dir_node,vnode** target,const char* component_name){ + ERROR("TODO"); + return -1; +} + +int lookupFAT(vnode* dir_node,vnode** target,const char* component_name){ + Content* content=(Content*)(dir_node->internal); + if(content->type!=1)ERROR("not a directory!"); + if(content->cache==0){ + unsigned char* buf; + unsigned int len=getChain(content->id,&buf); + vnode** childs=(vnode**)dalloc(len/32*8); + int cnt=0; + for(int i=0;icache=childs; + content->capacity=len/32; + content->len=cnt; + content->dirty=0; + } + + vnode** childs=(vnode**)(content->cache); + for(int i=0;ilen;++i){ + vnode* child=childs[i]; + Content* child_content=(Content*)(child->internal); + if(strcmp(child_content->name,component_name)==0){ + if(target){ + *target=child; + } + return i; + } + } + return -1; +} + +void parseRoot(vnode* root){ + unsigned char* table=(unsigned char*)falloc(metadata.table_size*512); + for(int i=0;iv_ops=(vnode_operations*)dalloc(sizeof(vnode_operations)); + root->v_ops->lookup=lookupFAT; + root->v_ops->create=createFAT; + root->f_ops=(file_operations*)dalloc(sizeof(file_operations)); + root->f_ops->read=readFAT; + root->f_ops->write=writeFAT; + root->f_ops->sync=syncFAT; + root->internal=(void*)dalloc(sizeof(Content)); + + Content* content=(Content*)(root->internal); + content->name[0]='.';content->name[1]=0; + content->type=1; + content->id=2; + content->cache=0; +} + +void parseFAT32(){ + unsigned char* buf=(unsigned char*)falloc(512); + readblock(metadata.partition_beg,buf); + + if(buf[510]!=0x55||buf[511]!=0xaa)ERROR("invalid FAT signature!"); + //unsigned int sector_size=*(unsigned short*)(buf+11);//need aligned + unsigned int sector_size=buf[12]; + sector_size=(sector_size<<8)+buf[11]; + if(sector_size!=512)ERROR("invalid sector_size!"); + unsigned int cluster_size=*(unsigned char*)(buf+13); + if(cluster_size!=1)ERROR("invalid cluster_size!"); + unsigned int table_beg=*(unsigned short*)(buf+14); + unsigned int table_num=buf[16]; + //unsigned int sector_num=*(unsigned short*)(buf+19);//need aligned + unsigned int sector_num=buf[20]; + sector_num=(sector_num<<8)+buf[19]; + if(sector_num==0)sector_num=*(unsigned int*)(buf+32); + unsigned int table_size=*(unsigned short*)(buf+22);//sectors/table + if(table_size!=0)ERROR("not FAT32!"); + table_size=*(unsigned int*)(buf+36); + //uart_printf("%d %d %d %d %d\n",sector_size,table_beg,table_num,sector_num,table_size); + metadata.sector_num=sector_num; + metadata.sector_size=sector_size; + metadata.table_beg=metadata.partition_beg+table_beg; + metadata.table_num=table_num; + metadata.table_size=table_size; + metadata.data_beg=metadata.table_beg+table_num*table_size-2;//-2 is important! + + ffree((unsigned long)buf); +} + +void parseMBR(){ + unsigned char* buf=(unsigned char*)falloc(512); + readblock(0,buf); + + if(buf[510]!=0x55||buf[511]!=0xaa)ERROR("invalid MBR signature!"); + if(buf[446]!=0x80)ERROR("invalid partition status!"); + unsigned char* partition_entry=buf+446; + unsigned char partition_type=*(unsigned char*)(partition_entry+4); + if(partition_type!=0xb)ERROR("not FAT32!"); + //unsigned int beg=*(unsigned int*)(partition_entry+8);//need aligned + //unsigned int num=*(unsigned int*)(partition_entry+12);//need aligned + for(int i=0;i<4;++i){ + buf[i]=partition_entry[8+i]; + buf[4+i]=partition_entry[12+i]; + } + unsigned int beg=*(unsigned int*)(buf); + unsigned int num=*(unsigned int*)(buf+4); + metadata.partition_beg=beg; + + ffree((unsigned long)buf); +} + +int fat_Setup(filesystem* fs,mount* mnt){ + char* name=(char*)dalloc(6); + name[0]='f'; + name[1]='a'; + name[2]='t'; + name[3]='f'; + name[4]='s'; + name[5]=0; + fs->name=name; + fs->setup_mount=fat_Setup; + mnt->root=(vnode*)dalloc(sizeof(vnode)); + mnt->fs=fs; + mnt->root->mnt=mnt; + parseMBR(); + parseFAT32(); + parseRoot(mnt->root); + return 0; +} \ No newline at end of file diff --git a/Lab8/inc/fat.h b/Lab8/inc/fat.h new file mode 100644 index 000000000..3d1765526 --- /dev/null +++ b/Lab8/inc/fat.h @@ -0,0 +1 @@ +void fat_Setup(filesystem* fs,mount* mnt); \ No newline at end of file diff --git a/Lab8/inc/linker.ld b/Lab8/inc/linker.ld new file mode 100644 index 000000000..d188ae59c --- /dev/null +++ b/Lab8/inc/linker.ld @@ -0,0 +1,19 @@ +SECTIONS +{ + . = 0xffff000000000000; + . += 0x80000; + __prog_start = .; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + __stk_start = __bss_end + (1<<16); + __prog_end = __stk_start; +} +__bss_size = (__bss_end - __bss_start)>>3; \ No newline at end of file diff --git a/Lab8/inc/mailbox.c b/Lab8/inc/mailbox.c new file mode 100644 index 000000000..6bf50bdad --- /dev/null +++ b/Lab8/inc/mailbox.c @@ -0,0 +1,86 @@ +#include "mailbox.h" +#include "mmio.h" + +#define MBOX_REQUEST 0 +#define MBOX_CH_PROP 8//CPU->GPU +#define MBOX_TAG_GETSERIAL 0x10004 +#define MBOX_TAG_GETREVISION 0x00010002 +#define MBOX_TAG_GETVCMEM 0x00010006 +#define MBOX_TAG_LAST 0 +#define TAG_REQUEST_CODE 0 + +#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880) +#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0)) +#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20)) +#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18)) +#define MBOX_EMPTY 0x40000000 +#define MBOX_FULL 0x80000000 +#define MBOX_RESPONSE 0x80000000 + + +volatile unsigned int __attribute__((aligned(16))) mbox[36];//message buffer + +int mbox_call(unsigned char ch){ + unsigned int r=(((unsigned long)mbox&~0xF) | (ch&0xF));//Combine the message address with channel number + do{ asm volatile("nop"); }while(*MBOX_STATUS & MBOX_FULL);//Check if Mailbox 0 status register’s full flag is set. + *MBOX_WRITE=r;//write to Mailbox 1 Read/Write register. + while(1){ + do{ asm volatile("nop"); }while(*MBOX_STATUS & MBOX_EMPTY);//Check if Mailbox 0 status register’s empty flag is set. + if(r==*MBOX_READ){//read from Mailbox 0 Read/Write register.Check if the value is the same as you wrote in step 1. + return mbox[1]==MBOX_RESPONSE;//is it a valid successful response? + } + } + return 0; +} + +int getSerialNum(unsigned int* dst){ + mbox[0]=8*4; + mbox[1]=MBOX_REQUEST; + mbox[2]=MBOX_TAG_GETSERIAL; + mbox[3]=8; + mbox[4]=TAG_REQUEST_CODE; + mbox[5]=0; + mbox[6]=0; + mbox[7]=MBOX_TAG_LAST; + + int success=mbox_call(MBOX_CH_PROP); + if(success){ + dst[0]=mbox[5]; + dst[1]=mbox[6]; + } + return success; +} + +int getBoardRevision(unsigned int* dst){//it should be 0xa020d3 for rpi3 b+ + mbox[0]=7*4; + mbox[1]=MBOX_REQUEST; + mbox[2]=MBOX_TAG_GETREVISION; + mbox[3]=4; + mbox[4]=TAG_REQUEST_CODE; + mbox[5]=0; + mbox[6]=MBOX_TAG_LAST; + + int success=mbox_call(MBOX_CH_PROP); + if(success){ + dst[0]=mbox[5]; + } + return success; +} + +int getVCMEM(unsigned int* dst){ + mbox[0]=8*4; + mbox[1]=MBOX_REQUEST; + mbox[2]=MBOX_TAG_GETVCMEM; + mbox[3]=8; + mbox[4]=TAG_REQUEST_CODE; + mbox[5]=0; + mbox[6]=0; + mbox[7]=MBOX_TAG_LAST; + + int success=mbox_call(MBOX_CH_PROP); + if(success){ + dst[0]=mbox[5]; + dst[1]=mbox[6]; + } + return success; +} \ No newline at end of file diff --git a/Lab8/inc/mailbox.h b/Lab8/inc/mailbox.h new file mode 100644 index 000000000..961e44450 --- /dev/null +++ b/Lab8/inc/mailbox.h @@ -0,0 +1,3 @@ +int getSerialNum(unsigned int* dst); +int getBoardRevision(unsigned int* dst); +int getVCMEM(unsigned int* dst); \ No newline at end of file diff --git a/Lab8/inc/main.c b/Lab8/inc/main.c new file mode 100644 index 000000000..9a66ddfa2 --- /dev/null +++ b/Lab8/inc/main.c @@ -0,0 +1,222 @@ +#include "inc/uart.h" +#include "inc/reboot.h" +#include "inc/mailbox.h" +#include "inc/cpio.h" +#include "inc/allocator.h" +#include "inc/thread.h" +#include "inc/tmpfs.h" +#include "inc/sd.h" +#include "inc/fat.h" + +#define min(a,b) ((a)<(b)?(a):(b)) + +void moveImg(){//should use register + asm volatile("cbz x14, endmove \n"::); + asm volatile("ldrb w0, [x13], #1 \n"::); + asm volatile("strb w0, [x12], #1 \n"::); + asm volatile("sub x14, x14, #1 \n"::); + asm volatile("br x10 \n"::); + asm volatile("endmove: \n"::); + asm volatile("br x11 \n"::); +} + +void loadImg(){ + extern unsigned long* __prog_start,__prog_end; + unsigned long c_addr,c_size; + c_addr=(unsigned long)&__prog_start; + c_size=(unsigned long)(&__prog_end)-(unsigned long)(&__prog_start);//include stack + + unsigned long k_addr=0,k_size=0; + char c; + uart_puts("Please enter kernel load address (Hex): "); + do{ + c=uart_getc(); + if(c>='0'&&c<='9'){ + k_addr=k_addr*16+c-'0'; + }else if(c>='a'&&c<='f'){ + k_addr=k_addr*16+c-'a'+10; + }else if(c>='A'&&c<='F'){ + k_addr=k_addr*16+c-'A'+10; + } + }while(c!='\n'); + uart_printf("0x%x\n",k_addr); + + uart_puts("Please enter kernel size (Dec): "); + do{ + c=uart_getc(); + if(c>='0'&&c<='9'){ + k_size=k_size*10+c-'0'; + } + }while(c!='\n'); + uart_printf("%d\n",k_size); + + uart_puts("Please send kernel image now...\n"); + if(c_addr>k_addr+k_size||c_addr+c_size>=12; + index[3]=tmp&0x1ff; + tmp>>=9; + index[2]=tmp&0x1ff; + tmp>>=9; + index[1]=tmp&0x1ff; + tmp>>=9; + index[0]=tmp&0x1ff; + + unsigned long* table=(unsigned long*)PA2VA(page_table0); + for(int i=0;i<=2;++i){ + if(table[index[i]]==0){ + initPT((void**)&table[index[i]]); + table[index[i]]|=PD_TABLE; + } + tmp=table[index[i]]; + tmp=tmp-(tmp&0xfff); + table=(unsigned long*)PA2VA(tmp); + } + if(table[index[3]]!=0)ERROR("invalid va!"); + void* frame=falloc(4096); + for(int i=0;i<4096;++i)((char*)frame)[i]=0; + table[index[3]]=VA2PA(frame)|(1<<10)|(1<<6)|MAIR_IDX_NORMAL_NOCACHE<<2|0b11; + return frame; +} + +void initMMULower(){//convenient to debug by aborting lower VA region + asm volatile("msr ttbr0_el1, %0\n"::"r"(-1)); +} + +void initMMU(){//be careful when using stack memory! + //setup tcr & mair + asm volatile("msr tcr_el1, %0\n"::"r"(TCR_CONFIG_DEFAULT)); + asm volatile("msr mair_el1, %0\n"::"r"(MAIR_CONFIG_DEFAULT)); + + //L0 table init + asm volatile("str %0, [%1]\n"::"r"(0x1000|BOOT_PGD_ATTR),"r"(0)); + + //L1 table init + asm volatile("str %0, [%1]\n"::"r"(0x2000|BOOT_PGD_ATTR),"r"(0x1000));//finer granularity for different memory type + asm volatile("str %0, [%1]\n"::"r"(0x40000000|BOOT_PUD_ATTR),"r"(0x1000+8)); + + //L2 table for 0~1G + asm volatile("\ + mov x10, %0\n\ + mov x11, %1\n\ + mov x0, #0x2000\n\ + mov x1, #512\n\ + mov x2, #0\n\ +beg1:\n\ + cbz x1, end1\n\ + ldr x3, =0x3F000000\n\ + cmp x2, x3\n\ + blt normalmem\n\ +peripheralsmem:\n\ + orr x3, x2, x10\n\ + b end2\n\ +normalmem:\n\ + orr x3, x2, x11\n\ + b end2\n\ +end2:\n\ + str x3, [x0]\n\ + add x0, x0, #8\n\ + sub x1, x1, #1\n\ + add x2, x2, #0x200000\n\ + b beg1\n\ +end1:\n\ + "::"r"(BOOT_L2D_ATTR),"r"(BOOT_L2N_ATTR)); + + //setting L0 table for lower VA region + asm volatile("msr ttbr0_el1, %0\n"::"r"(0));//ensure to read correct inst when mmu opened + + //setting L0 table for higher VA region + asm volatile("msr ttbr1_el1, %0\n"::"r"(0)); + + //enalble mmu + asm volatile("\ + mrs x2, sctlr_el1\n\ + orr x2 , x2, 1\n\ + msr sctlr_el1, x2\n\ + "::); + + //no longer running on 0x80000 + asm volatile("\ + ldr x0, =0xffff000000000000\n\ + add x30, x30, x0\n\ + "::); +} diff --git a/Lab8/inc/mmu.h b/Lab8/inc/mmu.h new file mode 100644 index 000000000..7fb02c452 --- /dev/null +++ b/Lab8/inc/mmu.h @@ -0,0 +1,4 @@ +void dupPT(void* page_table_src,void* page_table_dst,int level); +void removePT(void* page_table,int level); +void* updatePT(void* page_table0,void* va); +void initPT(void** page_table); \ No newline at end of file diff --git a/Lab8/inc/printf.c b/Lab8/inc/printf.c new file mode 100644 index 000000000..b37854c5f --- /dev/null +++ b/Lab8/inc/printf.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +/** + * minimal sprintf implementation + */ +unsigned int vsprintf(char *dst, char* fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig=dst, tmpstr[19]; + + // failsafes + if(dst==(void*)0 || fmt==(void*)0) { + return 0; + } + + // main loop + arg = 0; + while(*fmt) { + // argument access + if(*fmt=='%') { + fmt++; + // literal % + if(*fmt=='%') { + goto put; + } + len=0; + // size modifier + while(*fmt>='0' && *fmt<='9') { + len *= 10; + len += *fmt-'0'; + fmt++; + } + // skip long modifier + if(*fmt=='l') { + fmt++; + } + // character + if(*fmt=='c') { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } else + // decimal number + if(*fmt=='d') { + arg = __builtin_va_arg(args, int); + // check input + sign=0; + if((int)arg<0) { + arg*=-1; + sign++; + } + if(arg>99999999999999999L) { + arg=99999999999999999L; + } + // convert to string + i=18; + tmpstr[i]=0; + do { + tmpstr[--i]='0'+(arg%10); + arg/=10; + } while(arg!=0 && i>0); + if(sign) { + tmpstr[--i]='-'; + } + // padding, only space + if(len>0 && len<18) { + while(i>18-len) { + tmpstr[--i]=' '; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // hex number + if(*fmt=='x') { + arg = __builtin_va_arg(args, long int); + // convert to string + i=16; + tmpstr[i]=0; + do { + char n=arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i]=n+(n>9?0x37:0x30); + arg>>=4; + } while(arg!=0 && i>0); + // padding, only leading zeros + if(len>0 && len<=16) { + while(i>16-len) { + tmpstr[--i]='0'; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // string + if(*fmt=='s') { + p = __builtin_va_arg(args, char*); +copystring: if(p==(void*)0) { + p="(null)"; + } + while(*p) { + *dst++ = *p++; + } + } + } else { +put: *dst++ = *fmt; + } + fmt++; + } + *dst=0; + // number of bytes written + return dst-orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char* fmt, ...) +{ + //__builtin_va_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst,fmt,args); +} \ No newline at end of file diff --git a/Lab8/inc/printf.h b/Lab8/inc/printf.h new file mode 100644 index 000000000..101e564e3 --- /dev/null +++ b/Lab8/inc/printf.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); \ No newline at end of file diff --git a/Lab8/inc/reboot.c b/Lab8/inc/reboot.c new file mode 100644 index 000000000..4f3b54ecb --- /dev/null +++ b/Lab8/inc/reboot.c @@ -0,0 +1,15 @@ +#include "reboot.h" +#include "mmio.h" + +#define PM_RSTC ((volatile unsigned int*)(MMIO_BASE+0x10001c)) +#define PM_WDOG ((volatile unsigned int*)(MMIO_BASE+0x100024)) +#define PM_PASSWORD 0x5a000000 + +void reboot(){ + int tick=87; + *PM_RSTC=PM_PASSWORD|0x20; + *PM_WDOG=PM_PASSWORD|tick; + while(1){ + //rebooting... + } +} \ No newline at end of file diff --git a/Lab8/inc/reboot.h b/Lab8/inc/reboot.h new file mode 100644 index 000000000..8683c6bbf --- /dev/null +++ b/Lab8/inc/reboot.h @@ -0,0 +1 @@ +void reboot(); \ No newline at end of file diff --git a/Lab8/inc/sd.c b/Lab8/inc/sd.c new file mode 100644 index 000000000..1bd6fedc7 --- /dev/null +++ b/Lab8/inc/sd.c @@ -0,0 +1,241 @@ +#include "mmio.h" + +// SD card command +#define GO_IDLE_STATE 0 +#define SEND_OP_CMD 1 +#define ALL_SEND_CID 2 +#define SEND_RELATIVE_ADDR 3 +#define SELECT_CARD 7 +#define SEND_IF_COND 8 + #define VOLTAGE_CHECK_PATTERN 0x1aa +#define STOP_TRANSMISSION 12 +#define SET_BLOCKLEN 16 +#define READ_SINGLE_BLOCK 17 +#define WRITE_SINGLE_BLOCK 24 +#define SD_APP_OP_COND 41 + #define SDCARD_3_3V (1 << 21) + #define SDCARD_ISHCS (1 << 30) + #define SDCARD_READY (1 << 31) +#define APP_CMD 55 + +// gpio +#define GPIO_BASE (MMIO_BASE + 0x200000) +#define GPIO_GPFSEL4 (GPIO_BASE + 0x10) +#define GPIO_GPFSEL5 (GPIO_BASE + 0x14) +#define GPIO_GPPUD (GPIO_BASE + 0x94) +#define GPIO_GPPUDCLK1 (GPIO_BASE + 0x9c) + +// sdhost +#define SDHOST_BASE (MMIO_BASE + 0x202000) +#define SDHOST_CMD (SDHOST_BASE + 0) + #define SDHOST_READ 0x40 + #define SDHOST_WRITE 0x80 + #define SDHOST_LONG_RESPONSE 0x200 + #define SDHOST_NO_REPONSE 0x400 + #define SDHOST_BUSY 0x800 + #define SDHOST_NEW_CMD 0x8000 +#define SDHOST_ARG (SDHOST_BASE + 0x4) +#define SDHOST_TOUT (SDHOST_BASE + 0x8) + #define SDHOST_TOUT_DEFAULT 0xf00000 +#define SDHOST_CDIV (SDHOST_BASE + 0xc) + #define SDHOST_CDIV_MAXDIV 0x7ff + #define SDHOST_CDIV_DEFAULT 0x148 +#define SDHOST_RESP0 (SDHOST_BASE + 0x10) +#define SDHOST_RESP1 (SDHOST_BASE + 0x14) +#define SDHOST_RESP2 (SDHOST_BASE + 0x18) +#define SDHOST_RESP3 (SDHOST_BASE + 0x1c) +#define SDHOST_HSTS (SDHOST_BASE + 0x20) + #define SDHOST_HSTS_MASK (0x7f8) + #define SDHOST_HSTS_ERR_MASK (0xf8) + #define SDHOST_HSTS_DATA (1 << 0) +#define SDHOST_PWR (SDHOST_BASE + 0x30) +#define SDHOST_DBG (SDHOST_BASE + 0x34) + #define SDHOST_DBG_FSM_DATA 1 + #define SDHOST_DBG_FSM_MASK 0xf + #define SDHOST_DBG_MASK (0x1f << 14 | 0x1f << 9) + #define SDHOST_DBG_FIFO (0x4 << 14 | 0x4 << 9) +#define SDHOST_CFG (SDHOST_BASE + 0x38) + #define SDHOST_CFG_DATA_EN (1 << 4) + #define SDHOST_CFG_SLOW (1 << 3) + #define SDHOST_CFG_INTBUS (1 << 1) +#define SDHOST_SIZE (SDHOST_BASE + 0x3c) +#define SDHOST_DATA (SDHOST_BASE + 0x40) +#define SDHOST_CNT (SDHOST_BASE + 0x50) + +// helper +#define set(io_addr, val) \ + asm volatile("str %w1, [%0]" ::"r"(io_addr), "r"(val) : "memory"); + +#define get(io_addr, val) \ + asm volatile("ldr %w0, [%1]" : "=r"(val) : "r"(io_addr) : "memory"); + +static inline void delay(unsigned long tick) { + while (tick--) { + asm volatile("nop"); + } +} + +static int is_hcs; // high capcacity(SDHC) + +static void pin_setup() { + set(GPIO_GPFSEL4, 0x24000000); + set(GPIO_GPFSEL5, 0x924); + set(GPIO_GPPUD, 0); + delay(15000); + set(GPIO_GPPUDCLK1, 0xffffffff); + delay(15000); + set(GPIO_GPPUDCLK1, 0); +} + +static void sdhost_setup() { + unsigned int tmp; + set(SDHOST_PWR, 0); + set(SDHOST_CMD, 0); + set(SDHOST_ARG, 0); + set(SDHOST_TOUT, SDHOST_TOUT_DEFAULT); + set(SDHOST_CDIV, 0); + set(SDHOST_HSTS, SDHOST_HSTS_MASK); + set(SDHOST_CFG, 0); + set(SDHOST_CNT, 0); + set(SDHOST_SIZE, 0); + get(SDHOST_DBG, tmp); + tmp &= ~SDHOST_DBG_MASK; + tmp |= SDHOST_DBG_FIFO; + set(SDHOST_DBG, tmp); + delay(250000); + set(SDHOST_PWR, 1); + delay(250000); + set(SDHOST_CFG, SDHOST_CFG_SLOW | SDHOST_CFG_INTBUS | SDHOST_CFG_DATA_EN); + set(SDHOST_CDIV, SDHOST_CDIV_DEFAULT); +} + +static int wait_sd() { + int cnt = 1000000; + unsigned int cmd; + do { + if (cnt == 0) { + return -1; + } + get(SDHOST_CMD, cmd); + --cnt; + } while (cmd & SDHOST_NEW_CMD); + return 0; +} + +static int sd_cmd(unsigned cmd, unsigned int arg) { + set(SDHOST_ARG, arg); + set(SDHOST_CMD, cmd | SDHOST_NEW_CMD); + return wait_sd(); +} + +static int sdcard_setup() { + unsigned int tmp; + sd_cmd(GO_IDLE_STATE | SDHOST_NO_REPONSE, 0); + sd_cmd(SEND_IF_COND, VOLTAGE_CHECK_PATTERN); + get(SDHOST_RESP0, tmp); + if (tmp != VOLTAGE_CHECK_PATTERN) { + return -1; + } + while (1) { + if (sd_cmd(APP_CMD, 0) == -1) { + // MMC card or invalid card status + // currently not support + continue; + } + sd_cmd(SD_APP_OP_COND, SDCARD_3_3V | SDCARD_ISHCS); + get(SDHOST_RESP0, tmp); + if (tmp & SDCARD_READY) { + break; + } + delay(1000000); + } + + is_hcs = tmp & SDCARD_ISHCS; + sd_cmd(ALL_SEND_CID | SDHOST_LONG_RESPONSE, 0); + sd_cmd(SEND_RELATIVE_ADDR, 0); + get(SDHOST_RESP0, tmp); + sd_cmd(SELECT_CARD, tmp); + sd_cmd(SET_BLOCKLEN, 512); + return 0; +} + +static int wait_fifo() { + int cnt = 1000000; + unsigned int hsts; + do { + if (cnt == 0) { + return -1; + } + get(SDHOST_HSTS, hsts); + --cnt; + } while ((hsts & SDHOST_HSTS_DATA) == 0); + return 0; +} + +static void set_block(int size, int cnt) { + set(SDHOST_SIZE, size); + set(SDHOST_CNT, cnt); +} + +static void wait_finish() { + unsigned int dbg; + do { + get(SDHOST_DBG, dbg); + } while ((dbg & SDHOST_DBG_FSM_MASK) != SDHOST_HSTS_DATA); +} + +void readblock(int block_idx, void* buf) { + unsigned int* buf_u = (unsigned int*)buf; + int succ = 0; + if (!is_hcs) { + block_idx <<= 9; + } + do{ + set_block(512, 1); + sd_cmd(READ_SINGLE_BLOCK | SDHOST_READ, block_idx); + for (int i = 0; i < 128; ++i) { + wait_fifo(); + get(SDHOST_DATA, buf_u[i]); + } + unsigned int hsts; + get(SDHOST_HSTS, hsts); + if (hsts & SDHOST_HSTS_ERR_MASK) { + set(SDHOST_HSTS, SDHOST_HSTS_ERR_MASK); + sd_cmd(STOP_TRANSMISSION | SDHOST_BUSY, 0); + } else { + succ = 1; + } + } while(!succ); + wait_finish(); +} + +void writeblock(int block_idx, void* buf) { + unsigned int* buf_u = (unsigned int*)buf; + int succ = 0; + if (!is_hcs) { + block_idx <<= 9; + } + do{ + set_block(512, 1); + sd_cmd(WRITE_SINGLE_BLOCK | SDHOST_WRITE, block_idx); + for (int i = 0; i < 128; ++i) { + wait_fifo(); + set(SDHOST_DATA, buf_u[i]); + } + unsigned int hsts; + get(SDHOST_HSTS, hsts); + if (hsts & SDHOST_HSTS_ERR_MASK) { + set(SDHOST_HSTS, SDHOST_HSTS_ERR_MASK); + sd_cmd(STOP_TRANSMISSION | SDHOST_BUSY, 0); + } else { + succ = 1; + } + } while(!succ); + wait_finish(); +} + +void sd_init() { + pin_setup(); + sdhost_setup(); + sdcard_setup(); +} \ No newline at end of file diff --git a/Lab8/inc/sd.h b/Lab8/inc/sd.h new file mode 100644 index 000000000..1e0d62d43 --- /dev/null +++ b/Lab8/inc/sd.h @@ -0,0 +1,3 @@ +void readblock(int block_idx, void* buf); +void writeblock(int block_idx, void* buf); +void sd_init(); \ No newline at end of file diff --git a/Lab8/inc/start.S b/Lab8/inc/start.S new file mode 100644 index 000000000..cf9483859 --- /dev/null +++ b/Lab8/inc/start.S @@ -0,0 +1,220 @@ +.macro save_regs + sub sp, sp, 32 * 8 + stp x0, x1, [sp ,16 * 0] + stp x2, x3, [sp ,16 * 1] + stp x4, x5, [sp ,16 * 2] + stp x6, x7, [sp ,16 * 3] + stp x8, x9, [sp ,16 * 4] + stp x10, x11, [sp ,16 * 5] + stp x12, x13, [sp ,16 * 6] + stp x14, x15, [sp ,16 * 7] + stp x16, x17, [sp ,16 * 8] + stp x18, x19, [sp ,16 * 9] + stp x20, x21, [sp ,16 * 10] + stp x22, x23, [sp ,16 * 11] + stp x24, x25, [sp ,16 * 12] + stp x26, x27, [sp ,16 * 13] + stp x28, x29, [sp ,16 * 14] + str x30, [sp, 16 * 15] +.endm + +.macro load_regs + ldp x0, x1, [sp ,16 * 0] + ldp x2, x3, [sp ,16 * 1] + ldp x4, x5, [sp ,16 * 2] + ldp x6, x7, [sp ,16 * 3] + ldp x8, x9, [sp ,16 * 4] + ldp x10, x11, [sp ,16 * 5] + ldp x12, x13, [sp ,16 * 6] + ldp x14, x15, [sp ,16 * 7] + ldp x16, x17, [sp ,16 * 8] + ldp x18, x19, [sp ,16 * 9] + ldp x20, x21, [sp ,16 * 10] + ldp x22, x23, [sp ,16 * 11] + ldp x24, x25, [sp ,16 * 12] + ldp x26, x27, [sp ,16 * 13] + ldp x28, x29, [sp ,16 * 14] + ldr x30, [sp, 16 * 15] + add sp, sp, 32 * 8 +.endm + +.macro save_task + str x0, [sp, -8] + mrs x0, tpidr_el1 + //store x0&x1 later + stp x2, x3, [x0, 8 * 18] + stp x4, x5, [x0, 8 * 20] + stp x6, x7, [x0, 8 * 22] + stp x8, x9, [x0, 8 * 24] + stp x10, x11, [x0, 8 * 26] + stp x12, x13, [x0, 8 * 28] + stp x14, x15, [x0, 8 * 30] + stp x16, x17, [x0, 8 * 32] + stp x18, x19, [x0, 8 * 34] + stp x20, x21, [x0, 8 * 36] + stp x22, x23, [x0, 8 * 38] + stp x24, x25, [x0, 8 * 40] + stp x26, x27, [x0, 8 * 42] + stp x28, x29, [x0, 8 * 44] + str x30, [x0, 8 * 46] + mov x9, x0 + ldr x0, [sp, -8] + stp x0, x1, [x9 ,8 * 16] + mrs x10, spsr_el1 + mrs x11, elr_el1 + mrs x12, sp_el0 + str x10, [x9, 8 * 13] + stp x11, x12, [x9, 8 * 14] +.endm + +.macro restore_task + mrs x9, tpidr_el1 + ldr x10, [x9, 8 * 13] + ldp x11, x12, [x9, 8 * 14] + msr spsr_el1, x10 + msr elr_el1, x11 + msr sp_el0, x12 + mov x0, x9 + //restore x0&x1 later + ldp x2, x3, [x0, 8 * 18] + ldp x4, x5, [x0, 8 * 20] + ldp x6, x7, [x0, 8 * 22] + ldp x8, x9, [x0, 8 * 24] + ldp x10, x11, [x0, 8 * 26] + ldp x12, x13, [x0, 8 * 28] + ldp x14, x15, [x0, 8 * 30] + ldp x16, x17, [x0, 8 * 32] + ldp x18, x19, [x0, 8 * 34] + ldp x20, x21, [x0, 8 * 36] + ldp x22, x23, [x0, 8 * 38] + ldp x24, x25, [x0, 8 * 40] + ldp x26, x27, [x0, 8 * 42] + ldp x28, x29, [x0, 8 * 44] + ldr x30, [x0, 8 * 46] + ldp x0, x1, [x0, 8 * 16] +.endm + +.section ".text.boot" + +_start: +//cpu init + mrs x1, mpidr_el1//read cpu id + and x1, x1, #3 + cbz x1, 2f +1://id>0, stop + wfe + b 1b +2://id=0, exec + +//exception level init + bl from_el2_to_el1 + +//exception table init + ldr x0, =exception_table + msr VBAR_EL1, x0 + +//MMU init + bl initMMU + bl initMMULower + +//bss init + ldr x1, =__bss_start//64-bit load + ldr w2, =__bss_size//32-bit load +3: + cbz w2, 4f + str xzr, [x1], #8//64-bit store + sub w2, w2, #1 + b 3b +4: + +//stack init + ldr x1, =__stk_start + mov sp, x1 + +//jump to main + bl main//function call + +//for failsafe + b 1b + +//el2->el1 +from_el2_to_el1: + mov x0, (1 << 31) // EL1 uses aarch64 + msr hcr_el2, x0 + mov x0, 0x3c5 // EL1h (SPSel = 1) with interrupt disabled + msr spsr_el2, x0 + msr elr_el2, x30//x30 = link register + + // disable SIMD traps: built-ins of uart_printf will use SIMD + // https://github.com/bztsrc/raspi3-tutorial/tree/master/12_printf + mov x0, #(3 << 20) + msr cpacr_el1, x0 + + //enable the core timer’s interrupt + mov x0, 1 + msr cntp_ctl_el0, x0 + mov x0, 0 + msr cntp_tval_el0, x0 + mov x0, 2 + ldr x1, =0x40000040 + str w0, [x1] + + eret // return to EL1 + +//exception table +.align 11 +exception_table: + b TODO + .align 7 + b TODO + .align 7 + b TODO + .align 7 + b TODO + + .align 7 + b TODO + .align 7 + b TODO + .align 7 + b TODO + .align 7 + b TODO + + .align 7 + b lowerSynchronous + .align 7 + b lowerIRQ + .align 7 + b TODO + .align 7 + b TODO + + .align 7 + b TODO + .align 7 + b TODO + .align 7 + b TODO + .align 7 + b TODO + +//Synchronous from lower level +lowerSynchronous: + save_task + bl exception_handler + restore_task + eret + +//IRQ from lower level +lowerIRQ: + save_task + bl interrupt_handler + restore_task + eret + +TODO: + save_task + bl error_handler + restore_task + eret \ No newline at end of file diff --git a/Lab8/inc/thread.c b/Lab8/inc/thread.c new file mode 100644 index 000000000..66e39d70b --- /dev/null +++ b/Lab8/inc/thread.c @@ -0,0 +1,423 @@ +#include "thread.h" +#include "uart.h" +#include "allocator.h" +#include "cpio.h" +#include "vfs.h" +#include "error.h" +#include "mmu.h" + +#define TASKSIZE 4096 +#define FD_TABLE_SIZE 5 +#define TASKEXIT 1 +#define TASKFORK 2 + +typedef struct _Task{ + unsigned long context[12+1+2+1+31];//kreg+ksp & spsr+elr & usp+ureg + int id; + int status; + unsigned long a_addr,a_size,child; + file* fd_table[FD_TABLE_SIZE]; + void* page_table; + struct _Task* next; + /* + task stack:this ~ this+TASKSIZE + */ +}Task; + +typedef struct{ + Task *beg,*end; +}RQ; + +static RQ rq; +static int task_cnter; + +void threadSwitch(){ + asm volatile("\ +_threadSwitch:\n\ + stp x19, x20, [x0, 16 * 0]\n\ + stp x21, x22, [x0, 16 * 1]\n\ + stp x23, x24, [x0, 16 * 2]\n\ + stp x25, x26, [x0, 16 * 3]\n\ + stp x27, x28, [x0, 16 * 4]\n\ + stp x29, x30, [x0, 16 * 5]\n\ + mov x9, sp\n\ + str x9, [x0, 16 * 6]\n\ + \n\ + ldp x19, x20, [x1, 16 * 0]\n\ + ldp x21, x22, [x1, 16 * 1]\n\ + ldp x23, x24, [x1, 16 * 2]\n\ + ldp x25, x26, [x1, 16 * 3]\n\ + ldp x27, x28, [x1, 16 * 4]\n\ + ldp x29, x30, [x1, 16 * 5]\n\ + ldr x9, [x1, 16 * 6]\n\ + mov sp, x9\n\ + \n\ + msr tpidr_el1, x1\n\ + \n\ + ret\n\ + "::); +} + +void threadSchedule(){ + if(!rq.beg){ + uart_printf("rq is empty!!\n"); + while(1){} + } + + if(rq.beg==rq.end){ + //no other task, all done + }else{ + do{ + rq.end->next=rq.beg; + rq.end=rq.beg; + rq.beg=rq.beg->next; + rq.end->next=0; + }while(rq.beg->status);//ignore abnormal task + + //uart_printf("%d %x %x %x\n",rq.beg->id,rq.beg->context[10],rq.beg->context[11],rq.beg->context[12]); + //uart_printf("%d -> %d\n",rq.end->id,rq.beg->id); + + //change page table + asm volatile("\ + mov x0, %0\n\ + dsb ish\n\ + msr ttbr0_el1, x0\n\ + tlbi vmalle1is\n\ + dsb ish\n\ + isb\n\ + "::"r"(rq.beg->page_table)); + //change control flow + asm volatile("\ + mov x1, %0\n\ + mrs x0, tpidr_el1\n\ + bl _threadSwitch\n\ + "::"r"(rq.beg));//only use bl to avoid stack usage + } +} + +Task* threadCreate(void* func){ + Task* new_task=(Task*)falloc(TASKSIZE); + if((unsigned long)new_task%TASKSIZE){//aligned + uart_printf("new_task isn't aligned!!\n"); + while(1){} + } + + new_task->context[10]=(unsigned long)new_task+TASKSIZE;//fp + new_task->context[11]=(unsigned long)func;//lr + new_task->context[12]=(unsigned long)new_task+TASKSIZE;//sp + new_task->id=task_cnter++; + new_task->status=0; + new_task->a_addr=new_task->a_size=new_task->child=0; + for(int i=0;ifd_table[i]=0; + new_task->page_table=0; + new_task->next=0; + + if(rq.beg){ + rq.end->next=new_task; + rq.end=rq.end->next; + }else{ + rq.beg=rq.end=new_task; + } + + return new_task; +} + +/*--------------------------------------------*/ + +void zombiesKill(){//called by idle() + Task* tar=rq.beg; + while(1){ + while(tar->next&&(tar->next->status&TASKEXIT)){ + Task* tmp=tar->next->next; + ffree((unsigned long)(tar->next)); + tar->next=tmp; + } + + if(!tar->next){ + rq.end=tar; + break; + }else{ + tar=tar->next; + } + } +} + +void taskUpdate(Task* p,Task* c){ + p->status^=TASKFORK; + p->child=c->id; + + Task* tmp=c->next; + char* src=(char*)p; + char* dst=(char*)c; + for(int i=0;iid=p->child; + c->child=0; + for(int i=0;ifd_table[i]=0;//TODO: give child new fds + uart_printf("%s %s\n",p->page_table, c->page_table); + initPT(&(c->page_table)); + dupPT(p->page_table,c->page_table,0); + c->next=tmp; + + long k_delta=(long)c-(long)p; + c->context[10]+=k_delta;//kernel fp + c->context[12]+=k_delta;//kernel sp +} + +void doFork(){//called by idle() + Task* tar=rq.beg->next; + while(tar){ + if((tar->status)&TASKFORK){ + Task* child=threadCreate(0); + taskUpdate(tar,child); + } + tar=tar->next; + } +} + +void idle(){ + while(1){ + //uart_printf("idle()\n"); + //uart_getc(); + zombiesKill(); + doFork(); + threadSchedule(); + if(rq.beg==rq.end)break; + } +} + +/*--------------------------------------------*/ + +unsigned long putArgv(char** argv,unsigned long ret){ + int cnt1=0,cnt2=0; + for(int i=0;;++i){ + cnt1++;//with null + if(!argv[i])break; + + for(int j=0;;++j){ + cnt2++;//with null + if(!argv[i][j])break; + } + } + + int sum=8+8+8*cnt1+cnt2; + ret=(ret-sum); + //alignment + ret=ret-(ret&15); + + char* tmp=(char*)ret; + *(unsigned long*)tmp=cnt1-1; + tmp+=8; + *(unsigned long*)tmp=(unsigned long)(tmp+8); + tmp+=8; + char* buffer=tmp+8*cnt1; + for(int i=0;ia_addr=a_addr; + //task->a_size=?;//TODO + + //init page table + initPT(&(task->page_table)); + asm volatile("mov x0, %0 \n"::"r"(task->page_table)); + asm volatile("msr ttbr0_el1, x0 \n"); + + //load program + file* f=vfs_open(path,0); + for(unsigned long va=a_addr;;va+=4096){ + updatePT(task->page_table,(void*)va); + int cnt=vfs_read(f,(void*)va,4096); + if(cnt<4096)break; + } + vfs_close(f); + + //load arg + updatePT(task->page_table,(void*)(a_addr-4096)); + unsigned long sp_addr=putArgv(argv,a_addr); + + uart_puts("loading...\n"); + asm volatile("mov x0, 0x340 \n");//enable interrupt + asm volatile("msr spsr_el1, x0 \n"); + asm volatile("msr elr_el1, %0 \n"::"r"(a_addr)); + asm volatile("msr sp_el0, %0 \n"::"r"(sp_addr)); + + asm volatile("mov x3, %0 \n"::"r"(sp_addr)); + asm volatile("ldr x0, [x3, 0] \n"::); + asm volatile("ldr x1, [x3, 8] \n"::); + + asm volatile("eret \n"); +} + +int tidGet(){ + Task* cur; + asm volatile("mrs %0, tpidr_el1\n":"=r"(cur):); + return cur->id; +} + +void exec(char* path,char** argv){//TODO: reset sp + unsigned long a_addr; + while(1){ + uart_puts("Please enter app link address (Hex): "); + a_addr=uart_getX(1); + if(a_addr%4096){ + uart_puts("Not aligned!\n"); + }else{ + break; + } + } + loadFSApp(path,a_addr,argv,rq.beg); + ERROR("exec fail!"); +} + +void exit(){ + Task* cur; + asm volatile("mrs %0, tpidr_el1\n":"=r"(cur):); + for(int i=0;ifd_table[i]){ + sys_close(i); + } + } + if(cur->page_table!=0)removePT(cur->page_table,0); + cur->status|=TASKEXIT; + threadSchedule(); + + while(1){ + uart_printf("exit() failed!!\n"); + } +} + +int fork(){ + rq.beg->status|=TASKFORK; + threadSchedule(); + return rq.beg->child; +} + +int sys_open(const char *pathname,int flags){ + Task* cur; + asm volatile("mrs %0, tpidr_el1\n":"=r"(cur):); + int ret=-1; + for(int i=0;ifd_table[i]==0){ + ret=i; + cur->fd_table[i]=vfs_open(pathname,flags); + break; + } + } + return ret; +} + +int sys_close(int fd){ + if(fd<0||fd>=FD_TABLE_SIZE)ERROR("invalid fd!!"); + Task* cur; + asm volatile("mrs %0, tpidr_el1\n":"=r"(cur):); + if(cur->fd_table[fd]){ + vfs_sync(cur->fd_table[fd]); + vfs_close(cur->fd_table[fd]); + cur->fd_table[fd]=0; + } + return 0; +} + +int sys_write(int fd,const void *buf,int count){ + if(fd<0||fd>=FD_TABLE_SIZE)ERROR("invalid fd!!"); + Task* cur; + asm volatile("mrs %0, tpidr_el1\n":"=r"(cur):); + if(cur->fd_table[fd]){ + return vfs_write(cur->fd_table[fd],buf,count); + } + return 0; +} + +int sys_read(int fd,void *buf,int count){ + if(fd<0||fd>=FD_TABLE_SIZE)ERROR("invalid fd!!"); + Task* cur; + asm volatile("mrs %0, tpidr_el1\n":"=r"(cur):); + if(cur->fd_table[fd]){ + return vfs_read(cur->fd_table[fd],buf,count); + } + return 0; +} + +/*--------------------------------------------*/ + +void foo(){ + char buf[10][50]; + char* argv[10]; + for(int i=0;i<10;++i){ + uart_printf("arg%d: ",i); + int n=uart_gets(buf[i],50,1); + argv[i]=buf[i]; + if(n==0||i==9){ + argv[i]=0; + break; + } + } + exec(argv[0],argv); +} + +void threadTest(){ + Task* cur=threadCreate(0);//use startup stack (not kernel stack) + asm volatile("msr tpidr_el1, %0\n"::"r"((unsigned long)cur)); + + threadCreate(foo); + + idle(); + + //no task anymore + ffree((unsigned long)cur); + rq.beg=rq.end=0; + task_cnter=0; +} + +void foo1(){ + for(int i=0;i<10;++i){ + uart_printf("Thread id: %d %d\n",tidGet(),i); + //uart_getc(); + threadSchedule(); + } + + exit(); +} + +void threadTest1(){ + Task* cur=threadCreate(0);//use startup stack (not kernel stack) + asm volatile("msr tpidr_el1, %0\n"::"r"((unsigned long)cur)); + + for(int i=0;i<3;++i){ + threadCreate(foo1); + } + + idle(); +} + +void foo2(){ + char* argv[]={"argv_test","-o","arg2",0}; + exec("app1",argv); +} + +void threadTest2(){ + Task* cur=threadCreate(0);//use startup stack (not kernel stack) + asm volatile("msr tpidr_el1, %0\n"::"r"((unsigned long)cur)); + + threadCreate(foo2); + + idle(); +} diff --git a/Lab8/inc/thread.h b/Lab8/inc/thread.h new file mode 100644 index 000000000..8b85db946 --- /dev/null +++ b/Lab8/inc/thread.h @@ -0,0 +1,12 @@ +void threadSchedule(); +int tidGet(); +void exec(char* path,char** argv); +void exit(); +int fork(); +int sys_open(const char *pathname,int flags); +int sys_close(int fd); +int sys_write(int fd,const void *buf,int count); +int sys_read(int fd,void *buf,int count); +void threadTest(); +void threadTest1(); +void threadTest2(); \ No newline at end of file diff --git a/Lab8/inc/tmpfs.c b/Lab8/inc/tmpfs.c new file mode 100644 index 000000000..54610dfb0 --- /dev/null +++ b/Lab8/inc/tmpfs.c @@ -0,0 +1,270 @@ +#include "tmpfs.h" +#include "allocator.h" +#include "uart.h" +#include "cpio.h" +#include "error.h" + +#define DIR_TYPE 1 +#define FILE_TYPE 2 +#define DIR_CAP 10 + +typedef struct{ + char* name; + int type; + int capacity; + int size; + void* data; + void* cache;//only for FILE_TYPE +}Content; + +void cacheInit(Content* content){ + if(content->cache)ERROR("cacheInit error!!"); + if(content->capacity==0){ + content->capacity=2; + } + content->cache=(void*)dalloc(content->capacity); + char* src=(char*)(content->data); + char* dst=(char*)(content->cache); + for(int i=0;isize;++i){ + dst[i]=src[i]; + } +} + +int tmpfs_Write(file* f,const void* buf,unsigned long len){ + vnode* node=f->node; + Content* content=(Content*)(node->internal); + if(content->type==FILE_TYPE){ + if(content->cache==0)cacheInit(content); + char* cache=(char*)(content->cache); + + if(f->f_pos+len > content->capacity){ + char* new_cache=(char*)dalloc((f->f_pos+len)*2); + for(int i=0;isize;++i)new_cache[i]=cache[i]; + content->capacity=(f->f_pos+len)*2; + content->cache=new_cache; + dfree((unsigned long)cache); + cache=new_cache; + } + + const char* buffer=(const char*)buf; + for(int i=0;if_pos]=buffer[i]; + f->f_pos++; + } + + if(content->size < f->f_pos){ + content->size=f->f_pos; + } + + return len; + }else{ + return 0; + } +} + +int tmpfs_Read(file* f,void* buf,unsigned long len){ + vnode* node=f->node; + Content* content=(Content*)(node->internal); + int size=content->size; + if(content->type==FILE_TYPE){ + if(content->cache==0)cacheInit(content); + char* cache=(char*)(content->cache); + + char* buffer=(char*)buf; + int ret=0; + for(int i=f->f_pos;if_pos+=ret; + return ret; + }else if(content->type==DIR_TYPE){ + if(f->f_pos>=size)return 0; + char* buffer=(char*)(buf); + vnode* child=((vnode**)(content->data))[f->f_pos++]; + content=(Content*)(child->internal); + int ret=0; + for(int i=0;iname[i])break; + buffer[i]=content->name[i]; + ret++; + } + return ret; + }else{ + return 0; + } +} + +void tmpfs_Dump(vnode* cur,int level){ + Content* content=(Content*)(cur->internal); + + for(int i=0;itype==DIR_TYPE){ + uart_printf("%s\n",content->name); + vnode** childs=(vnode**)(content->data); + for(int i=0;isize;++i){ + tmpfs_Dump(childs[i],level+1); + } + }else if(content->type==FILE_TYPE){ + uart_printf("%s (%d bytes)\n",content->name,content->size); + } +} + +int tmpfs_Creat(vnode* dir_node,vnode** target,const char* component_name){ + Content* content=(Content*)(dir_node->internal); + if(content->type!=DIR_TYPE){ + uart_printf("tmpfs_Creat error!!\n"); + while(1){} + } + vnode** childs=(vnode**)content->data; + + int idx=-1; + if(content->capacity>content->size){ + idx=content->size++; + }else{ + uart_printf("tmpfs_Creat: space is not enough!!\n"); + while(1){} + //TODO: move to larger array + } + + vnode* new_node=(vnode*)dalloc(sizeof(vnode)); + new_node->mnt=dir_node->mnt; + new_node->v_ops=dir_node->v_ops; + new_node->f_ops=dir_node->f_ops; + new_node->internal=(Content*)dalloc(sizeof(Content)); + + content=(Content*)new_node->internal; + content->name=(char*)dalloc(PREFIX_LEN); + slashIgnore(component_name,content->name,PREFIX_LEN); + content->type=FILE_TYPE; + content->capacity=0; + content->size=0; + content->data=0; + content->cache=0; + + childs[idx]=new_node; + if(target){ + *target=new_node; + } + return idx; +} + +int tmpfs_Lookup(vnode* dir_node,vnode** target,const char* component_name){ + Content* content=(Content*)(dir_node->internal); + if(content->type!=DIR_TYPE){ + uart_printf("tmpfs_Lookup error!!\n"); + while(1){} + } + vnode** childs=(vnode**)(content->data); + + for(int i=0;isize;++i){ + vnode* child=childs[i]; + Content* child_content=(Content*)(child->internal); + if(strcmp(child_content->name,component_name)==0){ + if(target){ + *target=child; + } + return i; + } + } + return -1; +} + +int tmpfs_nodeInit(mount* mnt,vnode* root){ + root->mnt=mnt; + root->v_ops=(vnode_operations*)dalloc(sizeof(vnode_operations)); + root->v_ops->lookup=tmpfs_Lookup; + root->v_ops->create=tmpfs_Creat; + root->f_ops=(file_operations*)dalloc(sizeof(file_operations)); + root->f_ops->write=tmpfs_Write; + root->f_ops->read=tmpfs_Read; + root->internal=(void*)dalloc(sizeof(Content)); + + Content* content=(Content*)(root->internal); + content->name=0; + content->type=DIR_TYPE; + content->capacity=DIR_CAP; + content->size=0; + content->data=(void*)dalloc(DIR_CAP*8); + + void* f=fbaseGet(); + unsigned long size; + while(1){//build tree + const char* fname=fnameGet(f,&size); + char* fdata=fdataGet(f,&size); + int fmode=fmodeGet(f); + if(strcmp(fname,"TRAILER!!!")==0)break; + + //insert file from root + vnode* dir_node=root; + content=(Content*)(dir_node->internal); + vnode** target=(vnode**)(content->data); + while(1){//iterative search + char prefix[PREFIX_LEN]; + fname=slashIgnore(fname,prefix,PREFIX_LEN); + int idx=tmpfs_Lookup(dir_node,0,prefix); + if(idx>=0){//next level + dir_node=target[idx]; + content=(Content*)(dir_node->internal); + target=(vnode**)(content->data); + }else{//final level + if(fname!=0){ + uart_printf("tmpfs_nodeInit error!!\n"); + uart_printf("%s\n%s\n",prefix,fname); + while(1){} + } + + idx=tmpfs_Creat(dir_node,0,prefix); + vnode* new_node=target[idx]; + content=(Content*)(new_node->internal); + if(fmode==1){ + content->type=DIR_TYPE; + content->capacity=DIR_CAP; + content->size=0; + content->data=(void*)dalloc(DIR_CAP*8); + }else if(fmode==2){ + content->type=FILE_TYPE; + content->capacity=size; + content->size=size; + content->data=fdata; + content->cache=0; + //uart_printf("%s,%d\n",content->name,content->size); + }else{ + uart_printf("unknown file type!!\n"); + while(1){} + } + content=(Content*)(root->internal); + target=(vnode**)(content->data); + break; + } + } + + f=nextfGet(f); + } + + return 0; +} + +int tmpfs_Setup(filesystem* fs,mount* mnt){ + char* name=(char*)dalloc(6); + //char tmp[]="tmpfs";//raspi bug!! + name[0]='t'; + name[1]='m'; + name[2]='p'; + name[3]='f'; + name[4]='s'; + name[5]=0; + fs->name=name; + fs->setup_mount=tmpfs_Setup; + mnt->root=(vnode*)dalloc(sizeof(vnode)); + mnt->fs=fs; + + tmpfs_nodeInit(mnt,mnt->root); + tmpfs_Dump(mnt->root,0); + return 0; +} \ No newline at end of file diff --git a/Lab8/inc/tmpfs.h b/Lab8/inc/tmpfs.h new file mode 100644 index 000000000..41cbb916a --- /dev/null +++ b/Lab8/inc/tmpfs.h @@ -0,0 +1,3 @@ +#include "vfs.h" + +int tmpfs_Setup(filesystem* fs,mount* mnt);//setup vnode \ No newline at end of file diff --git a/Lab8/inc/uart.c b/Lab8/inc/uart.c new file mode 100644 index 000000000..e729a27ce --- /dev/null +++ b/Lab8/inc/uart.c @@ -0,0 +1,164 @@ +#include "uart.h" +#include "mmio.h" +#include "printf.h" + +//GPIO registers +#define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE+0x00200004)) +#define GPPUD ((volatile unsigned int*)(MMIO_BASE+0x00200094)) +#define GPPUDCLK0 ((volatile unsigned int*)(MMIO_BASE+0x00200098)) + +//auxilary mini UART registers +#define AUX_ENABLE ((volatile unsigned int*)(MMIO_BASE+0x00215004)) +#define AUX_MU_CNTL ((volatile unsigned int*)(MMIO_BASE+0x00215060)) +#define AUX_MU_IER ((volatile unsigned int*)(MMIO_BASE+0x00215044)) +#define AUX_MU_LCR ((volatile unsigned int*)(MMIO_BASE+0x0021504C)) +#define AUX_MU_MCR ((volatile unsigned int*)(MMIO_BASE+0x00215050)) +#define AUX_MU_BAUD ((volatile unsigned int*)(MMIO_BASE+0x00215068)) +#define AUX_MU_IIR ((volatile unsigned int*)(MMIO_BASE+0x00215048)) +#define AUX_MU_LSR ((volatile unsigned int*)(MMIO_BASE+0x00215054)) +#define AUX_MU_IO ((volatile unsigned int*)(MMIO_BASE+0x00215040)) + +void uart_init(){ + register unsigned int r; + + //init UART + *AUX_ENABLE|=1;//enable mini UART + *AUX_MU_CNTL=0;//disable transmitter and receiver during configuration + *AUX_MU_IER=0;//disable interrupt because currently you don’t need interrupt + *AUX_MU_LCR=3;//set the data size to 8 bit + *AUX_MU_MCR=0;//don’t need auto flow control + *AUX_MU_BAUD=270;//set baud rate to 115200 + *AUX_MU_IIR=0xc6;//no FIFO + + //change alternate function + r=*GPFSEL1; + r&=~((7<<12)|(7<<15)); + r|=(2<<12)|(2<<15);//alt5 + *GPFSEL1=r; + + //disable GPIO pull up/down + *GPPUD=0; + r=150;while(r--){ asm volatile("nop"); } + *GPPUDCLK0=(1<<14)|(1<<15); + r=150;while(r--){ asm volatile("nop"); } + *GPPUDCLK0=0; + + *AUX_MU_CNTL=3;//enable the transmitter and receiver + + //flush read buffer + while(*AUX_MU_LSR&0x01){ + char tmp=(char)(*AUX_MU_IO); + } +} + +void uart_send(unsigned int c){ + if(c=='\n'){//convert "\n" to "\r\n" + uart_send('\r');//recursive + } + + do{ asm volatile("nop"); }while(!(*AUX_MU_LSR&0x20)); + *AUX_MU_IO=c; +} + +char uart_getc(){ + char r; + do{ asm volatile("nop"); }while(!(*AUX_MU_LSR&0x01)); + r=(char)(*AUX_MU_IO); + return r=='\r'?'\n':r; +} + +unsigned char uart_getb(){//for data transfer + unsigned char r; + do{ asm volatile("nop"); }while(!(*AUX_MU_LSR&0x01)); + r=(unsigned char)(*AUX_MU_IO); + return r; +} + +unsigned long uart_getX(int display){ + unsigned long ret=0; + char c; + while(1){ + c=uart_getc(); + if(display)uart_send(c); + if(c=='\n')break; + if(c>='0'&&c<='9'){ + ret=ret*16+c-'0'; + }else if(c>='a'&&c<='f'){ + ret=ret*16+c-'a'+10; + }else if(c>='A'&&c<='F'){ + ret=ret*16+c-'A'+10; + } + } + return ret; +} + +unsigned long uart_getU(int display){ + unsigned long ret=0; + char c; + while(1){ + c=uart_getc(); + if(display)uart_send(c); + if(c=='\n')break; + if(c>='0'&&c<='9'){ + ret=ret*10+c-'0'; + } + } + return ret; +} + +int uart_gets(char* s,int size,int display){ + for(int i=0;;++i){ + if(i==size){ + uart_puts("buffer overflow!\n"); + return i; + } + + s[i]=uart_getc(); + if(display)uart_send(s[i]); + + if(s[i]=='\n'){ + s[i]=0; + return i; + } + } +} + +void uart_puts(char *s){ + while(*s){ + uart_send(*s); + s++; + } +} + +void uart_puthex(unsigned int hex){ + uart_puts("0x"); + for(int i=28;i>=0;i-=4){ + unsigned int v=(hex>>i)&0xf; + if(v<10){ + uart_send('0'+v); + }else{ + uart_send('a'+v-10); + } + } +} + +unsigned int uart_printf(char* fmt,...){ + char dst[100]; + //__builtin_va_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args,fmt); + unsigned int ret=vsprintf(dst,fmt,args); + uart_puts(dst); + return ret; +} + +int strcmp(const char* a,const char* b){ + while(*a){ + if(*a!=*b)return 1; + a++; + b++; + } + if(*a!=*b)return 1; + return 0; +} \ No newline at end of file diff --git a/Lab8/inc/uart.h b/Lab8/inc/uart.h new file mode 100644 index 000000000..27746522f --- /dev/null +++ b/Lab8/inc/uart.h @@ -0,0 +1,11 @@ +void uart_init(); +void uart_send(unsigned int c); +char uart_getc(); +unsigned char uart_getb(); +unsigned long uart_getX(int display); +unsigned long uart_getU(int display); +int uart_gets(char* s,int size,int display); +void uart_puts(char *s); +void uart_puthex(unsigned int hex); +unsigned int uart_printf(char* fmt,...); +int strcmp(const char* a,const char* b); \ No newline at end of file diff --git a/Lab8/inc/vfs.c b/Lab8/inc/vfs.c new file mode 100644 index 000000000..ded27edeb --- /dev/null +++ b/Lab8/inc/vfs.c @@ -0,0 +1,80 @@ +#include "vfs.h" +#include "allocator.h" +#include "error.h" +#include "uart.h" + +static mount my_mount; +static filesystem my_filesystem; + +const char* slashIgnore(const char* src,char* dst,int size){ + for(int i=0;iv_ops->lookup(dir,&child,prefix); + + if(pathname){ + if(idx>=0){ + dir=child; + }else{ + ERROR("invalid directory!!"); + } + }else{ + if(idx>=0){ + break;//already exist + }else{ + if((flags&O_CREAT)==0)ERROR("invalid file!!"); + dir->v_ops->create(dir,&child,prefix); + break; + } + } + } + + file* ret=(file*)dalloc(sizeof(file)); + ret->node=child; + ret->f_pos=0; + ret->f_ops=my_mount.root->f_ops; + ret->flags=flags; + return ret; +} + +int vfs_close(file* f){ + dfree((unsigned long)f); + return 0; +} + +int vfs_write(file* f,const void* buf,unsigned long len){ + return f->f_ops->write(f,buf,len); +} + +int vfs_read(file* f,void* buf,unsigned long len){ + return f->f_ops->read(f,buf,len); +} + +void vfs_sync(file* f){ + f->f_ops->sync(f); +} + +void vfs_init(void* setup_mount_f){ + int (*setup_mount)(filesystem*,mount*)=setup_mount_f; + + setup_mount(&my_filesystem,&my_mount); + uart_printf("%s have been setup.\n\n",my_filesystem.name); +} \ No newline at end of file diff --git a/Lab8/inc/vfs.h b/Lab8/inc/vfs.h new file mode 100644 index 000000000..b300b6a0e --- /dev/null +++ b/Lab8/inc/vfs.h @@ -0,0 +1,52 @@ +struct mount { + struct vnode* root; + struct filesystem* fs; +}; + +struct filesystem { + const char* name; + int (*setup_mount)(struct filesystem* fs, struct mount* mnt); +}; + +struct vnode { + struct mount* mnt; + struct vnode_operations* v_ops; + struct file_operations* f_ops; + void* internal; +}; + +struct vnode_operations { + int (*lookup)(struct vnode* dir_node, struct vnode** target, const char* component_name); + int (*create)(struct vnode* dir_node, struct vnode** target, const char* component_name); +}; + +struct file { + struct vnode* node; + unsigned long f_pos; // The next read/write position of this opened file + struct file_operations* f_ops; + int flags; +}; + +struct file_operations { + int (*write) (struct file* f, const void* buf, unsigned long len); + int (*read) (struct file* f, void* buf, unsigned long len); + void (*sync) (struct file* f); +}; + +typedef struct mount mount; +typedef struct filesystem filesystem; +typedef struct vnode vnode; +typedef struct vnode_operations vnode_operations; +typedef struct file file; +typedef struct file_operations file_operations; + +#define PREFIX_LEN 50 +#define O_CREAT 2 + +const char* slashIgnore(const char* src,char* dst,int size); +file* vfs_open(const char* pathname, int flags); +int vfs_close(file* f); +int vfs_write(file* f,const void* buf,unsigned long len); +int vfs_read(file* f,void* buf,unsigned long len); +void vfs_sync(file* f); +void vfs_init(void* setup_mount_f); \ No newline at end of file diff --git a/README.md b/README.md index fb98ddaf9..85117710e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ | 學號 | GitHub 帳號 | 姓名 | Email | | --- | ----------- | --- | --- | -|`309551087`| `bensonlu0120` | `劉柏嶔` | at881005@gmail.com | +|`309551087`| `bensonlu0120` | `劉柏嶔` | benson55123@gmail.com | ## How to build