From bb70ca7eccc1b70e77b80eaab3f6107d7df031e2 Mon Sep 17 00:00:00 2001 From: Pierre Wilke <pierre.wilke@centralesupelec.fr> Date: Thu, 14 May 2020 02:51:40 +0200 Subject: [PATCH] Squelette TP2 --- Makefile | 5 +- kernel/defs.h | 13 +++- kernel/exec.c | 62 +++++++++++++----- kernel/kalloc.c | 4 +- kernel/memlayout.h | 6 ++ kernel/proc.c | 156 ++++++++++++++++++++++++++++++++++---------- kernel/proc.h | 43 ++++++++++++ kernel/spinlock.c | 18 ++++- kernel/spinlock.h | 2 + kernel/sysproc.c | 8 +-- kernel/trap.c | 33 +++++++++- kernel/vm.c | 69 +++++++++++++++++--- user/naivefib.c | 27 ++++++++ user/rwtest.c | 83 +++++++++++++++++++++++ user/sbrk-dealloc.c | 49 ++++++++++++++ user/suicide.c | 14 ++++ user/user.h | 2 +- user/usertests.c | 136 +++++++++++++++++++++----------------- 18 files changed, 593 insertions(+), 137 deletions(-) create mode 100644 user/naivefib.c create mode 100644 user/rwtest.c create mode 100644 user/sbrk-dealloc.c create mode 100644 user/suicide.c diff --git a/Makefile b/Makefile index a2784fd..943d551 100644 --- a/Makefile +++ b/Makefile @@ -144,7 +144,10 @@ UPROGS=\ $U/_mutest2\ $U/_rocky\ $U/_watchdog-panic\ - + $U/_sbrk-dealloc\ + $U/_suicide\ + $U/_rwtest\ + $U/_naivefib\ fs.img: mkfs/mkfs README $(UPROGS) mkfs/mkfs fs.img README $(UPROGS) diff --git a/kernel/defs.h b/kernel/defs.h index df618ee..1b78d73 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -94,7 +94,7 @@ int cpuid(void); void exit(int); int fork(void); int nice(int,int); -int growproc(int); +int growproc(long); pagetable_t proc_pagetable(struct proc *); void proc_freepagetable(pagetable_t, uint64); int kill(int); @@ -114,7 +114,7 @@ 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 procdump(void); void priodump(void); - +void proc_vmprint(struct proc* p); // swtch.S void swtch(struct context*, struct context*); @@ -183,13 +183,15 @@ uint64 walkaddr(pagetable_t, uint64); int copyout(pagetable_t, uint64, char *, uint64); int copyin(pagetable_t, char *, uint64, uint64); int copyinstr(pagetable_t, char *, uint64, uint64); - +void vmprint(pagetable_t pt, uint64 pid, char* cmd); // plic.c void plicinit(void); void plicinithart(void); int plic_claim(void); void plic_complete(int); +int allocate_if_possible(pagetable_t pagetable, struct proc*, uint64 addr); + // virtio_disk.c void virtio_disk_init(int); void virtio_disk_rw(int, struct buf *, int); @@ -219,4 +221,9 @@ void *lst_pop(struct list*); void lst_print(struct list*); int lst_empty(struct list*); +#define ENOVMA (-(1L << 1)) +#define ENOMEM (-(1L << 2)) +#define ENOFILE (-(1L << 3)) +#define EMAPFAILED (-(1L << 4)) + #endif diff --git a/kernel/exec.c b/kernel/exec.c index fb72925..69f8b40 100644 --- a/kernel/exec.c +++ b/kernel/exec.c @@ -32,31 +32,47 @@ exec(char *path, char **argv) ilock(ip); // Check ELF header - if(readi(ip, 0, (uint64)&elf, 0, sizeof(elf)) != sizeof(elf)) + if(readi(ip, 0, (uint64)&elf, 0, sizeof(elf)) != sizeof(elf)){ + printf("exec: readi error\n"); goto bad; - if(elf.magic != ELF_MAGIC) + } + if(elf.magic != ELF_MAGIC){ + printf("exec: bad number error\n"); goto bad; - - if((pagetable = proc_pagetable(p)) == 0) + } + if((pagetable = proc_pagetable(p)) == 0){ + printf("exec: proc_pagetable error\n"); goto bad; + } // Load program into memory. sz = 0; for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){ - if(readi(ip, 0, (uint64)&ph, off, sizeof(ph)) != sizeof(ph)) - goto bad; + if(readi(ip, 0, (uint64)&ph, off, sizeof(ph)) != sizeof(ph)){ + printf("exec: program header error\n"); + } if(ph.type != ELF_PROG_LOAD) continue; - if(ph.memsz < ph.filesz) + if(ph.memsz < ph.filesz){ + printf("exec: program header memsz < filesz\n"); goto bad; - if(ph.vaddr + ph.memsz < ph.vaddr) + } + if(ph.vaddr + ph.memsz < ph.vaddr){ + printf("exec: program header vaddr + memsz < vaddr\n"); goto bad; - if((sz = uvmalloc(pagetable, sz, ph.vaddr + ph.memsz)) == 0) + } + if((sz = uvmalloc(pagetable, sz, ph.vaddr + ph.memsz)) == 0){ + printf("exec: uvmalloc failed\n"); goto bad; - if(ph.vaddr % PGSIZE != 0) + } + if(ph.vaddr % PGSIZE != 0){ + printf("exec: vaddr not page aligned\n"); goto bad; - if(loadseg(pagetable, ph.vaddr, ip, ph.off, ph.filesz) < 0) + } + if(loadseg(pagetable, ph.vaddr, ip, ph.off, ph.filesz) < 0){ + printf("exec: loadseg failed\n"); goto bad; + } } iunlockput(ip); end_op(ROOTDEV); @@ -68,22 +84,30 @@ exec(char *path, char **argv) // Allocate two pages at the next page boundary. // Use the second as the user stack. sz = PGROUNDUP(sz); - if((sz = uvmalloc(pagetable, sz, sz + 2*PGSIZE)) == 0) + if((sz = uvmalloc(pagetable, sz, sz + 2*PGSIZE)) == 0){ + printf("exec: uvmalloc failed for the stack\n"); goto bad; + } uvmclear(pagetable, sz-2*PGSIZE); sp = sz; stackbase = sp - PGSIZE; // Push argument strings, prepare rest of stack in ustack. for(argc = 0; argv[argc]; argc++) { - if(argc >= MAXARG) + if(argc >= MAXARG){ + printf("exec: too many args\n"); goto bad; + } sp -= strlen(argv[argc]) + 1; sp -= sp % 16; // riscv sp must be 16-byte aligned - if(sp < stackbase) + if(sp < stackbase){ + printf("exec: sp < stackbase\n"); goto bad; - if(copyout(pagetable, sp, argv[argc], strlen(argv[argc]) + 1) < 0) + } + if(copyout(pagetable, sp, argv[argc], strlen(argv[argc]) + 1) < 0){ + printf("exec: copy argument strings failed\n"); goto bad; + } ustack[argc] = sp; } ustack[argc] = 0; @@ -91,10 +115,14 @@ exec(char *path, char **argv) // push the array of argv[] pointers. sp -= (argc+1) * sizeof(uint64); sp -= sp % 16; - if(sp < stackbase) + if(sp < stackbase){ + printf("exec: sp < stackbase, le retour\n"); goto bad; - if(copyout(pagetable, sp, (char *)ustack, (argc+1)*sizeof(uint64)) < 0) + } + if(copyout(pagetable, sp, (char *)ustack, (argc+1)*sizeof(uint64)) < 0){ + printf("exec: copy argument pointers failed\n"); goto bad; + } // arguments to user main(argc, argv) // argc is returned via the system call return diff --git a/kernel/kalloc.c b/kernel/kalloc.c index 12e64af..30c919a 100644 --- a/kernel/kalloc.c +++ b/kernel/kalloc.c @@ -35,5 +35,7 @@ kfree(void *pa) void * kalloc(void) { - return bd_malloc(PGSIZE); + char* mem = bd_malloc(PGSIZE); + if(mem) memset(mem, 0, PGSIZE); + return mem; } diff --git a/kernel/memlayout.h b/kernel/memlayout.h index a9fc66c..d5a2f9a 100644 --- a/kernel/memlayout.h +++ b/kernel/memlayout.h @@ -70,4 +70,10 @@ // TRAMPOLINE (the same page as in the kernel) #define TRAPFRAME (TRAMPOLINE - PGSIZE) +#define HEAP_THRESHOLD (8*1024*1024) + +#define USTACK_BOTTOM (256*1024*1024) +#define USTACK_LIMIT (4 * 1024) +#define USTACK_TOP (USTACK_BOTTOM + USTACK_LIMIT) + #endif diff --git a/kernel/proc.c b/kernel/proc.c index 4efe499..a69b9fa 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -14,7 +14,7 @@ struct cpu cpus[NCPU]; struct proc proc[NPROC]; struct list_proc* prio[NPRIO]; -struct spinlock prio_lock; +struct spinlock prio_lock[NPRIO]; struct proc *initproc; @@ -26,60 +26,131 @@ static void wakeup1(struct proc *chan); extern char trampoline[]; // trampoline.S -/* Solution insert et remove +/* Ajoute une VMA à la liste de VMAs d'un processus. + * Prend le début et la fin de la VMA en paramètre. + * Retourne un pointeur vers la nouvelle entrée. + */ +struct vma* add_memory_area(struct proc* p, + uint64 va_begin, + uint64 va_end){ + acquire(&p->vma_lock); + struct vma* entry = bd_malloc(sizeof(struct vma)); + if(!entry){ + panic("bd_malloc failed\n"); + } + entry->va_begin = va_begin; + entry->va_end = va_end; + entry->next = p->memory_areas; + entry->file = 0; + entry->vma_flags = 0; + entry->file_offset = 0; + entry->file_nbytes = 0; + p->memory_areas = entry; + release(&p->vma_lock); + return entry; +} -// Needs lock on p and prio_lock[p->priority] -void insert_into_prio_queue(struct proc* p){ - struct list_proc* new = bd_malloc(sizeof(struct list_proc)); - new->next = 0; - new->p = p; - if(!prio[p->priority]){ - prio[p->priority] = new; +/* Libère une liste de VMAs. Suppose qu'on tient un verrou sur cette liste. */ +void free_vma(struct vma* vmas){ + struct vma* ma = vmas; + while(ma){ + struct vma* old = ma; + ma = ma -> next; + bd_free(old); } - else { - struct list_proc* last = prio[p->priority]; - while(last && last->next){ - last = last->next; +} + +/* Récupère la VMA associée à une adresse virtuelle, ou 0 si aucune VMA n'est + * associée à cette adresse. + * Nécessite que le verrou p->vma_lock soit tenu. + */ +struct vma* get_memory_area(struct proc* p, uint64 va){ + if(!holding(&p->vma_lock)){ + panic("get_memory_area: should hold vma_lock!\n"); + } + struct vma* ma = p->memory_areas; + while(ma){ + if (ma->va_begin <= va && va < ma->va_end){ + return ma; } - last->next = new; + ma = ma -> next; } + return 0; } -// Needs lock on p and prio_lock[p->priority] -void remove_from_prio_queue(struct proc* p){ - struct list_proc* old = prio[p->priority]; - struct list_proc* prev = 0; - struct list_proc* head = old; +/* Retourne l'adresse maximale utilisée par l'ensemble des VMAs. */ +uint64 max_addr_in_memory_areas(struct proc* p){ + acquire(&p->vma_lock); + struct vma* ma = p->memory_areas; + uint64 max = 0; + while(ma){ + if (ma->va_end > max) max = ma->va_end; + ma = ma->next; + } + release(&p->vma_lock); + return max; +} - while(old){ - if(old->p == p) { - if(old == head){ - head = old->next; - } else { - prev->next = old->next; - } - bd_free(old); - break; - } - prev = old; - old = old->next; +/* Affiche une VMA. */ +void print_memory_area(struct proc* p, struct vma* ma){ + printf("VA = [%p; %p[ RWX=%d%d%d", + ma->va_begin, ma->va_end, + (ma->vma_flags & VMA_R) != 0, + (ma->vma_flags & VMA_W) != 0, + (ma->vma_flags & VMA_X) != 0 + ); + if(ma->file){ + printf(" file=%s off=0x%x n=0x%x", ma->file, ma->file_offset, ma->file_nbytes); } + if(ma == p->stack_vma) printf(" [stack]"); + if(ma == p->heap_vma) printf(" [heap]"); + printf("\n"); +} - prio[p->priority] = head; +/* Affiche la liste de VMAs associée à un processus. */ +void print_memory_areas(struct proc* p){ + struct vma* ma = p->memory_areas; + printf("Memory areas:\n"); + while(ma){ + print_memory_area(p, ma); + ma = ma -> next; + } + printf("==============\n"); } - */ + +/* Copie les VMAs d'un processus [psrc] vers un processus [pdst]. */ +void vma_copy(struct proc * pdst, struct proc* psrc){ + acquire(&psrc->vma_lock); + struct vma * ma = psrc->memory_areas; + while(ma){ + struct vma* new_vma = add_memory_area(pdst, ma->va_begin, ma->va_end); + if(ma->file) + new_vma->file = strdup(ma->file); + else + new_vma->file = 0; + new_vma->file_offset = ma->file_offset; + new_vma->file_nbytes = ma->file_nbytes; + new_vma->vma_flags = ma->vma_flags; + if(ma == psrc->stack_vma) pdst->stack_vma = new_vma; + if(ma == psrc->heap_vma) pdst->heap_vma = new_vma; + ma = ma->next; + } + release(&psrc->vma_lock); +} + void procinit(void) { struct proc *p; - initlock(&prio_lock, "priolock"); for(int i = 0; i < NPRIO; i++){ + initlock(&prio_lock[i], "priolock"); prio[i] = 0; } initlock(&pid_lock, "nextpid"); for(p = proc; p < &proc[NPROC]; p++) { initlock(&p->lock, "proc"); + initlock(&p->vma_lock, "vma"); // Allocate a page for the process's kernel stack. // Map it high in memory, followed by an invalid @@ -167,6 +238,7 @@ found: p->pagetable = proc_pagetable(p); p->priority = DEF_PRIO; + p->memory_areas = 0; // Set up new context to start executing at forkret, // which returns to user space. @@ -193,6 +265,12 @@ freeproc(struct proc *p) p->cmd = 0; p->priority = 0; p->pagetable = 0; + acquire(&p->vma_lock); + free_vma(p->memory_areas); + release(&p->vma_lock); + p->memory_areas = 0; + p->stack_vma = 0; + p->heap_vma = 0; p->sz = 0; p->pid = 0; p->parent = 0; @@ -279,9 +357,9 @@ userinit(void) // Grow or shrink user memory by n bytes. // Return 0 on success, -1 on failure. int -growproc(int n) +growproc(long n) { - uint sz; + uint64 sz; struct proc *p = myproc(); sz = p->sz; @@ -316,6 +394,7 @@ fork(void) release(&np->lock); return -1; } + vma_copy(np, p); np->sz = p->sz; np->parent = p; @@ -764,3 +843,8 @@ void priodump(void){ printf("\n"); } } + +void proc_vmprint(struct proc* p){ + vmprint(p->pagetable, p->pid, p->cmd); + print_memory_areas(p); +} diff --git a/kernel/proc.h b/kernel/proc.h index 9d1def6..30ef880 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -87,6 +87,45 @@ struct trapframe { /* 280 */ uint64 t6; }; +/* La structure qui représente une VMA (Virtual Memory Area). */ +struct vma { + /* C'est une structure de liste chaînée : le pointeur next pointe sur la + * prochaine VMA dans la liste. */ + struct vma * next; + + /* Le début et la fin de la VMA. */ + uint64 va_begin; + uint64 va_end; + + /* Éventuellement, cette VMA peut être peuplée par le contenu d'un fichier. Si + * c'est le cas, [file] donne le nom du fichier, [file_offset] le déplacement + * dans le fichier, et [file_nbytes] le nombre d'octets à lire dans le + * fichier. + * + * Par exemple, si [file_offset] vaut 0x300, [file_nbytes] vaut 0x60, [file] + * vaut "toto", [va_begin] vaut 0x1000 et [va_end] vaut 0x1fff, alors on + * chargera les octets 0x300-0x35f aux adresses virtuelles 0x1000-0x105f, et + * les adresses virtuelles 0x1060-0x1fff seront remplies de 0. + */ + char* file; + uint64 file_offset; + uint64 file_nbytes; + + /* Les permissions de cette VMA. (VMA_R, VMA_W, VMA_X) */ + unsigned char vma_flags; +}; + +#define VMA_R (1 << 1) +#define VMA_W (1 << 2) +#define VMA_X (1 << 3) + +struct vma* add_memory_area(struct proc*, uint64, uint64); +struct vma* get_memory_area(struct proc*, uint64); +void print_memory_areas(struct proc*); +void print_memory_area(struct proc*, struct vma*); +uint64 max_addr_in_memory_areas(struct proc*); +void free_vma(struct vma*); + enum procstate { UNUSED, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; // Per-process state @@ -106,6 +145,10 @@ struct proc { // 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) + struct spinlock vma_lock; + struct vma * memory_areas; // VMAs du processus + struct vma * stack_vma; // Une VMA particulière pour la pile + struct vma * heap_vma; // Une VMA particulière pour le tas pagetable_t pagetable; // Page table struct trapframe *tf; // data page for trampoline.S struct context context; // swtch() here to run process diff --git a/kernel/spinlock.c b/kernel/spinlock.c index 56e0820..a410257 100644 --- a/kernel/spinlock.c +++ b/kernel/spinlock.c @@ -28,7 +28,23 @@ initlock(struct spinlock *lk, char *name) nlock++; } -#define MAXTRIES 100000 + +void dump_locks(void){ + printf_no_lock("LID\tLOCKED\tCPU\tPID\tNAME\t\tPC\n"); + for(int i = 0; i < nlock; i++){ + if(locks[i]->locked) + printf_no_lock("%d\t%d\t%d\t%d\t%s\t\t%p\n", + i, + locks[i]->locked, + locks[i]->cpu - cpus, + locks[i]->pid, + locks[i]->name, + locks[i]->pc + ); + } +} + +#define MAXTRIES 2000000 // Acquire the lock. // Loops (spins) until the lock is acquired. diff --git a/kernel/spinlock.h b/kernel/spinlock.h index 1493600..45d12ed 100644 --- a/kernel/spinlock.h +++ b/kernel/spinlock.h @@ -14,4 +14,6 @@ struct spinlock { uint nts; }; +void dump_locks(void); + #endif diff --git a/kernel/sysproc.c b/kernel/sysproc.c index e4e45c8..17587dc 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -41,13 +41,13 @@ sys_wait(void) uint64 sys_sbrk(void) { - int addr; - int n; + uint64 addr; + uint64 n; - if(argint(0, &n) < 0) + if(argaddr(0, &n) < 0) return -1; addr = myproc()->sz; - if(growproc(n) < 0) + if(growproc((long)n) < 0) return -1; return addr; } diff --git a/kernel/trap.c b/kernel/trap.c index 78c97a5..4a0dd92 100644 --- a/kernel/trap.c +++ b/kernel/trap.c @@ -33,6 +33,31 @@ trapinithart(void) w_stvec((uint64)kernelvec); } +int handle_page_fault(struct proc* p, uint64 scause, uint64 stval, uint64 sepc){ + uint64 addr = PGROUNDDOWN(stval); + acquire(&p->vma_lock); + int flags = allocate_if_possible(p->pagetable, p, addr); + release(&p->vma_lock); + if(flags < 0){ + if(flags == ENOVMA){ + printf("Could not find VMA associated with addr=%p\n", addr); + } else if (flags == ENOMEM){ + printf("No more memory could be allocated from the kernel\n"); + } else if (flags == ENOFILE){ + printf("Could not read file associated with memory area\n"); + } else if (flags == EMAPFAILED){ + printf("mappages failed for an unknown reason\n"); + } + + proc_vmprint(p); + printf("unrecoverable page fault by pid=%d at sepc=%p stval=%p scause=%x\n", + p->pid, sepc, stval, scause); + p->killed = 1; + return -1; + } + return 0; +} + // // handle an interrupt, exception, or system call from user space. // called from trampoline.S @@ -53,8 +78,10 @@ usertrap(void) // save user program counter. p->tf->epc = r_sepc(); - - if(r_scause() == 8){ + + uint64 scause = r_scause(); + + if(scause == 8){ // system call if(p->killed) @@ -69,6 +96,8 @@ usertrap(void) intr_on(); syscall(); + } else if (scause == 0xf || scause == 0xd) { + handle_page_fault(p, scause, r_stval(), r_sepc()); } else if((which_dev = devintr()) != 0){ // ok } else { diff --git a/kernel/vm.c b/kernel/vm.c index dd65184..3d849fe 100644 --- a/kernel/vm.c +++ b/kernel/vm.c @@ -182,11 +182,10 @@ uvmunmap(pagetable_t pagetable, uint64 va, uint64 size, int do_free) { uint64 a, last; pte_t *pte; - uint64 pa; a = PGROUNDDOWN(va); last = PGROUNDDOWN(va + size - 1); - for(;;){ + for(; a <= last; a+=PGSIZE){ if((pte = walk(pagetable, a, 0)) == 0) panic("uvmunmap: walk"); if((*pte & PTE_V) == 0){ @@ -196,14 +195,9 @@ uvmunmap(pagetable_t pagetable, uint64 va, uint64 size, int do_free) if(PTE_FLAGS(*pte) == PTE_V) panic("uvmunmap: not a leaf"); if(do_free){ - pa = PTE2PA(*pte); - kfree((void*)pa); + kfree((void*)PTE2PA(*pte)); } *pte = 0; - if(a == last) - break; - a += PGSIZE; - pa += PGSIZE; } } @@ -359,6 +353,14 @@ uvmclear(pagetable_t pagetable, uint64 va) *pte &= ~PTE_U; } +int allocate_if_possible(pagetable_t pagetable, struct proc* p, uint64 addr){ + return 0; +} + +int allocate_if_possible_range(pagetable_t pagetable, struct proc* p, uint64 addr, uint64 len){ + return 0; +} + // 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. @@ -367,6 +369,9 @@ copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len) { uint64 n, va0, pa0; + int f = allocate_if_possible_range(pagetable, myproc(), dstva, len); + if(f < 0) return -1; + while(len > 0){ va0 = PGROUNDDOWN(dstva); pa0 = walkaddr(pagetable, va0); @@ -392,6 +397,9 @@ copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len) { uint64 n, va0, pa0; + int f = allocate_if_possible_range(pagetable, myproc(), srcva, len); + if(f < 0) return -1; + while(len > 0){ va0 = PGROUNDDOWN(srcva); pa0 = walkaddr(pagetable, va0); @@ -418,12 +426,21 @@ copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max) { uint64 n, va0, pa0; int got_null = 0; - + int num_allocated = 0; + acquire(&myproc()->vma_lock); while(got_null == 0 && max > 0){ va0 = PGROUNDDOWN(srcva); + int f = allocate_if_possible(pagetable, myproc(), srcva); + if(f < 0) { + release(&myproc()->vma_lock); + return -1; + } + num_allocated += f; pa0 = walkaddr(pagetable, va0); - if(pa0 == 0) + if(pa0 == 0){ + release(&myproc()->vma_lock); return -1; + } n = PGSIZE - (srcva - va0); if(n > max) n = max; @@ -445,9 +462,41 @@ copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max) srcva = va0 + PGSIZE; } + release(&myproc()->vma_lock); if(got_null){ return 0; } else { return -1; } } + +void vmprint(pagetable_t pt, uint64 pid, char* cmd){ + printf("page table for pid=%d, cmd=%s, @%p\n", pid, cmd, pt); + for(int i = 0; i < PGSIZE/sizeof(uint64); i++){ + pte_t pgd = pt[i]; + if(pgd != 0){ + printf("..0x%x:\n", i); + for(int j = 0; j < 512; j++){ + pte_t pmd = ((uint64*)(PTE2PA(pgd)))[j]; + if(pmd != 0){ + printf(".. ..0x%x: \n", j); + for(int k = 0; k < 512; k++){ + pte_t pte = ((uint64*)(PTE2PA(pmd)))[k]; + if(pte != 0){ + printf(".. .. ..0x%x:\t V=%x R=%x W=%x X=%x U=%x VAs=[%p; %p]\n", + k, + (pte & PTE_V) != 0, + (pte & PTE_R) != 0, + (pte & PTE_W) != 0, + (pte & PTE_X) != 0, + (pte & PTE_U) != 0, + ((((i << 9) + j) << 9) + k) << 12, + (((((i << 9) + j) << 9) + k + 1) << 12) - 1 + ); + } + } + } + } + } + } +} diff --git a/user/naivefib.c b/user/naivefib.c new file mode 100644 index 0000000..b0ccc4a --- /dev/null +++ b/user/naivefib.c @@ -0,0 +1,27 @@ +#include "kernel/types.h" +#include "kernel/stat.h" +#include "user/user.h" + +int fib(int* tableau, int n){ + + if(n <=0) + return 0; + if (n == 1) + return 1; + tableau[n] = fib(tableau, n-1)+fib(tableau, n-2); + return tableau[n]; +} + +int +main(int argc, char **argv) +{ + if(argc < 2){ + printf("Usage: %s N\n", argv[0]); + exit(1); + } + int tableau[800]; + int n = atoi(argv[1]); + int res = fib(tableau, n); + printf("fib(%d)=%d\n", n, res); + exit(0); +} diff --git a/user/rwtest.c b/user/rwtest.c new file mode 100644 index 0000000..1099f75 --- /dev/null +++ b/user/rwtest.c @@ -0,0 +1,83 @@ +#include "kernel/param.h" +#include "kernel/types.h" +#include "kernel/stat.h" +#include "user/user.h" +#include "kernel/fs.h" +#include "kernel/fcntl.h" +#include "kernel/syscall.h" +#include "kernel/memlayout.h" +#include "kernel/riscv.h" + +int +main(int argc, char** argv) +{ + char *a; + int fd, n; + + char s[] = "rwtest"; + + a = sbrk(PGSIZE); + fd = open("sbrk", O_CREATE|O_WRONLY); + if(fd < 0) { + printf("%s: open sbrk failed\n", s); + exit(1); + } + if ((n = write(fd, a, PGSIZE)) < 0) { + printf("%s: write sbrk failed\n", s); + exit(1); + } + close(fd); + + a = sbrk(PGSIZE); + fd = open("sbrk", O_RDONLY); + if(fd < 0) { + printf("%s: open sbrk failed\n", s); + exit(1); + } + if ((n = read(fd, a, PGSIZE)) < 0) { + printf("%s: write sbrk failed\n", s); + exit(1); + } + close(fd); + unlink("sbrk"); + + a = sbrk(2*PGSIZE); + + /* int i = 4069; */ + /* a[i++] = 'H'; */ + /* a[i++] = 'A'; */ + /* a[i++] = 'H'; */ + /* a[i++] = 'A'; */ + /* a[i++] = '!'; */ + /* a[i++] = '\0'; */ + /* a[i++] = 'e'; */ + /* a[i++] = 'c'; */ + /* a[i++] = 'h'; */ + /* a[i++] = 'o'; */ + /* a[i++] = '\0'; */ + /* *(char**)(a+i++) = &a[4075]; */ + /* *(char**)(a+i++) = &a[4069]; */ + /* char** uargv = (char**)(a+4080); */ + + a[PGSIZE-5] = 'H'; + a[PGSIZE-4] = 'A'; + a[PGSIZE-3] = 'H'; + a[PGSIZE-2] = 'A'; + a[PGSIZE-1] = '!'; + char** uargv = (char**)a; + uargv[0] = &a[20]; + uargv[1] = &a[PGSIZE-5]; + uargv[2] = 0; + + a[30] = 'e'; + a[31] = 'c'; + a[32] = 'h'; + a[33] = 'o'; + a[34] = '\0'; + exec("echo", uargv); + + printf("This should never be displayed.\n"); + + exit(0); +} + diff --git a/user/sbrk-dealloc.c b/user/sbrk-dealloc.c new file mode 100644 index 0000000..1cf42dd --- /dev/null +++ b/user/sbrk-dealloc.c @@ -0,0 +1,49 @@ +#include "kernel/types.h" +#include "kernel/stat.h" +#include "user/user.h" +#include "kernel/riscv.h" + +int main(int argc, char** argv){ + uint64 BIG= 25 * PGSIZE; + char *a, *lastaddr; + uint64 amt; + + printf("Coucou\n"); // Initialise le buffer dans printf + // Effectivement, lui aussi, fait un sbrk... + + // Break courant + a = sbrk(0); + printf("a = %p\n", a); + a = sbrk(0); + printf("a = %p\n", a); + a = sbrk(0); + printf("a = %p\n", a); + + BIG = (uint64)a + PGSIZE; + amt = BIG - (uint64)a; + printf("BIG= %p\n", BIG); + printf("amt= %p\n", amt); + sbrk(amt); + + // + lastaddr = (char*) (BIG-1); + printf("lastaddr = %p\n", lastaddr); + *lastaddr = 99; // 1er page fault + *a = 11; + sbrk(-PGSIZE); + sbrk(PGSIZE); + printf("%d\n", *a); // 2eme page fault + printf("%d\n", *lastaddr); + if(*lastaddr == 99){ + printf("sbrk de-allocation didn't really deallocate\n"); + exit(1); + } + exit(0); + + /* char* a = sbrk(PGSIZE); */ + /* *a = 2; */ + /* sbrk(-PGSIZE); */ + /* sbrk(PGSIZE); */ + /* printf("%d\n", *a); */ + /* exit (0); */ +} diff --git a/user/suicide.c b/user/suicide.c new file mode 100644 index 0000000..129ee4c --- /dev/null +++ b/user/suicide.c @@ -0,0 +1,14 @@ +#include "kernel/types.h" +#include "kernel/stat.h" +#include "user/user.h" + +int +main(int argc, char **argv) +{ + // TODO: insérez votre code ci-dessous pour désallouer toute la mémoire du processus. + + // FIN TODO + printf("This is the end.\n"); + + exit(0); +} diff --git a/user/user.h b/user/user.h index 4a8b93d..1e74ce9 100644 --- a/user/user.h +++ b/user/user.h @@ -25,7 +25,7 @@ int mkdir(const char*); int chdir(const char*); int dup(int); int getpid(void); -char* sbrk(int); +char* sbrk(uint64); int sleep(int); int uptime(void); int ntas(); diff --git a/user/usertests.c b/user/usertests.c index 3f25eab..428574e 100644 --- a/user/usertests.c +++ b/user/usertests.c @@ -1590,11 +1590,11 @@ sbrkbasic(char *s) char *c, *a, *b; // does sbrk() return the expected failure value? - a = sbrk(TOOMUCH); - if(a != (char*)0xffffffffffffffffL){ - printf("%s: sbrk(<toomuch>) returned %p\n", a); - exit(1); - } + /* a = sbrk(TOOMUCH); */ + /* if(a != (char*)0xffffffffffffffffL){ */ + /* printf("%s: sbrk(<toomuch>) returned %p\n", a); */ + /* exit(1); */ + /* } */ // can one sbrk() less than a page? a = sbrk(0); @@ -1627,7 +1627,8 @@ sbrkbasic(char *s) void sbrkmuch(char *s) { - enum { BIG=100*1024*1024 }; + uint64 BIG= 8*1024*1024 - 10 * PGSIZE; + printf("BIG = %p\n", BIG); char *c, *oldbrk, *a, *lastaddr, *p; uint64 amt; @@ -2123,75 +2124,88 @@ main(int argc, char *argv[]) struct test { void (*f)(char *); char *s; + int ok; } tests[] = { - {reparent2, "reparent2"}, - {pgbug, "pgbug" }, - {sbrkbugs, "sbrkbugs" }, - // {badwrite, "badwrite" }, - {badarg, "badarg" }, - {reparent, "reparent" }, - {twochildren, "twochildren"}, - {forkfork, "forkfork"}, - {forkforkfork, "forkforkfork"}, - {argptest, "argptest"}, - {createdelete, "createdelete"}, - {linkunlink, "linkunlink"}, - {linktest, "linktest"}, - {unlinkread, "unlinkread"}, - {concreate, "concreate"}, - {subdir, "subdir"}, - {fourfiles, "fourfiles"}, - {sharedfd, "sharedfd"}, - {exectest, "exectest"}, - {bigargtest, "bigargtest"}, - {bigwrite, "bigwrite"}, - {bsstest, "bsstest"}, - {sbrkbasic, "sbrkbasic"}, - {sbrkmuch, "sbrkmuch"}, - {kernmem, "kernmem"}, - {sbrkfail, "sbrkfail"}, - {sbrkarg, "sbrkarg"}, - {validatetest, "validatetest"}, - {stacktest, "stacktest"}, - {opentest, "opentest"}, - {writetest, "writetest"}, - {writebig, "writebig"}, - {createtest, "createtest"}, - {openiputtest, "openiput"}, - {exitiputtest, "exitiput"}, - {iputtest, "iput"}, - {mem, "mem"}, - {pipe1, "pipe1"}, - {preempt, "preempt"}, - {exitwait, "exitwait"}, - {rmdot, "rmdot"}, - {fourteen, "fourteen"}, - {bigfile, "bigfile"}, - {dirfile, "dirfile"}, - {iref, "iref"}, - {forktest, "forktest"}, - {bigdir, "bigdir"}, // slow - { 0, 0}, + {reparent2, "reparent2", 0}, + {pgbug, "pgbug" , 0}, + {sbrkbugs, "sbrkbugs" , 0}, + // {badwrite, "badwrite" , 0}, + {badarg, "badarg" , 0}, + {reparent, "reparent" , 0}, + {twochildren, "twochildren", 0}, + {forkfork, "forkfork", 0}, + {forkforkfork, "forkforkfork", 0}, + {argptest, "argptest", 0}, + {createdelete, "createdelete", 0}, + {linkunlink, "linkunlink", 0}, + {linktest, "linktest", 0}, + {unlinkread, "unlinkread", 0}, + {concreate, "concreate", 0}, + {subdir, "subdir", 0}, + {fourfiles, "fourfiles", 0}, + {sharedfd, "sharedfd", 0}, + {exectest, "exectest", 0}, + {bigargtest, "bigargtest", 0}, + {bigwrite, "bigwrite", 0}, + {bsstest, "bsstest", 0}, + {sbrkbasic, "sbrkbasic", 0}, + {sbrkmuch, "sbrkmuch", 0}, + {kernmem, "kernmem", 0}, + {sbrkfail, "sbrkfail", 0}, + {sbrkarg, "sbrkarg", 0}, + {validatetest, "validatetest", 0}, + {stacktest, "stacktest", 0}, + {opentest, "opentest", 0}, + {writetest, "writetest", 0}, + {writebig, "writebig", 0}, + {createtest, "createtest", 0}, + {openiputtest, "openiput", 0}, + {exitiputtest, "exitiput", 0}, + {iputtest, "iput", 0}, + {mem, "mem", 0}, + {pipe1, "pipe1", 0}, + {preempt, "preempt", 0}, + {exitwait, "exitwait", 0}, + {rmdot, "rmdot", 0}, + {fourteen, "fourteen", 0}, + {bigfile, "bigfile", 0}, + {dirfile, "dirfile", 0}, + {iref, "iref", 0}, + {forktest, "forktest", 0}, + {bigdir, "bigdir", 0}, // slow + { 0, 0, 0}, }; printf("usertests starting\n"); - if(open("usertests.ran", 0) >= 0){ - printf("already ran user tests -- rebuild fs.img (rm fs.img; make fs.img)\n"); - exit(1); - } - close(open("usertests.ran", O_CREATE)); + /* if(open("usertests.ran", 0) >= 0){ */ + /* printf("already ran user tests -- rebuild fs.img (rm fs.img; make fs.img)\n"); */ + /* exit(1); */ + /* } */ + /* close(open("usertests.ran", O_CREATE)); */ int fail = 0; for (struct test *t = tests; t->s != 0; t++) { if((n == 0) || strcmp(t->s, n) == 0) { - if(!run(t->f, t->s)) + if(!run(t->f, t->s)){ fail = 1; + t->ok = 0; + } else { + t->ok = 1; + } } } if(!fail) printf("ALL TESTS PASSED\n"); - else + else{ printf("SOME TESTS FAILED\n"); + for (struct test *t = tests; t->s != 0; t++) { + if((n == 0) || strcmp(t->s, n) == 0) { + if(t->ok == 0){ + printf("Test %s failed.\n", t->s); + } + } + } + } exit(1); // not reached. } -- GitLab