diff --git a/.gitignore b/.gitignore index 25ad24c73..511251e44 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,5 @@ *.o *libmusl.a *liblwip.a -*/build/* +*build/* .DS_Store diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/mmu/src/bootmmu.c b/Ubiquitous/XiZi_AIoT/hardkernel/mmu/src/bootmmu.c index b6c360944..130f1e15b 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/mmu/src/bootmmu.c +++ b/Ubiquitous/XiZi_AIoT/hardkernel/mmu/src/bootmmu.c @@ -1,6 +1,5 @@ #include "memlayout.h" -#include "mmu.h" #include "vm.h" diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/trap/src/trap_driver.c b/Ubiquitous/XiZi_AIoT/hardkernel/trap/src/trap_driver.c index 8923d388c..debc08ab5 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/trap/src/trap_driver.c +++ b/Ubiquitous/XiZi_AIoT/hardkernel/trap/src/trap_driver.c @@ -40,7 +40,7 @@ static void _sys_irq_init() // initialize the stacks for different mode for (i = 0; i < sizeof(modes) / sizeof(uint32_t); i++) { - if (!(xizi_trap_driver.mode_stack_pages[i] = (uint32_t*)kalloc())) { + if (!(xizi_trap_driver.mode_stack_pages[i] = (uint32_t*)kalloc(PAGE_SIZE))) { // panic("irq stack allocation failed"); } init_stack(modes[i], (uint32_t)xizi_trap_driver.mode_stack_pages[i]); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/buddy.h b/Ubiquitous/XiZi_AIoT/softkernel/include/buddy.h new file mode 100644 index 000000000..25bfd9ed3 --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/buddy.h @@ -0,0 +1,80 @@ + +#pragma once + +#include "list.h" +#include "memlayout.h" +#include "spinlock.h" +#include "vm.h" + +#include +#include + +#define MAX_BUDDY_ORDER (10) + +#define FREE_LIST_INDEX(order) \ + (1 << order) + +#define IS_BUDDY_PAGE(buddy, order) \ + (buddy->order == order && buddy->node.next != &buddy->node) + +#define BUDDY_PAGE_INDEX(page_idx, order) \ + (page_idx ^ (FREE_LIST_INDEX(order))) + +#define COMBINED_PAGE_INDEX(page_idx, order) \ + (page_idx & ~(FREE_LIST_INDEX(order))) + +#define CALCULATE_NPAGES(size) \ + (ALIGNUP(size, PAGE_SIZE) >> PTE_SHIFT) + + +struct KPage +{ + struct double_list_node node; + union { + uint32_t order; + struct KPage *page_node; + }; +}; + +struct KFreeList +{ + uint32_t n_free_pages; + struct double_list_node list_head; +}; + +struct KBuddy { + uint32_t n_pages; + uint32_t use_lock; + struct spinlock lock; + struct KFreeList free_list[MAX_BUDDY_ORDER]; + struct KPage *first_page; +}; + +/********************************************* +* Buddy system public functions +*********************************************/ +/* +* Buddy system init function +* @param void +* @return void +*/ +void KBuddySysInit(); + +/* +* Continuous pages alloc by size +* @param size(uint32_t) size of need alloc +* @return NULL or v_addr (char*) return NULL if alloc failed, or return virtual page's addr +*/ +char* KBuddyAlloc(uint32_t size); + +/* +* Continuous pages free from vaddr +* @param vaddr(char*) virtual addr +* @param isFreeSuccess(bool) return false if free failed, or return true +*/ +bool KBuddyFree(char* vaddr); + +/* +* Print current free pages for debug. +*/ +void KFreePagesInfo(); \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/list.h b/Ubiquitous/XiZi_AIoT/softkernel/include/list.h index 0237f37cf..39836a233 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/list.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/list.h @@ -4,5 +4,55 @@ struct list_node { struct list_node* next; }; +struct double_list_node { + struct double_list_node *next; + struct double_list_node *prev; +}; + #define CONTAINER_OF(item, type, member) \ ((type*)((char*)(item) - (unsigned long)(&((type*)0)->member))) + +#define IS_DOUBLE_LIST_EMPTY(head) \ + ((head)->next == (head)) + +/********************************************* +* +* Double linked list operation functions +* +*********************************************/ +__attribute__((always_inline)) +static void inline doubleListNodeInit(struct double_list_node *list) +{ + list->next = list; + list->prev = list; +} + +__attribute__((always_inline)) +static void inline _double_list_add(struct double_list_node* new, struct double_list_node* prev, struct double_list_node* next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +__attribute__((always_inline)) +static void inline _double_list_del(struct double_list_node *prev, struct double_list_node *next) +{ + next->prev = prev; + prev->next = next; +} + +__attribute__((always_inline)) +static void inline doubleListAddOnHead(struct double_list_node *new, struct double_list_node *head) +{ + _double_list_add(new, head, head->next); +} + +__attribute__((always_inline)) +static void inline doubleListDel(struct double_list_node *entry) +{ + _double_list_del(entry->prev, entry->next); + entry->next = entry; + entry->prev = entry; +} diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/log.h b/Ubiquitous/XiZi_AIoT/softkernel/include/log.h index 4e2ee0981..c755945cc 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/log.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/log.h @@ -6,10 +6,13 @@ extern void KPrintf(char* fmt, ...); KPrintf("LOG: [%s] ", __func__); \ KPrintf(f, ##args) -#define DEBUG(f, args...) \ - KPrintf("DEBUG: [%s] ", __func__); \ +#define DEBUG_PRINTF(f, args...) \ KPrintf(f, ##args) +#define DEBUG(f, args...) \ + DEBUG_PRINTF("DEBUG: [%s] ", __func__); \ + DEBUG_PRINTF(f, ##args) + #define ERROR(f, args...) \ KPrintf("ERROR: [%s] ", __func__); \ KPrintf(f, ##args) diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/phymem.h b/Ubiquitous/XiZi_AIoT/softkernel/include/phymem.h index c237b46c3..0f22a833b 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/phymem.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/phymem.h @@ -1,28 +1,11 @@ #pragma once -#include "memlayout.h" -#include "mmu.h" - -#include "spinlock.h" - -#include - -struct run { - struct run* next; -}; - -struct { - struct spinlock lock; - // int use_lock; - struct run* freelist; -} kmem; - -extern int nr_free_pages; +#include "vm.h" void phymem_init(); -void freerange(void* vstart, void* vend); +bool kfree(char* vaddr); -void kfree(char* v); +char* kalloc(uint32_t size); -char* kalloc(void); +void show_phymem_info(); \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/vm.h b/Ubiquitous/XiZi_AIoT/softkernel/include/vm.h index ccfa2e808..501c58be9 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/vm.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/vm.h @@ -4,6 +4,7 @@ #include #include +#include #define ALIGNUP(sz, al) (((uint32_t)(sz) + (uint32_t)(al)-1) & ~((uint32_t)(al)-1)) #define ALIGNDOWN(sz, al) ((uint32_t)(sz) & ~((uint32_t)(al)-1)) @@ -14,6 +15,8 @@ #define PTE_IDX(v) (((uintptr_t)(v) >> PTE_SHIFT) & (NUM_PTE - 1)) #define PTE_ADDR(v) ALIGNDOWN(v, PTE_SZ) +#define PAGE_SIZE PTE_SZ + #define PDE_SHIFT 20 // mem range represented by 1 pde #define PDE_SZ (1 << PDE_SHIFT) diff --git a/Ubiquitous/XiZi_AIoT/softkernel/main.c b/Ubiquitous/XiZi_AIoT/softkernel/main.c index 794c94d84..c32a5347c 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/main.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/main.c @@ -39,6 +39,8 @@ extern void proc_switch(struct context**, struct context*); void kmain(void) { phymem_init(); + LOG("Buddy System Init Done.\r\n"); + show_phymem_info(); xizi_kern_driver_init(); @@ -51,26 +53,28 @@ void kmain(void) struct PCB* pcb = 0; DEBUG("Begin| nr_free_pcb: %d\r\n", xizi_proc_maintainer.nr_pcb_free); - DEBUG("Begin| nr_free_pages: %d\r\n", nr_free_pages); + show_phymem_info(); pcb = xizi_proc_maintainer.new_pcb(); - DEBUG("New PCB| nr_free_pages: %d\r\n", nr_free_pages); + show_phymem_info(); DEBUG("New PCB| nr_free_pcb: %d\r\n", xizi_proc_maintainer.nr_pcb_free); extern char _binary_initcode_start[], _binary_initcode_end[]; DEBUG("initcode start: %x, initcode end: %x\r\n", _binary_initcode_start, _binary_initcode_end); xizi_pager.map_pages(&pcb->pgdir, 0, (uintptr_t)_binary_initcode_start, (uintptr_t)(_binary_initcode_end - _binary_initcode_start), AP_KU); - DEBUG("Map pages| nr_free_pages: %d\r\n", nr_free_pages); + show_phymem_info(); xizi_proc_maintainer.free_pcb(pcb); - DEBUG("Free PCB| nr_free_pages: %d\r\n", nr_free_pages); + show_phymem_info(); DEBUG("Free PCB| nr_free_pcb: %d\r\n", xizi_proc_maintainer.nr_pcb_free); LOG("kernel init done.\r\n"); struct PCB* proc = first_proc(); + show_phymem_info(); + struct CPU* cpu = cur_cpu(); cpu->proc = proc; proc_switch(&cpu->scheduler, proc->main_thread.context); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/Makefile b/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/Makefile index abccc671f..9d0da9dae 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/Makefile +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/Makefile @@ -1,3 +1,3 @@ -SRC_FILES:= phymem.c pager.c +SRC_FILES:= phymem.c pager.c buddy.c include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/buddy.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/buddy.c new file mode 100644 index 000000000..84e30d20e --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/buddy.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/** + * @file: buddy.c + * @brief: the buddy management of system memory + * @version: 3.0 + * @author: AIIT XUOS Lab + * @date: 2023/4/27 + * + */ + +#include "buddy.h" +#include "log.h" + +struct KBuddy global_KBuddy; +static uint32_t v_manager_mem_start; +extern char kern_end[]; + +static void _buddy_split_page(struct KPage* page, uint32_t low_order, uint32_t high_order, struct KFreeList* list) +{ + uint32_t size = (1 << high_order); + while (high_order > low_order) { + list--; + size >>= 1; + doubleListAddOnHead(&page[size].node, &list->list_head); + list->n_free_pages++; + high_order--; + } +} + +__attribute__((always_inline)) static void inline _buddy_set_pages_order(struct KPage* page, int order) +{ + int i; + struct KPage* p = NULL; + page->order = order; + for (i = 1; i < FREE_LIST_INDEX(order); i++) { + p = page + i; + p->page_node = page; + } +} + +__attribute__((always_inline)) static void inline _buddy_page_to_vaddr(struct KPage* page, char** vaddr) +{ + uint32_t offset = page - global_KBuddy.first_page; + *vaddr = (char*)(v_manager_mem_start + (offset << PTE_SHIFT)); + return; +} + +__attribute__((always_inline)) static void inline _buddy_vaddr_to_page(struct KPage** page, char* vaddr) +{ + uint32_t offset = (uint32_t)vaddr - v_manager_mem_start; + *page = (struct KPage*)(global_KBuddy.first_page + (offset >> PTE_SHIFT)); + return; +} + +// find free page and split it to small page if need +static struct KPage* KBuddyPagesAlloc(int nPages) +{ + struct KPage* page = NULL; + struct KFreeList* list = NULL; + int i = 0, order = 0; + + spinlock_lock(&global_KBuddy.lock); + + // find order + for (order = 0; (FREE_LIST_INDEX(order)) < nPages; order++) + ; + + // find the free page list + for (i = order; i < MAX_BUDDY_ORDER; i++) { + list = global_KBuddy.free_list + i; + if (IS_DOUBLE_LIST_EMPTY(&list->list_head)) { + continue; + } + + // find the page + page = CONTAINER_OF(list->list_head.next, struct KPage, node); + doubleListDel(&page->node); + list->n_free_pages--; + + // split the page to some small pages + _buddy_split_page(page, order, i, list); + + // set the pages' order + _buddy_set_pages_order(page, order); + + spinlock_unlock(&global_KBuddy.lock); + return page; + } + + // there is no enough free page to satisfy the nPages + spinlock_unlock(&global_KBuddy.lock); + return NULL; +} + +// free continuous pages from page pointer +static void KBuddyPagesFree(struct KPage* page) +{ + struct KPage* buddy = NULL; + uint32_t order = (page->order >= MAX_BUDDY_ORDER) ? 0 : page->order; + uint32_t buddy_idx = 0, new_buddy_idx = 0; + uint32_t page_idx = page - global_KBuddy.first_page; + + spinlock_lock(&global_KBuddy.lock); + + for (; order < MAX_BUDDY_ORDER - 1; order++) { + // find and delete buddy to combine + buddy_idx = BUDDY_PAGE_INDEX(page_idx, order); + if (buddy_idx > global_KBuddy.n_pages - 1) { + break; + } + buddy = page + (buddy_idx - page_idx); + if (!IS_BUDDY_PAGE(buddy, order)) { + break; + } + // remove buddy + doubleListDel(&buddy->node); + global_KBuddy.free_list[order].n_free_pages--; + buddy->order = MAX_BUDDY_ORDER; + // update page and page_idx after combined + new_buddy_idx = COMBINED_PAGE_INDEX(page_idx, order); + page = page + (new_buddy_idx - page_idx); + page_idx = new_buddy_idx; + } + page->order = order; + doubleListAddOnHead(&page->node, &global_KBuddy.free_list[order].list_head); + global_KBuddy.free_list[order].n_free_pages++; + + spinlock_unlock(&global_KBuddy.lock); + return; +} + +void KBuddySysInit() +{ + uint32_t i = 0; + struct KPage* page = NULL; + struct KFreeList* free_list = NULL; + + // init spinlock + spinlock_init(&global_KBuddy.lock, "kbuddy"); + + // init global kernel Buddy system + uint32_t n_page_total = ALIGNDOWN(((uint32_t)P2V(PHYSTOP) - (uint32_t)&kern_end), PAGE_SIZE) >> PTE_SHIFT; + uint32_t k_page_size = ALIGNUP((n_page_total * sizeof(struct KPage)), PAGE_SIZE); + uint32_t n_k_page = k_page_size >> PTE_SHIFT; + global_KBuddy.n_pages = n_page_total - n_k_page; + + v_manager_mem_start = (uint32_t)&kern_end + k_page_size; + global_KBuddy.first_page = (struct KPage*)&kern_end; + memset(global_KBuddy.first_page, 0, k_page_size); + + // init each free page list from 2^0 to 2^8 + for (; i < MAX_BUDDY_ORDER; i++) { + free_list = global_KBuddy.free_list + i; + doubleListNodeInit(&free_list->list_head); + free_list->n_free_pages = 0; + } + + // init and free each page + for (i = 0; i < global_KBuddy.n_pages; i++) { + page = global_KBuddy.first_page + i; + page->order = MAX_BUDDY_ORDER; + } + for (i = 0; i < global_KBuddy.n_pages; i++) { + page = global_KBuddy.first_page + i; + doubleListNodeInit(&page->node); + KBuddyPagesFree(page); + } +} + +char* KBuddyAlloc(uint32_t size) +{ + int nPages = CALCULATE_NPAGES(size); + struct KPage* page = KBuddyPagesAlloc(nPages); + if (page == NULL) + return NULL; + + char* v_addr = NULL; + _buddy_page_to_vaddr(page, &v_addr); + + return v_addr; +} + +bool KBuddyFree(char* vaddr) +{ + struct KPage* page = NULL; + + if ((uint32_t)vaddr % (PAGE_SIZE)) { + ERROR("kbuddyfree - unaligned\r\n"); + return false; + } + if ((uint32_t)vaddr < (uint32_t)&kern_end) { + ERROR("kbuddyfree - under kern_end\r\n"); + return false; + } + if (V2P(vaddr) >= PHYSTOP) { + ERROR("kbuddyfree - over PHYSTOP\r\n"); + return false; + } + + _buddy_vaddr_to_page(&page, vaddr); + KBuddyPagesFree(page); + + return true; +} + +void KFreePagesInfo() +{ + DEBUG("Buddy structure:"); + for (int j = 0; j < MAX_BUDDY_ORDER; j++) { + DEBUG_PRINTF(" %d ", global_KBuddy.free_list[j].n_free_pages); + } + DEBUG_PRINTF("\r\n"); +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/pager.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/pager.c index 071bcebd6..41c2c164a 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/pager.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/pager.c @@ -8,7 +8,7 @@ static bool _new_user_pgdir(struct PageDirectory* pgdir, uintptr_t vrange) { void* new_pgdir_addr = 0; - if ((new_pgdir_addr = kalloc()) == NULL) { + if ((new_pgdir_addr = kalloc(4 * PAGE_SIZE)) == NULL) { LOG("new pgdir address: %x\r\n", new_pgdir_addr); return false; } @@ -29,12 +29,12 @@ static uintptr_t* _page_walk(struct PageDirectory* pgdir, uintptr_t vaddr, bool if (*pde != 0) { pgtbl_vaddr = P2V(PTE_ADDR(*pde)); } else { - if (!alloc || !(pgtbl_vaddr = (uintptr_t*)kalloc())) { + if (!alloc || !(pgtbl_vaddr = (uintptr_t*)kalloc(sizeof(uintptr_t) * NUM_PTE))) { return 0; } LOG("alloc %x for pgtbl\r\n", pgtbl_vaddr); - memset(pgtbl_vaddr, 0, PGSIZE); + memset(pgtbl_vaddr, 0, sizeof(uintptr_t) * NUM_PTE); *pde = V2P(pgtbl_vaddr) | PDE_COARSE; } diff --git a/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/phymem.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/phymem.c index 790fd7bf6..0696b4415 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/phymem.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/phymem.c @@ -18,71 +18,26 @@ * @date: 2023/4/27 * */ -#include - #include "phymem.h" -extern char kern_end[]; // first address after kernel loaded from ELF file - // defined by the kernel linker script in kernel.ld -int nr_free_pages; - -extern void KPrintf(char* fmt, ...); +#include "buddy.h" void phymem_init() { - spinlock_init(&kmem.lock, "kmem"); - nr_free_pages = 0; - // kmem.use_lock = 0; - freerange(kern_end, P2V(PHYSTOP)); + KBuddySysInit(); } -void freerange(void* vstart, void* vend) +bool kfree(char* vaddr) { - char* p; - p = (char*)ALIGNUP((uint32_t)vstart, 4 * PGSIZE); - for (; p + 4 * PGSIZE <= (char*)vend; p += 4 * PGSIZE) { - kfree(p); - } + return KBuddyFree(vaddr); } -void kfree(char* v) +char* kalloc(uint32_t size) { - struct run* r; - - if ((uint32_t)v % (4 * PGSIZE)) - KPrintf("kfree - unaligned\r\n"); - if (v < kern_end) - KPrintf("kfree - under kern_end\r\n"); - if ((uint32_t)V2P(v) >= (uint32_t)PHYSTOP) - KPrintf("kfree - over PHYSTOP, v: %x, p: %x\r\n", v, V2P(v)); - - // Fill with junk to catch dangling refs. - memset(v, 0, 4 * PGSIZE); - - // freeing a page - spinlock_lock(&kmem.lock); - - r = (struct run*)v; - r->next = kmem.freelist; - kmem.freelist = r; - - nr_free_pages += 1; - - spinlock_unlock(&kmem.lock); + return KBuddyAlloc(size); } -char* kalloc(void) +void show_phymem_info() { - struct run* r = NULL; - - spinlock_lock(&kmem.lock); - - if ((r = kmem.freelist)) - kmem.freelist = r->next; - - nr_free_pages -= 1; - - spinlock_unlock(&kmem.lock); - - return (char*)r; + KFreePagesInfo(); } \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/proc/process.c b/Ubiquitous/XiZi_AIoT/softkernel/proc/process.c index 874b367d2..804d43863 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/proc/process.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/proc/process.c @@ -8,14 +8,14 @@ struct CPU global_cpus[NR_CPU]; // return: number of PCBs stored in one page static int _alloc_page_for_pcb() { - void* proc_addr = kalloc(); + void* proc_addr = kalloc(PAGE_SIZE); if (proc_addr == NULL) { return 0; } LOG("proc page addr: %x\r\n", proc_addr); - void* proc_end = proc_addr + PGSIZE - sizeof(struct PCB); + void* proc_end = proc_addr + PAGE_SIZE - sizeof(struct PCB); spinlock_lock(&xizi_proc_maintainer.lock); @@ -139,7 +139,7 @@ static struct PCB* _new_pcb() // init main thread of proc pcb->main_thread.proc = pcb; // alloc stack page for proc - if ((void*)(pcb->main_thread.stack_addr = (uintptr_t)kalloc()) == NULL) { + if ((void*)(pcb->main_thread.stack_addr = (uintptr_t)kalloc(PAGE_SIZE)) == NULL) { _dealloc_pcb(pcb); return NULL; }