diff --git a/.vscode/bookmarks.json b/.vscode/bookmarks.json index 2bfe4576bab5890ce1aec88ec848f9f5a048aee9..77c02dea45a03f229f6ab6f38f057b18bd163f4c 100644 --- a/.vscode/bookmarks.json +++ b/.vscode/bookmarks.json @@ -4,12 +4,12 @@ "path": "src/kernel/syscall.c", "bookmarks": [ { - "line": 94, + "line": 93, "column": 0, "label": "" }, { - "line": 99, + "line": 98, "column": 0, "label": "" } diff --git a/.vscode/launch.json b/.vscode/launch.json index e0139668505735c721e7795f27b5b22a7e63d28c..7af94967bcf8a0d2b05f00f08f9bb4ad225e473f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,25 +8,29 @@ "name": "(gdb) å¯åЍ", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/test/buddy/buddy", + "program": "${workspaceFolder}/build/kernel", "args": [], "stopAtEntry": false, "cwd": "${fileDirname}", "environment": [], "externalConsole": false, "MIMode": "gdb", + // "miDebuggerPath": "/opt/kendryte-toolchain/bin/riscv64-unknown-elf-gdb", + "miDebuggerPath": "/usr/bin/gdb-multiarch", + "miDebuggerServerAddress": "192.168.137.100:26000", "setupCommands": [ { "description": "为 gdb å¯ç”¨æ•´é½æ‰“å°", "text": "-enable-pretty-printing", "ignoreFailures": true }, - { - "description": "将忱‡ç¼–é£Žæ ¼è®¾ç½®ä¸º Intel", - "text": "-gdb-set disassembly-flavor intel", - "ignoreFailures": true - } - ] + // { + // "description": "将忱‡ç¼–é£Žæ ¼è®¾ç½®ä¸º Intel", + // "text": "-gdb-set disassembly-flavor intel", + // "ignoreFailures": true + // } + ], + } ] diff --git a/.vscode/settings.json b/.vscode/settings.json index 22785168ad0258fb1b0f126f539b6a61f8616913..1341037c335bb5b638a1ecc62572eae522b09231 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -98,7 +98,8 @@ "syscall_ids.h": "c", "syscall_arch.h": "c", "profile_gen.h": "c", - "profile.h": "c" + "profile.h": "c", + "mmap.h": "c" }, "C_Cpp.errorSquiggles": "Enabled", "todohighlight.keywords": [ diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000000000000000000000000000000000000..55f32aeda69e88054c38fa65c70ec79e0814282b --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,13 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "run qemu", + "type": "shell", + "command": "./run-gdb.sh", + "args": [], + } + ] +} \ No newline at end of file diff --git a/entry/syscall.tbl b/entry/syscall.tbl index 19a48f257a1c257a73ed8ea0de0f17cd25a01f5d..4571cc256ffd121b7a9aace8c977b2ba030c1ba1 100644 --- a/entry/syscall.tbl +++ b/entry/syscall.tbl @@ -30,8 +30,8 @@ 80 fstat sys_fstat ##############MM################ 214 sbrk sys_sbrk -215 munmap sys_munmap -222 mmap sys_mmap +#215 munmap sys_munmap +#222 mmap sys_mmap ############Others############## 153 times sys_times 160 uname sys_uname diff --git a/include/fs/fcntl.h b/include/fs/fcntl.h index 949c66064e664b108b67e61780cb29aa446bf305..9733c1f842a42c78ec8076ef67ebe64c4e838119 100644 --- a/include/fs/fcntl.h +++ b/include/fs/fcntl.h @@ -8,13 +8,13 @@ #define O_DIRECTORY 0x0200000 // mmap -#define PROT_NONE 0x0 -#define PROT_READ 0x1 -#define PROT_WRITE 0x2 -#define PROT_EXEC 0x4 +// #define PROT_NONE 0x0 +// #define PROT_READ 0x1 +// #define PROT_WRITE 0x2 +// #define PROT_EXEC 0x4 -#define MAP_SHARED 0x01 -#define MAP_PRIVATE 0x02 +// #define MAP_SHARED (1UL << 0) +// #define MAP_PRIVATE (1UL << 1) #define AT_FDCWD -100 diff --git a/include/kernel/proc.h b/include/kernel/proc.h index 8796c52f30c87a3092086ec649c0638f694c407c..932779b21e5d6fc374eda876b9c46d7d9b99c9d9 100644 --- a/include/kernel/proc.h +++ b/include/kernel/proc.h @@ -3,6 +3,7 @@ #include "atomic/spinlock.h" #include "platform.h" +#include "mm/mmap.h" // Saved registers for kernel context switches. struct context { @@ -36,72 +37,13 @@ struct cpu { extern struct cpu cpus[NUM_CORES]; -// per-process data for the trap handling code in trampoline.S. -// sits in a page by itself just under the trampoline page in the -// user page table. not specially mapped in the kernel page table. -// the sscratch register points here. -// uservec in trampoline.S saves user registers in the trapframe, -// then initializes registers from the trapframe's -// kernel_sp, kernel_hartid, kernel_satp, and jumps to kernel_trap. -// usertrapret() and userret in trampoline.S set up -// the trapframe's kernel_*, restore user registers from the -// trapframe, switch to the user page table, and enter user space. -// the trapframe includes callee-saved user registers like s0-s11 because the -// return-to-user path via usertrapret() doesn't return through -// the entire kernel call stack. -struct trapframe { - /* 0 @depercated */ uint64 kernel_satp; // kernel page table - /* 8 */ uint64 kernel_sp; // top of process's kernel stack - /* 16 */ uint64 kernel_trap; // usertrap() - /* 24 */ uint64 epc; // saved user program counter - /* 32 */ uint64 kernel_hartid; // saved kernel tp - /* 40 */ uint64 ra; - /* 48 */ uint64 sp; - /* 56 */ uint64 gp; - /* 64 */ uint64 tp; - /* 72 */ uint64 t0; - /* 80 */ uint64 t1; - /* 88 */ uint64 t2; - /* 96 */ uint64 s0; - /* 104 */ uint64 s1; - /* 112 */ uint64 a0; - /* 120 */ uint64 a1; - /* 128 */ uint64 a2; - /* 136 */ uint64 a3; - /* 144 */ uint64 a4; - /* 152 */ uint64 a5; - /* 160 */ uint64 a6; - /* 168 */ uint64 a7; - /* 176 */ uint64 s2; - /* 184 */ uint64 s3; - /* 192 */ uint64 s4; - /* 200 */ uint64 s5; - /* 208 */ uint64 s6; - /* 216 */ uint64 s7; - /* 224 */ uint64 s8; - /* 232 */ uint64 s9; - /* 240 */ uint64 s10; - /* 248 */ uint64 s11; - /* 256 */ uint64 t3; - /* 264 */ uint64 t4; - /* 272 */ uint64 t5; - /* 280 */ uint64 t6; -}; enum procstate { UNUSED, USED, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; -#define VMA_NUM 16 -struct vma{ - uint64 addr; - uint64 end;//aligned to pages - uint64 len; - int prot; - int flags; - uint64 off; - - struct file *map_file; - enum{VMA_UNUSED, VMA_USED} state; -}; + +#define PROC_KSTACK(proc) ((proc)->memlayout.kstack->addr) +#define PROC_TRAPFRAME(proc) ((struct trapframe *)((proc)->memlayout.trapframe->addr)) +#define PROC_VMA_HEAD(proc) ((proc)->memlayout.vma_head) struct fat_entry; // Per-process state @@ -119,10 +61,11 @@ struct proc { struct proc *parent; // Parent process // these are private to the process, so p->lock need not be held. - uint64 kstack; // Virtual address of kernel stack - uint64 sz; // Size of process memory (bytes) - pagetable_t pagetable; // User page table - struct trapframe *trapframe; // data page for trampoline.S + // uint64 kstack; // Virtual address of kernel stack + // uint64 sz; // Size of process memory (bytes) + mm_t *mm; + + // struct trapframe *trapframe; // data page for trampoline.S struct context context; // swtch() here to run process struct file *ofile[NOFILE]; // Open files struct file **ext_ofile; @@ -131,8 +74,8 @@ struct proc { // struct inode *cwd; // Current directory char name[16]; // Process name (debugging) uint64 ktrap_fp; - - struct vma vma[VMA_NUM]; + // todo: mmap + // struct vma vma[VMA_NUM]; uint64 cur_mmap_sz; }; @@ -141,7 +84,7 @@ typedef struct proc proc_t; void exit(int); int do_clone(uint64_t stack); -int growproc(int); +uint64 growproc(int); void proc_mapstacks(); pagetable_t proc_pagetable(struct proc *); void proc_freepagetable(pagetable_t, uint64); @@ -158,4 +101,8 @@ int waitpid(int cid, uint64 addr); void wakeup(void*); void yield(void); void procdump(void); +void proc_setmm(proc_t *p, mm_t *newmm); + + + #endif \ No newline at end of file diff --git a/include/list.h b/include/list.h new file mode 100644 index 0000000000000000000000000000000000000000..f9b0868b8b7d574e081fa43cde6b90c650fc2997 --- /dev/null +++ b/include/list.h @@ -0,0 +1,356 @@ +#ifndef _H_LINKED_LIST +#define _H_LINKED_LIST + + +#include"types.h" + + +/* + * These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +#define LIST_POISON0 ((void *) 0x00100100) +#define LIST_POISON1 ((void *) 0x00200200) + +struct list_head{ + struct list_head *next, *prev; +}; + +typedef struct list_head list_head_t; + + +#define LIST_HEAD_INIT(name) {&(name), &(name)} + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/** + * 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; +} + +/* + * Insert a pnew entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *pnew, + struct list_head *prev, + struct list_head *next) +{ + next->prev = pnew; + pnew->next = next; + pnew->prev = prev; + prev->next = pnew; +} +/** + * list_add - add a pnew entry + * @pnew: pnew entry to be added + * @head: list head to add it after + * + * Insert a pnew entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *pnew, struct list_head *head) +{ + __list_add(pnew, head, head->next); +} + +/** + * list_add_tail - add a pnew entry + * @pnew: pnew entry to be added + * @head: list head to add it before + * + * Insert a pnew entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *pnew, struct list_head *head) +{ + __list_add(pnew, 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) +{ + // if (!__list_del_entry_valid(entry)) + // return; + + __list_del(entry->prev, entry->next); +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del_entry(entry); + // entry->next = LIST_POISON1; + // entry->prev = LIST_POISON2; + entry->next = (list_head_t *)NULL; + entry->prev = (list_head_t *)NULL; +} + +/** + * list_replace - replace old entry by pnew one + * @old : the element to be replaced + * @pnew : the pnew element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *pnew) +{ + pnew->next = old->next; + pnew->next->prev = pnew; + pnew->prev = old->prev; + pnew->prev->next = pnew; +} + + +/** + * list_replace_init - replace old entry by pnew one and initialize the old one + * @old : the element to be replaced + * @pnew : the pnew element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace_init(struct list_head *old, + struct list_head *pnew) +{ + list_replace(old, pnew); + INIT_LIST_HEAD(old); +} + +/** + * list_swap - replace entry1 with entry2 and re-add entry1 at entry2's position + * @entry1: the location to place entry2 + * @entry2: the location to place entry1 + */ +static inline void list_swap(struct list_head *entry1, + struct list_head *entry2) +{ + struct list_head *pos = entry2->prev; + + list_del(entry2); + list_replace(entry1, entry2); + if (pos == entry1) + pos = entry2; + list_add(entry1, pos); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del_entry(entry); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + + + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_last_entry - get the last element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_last_entry(ptr, type, member) \ + list_entry((ptr)->prev, type, member) + + + +/** + * list_next_entry - get the next element in list + * @pos: the type * to cursor + * @member: the name of the list_head within the struct. + */ +#define list_next_entry(pos, member) \ + list_entry((pos)->member.next, typeof(*(pos)), member) + +/** + * list_prev_entry - get the prev element in list + * @pos: the type * to cursor + * @member: the name of the list_head within the struct. + */ +#define list_prev_entry(pos, member) \ + list_entry((pos)->member.prev, typeof(*(pos)), member) + + +/** + * 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) + +/** + * list_entry_is_head - test if the entry points to the head of the list + * @pos: the type * to cursor + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_entry_is_head(pos, head, member) \ + (&pos->member == (head)) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member); \ + !list_entry_is_head(pos, head, member); \ + pos = list_next_entry(pos, member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_last_entry(head, typeof(*pos), member); \ + !list_entry_is_head(pos, head, member); \ + pos = list_prev_entry(pos, member)) + + + + + + +// // hash list +// #define HLIST_HEAD_INIT {.first = NULL} +// #define HLIST_HEAD(name) struct hlist_head name = {.first = NULL} +// #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) + +// static inline void INIT_HLIST_NODE(struct hlist_node *h){ +// h->next = NULL; +// h->pprev = NULL; +// } + + + + +// /** +// * hlist_add_head - add a pnew entry at the beginning of the hlist +// * @n: pnew entry to be added +// * @h: hlist head to add it after +// * +// * Insert a pnew entry after the specified head. +// * This is good for implementing stacks. +// */ +// static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +// { +// struct hlist_node *first = h->first; +// n->next = first; +// if (first) +// first->pprev = &n->next; +// h->first = n; +// n->pprev = &h->first; +// } + +// static __inline__ void __hlist_del(struct hlist_node *n) +// { +// struct hlist_node *next = n->next; +// struct hlist_node **pprev = n->pprev; +// *pprev = next; +// if (next) +// next->pprev = pprev; +// } + +// /** +// * hlist_del_rcu - deletes entry from hash list without re-initialization +// * @n: the element to delete from the hash list. +// * +// * Note: list_unhashed() on entry does not return true after this, +// * the entry is in an undefined state. It is useful for RCU based +// * lockfree traversal. +// * +// * In particular, it means that we can not poison the forward +// * pointers that may still be used for walking the hash list. +// */ +// static inline void hlist_del_rcu(struct hlist_node *n) +// { +// __hlist_del(n); +// n->pprev = LIST_POISON2; +// } + + +#endif \ No newline at end of file diff --git a/include/memlayout.h b/include/memlayout.h index 1aa4fdc56013b1b58b67eec964d5c9252b4b2d75..4c1d9071c27cb0dac69b42614d5a16d9292f9e95 100644 --- a/include/memlayout.h +++ b/include/memlayout.h @@ -8,7 +8,8 @@ #define IO_BASE_ADDRESS 0x1F00000000 #define KSTACK_SZ PGSIZE -#define KSTACK (MAXVA - KSTACK_SZ) +#define TRAPFRAME (MAXVA - PGSIZE) +#define KSTACK (TRAPFRAME - KSTACK_SZ) #define MMAP_BASE 0x60000000 #endif \ No newline at end of file diff --git a/include/mm/mmap.h b/include/mm/mmap.h new file mode 100644 index 0000000000000000000000000000000000000000..68b47e9db5ee7019d8aa35f3b2d5977152ff7dd0 --- /dev/null +++ b/include/mm/mmap.h @@ -0,0 +1,115 @@ +#ifndef _H_MM_ +#define _H_MM_ +#include "list.h" +#include "common.h" +// #include "mm/vm.h" +// #include "proc.h" + +#define USERSPACE_END (0x80000000) // 2GB +#define PROGRAM_BREAK(mm) ((mm)->uheap->addr + (mm)->uheap->addr) + + +struct trapframe { + /* 0 @depercated */ uint64 kernel_satp; // kernel page table + /* 8 */ uint64 kernel_sp; // top of process's kernel stack + /* 16 */ uint64 kernel_trap; // usertrap() + /* 24 */ uint64 epc; // saved user program counter + /* 32 */ uint64 kernel_hartid; // saved kernel tp + /* 40 */ uint64 ra; + /* 48 */ uint64 sp; + /* 56 */ uint64 gp; + /* 64 */ uint64 tp; + /* 72 */ uint64 t0; + /* 80 */ uint64 t1; + /* 88 */ uint64 t2; + /* 96 */ uint64 s0; + /* 104 */ uint64 s1; + /* 112 */ uint64 a0; + /* 120 */ uint64 a1; + /* 128 */ uint64 a2; + /* 136 */ uint64 a3; + /* 144 */ uint64 a4; + /* 152 */ uint64 a5; + /* 160 */ uint64 a6; + /* 168 */ uint64 a7; + /* 176 */ uint64 s2; + /* 184 */ uint64 s3; + /* 192 */ uint64 s4; + /* 200 */ uint64 s5; + /* 208 */ uint64 s6; + /* 216 */ uint64 s7; + /* 224 */ uint64 s8; + /* 232 */ uint64 s9; + /* 240 */ uint64 s10; + /* 248 */ uint64 s11; + /* 256 */ uint64 t3; + /* 264 */ uint64 t4; + /* 272 */ uint64 t5; + /* 280 */ uint64 t6; +}; + +#define VMA_NUM 16 +/* 用于æè¿°ç‰¹å®šä¸€æ®µå†…å˜åŒºåŸŸï¼ˆæ®µï¼‰ */ +struct vma{ + uint64 addr; + uint64 len; + uint64_t pa; + uint offset; /* ç›®å‰ç”¨æ¥è®°å½•申请时给定地å€ä¸Žå…¶æ‰€åœ¨é¡µé¢çš„åç§»é‡ */ + + int flags; + int prot; + + list_head_t head; /* 用于串è”VMA结构 */ + + struct file *map_file; +}; + +typedef struct vma vma_t; + +// flags +#define MAP_ANONYMOUS (1L << 31) // 匿å,为0表示FILE +#define MAP_SHARED (1L << 30) // 共享,为0è¡¨ç¤ºç§æœ‰ +#define MAP_STACK (1L << 29) // 表示å‘ä¸‹æ‰©å±•çš„æ ˆ +// prot(与pteåŒ) +#define MAP_PROT_READ (PTE_R) +#define MAP_PROT_WRITE (PTE_W) +#define MAP_PROT_EXEC (PTE_X) +#define MAP_PROT_USER (PTE_U) + +/* æè¿°è¿›ç¨‹çš„å†…å˜æ®µ */ +struct mmlayout +{ + uint64_t kstack; /* å†…æ ¸æ ˆ */ + uint64_t trapframe; /* é™·å…¥æ ˆå¸§ */ + + vma_t *ustack; /* ç”¨æˆ·æ ˆ */ + vma_t *uheap; /* ç”¨æˆ·å † */ + + list_head_t vma_head; /* 其他内å˜åŒºåŸŸ */ + + pagetable_t pagetable; // User page table + // proc_t *owner; +}; + +typedef struct mmlayout mm_t; + + +int do_mmap(mm_t *mm, struct file *fp, uint64_t addr, uint64_t len, int flags, int prot); +int do_mmap_alloc(mm_t *mm, struct file *fp, uint64_t addr, uint64_t len, int flags, int prot); +void do_unmap(mm_t *mm, uint64_t addr, int do_free); +int mmap_init(mm_t *mm, mm_t *oldmm); +void mmap_free(mm_t **pmm); +vma_t *vma_find(mm_t *mm, uint64 addr); +vma_t *vma_exist(mm_t *mm, uint64_t addr, uint64_t len); +struct trapframe *get_trapframe(mm_t *mm); +uint64_t get_kstack(mm_t *mm); +int mmap_dup(mm_t *newm, mm_t *oldm); +int mmap_ext_heap(mm_t *mm, int newsize); +vma_t *__vma_find_strict(mm_t *mm, uint64 addr); +void mmap_print_vmas(mm_t *mm); +void mmap_print_vma(vma_t *vma); + +void switchuvm(mm_t *mm); +void switchkvm(); + +#endif \ No newline at end of file diff --git a/include/mm/vm.h b/include/mm/vm.h index e50862dd43c771937e016037145318fc20cbf1be..6e75ed000e0df6afaf4c764a9dc93d34d85059f5 100644 --- a/include/mm/vm.h +++ b/include/mm/vm.h @@ -1,6 +1,7 @@ -#ifndef _H_MM_ -#define _H_MM_ +#ifndef _H_VM_ +#define _H_VM_ +#include "mm/mmap.h" #include "mm/page.h" #include "mm/alloc.h" @@ -23,27 +24,27 @@ pagetable_t uvmcreate(void); void uvminit(pagetable_t, uchar *, uint); uint64 uvmalloc(pagetable_t, uint64, uint64); uint64 uvmdealloc(pagetable_t, uint64, uint64); -int uvmcopy(pagetable_t, pagetable_t, uint64); +int uvmcopy(pagetable_t old, pagetable_t new, uint64 addr, uint64_t len); void uvmfree(pagetable_t, uint64); void uvmclear(pagetable_t, uint64); uint64 _walkaddr(pagetable_t pagetable, uint64 va, int pg_spec); -int copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len); +void __copyout(mm_t *mm, uint64_t dstva, char *src, uint64 len, int walk); +int copyout(uint64 dstva, char *src, uint64 len); /** @deprecated use copy_from_user instead */ -int copyin(pagetable_t, char *, uint64, uint64); -int copyinstr(pagetable_t, char *, uint64, uint64); -int cow_copy(pagetable_t pagetable, uint64_t va, pte_t **pppte); +int copyin(char *, uint64, uint64); +int copyinstr(char *, uint64, uint64); +int cow_copy(uint64_t va, pte_t *pte); int copy_from_user(void *to, void *from, size_t n); int either_copyout(int user_dst, uint64 dst, void *src, uint64 len); int either_copyin(void *dst, int user_src, uint64 src, uint64 len); +void vmprint(pagetable_t pagetable); +void print_map(struct _kmap_t map); + int setupkvm(pagetable_t pagetable); void erasekvm(pagetable_t pagetable); -#include "kernel/proc.h" -void switchuvm(struct proc *p); -void switchkvm(); - #define walkaddr(pagetable, va) \ _walkaddr(pagetable, va, PGSPEC_NORMAL) diff --git a/include/param.h b/include/param.h index 75dde76fd6a317757184f593522ccc01490a3afc..f08199a620b16707b7b4dc697da85ebd390cae70 100644 --- a/include/param.h +++ b/include/param.h @@ -14,7 +14,7 @@ #define BSIZE 512 #define NENTRY 40 -#define MAX_FILE_NAME 20 +#define MAX_FILE_NAME 128 #define USTACKSIZE 8192 diff --git a/include/riscv.h b/include/riscv.h index 97f5c321026b17e692ae492e1118e1cba280dbf9..aa2e7e4f93d9e52f05a1c3a9887dc33cac108dca 100644 --- a/include/riscv.h +++ b/include/riscv.h @@ -25,6 +25,8 @@ r_mhartid() #define EXCP_LOAD_PAGE_FAULT (EXCEPTION + 13) #define EXCP_STORE_PAGE_FAULT (EXCEPTION + 15) +#define IS_INTR(scause) ((scause) & INTERRUPT) + static inline uint64 r_mstatus() { @@ -242,7 +244,7 @@ static inline uint64 r_fp() { uint64 x; - asm volatile("mv %0, fp" : "=r" (x) ); + asm volatile("mv %0, s0" : "=r" (x) ); return x; } diff --git a/run-gdb.sh b/run-gdb.sh index cbefad6b7bc8a3f3dff139b748fccdaf3c46ebc5..f782430789962849590cb73ad09d41251c025ce2 100755 --- a/run-gdb.sh +++ b/run-gdb.sh @@ -1,2 +1,2 @@ #!/bin/sh -make run platform=qemu EXTRA_QEMUOPTS='-S -gdb tcp::26000' CPUS=1 \ No newline at end of file +make run platform=qemu debug=on EXTRA_QEMUOPTS='-S -gdb tcp::26000' CPUS=1 \ No newline at end of file diff --git a/src/fs/fs.c b/src/fs/fs.c index 46e177bf384b8d7efe084c530904dbbdc631516c..05793b9f0cfcdb4fe182bb9dc2d98483954755fe 100644 --- a/src/fs/fs.c +++ b/src/fs/fs.c @@ -8,7 +8,7 @@ #include "str.h" #include "profile.h" -#define QUIET +// #define QUIET #define __MODULE_NAME__ FS #include "debug.h" diff --git a/src/fs/pipe.c b/src/fs/pipe.c index 39c9bd78998edca933e9dda69dcfb6edc94af60d..796836ea3e5fcf2c45bd7c16a5077e209e4b4c44 100644 --- a/src/fs/pipe.c +++ b/src/fs/pipe.c @@ -91,7 +91,7 @@ pipewrite(struct pipe *pi, uint64 addr, int n) sleep(&pi->nwrite, &pi->lock); } else { char ch; - if(copyin(pr->pagetable, &ch, addr + i, 1) == -1) + if(copyin(&ch, addr + i, 1) == -1) break; pi->data[pi->nwrite++ % PIPESIZE] = ch; i++; @@ -122,7 +122,7 @@ piperead(struct pipe *pi, uint64 addr, int n) if(pi->nread == pi->nwrite) break; ch = pi->data[pi->nread++ % PIPESIZE]; - if(copyout(pr->pagetable, addr + i, &ch, 1) == -1) + if(copyout(addr + i, &ch, 1) == -1) break; } wakeup(&pi->nwrite); //DOC: piperead-wakeup diff --git a/src/include/common.h b/src/include/common.h index 37fd5a322cc114ce32337a6e1aaba186831cd967..a48ead4cf2b727fc35e8f766cd0944205c53ae15 100644 --- a/src/include/common.h +++ b/src/include/common.h @@ -12,6 +12,12 @@ #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif + #define UNUSED(x) x __attribute__((__unused__)) #define likely(x) __builtin_expect(!!(x), 1) diff --git a/src/include/utils.h b/src/include/utils.h index 9b972f5bec41de2e5c9e46ce878702e219544ade..280f95428218829994ef4548c38a7d4b56a1724e 100644 --- a/src/include/utils.h +++ b/src/include/utils.h @@ -2,7 +2,6 @@ #define _H_UTILS_ #include "printf.h" -#include "mm/vm.h" #include "sbi.h" #define LOOP() {while(1) continue;} @@ -51,10 +50,9 @@ static inline uint32_t get_gpio_bit(volatile uint32_t *bits, size_t offset) } struct dir_item; +struct proc; -void vmprint(pagetable_t pagetable); -void backtrace(proc_t *p); -void print_map(kmap_t map); +void backtrace(struct proc *p); void print_sbiret(sbiret_t ret); int luaO_log2 (unsigned int x); void print_page(int pgnum); diff --git a/src/kernel/exec.c b/src/kernel/exec.c index 52c60289e9c57e3ac56019428a4e3af836e95d87..3fce60e45f204690de821c5ee10165a131683401 100644 --- a/src/kernel/exec.c +++ b/src/kernel/exec.c @@ -14,24 +14,68 @@ #define __MODULE_NAME__ EXEC #include "debug.h" -static int loadseg(pde_t *pgdir, uint64 addr, entry_t *ip, uint offset, uint sz); +// Load a program segment into pagetable at virtual address va. +// va must be page-aligned +// and the pages from va to va+sz must already be mapped. +// Returns 0 on success, -1 on failure. +static int loadseg(mm_t *mm, uint64 va, entry_t *ip, uint offset, uint sz) { + uint i, n; + uint64 pa; + + for(i = 0; i < sz; i += PGSIZE) { + pa = walkaddr(mm->pagetable, va + i); + if(pa == 0) + panic("loadseg: address should exist"); + if(sz - i < PGSIZE) + n = sz - i; + else + n = PGSIZE; + if(reade(ip, 0, (uint64)pa, offset+i, n) != n) + return -1; + } + + return 0; +} -int -exec(char *path, char **argv) -{ +int exec(char *path, char **argv) { char *s, *last; int i, off; - uint64 argc, sz = 0, sp, ustack[MAXARG + 1], stackbase; + uint64 argc; + uint64 ustack, ustackbase; struct elfhdr elf; entry_t *ep; struct proghdr ph; - pagetable_t pagetable = 0, oldpagetable; struct proc *p = myproc(); + mm_t *newmm; + /* alloc */ + if((newmm = kzalloc(sizeof(mm_t))) == NULL) { + debug("newmm alloc failure"); + return -1; + } + if((ustackbase = (uint64)kmalloc(USTACKSIZE)) == 0) { + debug("stack alloc failure"); + kfree(newmm); + return -1; + } + + ustack = ustackbase + USTACKSIZE; if((ep = namee(NULL, path)) == 0){ + debug("entry acquire failure"); + kfree(newmm); + kfree((void *)ustackbase); + return -1; + } + + /* load */ + if(mmap_init(newmm, p->mm) == -1) { + debug("newmm init fail"); + kfree(newmm); + kfree((void *)ustackbase); return -1; } + elock(ep); // Check ELF header @@ -40,11 +84,6 @@ exec(char *path, char **argv) if(elf.magic != ELF_MAGIC) goto bad; - if((pagetable = proc_pagetable(p)) == 0) - goto bad; - - - // vmprint(pagetable); // Load program into memory. for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){ if(reade(ep, 0, (uint64)&ph, off, sizeof(ph)) != sizeof(ph)){ @@ -56,62 +95,51 @@ exec(char *path, char **argv) goto bad; if(ph.vaddr + ph.memsz < ph.vaddr) goto bad; - uint64 sz1; - if((sz1 = uvmalloc(pagetable, sz, ph.vaddr + ph.memsz)) == 0) - goto bad; - sz = sz1; - if((ph.vaddr % PGSIZE) != 0) + if(do_mmap_alloc(newmm, NULL, ph.vaddr, ph.memsz, 0, MAP_PROT_READ|MAP_PROT_WRITE|MAP_PROT_EXEC|MAP_PROT_USER) == -1) goto bad; - if(loadseg(pagetable, ph.vaddr, ep, ph.off, ph.filesz) < 0) + if(loadseg(newmm, ph.vaddr, ep, ph.off, ph.filesz) < 0) goto bad; } - // printf("ph: %d\n", ph.vaddr + ph.memsz); - // vmprint(pagetable); eunlockput(ep); ep = NULL; p = myproc(); - uint64 oldsz = p->sz; - // alloc for user stack - sz = PGROUNDUP(sz); - uint64 sz1; - if((sz1 = uvmalloc(pagetable, sz, sz + PGSIZE + USTACKSIZE)) == 0) + /* stack */ + if(do_mmap(newmm, NULL, USERSPACE_END - USTACKSIZE, USTACKSIZE, MAP_STACK, MAP_PROT_READ|MAP_PROT_WRITE|MAP_PROT_USER) == -1) goto bad; - sz = sz1; - uvmclear(pagetable, sz - (PGSIZE + USTACKSIZE)); - sp = sz; - stackbase = sp - USTACKSIZE; - - // Push argument strings, prepare rest of stack in ustack. + uint64 argcv[MAXARG + 1]; + uint64 *argvs = argcv + 1; + // Push argument strings, prepare rest of stack in ustack. for(argc = 0; argv[argc]; argc++) { if(argc >= MAXARG) goto bad; - sp -= strlen(argv[argc]) + 1; - sp -= sp % 16; // riscv sp must be 16-byte aligned - if(sp < stackbase) - goto bad; - if(copyout(pagetable, sp, argv[argc], strlen(argv[argc]) + 1) < 0) + ustack -= strlen(argv[argc]) + 1; + ustack -= ustack % 16; // riscv sp must be 16-byte aligned + if(ustack < ustackbase) goto bad; - ustack[argc + 1] = sp; + memcpy((void *)ustack, argv[argc], strlen(argv[argc]) + 1); + argvs[argc] = ustack; } - ustack[0]= argc; - ustack[argc + 1] = 0; + argcv[0] = argc; + argvs[argc] = 0; - // push the array of argv[] pointers. - sp -= (argc+1+1) * sizeof(uint64); - sp -= sp % 16; - if(sp < stackbase) - goto bad; - if(copyout(pagetable, sp, (char *)ustack, (argc+1+1)*sizeof(uint64)) < 0) + ustack -= sizeof(uint64) * (1 + 1 + argc); // argc + agrv + 0 + ustack -= ustack % 16; + if(ustack < ustackbase) goto bad; + memcpy((void *)ustack, argcv, sizeof(uint64) * (1 + 1 + argc)); // arguments to user main(argc, argv) // argc is returned via the system call return // value, which goes in a0. - p->trapframe->a1 = sp; + get_trapframe(newmm)->sp = USERSPACE_END - USTACKSIZE + ustack - ustackbase; + + if(mappages(newmm->pagetable, USERSPACE_END - USTACKSIZE, USTACKSIZE, ustackbase, MAP_PROT_READ|MAP_PROT_WRITE|MAP_PROT_USER) == -1) { + goto bad; + } // Save program name for debugging. for(last=s=path; *s; s++) @@ -119,48 +147,14 @@ exec(char *path, char **argv) last = s+1; safestrcpy(p->name, last, sizeof(p->name)); - // Commit to the user image. - oldpagetable = p->pagetable; - p->pagetable = pagetable; - p->sz = sz; - // printf(rd("sz: %x\n"), sz); - p->trapframe->epc = elf.entry; // initial program counter = main - // debug("entry addr is %lx", elf.entry); - p->trapframe->sp = sp; // initial stack pointer - switchuvm(p); - proc_freepagetable(oldpagetable, oldsz); + get_trapframe(newmm)->epc = elf.entry; // initial program counter = main + proc_setmm(p, newmm); return argc; // this ends up in a0, the first argument to main(argc, argv) bad: - if(pagetable) - proc_freepagetable(pagetable, sz); - if(ep){ - eunlockput(ep); - } + // TODO: + panic("bad"); return -1; } -// Load a program segment into pagetable at virtual address va. -// va must be page-aligned -// and the pages from va to va+sz must already be mapped. -// Returns 0 on success, -1 on failure. -static int -loadseg(pagetable_t pagetable, uint64 va, entry_t *ip, uint offset, uint sz) -{ - uint i, n; - uint64 pa; - for(i = 0; i < sz; i += PGSIZE){ - pa = walkaddr(pagetable, va + i); - if(pa == 0) - panic("loadseg: address should exist"); - if(sz - i < PGSIZE) - n = sz - i; - else - n = PGSIZE; - if(reade(ip, 0, (uint64)pa, offset+i, n) != n) - return -1; - } - - return 0; -} diff --git a/src/kernel/initcode.c b/src/kernel/initcode.c index 40e1292b6767207151248e0b4116f547ff09a631..75f33b71902bf39a8f4927c9e29e5b695f8b3308 100644 --- a/src/kernel/initcode.c +++ b/src/kernel/initcode.c @@ -1,3 +1,199 @@ +// #include "usys.h" +// #include "stdarg.h" + +// void printf(const char *fmt, ...); +// void read_test(); + +// // FS +// // char *fs_testcase[] = { "mkdir_","openat", "dup2","close", "unlink", "getcwd", "getdents", +// // "chdir", "dup", "pipe", "open", "read", "write", "fstat", +// // "mount", "umount", "test_echo"}; +// // // +// // char *proc_testcase[] = { "getppid", "getpid", +// // "clone", "wait", "waitpid", +// // "yield", "fork", "execve", "exit", "sleep"}; + +// // char *mm_testcase[] = {"brk", "mmap", "munmap"}; + +// // char *other_testcase[] = {"gettimeofday", "times", "uname"}; +// // // å•项测试 +// // char* prog_name[] = {"ls"}; + +// // void readcase(int fd, char buf[]) { +// // while(read(fd, buf, )) +// // } + + +// void run(char *testcases[], int cnt); +// #define run(cases) run(cases, sizeof(cases)/sizeof(cases[0])) +// __attribute__((section(".startup"))) +// void main() { +// memuse(); +// // run(fs_testcase); +// // run(proc_testcase); +// // run(mm_testcase); +// // run(other_testcase); +// // run(prog_name); +// // int fd = openat(AT_FDCWD, "run_static.sh", O_RDONLY); +// char *argv[5]; +// argv[0] = "runtest.exe"; +// argv[1] = "-w"; +// argv[2] = "entry-static.exe"; +// argv[3] = "argv"; +// argv[4] = 0; +// printf("ready to run %s\n", argv[3]); +// int npid = fork(); +// if(npid < 0) { +// printf("fork failed"); +// for(;;); +// } +// if (npid == 0) { //å进程 +// int ret = exec(argv[0], argv); +// printf("exec fail with %d\n", ret); +// } else { // 父进程 +// int status; +// wait(&status); +// printf("child exit with %d\n", status); +// } +// memuse(); +// for(;;); +// } +// #undef run + +// void run(char *testcases[], int cnt) { +// char *argv[2]; +// argv[1] = 0; +// for (int t = 0; t < cnt; t++) { +// printf("ready to run %s\n", testcases[t]); +// int npid = fork(); +// if(npid < 0) { +// printf("fork failed"); +// for(;;); +// } +// if (npid == 0) { //å进程 +// argv[0] = testcases[t]; +// int ret = exec(argv[0], argv); +// printf("exec fail with %d\n", ret); +// } else { // 父进程 +// int status; +// wait(&status); +// printf("child exit with %d\n", status); +// } +// } +// } + + +// static char digits[] = "0123456789ABCDEF"; + +// static void +// putc(int fd, char c) +// { +// write(fd, &c, 1); +// } + +// static void +// printint(int fd, int xx, int base, int sgn) +// { +// char buf[16]; +// int i, neg; +// uint x; + +// neg = 0; +// if(sgn && xx < 0){ +// neg = 1; +// x = -xx; +// } else { +// x = xx; +// } + +// i = 0; +// do{ +// buf[i++] = digits[x % base]; +// }while((x /= base) != 0); +// if(neg) +// buf[i++] = '-'; + +// while(--i >= 0) +// putc(fd, buf[i]); +// } + +// static void +// printptr(int fd, uint64 x) { +// int i; +// putc(fd, '0'); +// putc(fd, 'x'); +// for (i = 0; i < (sizeof(uint64) * 2); i++, x <<= 4) +// putc(fd, digits[x >> (sizeof(uint64) * 8 - 4)]); +// } + +// // Print to the given fd. Only understands %d, %x, %p, %s. +// void +// vprintf(int fd, const char *fmt, va_list ap) +// { +// char *s; +// int c, i, state; + +// state = 0; +// for(i = 0; fmt[i]; i++){ +// c = fmt[i] & 0xff; +// if(state == 0){ +// if(c == '%'){ +// state = '%'; +// } else { +// putc(fd, c); +// } +// } else if(state == '%'){ +// if(c == 'd'){ +// printint(fd, va_arg(ap, int), 10, 1); +// } else if(c == 'l') { +// printint(fd, va_arg(ap, uint64), 10, 0); +// } else if(c == 'x') { +// printint(fd, va_arg(ap, int), 16, 0); +// } else if(c == 'p') { +// printptr(fd, va_arg(ap, uint64)); +// } else if(c == 's'){ +// s = va_arg(ap, char*); +// if(s == 0) +// s = "(null)"; +// while(*s != 0){ +// putc(fd, *s); +// s++; +// } +// } else if(c == 'c'){ +// putc(fd, va_arg(ap, uint)); +// } else if(c == '%'){ +// putc(fd, c); +// } else { +// // Unknown % sequence. Print it to draw attention. +// putc(fd, '%'); +// putc(fd, c); +// } +// state = 0; +// } +// } +// } + +// void +// fprintf(int fd, const char *fmt, ...) +// { +// va_list ap; + +// va_start(ap, fmt); +// vprintf(fd, fmt, ap); +// } + +// void +// printf(const char *fmt, ...) +// { +// va_list ap; + +// va_start(ap, fmt); +// vprintf(1, fmt, ap); +// } + + + +//////////////////////////////////////////////////// #include "usys.h" #include "stdarg.h" @@ -5,24 +201,19 @@ void printf(const char *fmt, ...); void read_test(); // FS -// char *fs_testcase[] = { "mkdir_","openat", "dup2","close", "unlink", "getcwd", "getdents", -// "chdir", "dup", "pipe", "open", "read", "write", "fstat", -// "mount", "umount", "test_echo"}; -// // -// char *proc_testcase[] = { "getppid", "getpid", -// "clone", "wait", "waitpid", -// "yield", "fork", "execve", "exit", "sleep"}; - -// char *mm_testcase[] = {"brk", "mmap", "munmap"}; - -// char *other_testcase[] = {"gettimeofday", "times", "uname"}; -// // å•项测试 -// char* prog_name[] = {"ls"}; - -// void readcase(int fd, char buf[]) { -// while(read(fd, buf, )) -// } +char *fs_testcase[] = { "mkdir_","openat", "dup2","close", "unlink", "getcwd", "getdents", + "chdir", "dup", "pipe", "open", "read", "write", "fstat", + "mount", "umount", "test_echo"}; +// +char *proc_testcase[] = { "getppid", "getpid", + "clone", "wait", "waitpid", + "yield", "fork", "execve", "exit", "sleep"}; + +char *mm_testcase[] = {"brk", "mmap", "munmap"}; +char *other_testcase[] = {"gettimeofday", "times", "uname"}; +// å•项测试 +char* prog_name[] = {"ls"}; void run(char *testcases[], int cnt); #define run(cases) run(cases, sizeof(cases)/sizeof(cases[0])) @@ -33,30 +224,9 @@ void main() { // run(proc_testcase); // run(mm_testcase); // run(other_testcase); - // run(prog_name); - // int fd = openat(AT_FDCWD, "run_static.sh", O_RDONLY); - char *argv[5]; - argv[0] = "runtest.exe"; - argv[1] = "-w"; - argv[2] = "entry-static.exe"; - argv[3] = "argv"; - argv[4] = 0; - printf("ready to run %s\n", argv[3]); - int npid = fork(); - if(npid < 0) { - printf("fork failed"); - for(;;); - } - if (npid == 0) { //å进程 - int ret = exec(argv[0], argv); - printf("exec fail with %d\n", ret); - } else { // 父进程 - int status; - wait(&status); - printf("child exit with %d\n", status); - } + run(prog_name); memuse(); - for(;;); + for(;;); } #undef run @@ -70,6 +240,7 @@ void run(char *testcases[], int cnt) { printf("fork failed"); for(;;); } + printf("fork done\n"); if (npid == 0) { //å进程 argv[0] = testcases[t]; int ret = exec(argv[0], argv); diff --git a/src/kernel/pagefault.c b/src/kernel/pagefault.c index e7d70acc8812d2bec6478f94d12a122dce5ce9e7..c6b214baf0c67469d5aa2d32a41a541a30a95928 100644 --- a/src/kernel/pagefault.c +++ b/src/kernel/pagefault.c @@ -15,61 +15,61 @@ * * @return int */ -int mmap_fetch(){ - struct proc *p = myproc(); - uint64 va = r_stval(), pa; - - struct vma *v = 0; - int i, j; - - for(i = 0; i < VMA_NUM; i++){ - v = &(p->vma[i]); - if(v->addr <= va && va < v->addr + v->len) - break; - } - - if(i == VMA_NUM) { - return -1; // cannot find - } - - for (j = 0; j * PGSIZE < v->len; j++) { - if (v->addr + j * PGSIZE <= va && va < v->addr + (j + 1) * PGSIZE) { - break; - pa = (uint64)kalloc(); - - memset((void*)pa, 0, PGSIZE); - if (mappages(p->pagetable, PGROUNDDOWN(va), PGSIZE, pa, - PTE_R | PTE_W | PTE_X | PTE_U) == -1) { - panic("map page failed!"); - } - - if (reade(v->map_file->ep, 1, PGROUNDDOWN(va), v->off + j * PGSIZE, - min(PGSIZE, v->end - PGROUNDDOWN(va))) == -1) { - panic("read file failed!"); - } - - } else { - p->killed = 1; - panic("va not find in vma!! lazy allocation is not implemented!"); - } - } - - pa = (uint64)kalloc(); - memset((void*)pa, 0, PGSIZE); - if (mappages(p->pagetable, PGROUNDDOWN(va), PGSIZE, pa, - PTE_R | PTE_W | PTE_X | PTE_U) == -1) { - panic("map page failed!"); - } - - // if(reade(v->map_file->ep, 1, PGROUNDDOWN(va), j*PGSIZE, PGSIZE) == -1){ - if (reade(v->map_file->ep, 1, PGROUNDDOWN(va), v->off + j * PGSIZE, - PGSIZE) == -1) { - // printf("%d\n", r); - panic("read file failed!"); - } - - return 0; -} +// int mmap_fetch(){ +// struct proc *p = myproc(); +// uint64 va = r_stval(), pa; + +// struct vma *v = 0; +// int i, j; + +// for(i = 0; i < VMA_NUM; i++){ +// v = &(p->vma[i]); +// if(v->addr <= va && va < v->addr + v->len) +// break; +// } + +// if(i == VMA_NUM) { +// return -1; // cannot find +// } + +// for (j = 0; j * PGSIZE < v->len; j++) { +// if (v->addr + j * PGSIZE <= va && va < v->addr + (j + 1) * PGSIZE) { +// break; +// pa = (uint64)kalloc(); + +// memset((void*)pa, 0, PGSIZE); +// if (mappages(p->pagetable, PGROUNDDOWN(va), PGSIZE, pa, +// PTE_R | PTE_W | PTE_X | PTE_U) == -1) { +// panic("map page failed!"); +// } + +// if (reade(v->map_file->ep, 1, PGROUNDDOWN(va), v->off + j * PGSIZE, +// min(PGSIZE, v->end - PGROUNDDOWN(va))) == -1) { +// panic("read file failed!"); +// } + +// } else { +// p->killed = 1; +// panic("va not find in vma!! lazy allocation is not implemented!"); +// } +// } + +// pa = (uint64)kalloc(); +// memset((void*)pa, 0, PGSIZE); +// if (mappages(p->pagetable, PGROUNDDOWN(va), PGSIZE, pa, +// PTE_R | PTE_W | PTE_X | PTE_U) == -1) { +// panic("map page failed!"); +// } + +// // if(reade(v->map_file->ep, 1, PGROUNDDOWN(va), j*PGSIZE, PGSIZE) == -1){ +// if (reade(v->map_file->ep, 1, PGROUNDDOWN(va), v->off + j * PGSIZE, +// PGSIZE) == -1) { +// // printf("%d\n", r); +// panic("read file failed!"); +// } + +// return 0; +// } /** * @return -1 if exception unhandled else 0 @@ -77,17 +77,19 @@ int mmap_fetch(){ int handle_pagefault(uint64_t scause) { // printf(grn("%d\n"), scause); proc_t *p = myproc(); + vma_t *vma; uint64_t va = read_csr(stval); // illegal address - if(va >= p->cur_mmap_sz) - goto bad; + // if(va >= p->cur_mmap_sz) + // goto bad; // 地å€ç¿»è¯‘与访问顺åºä¸ºï¼šVMA ---> MMU ---> PMA ---> PMP ---> ACCESSED // 在特æƒçº§1.12下,所有与MMU相关的错误都将触å‘xx_page_fault // 而对于PMP(Physical Memory Protection)相关的错误,都将触å‘xx_access_fault。 // 在特æƒçº§1.9下,由于没有pagefault(ref: p51)ï¼Œå› æ¤SBI帮我在底层åšäº†ä¸€ä¸‹è½¬æ¢ // 对于缺页的错误,它将éžç¼ºé¡µä»¥åŠéžPMP访问的异常都归结到了xx_access_faultä¸ï¼Œå› æ¤è¿™é‡Œéœ€è¦åР䏀层å®åˆ¤æ– + // 这似乎è¿èƒŒäº†SBI的宗旨 #if PRIVILEGE_VERSION == PRIVILEGE_VERSION_1_12 if(scause == EXCP_STORE_PAGE_FAULT) @@ -97,26 +99,61 @@ int handle_pagefault(uint64_t scause) { if(0) #endif { // store page fault - // cow - if(cow_copy(p->pagetable, va, NULL) == -1){ - if(mmap_fetch() == -1) - goto bad; + if((vma = __vma_find_strict(p->mm, va)) == NULL) { + goto bad; } + mmap_print_vma(vma); + if(vma->prot & MAP_PROT_WRITE) { + pte_t *pte = walk(p->mm->pagetable, va, 1); + // lazy + if((*pte & PTE_V) == 0) { + uint64_t newpage = (uint64)kzalloc(PGSIZE); + if(newpage == 0 || mappages(p->mm->pagetable, va, PGSIZE, newpage, vma->prot) == -1) + goto bad; + return 0; + } + // cow + if(*pte & PTE_COW) { + debug("cow trigger..."); + if(cow_copy(va, pte) == -1){ + goto bad; + } else { + return 0; + } + } + } else { + goto bad; + } + return 0; } - if(scause == EXCP_LOAD_PAGE_FAULT) { - mmap_fetch(); - return 0; + // mmap_fetch(); + if((vma = __vma_find_strict(p->mm, va)) == NULL) { + mmap_print_vmas(p->mm); + goto bad; + } + if(vma->prot & MAP_PROT_READ) { + pte_t *pte = walk(p->mm->pagetable, va, 1); + // lazy + if((*pte & PTE_V) == 0) { + uint64_t newpage = (uint64)kzalloc(PGSIZE); + if(newpage == 0 || mappages(p->mm->pagetable, va, PGSIZE, newpage, vma->prot) == -1) + goto bad; + return 0; + } + } else { + goto bad; + } } return -1; bad: - debug("page fault va is %lx sepc is %lx", va, r_sepc()); - p->killed = 1; + debug("page fault va is %lx sepc is %lx scause %lx", va, r_sepc(), scause); + myproc()->killed = 1; return 0; } \ No newline at end of file diff --git a/src/kernel/proc.c b/src/kernel/proc.c index 0bebf4982e5a4ee37230d5e35d805fee76503477..e004708d97a76ea5a87ce2cf36c5d71edfd651c7 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -8,14 +8,14 @@ #include "defs.h" #include "mm/vm.h" -#include "debug.h" + #include "fs/fcntl.h" #include "fs/stat.h" #include "fs/fs.h" #include "fs/file.h" -#define max(a, b) ((a) > (b) ? (a) : (b)) -#define min(a, b) ((a) < (b) ? (a) : (b)) +#define __MODULE_NAME__ PROC +#include "debug.h" struct cpu cpus[NUM_CORES]; @@ -48,7 +48,7 @@ procinit(void) for(p = proc; p < &proc[NPROC]; p++) { initlock(&p->lock, "proc"); p->state = UNUSED; - // p->kstack = KSTACK((int) (p - proc)); + memset(&p->mm, 0, sizeof(mm_t)); for(int i = 0; i < NOFILE; i++) { p->ofile[i] = NULL; } @@ -115,23 +115,10 @@ found: p->state = USED; p->nfd = NOFILE; p->ext_ofile = NULL; + p->mm = (mm_t *)kzalloc(sizeof(mm_t)); - // 申请Trapframe - if((p->trapframe = (struct trapframe *)kalloc()) == 0){ - freeproc(p); - release(&p->lock); - return 0; - } - // ç”³è¯·å†…æ ¸æ ˆ - if((p->kstack = (uint64_t)kmalloc(KSTACK_SZ)) == 0){ - freeproc(p); - release(&p->lock); - return 0; - } - - // 获å–ç©ºé¡µè¡¨ï¼ˆå·²ç»æ˜ å°„äº†å†…æ ¸åœ°å€ç©ºé—´ï¼Œtrapfram以åŠå†…æ ¸æ ˆï¼‰ - p->pagetable = proc_pagetable(p); - if(p->pagetable == 0){ + if(mmap_init(p->mm, NULL) == -1){ + debug("mmap_init failure"); freeproc(p); release(&p->lock); return 0; @@ -141,44 +128,39 @@ found: // which returns to user space. memset(&p->context, 0, sizeof(p->context)); p->context.ra = (uint64)forkret; - p->context.sp = p->kstack + PGSIZE; + p->context.sp = get_kstack(p->mm) + KSTACK_SZ; - p->cur_mmap_sz = MMAP_BASE; + // p->cur_mmap_sz = MMAP_BASE; return p; } -void -free_vma(struct proc *p){ - pte_t *pte; - struct vma *v; - int i; - uint64 a; - - // for(;;); - for(i=0; i < VMA_NUM; i++){ - v = &(p->vma[i]); - // v->state is cleared in sys_munmap - if(v->state == VMA_USED){ - for(a = PGROUNDDOWN(v->addr); a <= PGROUNDDOWN(v->end); a+=PGSIZE){ - if ((pte = walk(p->pagetable, a, 0)) == 0) - continue; - if ((*pte & PTE_V) == 0)//this include the case *pte == 0; or *pte not 0, but *pte & PTE_V == 0 - continue; - - // printf(ylw("a: %p\n"), a); - //may have bug here! - if (v->flags & MAP_SHARED) - { - // printf(ylw("PGMASK & : %p\n"), (v->end - a)); - // writee(v->map_file->ep, 1, a, v->off + (a - v->addr), min(PGSIZE, (v->end - a))); - } - // printf(ylw("free_vam a: %p\n"), a); - uvmunmap(p->pagetable, a, 1, 1); - - } - } - } -} +// void +// free_vma(struct proc *p){ +// pte_t *pte; +// struct vma *v; +// int i; +// uint64 a; + +// // for(;;); +// list_for_each_entry(v, &PROC_VMA_HEAD(p), head) { +// // v->state is cleared in sys_munmap +// for(a = PGROUNDDOWN(v->addr); a <= PGROUNDDOWN(v->end); a+=PGSIZE){ +// if ((pte = walk(p->pagetable, a, 0)) == 0) +// continue; +// if ((*pte & PTE_V) == 0)//this include the case *pte == 0; or *pte not 0, but *pte & PTE_V == 0 +// continue; +// //may have bug here! +// if (v->flags & MAP_SHARED) +// { +// // printf(ylw("PGMASK & : %p\n"), (v->end - a)); +// // writee(v->map_file->ep, 1, a, v->off + (a - v->addr), min(PGSIZE, (v->end - a))); +// } +// // printf(ylw("free_vam a: %p\n"), a); +// uvmunmap(p->pagetable, a, 1, 1); +// } + +// } +// } // free a proc structure and the data hanging from it, // including user pages. @@ -186,23 +168,9 @@ free_vma(struct proc *p){ static void freeproc(struct proc *p) { - if(p->trapframe) - kfree((void*)p->trapframe); - if(p->kstack) - kfree((void*)p->kstack); - if(p->ext_ofile) - kfree((void *)p->ext_ofile); - p->trapframe = 0; - p->kstack = 0; - - free_vma(p); - - // for(;;); - if(p->pagetable){ - proc_freepagetable(p->pagetable, p->sz); - p->pagetable = 0; - } - p->sz = 0; + mmap_free(&p->mm); + + // p->sz = 0; p->pid = 0; p->parent = 0; p->name[0] = 0; @@ -214,35 +182,35 @@ freeproc(struct proc *p) // Create a user page table for a given process, // with no user memory, but with trampoline pages. -pagetable_t -proc_pagetable(struct proc *p) -{ - pagetable_t pagetable; - - // An empty page table with kernel page table copy. - pagetable = uvmcreate(); - if(pagetable == 0) - return 0; - // æ˜ å°„å†…æ ¸æ ˆ - if(mappages(pagetable, KSTACK, KSTACK_SZ, - (uint64)(p->kstack), PTE_R | PTE_W) < 0){ - erasekvm(pagetable); - uvmfree(pagetable, 0); - return 0; - } - - return pagetable; -} +// pagetable_t +// proc_pagetable(struct proc *p) +// { +// pagetable_t pagetable; + +// // An empty page table with kernel page table copy. +// pagetable = uvmcreate(); +// if(pagetable == 0) +// return 0; +// // æ˜ å°„å†…æ ¸æ ˆ +// if(mappages(pagetable, KSTACK, KSTACK_SZ, +// (uint64)(p->kstack), PTE_R | PTE_W) < 0){ +// erasekvm(pagetable); +// uvmfree(pagetable, 0); +// return 0; +// } + +// return pagetable; +// } // Free a process's page table, and free the // physical memory it refers to. -void -proc_freepagetable(pagetable_t pagetable, uint64 sz) -{ - uvmunmap(pagetable, KSTACK, 1, 0); - erasekvm(pagetable); - uvmfree(pagetable, sz); -} +// void +// proc_freepagetable(proc_t *p) +// { + +// erasekvm(p->mm.pagetable); +// uvmfree(pagetable, sz); +// } // a user program that calls exec("/init") // od -t xC initcode @@ -279,21 +247,31 @@ void userinit(void) { struct proc *p; - p = allocproc(); initproc = p; - // allocate one user page and copy init's instructions - // and data into it. - uvminit(p->pagetable, initcode, sizeof(initcode)); - p->sz = PGSIZE; + if(sizeof(initcode) >= PGSIZE) + panic("inituvm: more than a page"); + + switchuvm(p->mm); + + if(do_mmap_alloc(p->mm, NULL, 0, PGSIZE, MAP_ANONYMOUS, MAP_PROT_WRITE|MAP_PROT_READ|MAP_PROT_EXEC|MAP_PROT_USER) == -1) { + panic("mmap alloc failure"); + } + + #if PRIVILEGE_VERSION == PRIVILEGE_VERSION_1_12 + enable_sum(); + #endif + memmove(0, initcode, sizeof(initcode)); + #if PRIVILEGE_VERSION == PRIVILEGE_VERSION_1_12 + disable_sum(); + #endif // prepare for the very first "return" from kernel to user. - p->trapframe->epc = 0; // user program counter - p->trapframe->sp = PGSIZE; // user stack pointer + get_trapframe(p->mm)->epc = 0; // user program counter + get_trapframe(p->mm)->sp = PGSIZE; // user stack pointer safestrcpy(p->name, "initcode", sizeof(p->name)); - // p->cwd = namei("/"); init_std(p); @@ -303,22 +281,16 @@ userinit(void) } -int -growproc(int n) -{ - uint sz; +uint64 growproc(int n) { struct proc *p = myproc(); - - sz = p->sz; - if(n > 0){ - if((sz = uvmalloc(p->pagetable, sz, sz + n)) == 0) { - return -1; - } - } else if(n < 0){ - sz = uvmdealloc(p->pagetable, sz, sz + n); + if(n == 0) { + return PROGRAM_BREAK(p->mm); } - p->sz = sz; - return 0; + if(mmap_ext_heap(p->mm, n) == -1) { + return -1; + } + + return PROGRAM_BREAK(p->mm); } // Create a new process, copying the parent. @@ -336,22 +308,18 @@ do_clone(uint64_t stack) } // æ‹·è´å†…å˜å¸ƒå±€(如果开å¯äº†COW,那么仅仅是å¤åˆ¶é¡µè¡¨) - if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){ + if(mmap_dup(np->mm, p->mm) == -1){ freeproc(np); release(&np->lock); return -1; } - np->sz = p->sz; - - // å¤åˆ¶trapframe - *(np->trapframe) = *(p->trapframe); - // 将返回地å€é‡ç½®ä¸º0 - np->trapframe->a0 = 0; + // 将返回值置为0 + get_trapframe(np->mm)->a0 = 0; // å¦‚æžœæŒ‡å®šäº†æ ˆï¼Œé‚£ä¹ˆé‡è®¾sp if(stack) - np->trapframe->sp = stack; + get_trapframe(np->mm)->sp = stack; // å¢žåŠ æ–‡ä»¶æè¿°ç¬¦å¼•用 for(i = 0; i < NOFILE; i++) @@ -374,7 +342,7 @@ do_clone(uint64_t stack) release(&np->lock); - np->cur_mmap_sz = p->cur_mmap_sz; + // np->cur_mmap_sz = p->cur_mmap_sz; return pid; } @@ -469,7 +437,7 @@ waitpid(int cid, uint64 addr) if(np->state == ZOMBIE){ // Found one. - if(addr != 0 && copyout(p->pagetable, addr, (char *)&np->xstate, + if(addr != 0 && copyout(addr, (char *)&np->xstate, sizeof(np->xstate)) < 0) { release(&np->lock); release(&wait_lock); @@ -521,7 +489,7 @@ scheduler(void) // before jumping back to us. p->state = RUNNING; c->proc = p; - switchuvm(p); + switchuvm(p->mm); swtch(&c->context, &p->context); switchkvm(); // Process is done running for now. @@ -578,9 +546,9 @@ void forkret(void) { static int first = 1; - + proc_t *p = myproc(); // Still holding p->lock from scheduler. - release(&myproc()->lock); + release(&p->lock); if (first) { // File system initialization must be run in the context of a @@ -589,10 +557,10 @@ forkret(void) first = 0; extern fat32_t *fat; - printf("ready to mount\n"); + debug("ready to mount\n"); fat_mount(ROOTDEV, &fat); - printf("mount done\n"); - myproc()->cwd = namee(NULL, "/"); + debug("mount done\n"); + p->cwd = namee(NULL, "/"); // LOOP(); // fsinit(ROOTDEV); @@ -683,9 +651,8 @@ kill(int pid) int either_copyout(int user_dst, uint64 dst, void *src, uint64 len) { - struct proc *p = myproc(); if(user_dst){ - return copyout(p->pagetable, dst, src, len); + return copyout(dst, src, len); } else { memmove((char *)dst, src, len); return 0; @@ -698,15 +665,22 @@ either_copyout(int user_dst, uint64 dst, void *src, uint64 len) int either_copyin(void *dst, int user_src, uint64 src, uint64 len) { - struct proc *p = myproc(); if(user_src){ - return copyin(p->pagetable, dst, src, len); + return copyin(dst, src, len); } else { memmove(dst, (char*)src, len); return 0; } } + +void proc_setmm(proc_t *p, mm_t *newmm) { + mm_t *oldmm = p->mm; + p->mm = newmm; + switchuvm(p->mm); + mmap_free(&oldmm); +} + // Print a process listing to console. For debugging. // Runs when user types ^P on console. // No lock to avoid wedging a stuck machine further. diff --git a/src/kernel/sys.c b/src/kernel/sys.c index 5d43a8f9bb8714b3ac6383d41c6581d581b0402e..8e2d7759272b31f6dba1b9eb83d6d6d496da5380 100644 --- a/src/kernel/sys.c +++ b/src/kernel/sys.c @@ -3,6 +3,7 @@ #include "defs.h" #include "profile.h" #include "mm/buddy.h" +#include "mm/vm.h" typedef struct { uint64_t hit; @@ -34,7 +35,7 @@ uint64 sys_bio_cache(void) { extern uint64_t bio_cache_hit, bio_cache_miss; rate.hit = bio_cache_hit; rate.miss = bio_cache_miss; - return copyout(myproc()->pagetable, addr, (char *)&rate, sizeof(rate)); + return copyout(addr, (char *)&rate, sizeof(rate)); #endif @@ -54,7 +55,7 @@ uint64_t sys_times(void) { if(argaddr(0, &addr) < 0) return -1; - if(copyout(myproc()->pagetable, addr, (char *)&ticks, sizeof(ticks)) == -1) + if(copyout(addr, (char *)&ticks, sizeof(ticks)) == -1) ret = -1; return ret; @@ -67,7 +68,7 @@ uint64_t sys_uname(void) { return -1; } - return copyout(myproc()->pagetable, addr, (char *)&sysname, sizeof(utsname_t)); + return copyout(addr, (char *)&sysname, sizeof(utsname_t)); } uint64_t sys_gettimeofday(void) { timespec_t time; @@ -79,7 +80,7 @@ uint64_t sys_gettimeofday(void) { time = TICK2TIMESPEC(ticks); - if(copyout(myproc()->pagetable, addr, (char *)&time, sizeof(time)) == -1) { + if(copyout(addr, (char *)&time, sizeof(time)) == -1) { ret = -1; } return ret; diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 4b1dc85b5e5818d0a6f569d02b993cec8a75029d..56aa08b6ba84a933c5d486e8276fd4c435f36cb0 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -13,9 +13,9 @@ int fetchaddr(uint64 addr, uint64 *ip) { struct proc *p = myproc(); - if(addr >= p->sz || addr+sizeof(uint64) > p->sz) + if(__vma_find_strict(p->mm, addr) == NULL) return -1; - if(copyin(p->pagetable, (char *)ip, addr, sizeof(*ip)) != 0) + if(copyin((char *)ip, addr, sizeof(*ip)) != 0) return -1; return 0; } @@ -25,8 +25,7 @@ fetchaddr(uint64 addr, uint64 *ip) int fetchstr(uint64 addr, char *buf, int max) { - struct proc *p = myproc(); - int err = copyinstr(p->pagetable, buf, addr, max); + int err = copyinstr(buf, addr, max); if(err < 0) return err; return strlen(buf); @@ -38,17 +37,17 @@ argraw(int n) struct proc *p = myproc(); switch (n) { case 0: - return p->trapframe->a0; + return get_trapframe(p->mm)->a0; case 1: - return p->trapframe->a1; + return get_trapframe(p->mm)->a1; case 2: - return p->trapframe->a2; + return get_trapframe(p->mm)->a2; case 3: - return p->trapframe->a3; + return get_trapframe(p->mm)->a3; case 4: - return p->trapframe->a4; + return get_trapframe(p->mm)->a4; case 5: - return p->trapframe->a5; + return get_trapframe(p->mm)->a5; } panic("argraw"); return -1; @@ -109,12 +108,12 @@ syscall(void) int num; struct proc *p = myproc(); - num = p->trapframe->a7; + num = get_trapframe(p->mm)->a7; if(num > 0 && num < NELEM(syscalls) && syscalls[num]) { - p->trapframe->a0 = syscalls[num](); + get_trapframe(p->mm)->a0 = syscalls[num](); } else { printf("%d %s: unknown sys call %d\n", p->pid, p->name, num); - p->trapframe->a0 = -1; + get_trapframe(p->mm)->a0 = -1; } } diff --git a/src/kernel/sysfile.c b/src/kernel/sysfile.c index 44240dc3f61a2ccd65c5a7d3f9793a26659bd271..1df2bfaa6cd848b50e5f68005e7de265b234c46a 100644 --- a/src/kernel/sysfile.c +++ b/src/kernel/sysfile.c @@ -12,12 +12,12 @@ #include "fs/fs.h" #include "fs/stat.h" #include "kernel/proc.h" +#include "mm/mmap.h" #include "mm/vm.h" #include "param.h" #include "riscv.h" -#include "types.h" -#define QUIET +// #define QUIET #define __MODULE_NAME__ SYS_FILE #include "debug.h" @@ -174,7 +174,6 @@ uint64 sys_close(void) { } uint64 sys_fstat(void) { - proc_t* p = myproc(); struct file* f; struct kstat stat; entry_t* entry; @@ -188,7 +187,7 @@ uint64 sys_fstat(void) { estat(entry, &stat); eunlock(entry); - return copyout(p->pagetable, addr, (char*)&stat, sizeof(stat)); + return copyout(addr, (char*)&stat, sizeof(stat)); } uint64 sys_getcwd(void) { @@ -204,7 +203,7 @@ uint64 sys_getcwd(void) { char* end = getcwd(p->cwd, buf); assert(*end == '\0'); // debug("%s", buf); - if (copyout(p->pagetable, addr, buf, size) == -1) { + if (copyout(addr, buf, size) == -1) { return 0; } @@ -248,7 +247,6 @@ uint64 sys_unlinkat(void) { } uint64 sys_getdents64(void) { - proc_t* p = myproc(); struct file* f; uint64_t addr; int len; @@ -261,7 +259,7 @@ uint64 sys_getdents64(void) { int ret = read_dents(f->ep, &f->off, buf, len); eunlock(f->ep); - if (copyout(p->pagetable, addr, buf, len) == -1) { + if (copyout(addr, buf, len) == -1) { kfree(buf); return -1; } @@ -399,7 +397,7 @@ uint64 sys_exec(void) { } argv[i] = kalloc(); if (argv[i] == 0) - goto bad; + goto bad; if (fetchstr(uarg, argv[i], PGSIZE) < 0) goto bad; } @@ -436,8 +434,8 @@ uint64 sys_pipe2(void) { fileclose(wf); return -1; } - if (copyout(p->pagetable, fdarray, (char*)&fd0, sizeof(fd0)) < 0 || - copyout(p->pagetable, fdarray + sizeof(fd0), (char*)&fd1, sizeof(fd1)) < + if (copyout(fdarray, (char*)&fd0, sizeof(fd0)) < 0 || + copyout(fdarray + sizeof(fd0), (char*)&fd1, sizeof(fd1)) < 0) { p->ofile[fd0] = 0; p->ofile[fd1] = 0; @@ -449,141 +447,110 @@ uint64 sys_pipe2(void) { } // todo: fdæ¢file -uint64 sys_mmap(void) { - uint64 addr, length, offset; - int prot, flags, fd, i; - struct proc* p = myproc(); - - if (argaddr(0, &addr) < 0 || argaddr(1, &length) < 0 || - argint(2, &prot) < 0 || argint(3, &flags) < 0 || argint(4, &fd) < 0 || - argaddr(5, &offset) < 0) - return -1; - - if ((get_file(fd)->writable == 0) && (prot & PROT_WRITE) && - (flags & MAP_SHARED)) - return -1; - - uint64 old_addr = p->cur_mmap_sz; +// uint64 sys_mmap(void) { +// uint64 addr, length, offset; +// int prot, flags, fd, i; +// struct proc* p = myproc(); + +// if (argaddr(0, &addr) < 0 || argaddr(1, &length) < 0 || +// argint(2, &prot) < 0 || argint(3, &flags) < 0 || argint(4, &fd) < 0 || +// argaddr(5, &offset) < 0) +// return -1; +// struct file *fp = get_file(fd); +// if (fp && (fp->writable == 0) && (prot & PROT_WRITE) && +// (flags & MAP_SHARED)) +// return -1; + +// if(do_file_mmap(&p->mm, fp, offset, addr, length, flags)) { +// return addr; +// } else { +// return addr; +// } + +// } + +// /** +// * @brief 一个最简å•的版本的munmapï¼Œå› ä¸ºv->addr都是页对é½çš„,所以 +// * è¦æ±‚va是页对é½çš„,并且len为PGSIZE的整数å€ï¼Œæˆ–者ç‰äºŽåŒºåŸŸçš„æ€»é•¿åº¦ +// * å¦åˆ™éœ€è¦è€ƒè™‘区域的分割ç‰é—®é¢˜ã€‚ +// * +// * @return uint64 +// */ +// uint64 sys_munmap(void) { +// uint64 va, len; +// if (argaddr(0, &va) < 0 || argaddr(1, &len) < 0) +// return -1; + +// struct proc* p = myproc(); +// struct vma* v = 0; +// int i; +// pte_t* pte; - //æœ‰ä¸ªé—®é¢˜ï¼Œä¸€ä¸ªæ–‡ä»¶ä¼¼ä¹Žå¿…é¡»å æ®æ•´ä¸ªé¡µï¼Œå¦‚æžœä¸¤ä¸ªæ–‡ä»¶æ˜ å°„åˆ°åŒä¸€ä¸ªé¡µï¼Œé‚£ä¹ˆ - //第一个触å‘é¡µé”™è¯¯çš„æ–‡ä»¶ä¼šå¯¼è‡´ç¬¬äºŒä¸ªæ— æ³•è§¦å‘页错误,从而第二个文件å¯èƒ½è¯»å†™ - //第一个文件的mmap区域。 - p->cur_mmap_sz += PGROUNDUP(length); - for (i = 0; i < VMA_NUM; i++) { // lock? - if (p->vma[i].state == VMA_UNUSED) { - p->vma[i].state = VMA_USED; - if (addr == 0) - p->vma[i].addr = old_addr; - else - p->vma[i].addr = addr; - p->vma[i].len = length; - p->vma[i].prot = prot; - p->vma[i].flags = flags; - p->vma[i].off = offset; - p->vma[i].end = (old_addr + length); - filedup(p->ofile[fd]); - p->vma[i].map_file = p->ofile[fd]; - - break; - } - } - if (i == VMA_NUM) - panic("vma is full!"); - - return old_addr; -} - -/** - * @brief 一个最简å•的版本的munmapï¼Œå› ä¸ºv->addr都是页对é½çš„,所以 - * è¦æ±‚va是页对é½çš„,并且len为PGSIZE的整数å€ï¼Œæˆ–者ç‰äºŽåŒºåŸŸçš„æ€»é•¿åº¦ - * å¦åˆ™éœ€è¦è€ƒè™‘区域的分割ç‰é—®é¢˜ã€‚ - * - * @return uint64 - */ -uint64 sys_munmap(void) { - uint64 va, len; - if (argaddr(0, &va) < 0 || argaddr(1, &len) < 0) - return -1; - - struct proc* p = myproc(); - struct vma* v = 0; - int i; - pte_t* pte; - - for (i = 0; i < VMA_NUM; i++) { - v = &(p->vma[i]); - if (v->state == VMA_USED && v->addr == va) - break; - } - if (i == VMA_NUM) // ummap null - panic("munmap: va is not equal to one of v->addr!"); - // return -1; - - if (len % PGSIZE != 0 && len != v->len) - panic("munmap: length is not a multiple of PGSIZE or vma length!"); - - va = PGROUNDUP(va); - // if a virtual address has been mapped to physic address, - // unmap it, otherwise do noting. - if (va <= PGROUNDDOWN(va + len)) - for (int a = va; a <= PGROUNDDOWN(va + len); a += PGSIZE) { - // printf(rd("a: %p\n"), a); - if ((pte = walk(p->pagetable, a, 0)) == 0) - continue; - if ((*pte & PTE_V) == 0) - continue; - - // write back to disk - if (v->flags & MAP_SHARED) { - writee(v->map_file->ep, 1, a, v->off + (a - v->addr), - min(PGSIZE, (v->end - a))); - } - uvmunmap(p->pagetable, a, 1, 1); - } - if (i == VMA_NUM) // ummap null - return -1; - - va = PGROUNDUP(va); - // if a virtual address has been mapped to physic address, - // unmap it, otherwise do noting. - if (va < PGROUNDDOWN(va + len)) - for (int a = va; a < PGROUNDDOWN(va + len); a += PGSIZE) { - if ((pte = walk(p->pagetable, a, 0)) == 0) - continue; - if ((*pte & PTE_V) == 0) - continue; - - // write back to disk - if (v->flags & MAP_SHARED) { - filewrite(v->map_file, va, PGSIZE); - } - uvmunmap(p->pagetable, a, 1, 1); - } - - // free the entire vma - if (va == v->addr && len == v->len) { - v->state = VMA_UNUSED; - fileclose(v->map_file); - } - - // for a simple version of mmap, we assume it's unmap from the head - // of a vma, namely va == v->addr - // if we unmap in the middle of a vma, the vma is split into two - v->addr += len; - v->len -= len; - - // free the entire vma - if (va == v->addr && len == v->len) { - // v->state = VMA_UNUSED; - // fileclose(v->map_file); - } - - // for a simple version of mmap, we assume it's unmap from the head - // of a vma, namely va == v->addr - // if we unmap in the middle of a vma, the vma is split into two - v->addr += len; - v->len -= len; + - return 0; -} \ No newline at end of file +// if (len % PGSIZE != 0 && len != v->len) +// panic("munmap: length is not a multiple of PGSIZE or vma length!"); + +// va = PGROUNDUP(va); +// // if a virtual address has been mapped to physic address, +// // unmap it, otherwise do noting. +// if (va <= PGROUNDDOWN(va + len)) +// for (int a = va; a <= PGROUNDDOWN(va + len); a += PGSIZE) { +// // printf(rd("a: %p\n"), a); +// if ((pte = walk(p->pagetable, a, 0)) == 0) +// continue; +// if ((*pte & PTE_V) == 0) +// continue; + +// // write back to disk +// if (v->flags & MAP_SHARED) { +// writee(v->map_file->ep, 1, a, v->off + (a - v->addr), +// min(PGSIZE, (v->end - a))); +// } +// uvmunmap(p->pagetable, a, 1, 1); +// } + +// va = PGROUNDUP(va); +// // if a virtual address has been mapped to physic address, +// // unmap it, otherwise do noting. +// if (va < PGROUNDDOWN(va + len)) +// for (int a = va; a < PGROUNDDOWN(va + len); a += PGSIZE) { +// if ((pte = walk(p->pagetable, a, 0)) == 0) +// continue; +// if ((*pte & PTE_V) == 0) +// continue; + +// // write back to disk +// if (v->flags & MAP_SHARED) { +// filewrite(v->map_file, va, PGSIZE); +// } +// uvmunmap(p->pagetable, a, 1, 1); +// } + +// // free the entire vma +// if (va == v->addr && len == v->len) { +// v->state = VMA_UNUSED; +// fileclose(v->map_file); +// } + +// // for a simple version of mmap, we assume it's unmap from the head +// // of a vma, namely va == v->addr +// // if we unmap in the middle of a vma, the vma is split into two +// v->addr += len; +// v->len -= len; + +// // free the entire vma +// if (va == v->addr && len == v->len) { +// // v->state = VMA_UNUSED; +// // fileclose(v->map_file); +// } + +// // for a simple version of mmap, we assume it's unmap from the head +// // of a vma, namely va == v->addr +// // if we unmap in the middle of a vma, the vma is split into two +// v->addr += len; +// v->len -= len; + +// return 0; +// } \ No newline at end of file diff --git a/src/kernel/sysproc.c b/src/kernel/sysproc.c index 0908d26e313d6a10b90dcb067de837e8f79ab32a..e1668930e869ff1444f98fb5067c95b961af9690 100644 --- a/src/kernel/sysproc.c +++ b/src/kernel/sysproc.c @@ -8,6 +8,7 @@ #include "kernel/proc.h" #include "common.h" #include "kernel/time.h" +#include "mm/vm.h" #define QUIET #define __MODULE_NAME__ SYS_PROC @@ -84,20 +85,12 @@ sys_wait4(void) uint64 sys_sbrk(void) { - int addr; int n; if(argint(0, &n) < 0) return -1; - addr = myproc()->sz; - - if(n == 0) - return addr; - - if(growproc(n - addr) < 0) - return -1; - return addr; + return growproc(n); } uint64 diff --git a/src/kernel/trap.c b/src/kernel/trap.c index f673bd241de212a64be47d1dd1b18066b195e512..116ebcc7c89cfd7cf4c19a07f5f3c767ca5bb966 100644 --- a/src/kernel/trap.c +++ b/src/kernel/trap.c @@ -54,6 +54,11 @@ usertrap(void) printf("sepc=%p stval=%p\n", read_csr(sepc), read_csr(stval)); panic("usertrap: not from user mode"); } + + // if(!IS_INTR(scause)) { + // debug("sepc is %lx scause is %lx stval is %lx intr is %d", r_sepc(), scause, r_stval(), intr_get()); + // LOOP(); + // } // send interrupts and exceptions to kerneltrap(), // since we're now in the kernel. // w_stvec((uint64)kernelvec); @@ -62,8 +67,7 @@ usertrap(void) struct proc *p = myproc(); // save user program counter. - // p->trapframe->epc = r_sepc(); - p->trapframe->epc = read_csr(sepc); + get_trapframe(p->mm)->epc = read_csr(sepc); if (scause == EXCP_SYSCALL) { if(p->killed) { @@ -71,7 +75,7 @@ usertrap(void) } // sepc points to the ecall instruction, // but we want to return to the next instruction. - p->trapframe->epc += 4; + get_trapframe(p->mm)->epc += 4; // an interrupt will change sstatus &c registers, // so don't enable until done with those registers. // debug("usertrap: proc is %s syscall num is %d", p->name, p->trapframe->a7); @@ -98,7 +102,7 @@ usertrap(void) // // return to user space // -void userret(struct trapframe *trapfram); +void userret(uint64 trapfram); void uservec(); void usertrapret(void) @@ -113,9 +117,9 @@ usertrapret(void) // set up trapframe values that uservec will need when // the process next re-enters the kernel. // kernel page table - p->trapframe->kernel_sp = p->kstack + PGSIZE; // process's kernel stack - p->trapframe->kernel_trap = (uint64)usertrap; - p->trapframe->kernel_hartid = r_tp(); // hartid for cpuid() + get_trapframe(p->mm)->kernel_sp = get_kstack(p->mm) + KSTACK_SZ; // process's kernel stack + get_trapframe(p->mm)->kernel_trap = (uint64)usertrap; + get_trapframe(p->mm)->kernel_hartid = r_tp(); // hartid for cpuid() // set up the registers that trampoline.S's sret will use // to get to user space. @@ -127,14 +131,14 @@ usertrapret(void) w_sstatus(x); // set S Exception Program Counter to the saved user pc. - w_sepc(p->trapframe->epc); + w_sepc(get_trapframe(p->mm)->epc); // tell trampoline.S the user page table to switch to. // uint64 satp = MAKE_SATP(p->pagetable); // jump to trampoline.S at the top of memory, which // switches to the user page table, restores user registers, // and switches to user mode with sret. - userret(p->trapframe); + userret((uint64)get_trapframe(p->mm)); } // interrupts and exceptions from kernel code go here via kernelvec, @@ -145,12 +149,19 @@ kerneltrap() uint64 sepc = r_sepc(); uint64 sstatus = r_sstatus(); uint64 scause = r_scause(); - // debug("kerneltrap: sepc is %lx scause is %lx stval is %lx intr is %d", r_sepc(), scause, r_stval(), intr_get()); - + + if(myproc()) { myproc()->ktrap_fp = *(uint64*)(r_fp()-16); } + if(!IS_INTR(scause)) { + debug("sepc is %lx scause is %lx stval is %lx intr is %d", r_sepc(), scause, r_stval(), intr_get()); + debug("kstack: %lx", myproc()->mm->kstack); + // backtrace(myproc()); + LOOP(); + } + if((sstatus & SSTATUS_SPP) == 0) panic("kerneltrap: not from supervisor mode"); if(intr_get() != 0) @@ -158,6 +169,8 @@ kerneltrap() if(devintr(scause) == 0) { // ok + } else if(handle_pagefault(scause) == 0) { + // ok } else{ printf("scause %p\n", scause); printf("sepc=%p stval=%p\n", r_sepc(), r_stval()); diff --git a/src/main.c b/src/main.c index d21faafb8d62e58a7ddd276b8b39de1cf692c9d1..2d736f68b63f7bb41601db2b710f5042b4c7b72c 100644 --- a/src/main.c +++ b/src/main.c @@ -5,6 +5,7 @@ #include "defs.h" #include "mm/vm.h" #include "platform.h" +#include "kernel/proc.h" #include "driver/plic.h" #include "test.h" #include "fs/blk_device.h" @@ -54,6 +55,7 @@ main() fs_init(); userinit(); // first user process + printf("user init success\n"); __sync_synchronize(); started = 1; } else { diff --git a/src/mm/Makefile b/src/mm/Makefile index 18f7d49a1ece954d8230b09dd2556aa973e65e49..f234cbc5b226228be58f5a049f30dafbe7ee37b5 100644 --- a/src/mm/Makefile +++ b/src/mm/Makefile @@ -5,4 +5,5 @@ obj-y += copy.o obj-y += page.o obj-y += buddy.o obj-y += alloc.o +obj-y += mmap.o obj-y += slob.o \ No newline at end of file diff --git a/src/mm/alloc.c b/src/mm/alloc.c index c6ef2540f9ed37688453f1807b171df72ebb6d88..08ee39e59b6445395392f2650931a45a0b47c409 100644 --- a/src/mm/alloc.c +++ b/src/mm/alloc.c @@ -53,7 +53,7 @@ void *kzalloc(size_t size) { * @deprecated use kmalloc(PGSIZE) instead */ void *kalloc(void) { - return kmalloc(PGSIZE); + return kzalloc(PGSIZE); } /** diff --git a/src/mm/copy.c b/src/mm/copy.c index c4e4e04c0cdde0d199a2e0a3bdacb037d232b9b0..784c9e9fd4df6ba4c7a6deb0a23966b7c906b58e 100644 --- a/src/mm/copy.c +++ b/src/mm/copy.c @@ -1,7 +1,12 @@ #include "utils.h" #include "mm/vm.h" +#include "mm/mmap.h" #include "defs.h" #include "platform.h" +#include "kernel/proc.h" + +#define __MODULE_NAME__ COPY +#include "debug.h" /* å¤åˆ¶COW页 */ static inline int __cow_copy(uint64_t va, pte_t *pte) { @@ -30,79 +35,93 @@ static inline int __cow_copy(uint64_t va, pte_t *pte) { return 0; } -int cow_copy(pagetable_t pagetable, uint64_t va, pte_t **pppte) { - pte_t *pte; - if(va >= MAXVA) - return -1; - pte = walk(pagetable, va, 0); - if(pte == 0 || (*pte & PTE_U) == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_COW) == 0) - return -1; +int cow_copy(uint64_t va, pte_t *pte) { + return __cow_copy(va, pte); +} - if(pppte) - *pppte = pte; +void __copyout(mm_t *mm, uint64_t dstva, char *src, uint64 len, int walk) { + if(walk) { + pte_t *pte; + uint64 va0, n, pa0; + while(len > 0){ + va0 = PGROUNDDOWN(dstva); + pte = walk(mm->pagetable, va0, 0); + if(pte == NULL || (*pte & PTE_V) == 0) + panic("unmapped"); + + n = PGSIZE - (dstva - va0); + if(n > len) n = len; + pa0 = PTE2PA(*pte); + // 由于是直接访问实地å€ï¼Œå› æ¤ä¸éœ€è¦è®¾ç½®SUM状æ€ä½ + memmove((void *)(pa0 + (dstva - va0)), src, n); - return __cow_copy(va, pte); + len -= n; + src += n; + dstva = va0 + PGSIZE; + } + } else { + #if PRIVILEGE_VERSION == PRIVILEGE_VERSION_1_12 + enable_sum(); + #endif + memmove((void *)dstva, src, len); + #if PRIVILEGE_VERSION == PRIVILEGE_VERSION_1_12 + disable_sum(); + #endif + } + + } // Copy from kernel to user. // Copy len bytes from src to virtual address dstva in a given page table. // Return 0 on success, -1 on error. int -copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len) +copyout(uint64 dstva, char *src, uint64 len) { - uint64 n, va0, pa0; - pte_t *pte; - while(len > 0){ - va0 = PGROUNDDOWN(dstva); - if(va0 >= MAXVA) - return -1; - pte = walk(pagetable, va0, 0); - if(pte == 0 || (*pte & PTE_U) == 0 || (*pte & PTE_V) == 0) - return -1; - - #ifdef COW - if((*pte & PTE_COW)) { - if(__cow_copy(va0, pte)) - return -1; - } - #endif - - n = PGSIZE - (dstva - va0); - if(n > len) n = len; - pa0 = PTE2PA(*pte); - memmove((void *)(pa0 + (dstva - va0)), src, n); - // printf("fd=%d\n", *(int *)src); - len -= n; - src += n; - dstva = va0 + PGSIZE; + vma_t *vma; + proc_t *p = myproc(); + if(!p) + panic("copyout: no process ctx"); + + // 1. é¦–å…ˆç¡®å®šç›®æ ‡æ®µæ˜¯å¦å˜åœ¨ + if((vma = vma_exist(p->mm, (uint64)dstva, len)) == NULL) { + return -1; } + // 2. æ˜¯å¦æ˜¯ç”¨æˆ·æ®µ + if((vma->prot & MAP_PROT_USER) == 0) { + return -1; + } + // 3. 由于å˜åœ¨æ˜ å°„ï¼Œç›´æŽ¥æ‹·è´ + __copyout(p->mm, dstva, src, len, 0); + return 0; } -#define check_range(va, n, limit, mmap_limit) \ - (((uint64_t)(va) + (uint64_t)(n) > (uint64_t)(va)) && \ - (((uint64_t)(va) + (uint64_t)(n) <= (uint64_t)(limit)) || \ - (((uint64_t)(va) + (uint64_t)(n) >= MMAP_BASE) && ((uint64_t)(va) + (uint64_t)(n) <= mmap_limit)))) + // Copy from user to kernel. // Copy len bytes to dst from virtual address srcva in a given page table. // Return 0 on success, -1 on error. int -copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len) +copyin(char *dst, uint64 srcva, uint64 len) { return copy_from_user(dst, (void *)srcva, len); } -/* We always think kernel address is legal... */ +/* We trust that kernel address is legal... */ int copy_from_user(void *to, void *from, size_t n) { proc_t *p = myproc(); if(!p) panic("copy_from_user: no process ctx"); - if(!check_range(from, n, p->sz, p->cur_mmap_sz)) - return -1; + // if(!check_range(from, n, p->sz, p->cur_mmap_sz)) + // return -1; // todo: more checks, such as: guard pages, **mmap**... - + if(vma_exist(p->mm, (uint64)from, n) == NULL) { + debug("not exist"); + return -1; + } + /* 在特æƒçº§1.9版本ä¸ï¼ŒSUMä½ä¸ºPUM为,其功能ä½ä¸ŽSUM作用相å */ #if PRIVILEGE_VERSION == PRIVILEGE_VERSION_1_12 enable_sum(); @@ -119,18 +138,24 @@ int copy_from_user(void *to, void *from, size_t n) { // until a '\0', or max. // Return 0 on success, -1 on error. int -copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max) +copyinstr(char *dst, uint64 srcva, uint64 max) { int got_null = 0; proc_t *proc = myproc(); + vma_t *vma; if(!proc) panic("copyinstr: no process context"); + if((vma = __vma_find_strict(proc->mm, srcva)) == NULL) { + return -1; + } + max = min(max, vma->len - (srcva - vma->addr)); + #if PRIVILEGE_VERSION == PRIVILEGE_VERSION_1_12 enable_sum(); #endif char *p = (char *)srcva; // no consider wrap - while(max > 0 && (uint64_t)p < proc->sz){ + while(max > 0){ *dst = *p; if(*p == '\0'){ got_null = 1; diff --git a/src/mm/mmap.c b/src/mm/mmap.c new file mode 100644 index 0000000000000000000000000000000000000000..e3f5789b1458b4655eeaf5b455affbcc655256c1 --- /dev/null +++ b/src/mm/mmap.c @@ -0,0 +1,373 @@ +#include "mm/mmap.h" +#include "fs/fs.h" +#include "str.h" +#include "mm/vm.h" + +#define __MODULE_NAME__ MMAP +#include "debug.h" + +#define VMA_LEN(vma) ((vma)->len) +#define VMA_PAGES(vma) (((vma)->len) / PGSIZE) +#define PAGETABLE(mm) ((mm)->owner->pagetable) + +#define KSTACK_VMA(mm) (&((mm)->kstack)) + + +#define check_range(va, len, limit) \ + (((uint64_t)(va) + (uint64_t)(len) > (uint64_t)(va)) && \ + (((uint64_t)(va) + (uint64_t)(len) <= (uint64_t)(limit)))) + + +static int check_flags(int flags1, int flags2) { + return flags1 == flags2; +} + +// TODO: 检查flag是å¦å…¼å®¹ï¼ˆç›®å‰åªæ˜¯ç®€å•的比较是å¦ç›¸ç‰ï¼‰ +static int check_prot(int prot1, int prot2) { + return prot1 == prot2; +} + +vma_t *__vma_find(mm_t *mm, uint64 addr) { + vma_t *ans; + list_for_each_entry(ans, &mm->vma_head, head) { + if(addr < ans->addr + ans->len) { + return ans; + } + } + return NULL; +} + +vma_t *__vma_find_strict(mm_t *mm, uint64 addr) { + vma_t *ans = __vma_find(mm, addr); + return ans && ans->addr <= addr ? ans : NULL; +} + +void vma_remove(mm_t *mm, vma_t *vma) { + list_del(&vma->head); +} + +vma_t *vma_previous(mm_t *mm, vma_t *vma) { + return list_prev_entry(vma, head); +} + +void vma_insert(mm_t *mm, vma_t *vma) { + vma_t *pre; + list_for_each_entry(pre, &mm->vma_head, head) { + if(vma->addr >= pre->addr + pre->len) { + list_add(&vma->head, &pre->head); + return; + } + } + debug("no entry found, insert directly"); + list_add(&vma->head, &mm->vma_head); +} + +int __vmaS_merge(mm_t *mm, vma_t *start, vma_t *end) { + if(start == NULL || end == NULL) return 0; + vma_t *tmp = start; + // åˆå¹¶æ£€æŸ¥ + while(tmp != end) { + vma_t *next = list_next_entry(tmp, head); + if(!check_prot(tmp->prot, next->prot)) return -1; + if(!check_flags(tmp->flags, next->flags)) return -1; + tmp = next; + } + // 执行åˆå¹¶ + while(1) { + vma_t *next = list_next_entry(tmp, head); + start->len = next->addr + next->len - start->addr; + vma_remove(mm, next); + kfree(next); + if(next == end) { + break; + } + } + return 0; +} + + +int __do_mmap(mm_t *mm, struct file *fp, int file_offset, uint64_t addr, uint64_t len, int flags, int prot) { + uint64_t end = addr + len; + // 寻找到第一个结æŸåœ°å€å¤§äºŽaddrçš„vma(å¯ä»¥ä¸åŒ…å«ï¼‰ + vma_t *vma = __vma_find(mm, addr); + // 寻找到第一个结æŸåœ°å€å¤§äºŽendçš„vma + vma_t *vma_end = __vma_find(mm, end);\ + if(vma_end && vma_end != vma && end < vma_end->addr) { + vma_end = vma_previous(mm, vma_end); + } + // ç»è¿‡ä¸Šè¿°å¤„ç†å®Œï¼Œæ‰¾åˆ°çš„vma布局如下所示: + // (addr) vma0] [vma1] [vma2 (end) + // 处ç†è¾¹ç•Œé—®é¢˜ + if(vma) { // 当å˜åœ¨ç›¸äº¤vma + if(check_flags(vma->flags, flags) == 0 || check_prot(vma->prot, prot) == 0) return -1; + if(__vmaS_merge(mm, vma, vma_end) == -1) return -1; + if(vma->addr > addr) { + vma->addr = PGROUNDDOWN(addr); + } + if(vma->addr + vma->len < end) { + vma->len = end - vma->addr; + } + } else { // ä¸å˜åœ¨ç›¸äº¤vma + vma = (vma_t *)kzalloc(sizeof(vma_t)); + vma->addr = PGROUNDDOWN(addr); + vma->len = len; + vma->flags = flags; + vma->map_file = fp; + vma->prot = prot; + vma->offset = file_offset; + vma_insert(mm, vma); + } + return 0; +} + +// int do_file_mmap(mm_t *mm, struct file *fp, int offset, uint64_t addr, uint64_t len, int flags, int prot) { +// if(fp == NULL) return -1; +// if(__do_mmap(mm, fp, offset, addr, len, flags, prot) == -1) return -1; +// } + +int do_mmap(mm_t *mm, struct file *fp, uint64_t addr, uint64_t len, int flags, int prot) { + flags |= (fp ? 0 : MAP_ANONYMOUS); + if(__do_mmap(mm, NULL, 0, addr, len, flags, prot) == -1) + return -1; + + return 0; +} + +void do_unmap(mm_t *mm, uint64_t addr, int do_free) { + vma_t *vma = __vma_find(mm, addr); + if(vma) { + // TODO: file map + uvmunmap(mm->pagetable, vma->addr, ROUND_COUNT(vma->len), do_free); + vma_remove(mm, vma); + kfree(vma); + } +} + +int do_mmap_alloc(mm_t *mm, struct file *fp, uint64_t addr, uint64_t len, int flags, int prot) { + char *mem; + uint64_t a; + + if(do_mmap(mm, fp, addr, len, flags, prot) == -1) { + return -1; + } + + for(a = PGROUNDDOWN(addr); a < addr + len; a += PGSIZE){ + mem = kzalloc(PGSIZE); + if(mem == 0){ + goto bad; + } + if(mappages(mm->pagetable, a, PGSIZE, (uint64)mem, prot) != 0){ + kfree(mem); + goto bad; + } + } + + + return 0; + + bad: + do_unmap(mm, addr, 0); + for(uint64_t i = PGROUNDDOWN(addr); i < a; i += PGSIZE) { + uvmunmap(mm->pagetable, i, 1, 1); + } + return -1; +} + +static int map_kstack(mm_t *mm) { + if((mm->kstack = (uint64)kmalloc(KSTACK_SZ)) == 0) { + return -1; + } + return 0; +} + +static void unmap_kstack(mm_t *mm) { + if(mm->kstack) { + kfree((void *)mm->kstack); + mm->kstack = 0; + } +} + +static void unmap_vmas(mm_t *mm) { + vma_t *vma, *next; + list_for_each_entry_safe(vma, next, &mm->vma_head, head) { + uvmunmap(mm->pagetable, vma->addr, ROUND_COUNT(vma->len), 1); + vma_remove(mm, vma); + kfree(vma); + } +} + + +static int map_trapframe(mm_t *mm) { + if((mm->trapframe = (uint64)kmalloc(PGSIZE)) == 0) { + return -1; + } + return 0; +} + +static void unmap_trapframe(mm_t *mm) { + if(mm->trapframe) { + kfree((void *)mm->trapframe); + mm->trapframe = 0; + } +} + +int mmap_init(mm_t *mm, mm_t *old) { + mm->pagetable = kzalloc(PGSIZE); + INIT_LIST_HEAD(&mm->vma_head); + if(mm->pagetable == NULL) { + debug("stub1"); + } + + if(map_kstack(mm) == -1) { + kfree(mm->pagetable); + return -1; + } + if(map_trapframe(mm) == -1) { + unmap_kstack(mm); + kfree(mm->pagetable); + return -1; + } + + if(setupkvm(mm->pagetable) == -1) { + unmap_kstack(mm); + unmap_trapframe(mm); + kfree(mm->pagetable); + return -1; + } + + // for exec + if(old) { + memcpy((void *)mm->kstack, (void *)old->kstack, KSTACK_SZ); + } + + return 0; +} + +void mmap_free(mm_t **pmm) { + mm_t *mm = *pmm; + if(mm == NULL) + panic("nullpointer"); + + unmap_vmas(mm); + unmap_kstack(mm); + unmap_trapframe(mm); + erasekvm(mm->pagetable); + kfree(mm->pagetable); + kfree(mm); + *pmm = NULL; +} + +static vma_t *vma_dup(vma_t *vma) { + vma_t *dup; + if((dup = (vma_t *)kmalloc(sizeof(vma_t))) == NULL) { + return NULL; + } + memcpy(dup, vma, sizeof(vma_t)); + return dup; +} + + +int mmap_dup(mm_t *newm, mm_t *oldm) { + vma_t *vma; + //TODO: file + list_for_each_entry(vma, &oldm->vma_head, head) { + vma_t *dup = vma_dup(vma); + if(dup == NULL) { + unmap_vmas(newm); + return -1; + } + if(uvmcopy(oldm->pagetable, newm->pagetable, vma->addr, vma->len) == -1) { + kfree(dup); + unmap_vmas(newm); + return -1; + } + vma_insert(newm, dup); + } + memcpy((void *)newm->kstack, (void *)oldm->kstack, KSTACK_SZ); + memcpy((void *)newm->trapframe, (void *)oldm->trapframe, PGSIZE); + + return 0; +} + +int mmap_ext_heap(mm_t *mm, int newsize) { + if(mm->uheap == NULL) return -1; + int cursize = mm->uheap->len; + if(cursize == newsize) { + return 0; + } else if(cursize < newsize) { + uvmunmap(mm->pagetable, + PGROUNDUP(mm->uheap->addr + newsize), + ROUND_COUNT(mm->uheap->addr + mm->uheap->len) - ROUND_COUNT(mm->uheap->addr + newsize), 1); + } else { + if(__vma_find_strict(mm, mm->uheap->addr + newsize)) { + return -1; + } + } + mm->uheap->len = newsize; + return 0; +} + +int mmap_ext_stack(mm_t *mm) { + // TODO: + return -1; +} + + +struct trapframe *get_trapframe(mm_t *mm) { + return (struct trapframe *)mm->trapframe; +} + +uint64_t get_kstack(mm_t *mm) { + return mm->kstack; +} + +vma_t *vma_exist(mm_t *mm, uint64_t addr, uint64_t len) { + // if(!check_range(addr, len, USERSPACE_END)) return NULL; + vma_t *ans = __vma_find_strict(mm, addr); + if(ans && addr - ans->addr <= ans->len - len) { + return ans; + } + + return NULL; +} + +void mmap_print_vma(vma_t *vma) { + if(vma == NULL) { + printf("vma: NULL\n"); + } else { + char perm[5]; + perm[4] = '\0'; + perm[0] = vma->prot & MAP_PROT_READ ? 'r' : '-'; + perm[1] = vma->prot & MAP_PROT_WRITE ? 'w' : '-'; + perm[2] = vma->prot & MAP_PROT_EXEC ? 'x' : '-'; + perm[3] = vma->prot & MAP_PROT_USER ? 'u' : '-'; + + printf("vma: %lx----%lx len: %ld %s\n", vma->addr, vma->addr + vma->len, vma->len, perm); + } +} + +void mmap_print_vmas(mm_t *mm) { + vma_t *vma; + int id = 1; + list_for_each_entry(vma, &mm->vma_head, head) { + printf("%d. ", id++); + mmap_print_vma(vma); + } +} + + +void switchuvm(mm_t *mm) { + if(mm->kstack == 0) + panic("switchuvm: no kstack"); + if(mm->pagetable == 0) + panic("switchuvm: no pgdir"); + + write_csr(satp, MAKE_SATP(mm->pagetable)); + sfence_vma(); +} + +extern pagetable_t kernel_pagetable; +void switchkvm() { + write_csr(satp, MAKE_SATP(kernel_pagetable)); + sfence_vma(); +} diff --git a/src/mm/page.c b/src/mm/page.c index 85097f982ca7a8ed73e4792523037594b7b35d0c..eb1be95453c9d297dc4afe2b53305cb84c050bad 100644 --- a/src/mm/page.c +++ b/src/mm/page.c @@ -121,12 +121,10 @@ _uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free, int spec for(a = va; a < va + npages*pgsize; a += pgsize){ if((pte = _walk(pagetable, a, 0, spec)) == 0){ - panic("uvmunmap: walk"); - // continue; + continue; } if((*pte & PTE_V) == 0){ - panic("uvmunmap: not mapped"); - // continue; + continue; } if((*pte & (PTE_R | PTE_W | PTE_X)) == 0) panic("uvmunmap: not a leaf"); diff --git a/src/mm/slob.c b/src/mm/slob.c index dde2cc44ef770110de12efcf77a8c26ae4ec880d..65536520aa6f2f1464181ce3f6567a86b6e30580 100644 --- a/src/mm/slob.c +++ b/src/mm/slob.c @@ -1,5 +1,6 @@ #include "atomic/spinlock.h" #include "common.h" +#include "mm/page.h" #define QUIET #define __MODULE_NAME__ SLOB diff --git a/src/mm/vm.c b/src/mm/vm.c index 176109f9257e22f93336d3865b0d96a82b677403..08abe4b3bfa107a5f98a3f4e68e4f86a988e7dea 100644 --- a/src/mm/vm.c +++ b/src/mm/vm.c @@ -25,7 +25,6 @@ extern char etext[]; // kernel.ld sets this to end of kernel code. // extern char trampoline[]; // trampoline.S -void freewalk(pagetable_t pagetable); // Initialize the one kernel_pagetable void @@ -143,111 +142,85 @@ void erasekvm(pagetable_t pagetable) { } } -// create an empty user page table. -// returns 0 if out of memory. -pagetable_t -uvmcreate() -{ - pagetable_t pagetable; - pagetable = (pagetable_t) kalloc(); - if(pagetable == 0) - return 0; - memset(pagetable, 0, PGSIZE); - if(setupkvm(pagetable) == -1) { - uvmfree(pagetable, 0); - return 0; - } - return pagetable; -} // Load the user initcode into address 0 of pagetable, // for the very first process. // sz must be less than a page. -void -uvminit(pagetable_t pagetable, uchar *src, uint sz) -{ - char *mem; - - if(sz >= PGSIZE) - panic("inituvm: more than a page"); - mem = kalloc(); - memset(mem, 0, PGSIZE); - mappages(pagetable, 0, PGSIZE, (uint64)mem, PTE_W|PTE_R|PTE_X|PTE_U); - memmove(mem, src, sz); -} +// void +// uvminit(pagetable_t pagetable, uchar *src, uint sz) +// { +// char *mem; + +// if(sz >= PGSIZE) +// panic("inituvm: more than a page"); +// mem = kalloc(); +// memset(mem, 0, PGSIZE); +// mappages(pagetable, 0, PGSIZE, (uint64)mem, PTE_W|PTE_R|PTE_X|PTE_U); +// memmove(mem, src, sz); +// } // Allocate PTEs and physical memory to grow process from oldsz to // newsz, which need not be page aligned. Returns new size or 0 on error. -uint64 -uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz) -{ - char *mem; - uint64 a; - - if(newsz < oldsz) - return oldsz; - - oldsz = PGROUNDUP(oldsz); - for(a = oldsz; a < newsz; a += PGSIZE){ - mem = kalloc(); - if(mem == 0){ - uvmdealloc(pagetable, a, oldsz); - return 0; - } - memset(mem, 0, PGSIZE); - if(mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U) != 0){ - kfree(mem); - uvmdealloc(pagetable, a, oldsz); - return 0; - } - } - return newsz; -} +// uint64 +// uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz) +// { +// char *mem; +// uint64 a; + +// if(newsz < oldsz) +// return oldsz; + +// oldsz = PGROUNDUP(oldsz); +// for(a = oldsz; a < newsz; a += PGSIZE){ +// mem = kalloc(); +// if(mem == 0){ +// uvmdealloc(pagetable, a, oldsz); +// return 0; +// } +// memset(mem, 0, PGSIZE); +// if(mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U) != 0){ +// kfree(mem); +// uvmdealloc(pagetable, a, oldsz); +// return 0; +// } +// } +// return newsz; +// } // Deallocate user pages to bring the process size from oldsz to // newsz. oldsz and newsz need not be page-aligned, nor does newsz // need to be less than oldsz. oldsz can be larger than the actual // process size. Returns the new process size. -uint64 -uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz) -{ - if(newsz >= oldsz) - return oldsz; +// uint64 +// uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz) +// { +// if(newsz >= oldsz) +// return oldsz; - if(PGROUNDUP(newsz) < PGROUNDUP(oldsz)){ - int npages = (PGROUNDUP(oldsz) - PGROUNDUP(newsz)) / PGSIZE; - uvmunmap(pagetable, PGROUNDUP(newsz), npages, 1); - } +// if(PGROUNDUP(newsz) < PGROUNDUP(oldsz)){ +// int npages = (PGROUNDUP(oldsz) - PGROUNDUP(newsz)) / PGSIZE; +// uvmunmap(pagetable, PGROUNDUP(newsz), npages, 1); +// } - return newsz; -} +// return newsz; +// } -// Free user memory pages, -// then free page-table pages. -void -uvmfree(pagetable_t pagetable, uint64 sz) -{ - if(sz > 0) - uvmunmap(pagetable, 0, PGROUNDUP(sz)/PGSIZE, 1); - freewalk(pagetable); -} - // Given a parent process's page table, copy // its memory into a child's page table. // Copies both the page table and the // physical memory. // returns 0 on success, -1 on failure. // frees any allocated pages on failure.' -#include "kernel/proc.h" -int -uvmcopy(pagetable_t old, pagetable_t new, uint64 sz) +// #include "kernel/proc.h" +// int +int uvmcopy(pagetable_t old, pagetable_t new, uint64 addr, uint64_t len) { pte_t *pte; uint64 pa, i; uint flags; - for(i = 0; i < sz; i += PGSIZE){ + for(i = addr; i < PGROUNDUP(addr + len); i += PGSIZE) { if((pte = walk(old, i, 0)) == 0) panic("uvmcopy: pte should exist"); if((*pte & PTE_V) == 0) @@ -286,52 +259,71 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz) // mark a PTE invalid for user access. // used by exec for the user stack guard page. -void -uvmclear(pagetable_t pagetable, uint64 va) -{ - pte_t *pte; +// void +// uvmclear(pagetable_t pagetable, uint64 va) +// { +// pte_t *pte; - pte = walk(pagetable, va, 0); - if(pte == 0) - panic("uvmclear"); - *pte &= ~PTE_U; -} +// pte = walk(pagetable, va, 0); +// if(pte == 0) +// panic("uvmclear"); +// *pte &= ~PTE_U; +// } // Recursively free page-table pages. // All leaf mappings must already have been removed. +// void +// freewalk(pagetable_t pagetable) +// { +// // there are 2^9 = 512 PTEs in a page table. +// for(int i = 0; i < 512; i++){ +// pte_t pte = pagetable[i]; +// if((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0){ // 目录节点 +// // this PTE points to a lower-level page table. +// uint64 child = PTE2PA(pte); +// freewalk((pagetable_t)child); +// pagetable[i] = 0; +// } else if(pte & PTE_V){ // å¶å节点 +// printf("\nnormal pa: %p\n", PTE2PA(pte)); +// panic("freewalk: leaf"); +// } +// } +// kfree((void*)pagetable); +// } + +static char* indents[] = { + ".. .. ..", + ".. ..", + "..", +}; + + void -freewalk(pagetable_t pagetable) -{ - // there are 2^9 = 512 PTEs in a page table. +_vmprint(pagetable_t pagetable, int level, int ignore_level) { + if(level == ignore_level) return; + char *indent = indents[level]; for(int i = 0; i < 512; i++){ pte_t pte = pagetable[i]; - if((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0){ // 目录节点 - // this PTE points to a lower-level page table. - uint64 child = PTE2PA(pte); - freewalk((pagetable_t)child); - pagetable[i] = 0; - } else if(pte & PTE_V){ // å¶å节点 - printf("\nnormal pa: %p\n", PTE2PA(pte)); - panic("freewalk: leaf"); + pagetable_t pa = (pagetable_t)PTE2PA(pte); + if(pte & PTE_V){ // å˜åœ¨ + if((pte & (PTE_R|PTE_W|PTE_X)) > 0) // 打å°å¶èŠ‚ç‚¹ + printf("%s %-3d: pte[LEAF] %p pa %p\n", indent, i, pte, PTE2PA(pte)); + else {// 打å°ä¸‹çº§é¡µè¡¨åœ°å€ + printf("%s %-3d: pte %p pa %p\n", indent, i, pte, pa); + _vmprint(pa, level - 1, ignore_level); + } } } - kfree((void*)pagetable); } - -void switchuvm(struct proc *p) { - if(p == 0) - panic("switchuvm: no process"); - if(p->kstack == 0) - panic("switchuvm: no kstack"); - if(p->pagetable == 0) - panic("switchuvm: no pgdir"); - - write_csr(satp, MAKE_SATP(p->pagetable)); - sfence_vma(); +void +vmprint(pagetable_t pagetable) { + printf("page table %p\n", pagetable); + _vmprint(pagetable, 2, -1); } -void switchkvm() { - write_csr(satp, MAKE_SATP(kernel_pagetable)); - sfence_vma(); +void +print_map(kmap_t map) { + printf("map:%p => %p, size: %#x type: %d\n", map.pa, map.va, map.size, map.pg_spec); } + diff --git a/src/platform/k210/driver/dmac.c b/src/platform/k210/driver/dmac.c index 292049f638d78f5ef16df8c76fa65a2f4ecd74f0..49fec0807812f7abc880751e39bf4e28ac871f84 100644 --- a/src/platform/k210/driver/dmac.c +++ b/src/platform/k210/driver/dmac.c @@ -20,6 +20,8 @@ #include "utils.h" #include "driver/plic.h" #include "mm/io.h" +#include "kernel/proc.h" +#include "mm/vm.h" volatile dmac_t *dmac; @@ -584,25 +586,6 @@ void dmac_init(void) dmac_enable(); } -static void list_add(struct list_head_t *new, struct list_head_t *prev, - struct list_head_t *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -void list_add_tail(struct list_head_t *new, struct list_head_t *head) -{ - list_add(new, head->prev, head); -} - -void INIT_LIST_HEAD(struct list_head_t *list) -{ - list->next = list; - list->prev = list; -} void dmac_link_list_item(dmac_channel_number_t channel_num, uint8_t LLI_row_num, int8_t LLI_last_row, diff --git a/src/platform/k210/driver/spi.c b/src/platform/k210/driver/spi.c index c77abcd3d9424d432d473b90fb5863b86809fb04..f70c61e5359ad90a87086c718fabbd0d30804f6f 100644 --- a/src/platform/k210/driver/spi.c +++ b/src/platform/k210/driver/spi.c @@ -22,6 +22,7 @@ #include "defs.h" #include "atomic/spinlock.h" #include "mm/io.h" +#include "mm/vm.h" #include "printf.h" uint64_t spi_pa[4] = diff --git a/src/tests/Makefile b/src/tests/Makefile index 440c4d7bd742f8989a19f4ff710b1c133f9ac42f..01cf480cf2079d8f306e7588a33eb5991539253a 100644 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -1 +1 @@ -obj-y+=mm.o \ No newline at end of file +obj-y+=mmtest.o \ No newline at end of file diff --git a/src/tests/mm.c b/src/tests/mmtest.c similarity index 100% rename from src/tests/mm.c rename to src/tests/mmtest.c diff --git a/src/utils.c b/src/utils.c index e3311bdb1cd81a7d4d3e3c6d72c36b80e97925e2..db542104d9868833d509183cd6850eb0a1d0ef9d 100644 --- a/src/utils.c +++ b/src/utils.c @@ -3,53 +3,8 @@ #include "mm/page.h" #include "fs/fat.h" #include "str.h" +#include "kernel/proc.h" -static char* indents[] = { - ".. .. ..", - ".. ..", - "..", -}; - -// void -// _vmprint(pagetable_t pagetable, int level, int ignore_level) { -// if(level == ignore_level) return; -// char *indent = indents[level]; -// for(int i = 0; i < 512; i++){ -// pte_t pte = pagetable[i]; -// pagetable_t pa = (pagetable_t)PTE2PA(pte); -// if(pte & PTE_V){ // å˜åœ¨ -// if((pte & (PTE_R|PTE_W|PTE_X)) > 0) // 打å°å¶èŠ‚ç‚¹ -// printf("%s %-3d: pte[LEAF] %p pa %p\n", indent, i, pte, PTE2PA_SPEC(pte, level)); -// else {// 打å°ä¸‹çº§é¡µè¡¨åœ°å€ -// printf("%s %-3d: pte %p pa %p\n", indent, i, pte, pa); -// _vmprint(pa, level - 1, ignore_level); -// } -// } -// } -// } - -void -_vmprint(pagetable_t pagetable, int level, int ignore_level) { - if(level == ignore_level) return; - char *indent = indents[level]; - for(int i = 0; i < 512; i++){ - pte_t pte = pagetable[i]; - pagetable_t pa = (pagetable_t)PTE2PA(pte); - if(pte & PTE_V){ // å˜åœ¨ - if((pte & (PTE_R|PTE_W|PTE_X)) > 0) // 打å°å¶èŠ‚ç‚¹ - printf("%s %-3d: pte[LEAF] %p pa %p\n", indent, i, pte, PTE2PA(pte)); - else {// 打å°ä¸‹çº§é¡µè¡¨åœ°å€ - printf("%s %-3d: pte %p pa %p\n", indent, i, pte, pa); - _vmprint(pa, level - 1, ignore_level); - } - } - } -} -void -vmprint(pagetable_t pagetable) { - printf("page table %p\n", pagetable); - _vmprint(pagetable, 2, -1); -} void backtrace(proc_t *p) { @@ -70,10 +25,7 @@ print_block(uint8_t *b) { } } -void -print_map(kmap_t map) { - printf("map:%p => %p, size: %#x type: %d\n", map.pa, map.va, map.size, map.pg_spec); -} + void print_sbiret(sbiret_t ret) {