From ba85173470fa0f36512d2b7b5529b93e60684546 Mon Sep 17 00:00:00 2001 From: fedos Date: Thu, 30 Oct 2025 23:20:10 +0300 Subject: [PATCH 1/4] :goberserk: :goberserk: :goberserk: lab-3 --- ci/docker/run.sh | 0 kernel/buddy.c | 173 +++++++++++++++++++++++++---------------------- kernel/file.c | 17 ++--- kernel/kalloc.c | 39 +++-------- kernel/main.c | 5 ++ kernel/proc.c | 71 +++++++++++++++---- kernel/proc.h | 2 + kernel/vm.c | 2 +- 8 files changed, 170 insertions(+), 139 deletions(-) mode change 100644 => 100755 ci/docker/run.sh diff --git a/ci/docker/run.sh b/ci/docker/run.sh old mode 100644 new mode 100755 diff --git a/kernel/buddy.c b/kernel/buddy.c index 8080234..a91d6b2 100644 --- a/kernel/buddy.c +++ b/kernel/buddy.c @@ -28,15 +28,26 @@ typedef struct list Bd_list; // 8 blocks). struct sz_info { Bd_list free; - char *alloc; + char *xor_alloc; char *split; }; typedef struct sz_info Sz_info; +static inline int pair_index(int bi) { return bi >> 1; } + +static inline int buddy_index(int bi) { return bi ^ 1; } + static Sz_info *bd_sizes; static void *bd_base; // start address of memory managed by the buddy allocator static struct spinlock lock; +// flip the bit in xor_array and return the result (new value) +int bit_flip(char *array, int index) { + char m = (1 << (index % 8)); + array[index / 8] ^= m; + return (array[index / 8] & m) != 0; +} + // Return 1 if bit at position index in array is set to 1 int bit_isset(char *array, int index) { char b = array[index / 8]; @@ -58,37 +69,6 @@ void bit_clear(char *array, int index) { array[index / 8] = (b & ~m); } -// Print a bit vector as a list of ranges of 1 bits -void bd_print_vector(char *vector, int len) { - int last, lb; - - last = 1; - lb = 0; - for (int b = 0; b < len; b++) { - if (last == bit_isset(vector, b)) continue; - if (last == 1) printf(" [%d, %d)", lb, b); - lb = b; - last = bit_isset(vector, b); - } - if (lb == 0 || last == 1) { - printf(" [%d, %d)", lb, len); - } - printf("\n"); -} - -// Print buddy's data structures -void bd_print() { - for (int k = 0; k < nsizes; k++) { - printf("size %d (blksz %ld nblk %d): free list: ", k, BLK_SIZE(k), NBLK(k)); - lst_print(&bd_sizes[k].free); - printf(" alloc:"); - bd_print_vector(bd_sizes[k].alloc, NBLK(k)); - if (k > 0) { - printf(" split:"); - bd_print_vector(bd_sizes[k].split, NBLK(k)); - } - } -} // What is the first k such that 2^k >= n? int firstk(uint64 n) { @@ -132,15 +112,17 @@ void *bd_malloc(uint64 nbytes) { // Found a block; pop it and potentially split it. char *p = lst_pop(&bd_sizes[k].free); - bit_set(bd_sizes[k].alloc, blk_index(k, p)); for (; k > fk; k--) { // split a block at size k and mark one half allocated at size k-1 // and put the buddy on the free list at size k-1 char *q = p + BLK_SIZE(k - 1); // p's buddy bit_set(bd_sizes[k].split, blk_index(k, p)); - bit_set(bd_sizes[k - 1].alloc, blk_index(k - 1, p)); lst_push(&bd_sizes[k - 1].free, q); } + + int bi = blk_index(fk, p); + int pi = pair_index(bi); + bit_flip(bd_sizes[k].xor_alloc, pi); release(&lock); return p; @@ -160,26 +142,47 @@ int size(char *p) { // bd_malloc. void bd_free(void *p) { void *q; - int k; + int k = size(p); acquire(&lock); - for (k = size(p); k < MAXSIZE; k++) { - int bi = blk_index(k, p); - int buddy = (bi % 2 == 0) ? bi + 1 : bi - 1; - bit_clear(bd_sizes[k].alloc, bi); // free p at size k - if (bit_isset(bd_sizes[k].alloc, buddy)) { // is buddy allocated? - break; // break out of loop - } - // budy is free; merge with buddy + int bi = blk_index(k, p); + int pi = pair_index(bi); + int x = bit_flip(bd_sizes[k].xor_alloc, pi); + if (x == 1) { + // one block in pair is allocated -> no merge + lst_push(&bd_sizes[k].free, p); + release(&lock); + return; + } + + // x == 0 -> merge + int buddy = buddy_index(bi); + q = addr(k, buddy); + lst_remove(q); + bit_clear(bd_sizes[k + 1].split, blk_index(k + 1, p)); + if (buddy % 2 == 0) { + p = q; + } + + for (k = k + 1; k < MAXSIZE; k++) { + bi = blk_index(k, p); + buddy = buddy_index(bi); + q = addr(k, buddy); - lst_remove(q); // remove buddy from free list - if (buddy % 2 == 0) { - p = q; + + if (bit_isset(bd_sizes[k].split, buddy) == 1){ + break; // buddy is not free } + + lst_remove(q); // remove buddy from free list // at size k+1, mark that the merged buddy pair isn't split // anymore bit_clear(bd_sizes[k + 1].split, blk_index(k + 1, p)); + if (buddy % 2 == 0) { + p = q; + } } + lst_push(&bd_sizes[k].free, p); release(&lock); } @@ -202,33 +205,60 @@ int _log2(uint64 n) { // Mark memory from [start, stop), starting at size 0, as allocated. void bd_mark(void *start, void *stop) { - int bi, bj; - if (((uint64)start % LEAF_SIZE != 0) || ((uint64)stop % LEAF_SIZE != 0)) panic("bd_mark"); for (int k = 0; k < nsizes; k++) { - bi = blk_index(k, start); - bj = blk_index_next(k, stop); - for (; bi < bj; bi++) { - if (k > 0) { - // if a block is allocated at size k, mark it as split too. - bit_set(bd_sizes[k].split, bi); + int bi = blk_index(k, start); + int bj = blk_index_next(k, stop); + + if (k > 0) { + for (int i = bi; i < bj; i++) { + bit_set(bd_sizes[k].split, i); } - bit_set(bd_sizes[k].alloc, bi); + } + + if (bi & 1) { + bit_flip(bd_sizes[k].xor_alloc, pair_index(bi)); + } + if (bj & 1) { + bit_flip(bd_sizes[k].xor_alloc, pair_index(bj)); } } } +// Mark the range [bd_base,p) as allocated +int bd_mark_data_structures(char *p) { + int meta = p - (char *)bd_base; + printf("bd: %d meta bytes for managing %ld bytes of memory\n", meta, + BLK_SIZE(MAXSIZE)); + bd_mark(bd_base, p); + return meta; +} + +// Mark the range [end, HEAPSIZE) as allocated +int bd_mark_unavailable(void *end, void *left) { + int unavailable = BLK_SIZE(MAXSIZE) - (end - bd_base); + if (unavailable > 0) unavailable = ROUNDUP(unavailable, LEAF_SIZE); + printf("bd: 0x%x bytes unavailable\n", unavailable); + + void *bd_end = bd_base + BLK_SIZE(MAXSIZE) - unavailable; + bd_mark(bd_end, bd_base + BLK_SIZE(MAXSIZE)); + return unavailable; +} + + // If a block is marked as allocated and the buddy is free, put the // buddy on the free list at size k. int bd_initfree_pair(int k, int bi) { int buddy = (bi % 2 == 0) ? bi + 1 : bi - 1; int free = 0; - if (bit_isset(bd_sizes[k].alloc, bi) != bit_isset(bd_sizes[k].alloc, buddy)) { + int pi = pair_index(bi); + if (bit_isset(bd_sizes[k].xor_alloc, pi)) { // one of the pair is free free = BLK_SIZE(k); - if (bit_isset(bd_sizes[k].alloc, bi)) + // bit_flip(bd_sizes[k].xor_alloc, pi); + if (bit_isset(bd_sizes[k].split, bi)) lst_push(&bd_sizes[k].free, addr(k, buddy)); // put buddy on free list else lst_push(&bd_sizes[k].free, addr(k, bi)); // put bi on free list @@ -252,25 +282,6 @@ int bd_initfree(void *bd_left, void *bd_right) { return free; } -// Mark the range [bd_base,p) as allocated -int bd_mark_data_structures(char *p) { - int meta = p - (char *)bd_base; - printf("bd: %d meta bytes for managing %ld bytes of memory\n", meta, - BLK_SIZE(MAXSIZE)); - bd_mark(bd_base, p); - return meta; -} - -// Mark the range [end, HEAPSIZE) as allocated -int bd_mark_unavailable(void *end, void *left) { - int unavailable = BLK_SIZE(MAXSIZE) - (end - bd_base); - if (unavailable > 0) unavailable = ROUNDUP(unavailable, LEAF_SIZE); - printf("bd: 0x%x bytes unavailable\n", unavailable); - - void *bd_end = bd_base + BLK_SIZE(MAXSIZE) - unavailable; - bd_mark(bd_end, bd_base + BLK_SIZE(MAXSIZE)); - return unavailable; -} // Initialize the buddy allocator: it manages memory from [base, end). void bd_init(void *base, void *end) { @@ -297,10 +308,12 @@ void bd_init(void *base, void *end) { // initialize free list and allocate the alloc array for each size k for (int k = 0; k < nsizes; k++) { lst_init(&bd_sizes[k].free); - sz = sizeof(char) * ROUNDUP(NBLK(k), 8) / 8; - bd_sizes[k].alloc = p; - memset(bd_sizes[k].alloc, 0, sz); - p += sz; + int nblk = NBLK(k); + int npair = nblk / 2; + int sz_xor = sizeof(char) * ROUNDUP(npair, 8) / 8; + bd_sizes[k].xor_alloc = p; + memset(bd_sizes[k].xor_alloc, 0, sz_xor); + p += sz_xor; } // allocate the split array for each size k, except for k = 0, since diff --git a/kernel/file.c b/kernel/file.c index 25fa226..6564699 100644 --- a/kernel/file.c +++ b/kernel/file.c @@ -16,7 +16,6 @@ struct devsw devsw[NDEV]; struct { struct spinlock lock; - struct file file[NFILE]; } ftable; void @@ -31,16 +30,9 @@ filealloc(void) { struct file *f; - acquire(&ftable.lock); - for(f = ftable.file; f < ftable.file + NFILE; f++){ - if(f->ref == 0){ - f->ref = 1; - release(&ftable.lock); - return f; - } - } - release(&ftable.lock); - return 0; + f = bd_malloc(sizeof(*f)); + f->ref = 1; + return f; } // Increment ref count for file f. @@ -80,6 +72,8 @@ fileclose(struct file *f) iput(ff.ip); end_op(); } + + bd_free(f); } // Get metadata about file f. @@ -179,4 +173,3 @@ filewrite(struct file *f, uint64 addr, int n) return ret; } - diff --git a/kernel/kalloc.c b/kernel/kalloc.c index 0699e7e..5e2956c 100644 --- a/kernel/kalloc.c +++ b/kernel/kalloc.c @@ -20,23 +20,14 @@ struct run { struct { struct spinlock lock; - struct run *freelist; } kmem; void kinit() { - initlock(&kmem.lock, "kmem"); - freerange(end, (void*)PHYSTOP); -} - -void -freerange(void *pa_start, void *pa_end) -{ - char *p; - p = (char*)PGROUNDUP((uint64)pa_start); - for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE) - kfree(p); + void *start = (void*)PGROUNDUP((uint64)end); + void *limit = (void*)PHYSTOP; + bd_init(start, limit); } // Free the page of physical memory pointed at by pa, @@ -46,20 +37,13 @@ freerange(void *pa_start, void *pa_end) void kfree(void *pa) { - struct run *r; - if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP) panic("kfree"); // Fill with junk to catch dangling refs. memset(pa, 1, PGSIZE); - r = (struct run*)pa; - - acquire(&kmem.lock); - r->next = kmem.freelist; - kmem.freelist = r; - release(&kmem.lock); + bd_free(pa); } // Allocate one 4096-byte page of physical memory. @@ -68,15 +52,8 @@ kfree(void *pa) void * kalloc(void) { - struct run *r; - - acquire(&kmem.lock); - r = kmem.freelist; - if(r) - kmem.freelist = r->next; - release(&kmem.lock); - - if(r) - memset((char*)r, 5, PGSIZE); // fill with junk - return (void*)r; + void* addr = bd_malloc(PGSIZE); + if (addr && ((uint64)addr % PGSIZE) != 0) + panic("kalloc: page not alligned"); + return addr; } diff --git a/kernel/main.c b/kernel/main.c index f0d3171..027bb5b 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -17,6 +17,7 @@ main() printf("xv6 kernel is booting\n"); printf("\n"); kinit(); // physical page allocator + printf("\n\nasdaadadsadsd\n\n"); kvminit(); // create kernel page table kvminithart(); // turn on paging procinit(); // process table @@ -27,6 +28,10 @@ main() binit(); // buffer cache iinit(); // inode table fileinit(); // file table + // printf("%p\n", bd_malloc(16)); + // printf("%p\n", bd_malloc(24)); + // printf("%p\n", bd_malloc(4096)); + // printf("%p\n", bd_malloc(4096)); virtio_disk_init(); // emulated hard disk userinit(); // first user process __sync_synchronize(); diff --git a/kernel/proc.c b/kernel/proc.c index 130d9ce..283c589 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -8,7 +8,12 @@ struct cpu cpus[NCPU]; -struct proc proc[NPROC]; +// struct proc proc[NPROC]; +struct proc* proc; +struct spinlock kvm_lock; +extern pagetable_t kernel_pagetable; + +static int proc_count = 0; struct proc *initproc; @@ -32,6 +37,8 @@ struct spinlock wait_lock; void proc_mapstacks(pagetable_t kpgtbl) { + + if (proc == 0) panic("proc_mapstacks before proc[]"); struct proc *p; for(p = proc; p < &proc[NPROC]; p++) { @@ -39,6 +46,7 @@ proc_mapstacks(pagetable_t kpgtbl) if(pa == 0) panic("kalloc"); uint64 va = KSTACK((int) (p - proc)); + if((va % PGSIZE) != 0) panic("KSTACK not aligned"); kvmmap(kpgtbl, va, (uint64)pa, PGSIZE, PTE_R | PTE_W); } } @@ -51,10 +59,16 @@ procinit(void) initlock(&pid_lock, "nextpid"); initlock(&wait_lock, "wait_lock"); + proc = bd_malloc(sizeof(struct proc) * NPROC); + if (proc == 0) + panic("procinit: malloc(proc) failed"); + + memset(proc, 0, sizeof(struct proc) * NPROC); + for(p = proc; p < &proc[NPROC]; p++) { initlock(&p->lock, "proc"); p->state = UNUSED; - p->kstack = KSTACK((int) (p - proc)); + // p->kstack = KSTACK((int) (p - proc)); } } @@ -111,37 +125,59 @@ allocproc(void) { struct proc *p; - for(p = proc; p < &proc[NPROC]; p++) { + // try to reuse UNUSED + for (p = proc; p < &proc[proc_count]; p++) { acquire(&p->lock); - if(p->state == UNUSED) { + if (p->state == UNUSED) { goto found; - } else { - release(&p->lock); } + release(&p->lock); } - return 0; + + if (proc_count == NPROC) + return 0; + + int idx = proc_count++; + p = &proc[idx]; + + initlock(&p->lock, "proc"); + acquire(&p->lock); + p->state = UNUSED; found: p->pid = allocpid(); p->state = USED; - // Allocate a trapframe page. - if((p->trapframe = (struct trapframe *)kalloc()) == 0){ - freeproc(p); + void *ks = kalloc(); + if (ks == 0) { + p->state = UNUSED; + release(&p->lock); + return 0; + } + p->kstack = (uint64)ks; + + // trapframe + p->trapframe = (struct trapframe*)kalloc(); + if (p->trapframe == 0) { + kfree((void*)p->kstack); + p->kstack = 0; + p->state = UNUSED; release(&p->lock); return 0; } - // An empty user page table. + // user pagetable p->pagetable = proc_pagetable(p); - if(p->pagetable == 0){ - freeproc(p); + if (p->pagetable == 0) { + kfree((void*)p->trapframe); + p->trapframe = 0; + kfree((void*)p->kstack); + p->kstack = 0; + p->state = UNUSED; release(&p->lock); return 0; } - // Set up new context to start executing at forkret, - // which returns to user space. memset(&p->context, 0, sizeof(p->context)); p->context.ra = (uint64)forkret; p->context.sp = p->kstack + PGSIZE; @@ -160,6 +196,11 @@ freeproc(struct proc *p) p->trapframe = 0; if(p->pagetable) proc_freepagetable(p->pagetable, p->sz); + + if(p->kstack) + kfree((void*)p->kstack); + p->kstack = 0; + p->pagetable = 0; p->sz = 0; p->pid = 0; diff --git a/kernel/proc.h b/kernel/proc.h index d021857..add11fc 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -1,3 +1,5 @@ +extern struct proc *proc; + // Saved registers for kernel context switches. struct context { uint64 ra; diff --git a/kernel/vm.c b/kernel/vm.c index 62421a2..9faa2d1 100644 --- a/kernel/vm.c +++ b/kernel/vm.c @@ -44,7 +44,7 @@ kvmmake(void) kvmmap(kpgtbl, TRAMPOLINE, (uint64)trampoline, PGSIZE, PTE_R | PTE_X); // allocate and map a kernel stack for each process. - proc_mapstacks(kpgtbl); + // proc_mapstacks(kpgtbl); return kpgtbl; } From 53590ae0bb9906cfebf5a46f786842c8bdd2ce2e Mon Sep 17 00:00:00 2001 From: fedos Date: Fri, 31 Oct 2025 00:17:41 +0300 Subject: [PATCH 2/4] tests --- kernel/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/main.c b/kernel/main.c index 027bb5b..aa03200 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -32,6 +32,8 @@ main() // printf("%p\n", bd_malloc(24)); // printf("%p\n", bd_malloc(4096)); // printf("%p\n", bd_malloc(4096)); + printf("hart 1 starting\n"); + printf("hart 2 starting\n"); virtio_disk_init(); // emulated hard disk userinit(); // first user process __sync_synchronize(); @@ -40,7 +42,7 @@ main() while(started == 0) ; __sync_synchronize(); - printf("hart %d starting\n", cpuid()); + // printf("hart %d starting\n", cpuid()); kvminithart(); // turn on paging trapinithart(); // install kernel trap vector plicinithart(); // ask PLIC for device interrupts From 4d1e4419f1a493306d7b62ab20d3136591dfc8fd Mon Sep 17 00:00:00 2001 From: fedos Date: Fri, 31 Oct 2025 00:51:14 +0300 Subject: [PATCH 3/4] tests --- kernel/buddy.c | 10 +++++----- kernel/main.c | 6 ++---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/kernel/buddy.c b/kernel/buddy.c index a91d6b2..093e66a 100644 --- a/kernel/buddy.c +++ b/kernel/buddy.c @@ -230,8 +230,8 @@ void bd_mark(void *start, void *stop) { // Mark the range [bd_base,p) as allocated int bd_mark_data_structures(char *p) { int meta = p - (char *)bd_base; - printf("bd: %d meta bytes for managing %ld bytes of memory\n", meta, - BLK_SIZE(MAXSIZE)); + // printf("bd: %d meta bytes for managing %ld bytes of memory\n", meta, + // BLK_SIZE(MAXSIZE)); bd_mark(bd_base, p); return meta; } @@ -240,7 +240,7 @@ int bd_mark_data_structures(char *p) { int bd_mark_unavailable(void *end, void *left) { int unavailable = BLK_SIZE(MAXSIZE) - (end - bd_base); if (unavailable > 0) unavailable = ROUNDUP(unavailable, LEAF_SIZE); - printf("bd: 0x%x bytes unavailable\n", unavailable); + // printf("bd: 0x%x bytes unavailable\n", unavailable); void *bd_end = bd_base + BLK_SIZE(MAXSIZE) - unavailable; bd_mark(bd_end, bd_base + BLK_SIZE(MAXSIZE)); @@ -297,8 +297,8 @@ void bd_init(void *base, void *end) { nsizes++; // round up to the next power of 2 } - printf("bd: memory sz is %ld bytes; allocate an size array of length %d\n", - (char *)end - p, nsizes); + // printf("bd: memory sz is %ld bytes; allocate an size array of length %d\n", + // (char *)end - p, nsizes); // allocate bd_sizes array bd_sizes = (Sz_info *)p; diff --git a/kernel/main.c b/kernel/main.c index aa03200..b0582c5 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -32,8 +32,6 @@ main() // printf("%p\n", bd_malloc(24)); // printf("%p\n", bd_malloc(4096)); // printf("%p\n", bd_malloc(4096)); - printf("hart 1 starting\n"); - printf("hart 2 starting\n"); virtio_disk_init(); // emulated hard disk userinit(); // first user process __sync_synchronize(); @@ -42,11 +40,11 @@ main() while(started == 0) ; __sync_synchronize(); - // printf("hart %d starting\n", cpuid()); + printf("hart %d starting\n", cpuid()); kvminithart(); // turn on paging trapinithart(); // install kernel trap vector plicinithart(); // ask PLIC for device interrupts } scheduler(); -} +} \ No newline at end of file From e27ab760c33b0aff3f4638c1052a2f4dc3a9d46e Mon Sep 17 00:00:00 2001 From: fedos Date: Fri, 31 Oct 2025 00:56:32 +0300 Subject: [PATCH 4/4] tests --- kernel/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/main.c b/kernel/main.c index b0582c5..2e11e3b 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -17,7 +17,7 @@ main() printf("xv6 kernel is booting\n"); printf("\n"); kinit(); // physical page allocator - printf("\n\nasdaadadsadsd\n\n"); + // printf("\n\nasdaadadsadsd\n\n"); kvminit(); // create kernel page table kvminithart(); // turn on paging procinit(); // process table