diff --git a/lab4/.gitignore b/lab4/.gitignore index fbdc48c..d4a9229 100644 --- a/lab4/.gitignore +++ b/lab4/.gitignore @@ -14,3 +14,5 @@ build *.out *.pyc chcore.out + +cmake-build-debug \ No newline at end of file diff --git a/lab4/CMakeLists.txt b/lab4/CMakeLists.txt index 6406c44..483fd25 100644 --- a/lab4/CMakeLists.txt +++ b/lab4/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required (VERSION 3.14) set(CMAKE_VERBOSE_MAKEFILE on) -set(CMAKE_BUILD_TYPE "Release") # "Release" or "Debug" +set(CMAKE_BUILD_TYPE "Debug") # "Release" or "Debug" set(CHCORE_PLAT "raspi3") set(CHCORE_ARCH "aarch64") diff --git a/lab4/kernel/common/printk.c b/lab4/kernel/common/printk.c index 29ebc95..4c2ca6e 100644 --- a/lab4/kernel/common/printk.c +++ b/lab4/kernel/common/printk.c @@ -119,7 +119,25 @@ static int printk_write_num(char **out, long long i, int base, int sign, // store the digitals in the buffer `print_buf`: // 1. the last postion of this buffer must be '\0' // 2. the format is only decided by `base` and `letbase` here - + int len = 0; + s = print_buf + 1; + while (u > 0) { + t = u % base; + u /= base; + if (t <= 9) + s[len++] = t + '0'; + else + s[len++] = t - 10 + (letbase ? 'a': 'A'); + } + s[len] = '\0'; + // swap print_buf + char ch; + for (int i = 0; i < len / 2; i++) { + ch = s[i]; + s[i] = s[len - 1 - i]; + s[len - 1 - i] = ch; + } + if (neg) { if (width && (flags & PAD_ZERO)) { simple_outputchar(out, '-'); diff --git a/lab4/kernel/exception/exception.c b/lab4/kernel/exception/exception.c index 61bc4cc..499f16b 100644 --- a/lab4/kernel/exception/exception.c +++ b/lab4/kernel/exception/exception.c @@ -38,6 +38,7 @@ void exception_init_per_cpu(void) * Lab3: Your code here * Setup the exception vector with the asm function written in exception.S */ + set_exception_vector(); disable_irq(); } @@ -49,7 +50,7 @@ void exception_init(void) void handle_entry_c(int type, u64 esr, u64 address) { - /** + /** * Lab4 * Acquire the big kernel lock, if the exception is not from kernel */ @@ -67,6 +68,15 @@ void handle_entry_c(int type, u64 esr, u64 address) * Handle exceptions as required in the lab document. Checking exception codes in * esr.h may help. */ + case ESR_EL1_EC_UNKNOWN: + // Unknown instruction + kinfo("%s", UNKNOWN); + sys_exit(-ESUPPORT); + break; + case ESR_EL1_EC_DABT_LEL: + case ESR_EL1_EC_DABT_CEL: + do_page_fault(esr, address); + break; default: kdebug("Unsupported Exception ESR %lx\n", esr); break; diff --git a/lab4/kernel/exception/exception_table.S b/lab4/kernel/exception/exception_table.S index cee80c8..c41a725 100644 --- a/lab4/kernel/exception/exception_table.S +++ b/lab4/kernel/exception/exception_table.S @@ -86,8 +86,8 @@ .endm -/** - * Lab4 +/** + * Lab4 * unlock the big kernel lock before returning to the user mode */ .macro exception_return @@ -131,6 +131,30 @@ .align 11 EXPORT(el1_vector) + // ELx SP_EL0 + exception_entry sync_el1t + exception_entry irq_el1t + exception_entry fiq_el1t + exception_entry error_el1t + + // ELx SP_ELx + exception_entry sync_el1h + exception_entry irq_el1h + exception_entry fiq_el1h + exception_entry error_el1h + + // EL0 AArch64 + exception_entry sync_el0_64 + exception_entry irq_el0_64 + exception_entry fiq_el0_64 + exception_entry error_el0_64 + + // EL0 AArch32 + exception_entry sync_el0_32 + exception_entry irq_el0_32 + exception_entry fiq_el0_32 + exception_entry error_el0_32 + sync_el1t: handle_entry 1, SYNC_EL1t @@ -167,9 +191,10 @@ sync_el0_64: exception_return el0_syscall: - /* Lab4 + /* Lab4 * Acquire the big kernel lock for syscall */ + // 保存现场 sub sp, sp, #16 * 8 stp x0, x1, [sp, #16 * 0] stp x2, x3, [sp, #16 * 1] @@ -192,6 +217,7 @@ el0_syscall: ldp x14, x15, [sp, #16 * 7] add sp, sp, #16 * 8 + // 系统调用号左移 2 位作为系统调用表偏移 adr x27, syscall_table // syscall table in x27 uxtw x16, w8 // syscall number in x16 ldr x16, [x27, x16, lsl #3] // find the syscall entry diff --git a/lab4/kernel/exception/pgfault.c b/lab4/kernel/exception/pgfault.c index 33588d7..483120a 100644 --- a/lab4/kernel/exception/pgfault.c +++ b/lab4/kernel/exception/pgfault.c @@ -69,6 +69,7 @@ int handle_trans_fault(struct vmspace *vmspace, vaddr_t fault_addr) struct pmobject *pmo; paddr_t pa; u64 offset; + int ret; /* * Lab3: your code here @@ -86,6 +87,28 @@ int handle_trans_fault(struct vmspace *vmspace, vaddr_t fault_addr) * are recorded in a radix tree for easy management. Such code * has been omitted in our lab for simplification. */ + vmr = find_vmr_for_va(vmspace, fault_addr); + if (vmr == NULL) { + return -ENOMAPPING; + } + + pmo = vmr->pmo; + if (pmo->type != PMO_ANONYM) { + return -ENOMAPPING; + } + + // 分配物理页 + pa = virt_to_phys(kmalloc(PAGE_SIZE)); + if ((void *) pa == NULL) { + return -ENOMAPPING; + } + // 应该调用但是此处省略:commit_page_to_pmo(pmo, ..., pa); + + // 映射 + ret = map_range_in_pgtbl(vmspace->pgtbl, ROUND_DOWN(fault_addr, PAGE_SIZE), pa, PAGE_SIZE, vmr->perm); + if (ret != 0) { + return -ENOMAPPING; + } return 0; } diff --git a/lab4/kernel/main.c b/lab4/kernel/main.c index f66f11b..d2fbcd6 100644 --- a/lab4/kernel/main.c +++ b/lab4/kernel/main.c @@ -90,9 +90,9 @@ void main(void *addr) BUG("No given TEST!"); #endif - /** + /** * Where the pimary CPU first returns to the user mode - * Leave the scheduler to do its job + * Leave the scheduler to do its job */ sched(); @@ -107,7 +107,7 @@ void secondary_start(void) kinfo("AP %u is activated!\n", smp_get_cpu_id()); exception_init_per_cpu(); - /** + /** * Lab4 * Inform the BSP at last to start cpu one by one * Hints: use cpu_status diff --git a/lab4/kernel/mm/buddy.c b/lab4/kernel/mm/buddy.c index 37bfd97..c8cac33 100644 --- a/lab4/kernel/mm/buddy.c +++ b/lab4/kernel/mm/buddy.c @@ -11,68 +11,69 @@ * The usable memory: [pool_start_addr, pool_start_addr + pool_mem_size). */ void init_buddy(struct phys_mem_pool *pool, struct page *start_page, - vaddr_t start_addr, u64 page_num) -{ - int order; - int page_idx; - struct page *page; + vaddr_t start_addr, u64 page_num) { + int order; + int page_idx; + struct page *page; - /* Init the physical memory pool. */ - pool->pool_start_addr = start_addr; - pool->page_metadata = start_page; - pool->pool_mem_size = page_num * BUDDY_PAGE_SIZE; - /* This field is for unit test only. */ - pool->pool_phys_page_num = page_num; + /* Init the physical memory pool. */ + pool->pool_start_addr = start_addr; + pool->page_metadata = start_page; + pool->pool_mem_size = page_num * BUDDY_PAGE_SIZE; + /* This field is for unit test only. */ + pool->pool_phys_page_num = page_num; - /* Init the free lists */ - for (order = 0; order < BUDDY_MAX_ORDER; ++order) { - pool->free_lists[order].nr_free = 0; - init_list_head(&(pool->free_lists[order].free_list)); - } + /* Init the free lists */ + for (order = 0; order < BUDDY_MAX_ORDER; ++order) { + pool->free_lists[order].nr_free = 0; + init_list_head(&(pool->free_lists[order].free_list)); // free lists 初始化为空链表 + } - /* Clear the page_metadata area. */ - memset((char *)start_page, 0, page_num * sizeof(struct page)); + /* Clear the page_metadata area. */ + memset((char *) start_page, 0, page_num * sizeof(struct page)); - /* Init the page_metadata area. */ - for (page_idx = 0; page_idx < page_num; ++page_idx) { - page = start_page + page_idx; - page->allocated = 1; - page->order = 0; - } + /* Init the page_metadata area. */ + for (page_idx = 0; page_idx < page_num; ++page_idx) { + page = start_page + page_idx; + page->allocated = 1; // 所有页面初始化为已分配 + page->order = 0; + } - /* Put each physical memory page into the free lists. */ - for (page_idx = 0; page_idx < page_num; ++page_idx) { - page = start_page + page_idx; - buddy_free_pages(pool, page); - } + /* Put each physical memory page into the free lists. */ + for (page_idx = 0; page_idx < page_num; ++page_idx) { + page = start_page + page_idx; + buddy_free_pages(pool, page); // 逐一去配页面以初始化 free lists + } } +/* + * 获得页面的伙伴页面 + */ static struct page *get_buddy_chunk(struct phys_mem_pool *pool, - struct page *chunk) -{ - u64 chunk_addr; - u64 buddy_chunk_addr; - int order; + struct page *chunk) { + u64 chunk_addr; + u64 buddy_chunk_addr; + int order; - /* Get the address of the chunk. */ - chunk_addr = (u64) page_to_virt(pool, chunk); - order = chunk->order; - /* - * Calculate the address of the buddy chunk according to the address - * relationship between buddies. - */ + /* Get the address of the chunk. */ + chunk_addr = (u64) page_to_virt(pool, chunk); + order = chunk->order; + /* + * Calculate the address of the buddy chunk according to the address + * relationship between buddies. + */ #define BUDDY_PAGE_SIZE_ORDER (12) - buddy_chunk_addr = chunk_addr ^ - (1UL << (order + BUDDY_PAGE_SIZE_ORDER)); + buddy_chunk_addr = chunk_addr ^ + (1UL << (order + BUDDY_PAGE_SIZE_ORDER)); - /* Check whether the buddy_chunk_addr belongs to pool. */ - if ((buddy_chunk_addr < pool->pool_start_addr) || - (buddy_chunk_addr >= (pool->pool_start_addr + - pool->pool_mem_size))) { - return NULL; - } + /* Check whether the buddy_chunk_addr belongs to pool. */ + if ((buddy_chunk_addr < pool->pool_start_addr) || + (buddy_chunk_addr >= (pool->pool_start_addr + + pool->pool_mem_size))) { + return NULL; + } - return virt_to_page(pool, (void *)buddy_chunk_addr); + return virt_to_page(pool, (void *) buddy_chunk_addr); } /* @@ -81,104 +82,181 @@ static struct page *get_buddy_chunk(struct phys_mem_pool *pool, * pool @ physical memory structure reserved in the kernel * order @ order for origin page block * page @ splitted page - * + * * Hints: don't forget to substract the free page number for the corresponding free_list. * you can invoke split_page recursively until the given page can not be splitted into two * smaller sub-pages. */ static struct page *split_page(struct phys_mem_pool *pool, u64 order, - struct page *page) -{ - // - struct page *split_page = NULL; - return split_page; - // + struct page *page) { + // + struct page *buddy = NULL; + + // 我理解的这个函数:把 page 递归切成 order,返回结果。过程修改的都是未分配区域。 + + // 递归出口 + if (page->order == order) { + return page; + } else if (page->order < order) { + return NULL; + } + // 分裂 + // 删除当前节点 + list_del(&page->node); + pool->free_lists[page->order].nr_free--; + // 降格 + page->order--; + // 找伙伴 + buddy = get_buddy_chunk(pool, page); + buddy->order = page->order; + // 加入 free list + list_add(&page->node, &pool->free_lists[page->order].free_list); + list_add(&buddy->node, &pool->free_lists[page->order].free_list); + pool->free_lists[page->order].nr_free += 2; + // 递归调用 + return split_page(pool, order, page); + // } /* * buddy_get_pages: get free page from buddy system. * pool @ physical memory structure reserved in the kernel * order @ get the (1< - struct page *page = NULL; +struct page *buddy_get_pages(struct phys_mem_pool *pool, u64 order) { + // + struct page *page = NULL, *free_page = NULL; - return page; - // + // 找可分配 order + u64 free_order = order; + while (free_order < BUDDY_MAX_ORDER && pool->free_lists[free_order].nr_free == 0) { + free_order++; + } + // 当前无可分配 + if (free_order == BUDDY_MAX_ORDER) { + return NULL; + } + // 有可分配,取一块切分 + free_page = (struct page *) pool->free_lists[free_order].free_list.next; + page = split_page(pool, order, free_page); + // 删除出 free list,分配 + list_del(&page->node); + pool->free_lists[page->order].nr_free--; + page->allocated = true; + + return page; + // } /* * merge_page: merge the given page with the buddy page * pool @ physical memory structure reserved in the kernel * page @ merged page (attempted) - * + * * Hints: you can invoke the merge_page recursively until * there is not corresponding buddy page. get_buddy_chunk * is helpful in this function. */ -static struct page *merge_page(struct phys_mem_pool *pool, struct page *page) -{ - // +static struct page *merge_page(struct phys_mem_pool *pool, struct page *page) { + // - struct page *merge_page = NULL; - return merge_page; - // + struct page *try_merge = NULL, *buddy = get_buddy_chunk(pool, page); + + // 不存在伙伴、伙伴已分配、order 不同则无法合并 + if (buddy == NULL || buddy->allocated || page->order != buddy->order) { + return NULL; + } + // 如果已经最大 order,则不合并 + if (page->order >= BUDDY_MAX_ORDER - 1) { + return NULL; + } + + // 双方都未分配,可以合并一次 + // 从 free 中删除两个节点 + list_del(&page->node); + list_del(&buddy->node); + pool->free_lists[page->order].nr_free -= 2; + // 选择左侧 page + struct page *t; + if (buddy < page) { + t = page; + page = buddy; + } + // 增加 page 的 order + page->order++; + // 链入上一层空列表 + list_add(&page->node, &pool->free_lists[page->order].free_list); + pool->free_lists[page->order].nr_free++; + // 尝试递归合并 + try_merge = merge_page(pool, page); + if (try_merge != NULL) { + return try_merge; + } + + return page; + + // } /* * buddy_free_pages: give back the pages to buddy system * pool @ physical memory structure reserved in the kernel * page @ free page structure - * + * * Hints: you can invoke merge_page. */ -void buddy_free_pages(struct phys_mem_pool *pool, struct page *page) -{ - // +void buddy_free_pages(struct phys_mem_pool *pool, struct page *page) { + // - // + if (!page->allocated) + return; + + // 设置标志 + page->allocated = false; + // 修改 free list + list_add(&page->node, &pool->free_lists[page->order].free_list); + pool->free_lists[page->order].nr_free++; + // 尝试合并当前页面 + merge_page(pool, page); + + // } -void *page_to_virt(struct phys_mem_pool *pool, struct page *page) -{ - u64 addr; +void *page_to_virt(struct phys_mem_pool *pool, struct page *page) { + u64 addr; - /* page_idx * BUDDY_PAGE_SIZE + start_addr */ - addr = (page - pool->page_metadata) * BUDDY_PAGE_SIZE + - pool->pool_start_addr; - return (void *)addr; + /* page_idx * BUDDY_PAGE_SIZE + start_addr */ + addr = (page - pool->page_metadata) * BUDDY_PAGE_SIZE + + pool->pool_start_addr; + return (void *) addr; } -struct page *virt_to_page(struct phys_mem_pool *pool, void *addr) -{ - struct page *page; +struct page *virt_to_page(struct phys_mem_pool *pool, void *addr) { + struct page *page; - page = pool->page_metadata + - (((u64) addr - pool->pool_start_addr) / BUDDY_PAGE_SIZE); - return page; + page = pool->page_metadata + + (((u64) addr - pool->pool_start_addr) / BUDDY_PAGE_SIZE); + return page; } -u64 get_free_mem_size_from_buddy(struct phys_mem_pool * pool) -{ - int order; - struct free_list *list; - u64 current_order_size; - u64 total_size = 0; +u64 get_free_mem_size_from_buddy(struct phys_mem_pool *pool) { + int order; + struct free_list *list; + u64 current_order_size; + u64 total_size = 0; - for (order = 0; order < BUDDY_MAX_ORDER; order++) { - /* 2^order * 4K */ - current_order_size = BUDDY_PAGE_SIZE * (1 << order); - list = pool->free_lists + order; - total_size += list->nr_free * current_order_size; + for (order = 0; order < BUDDY_MAX_ORDER; order++) { + /* 2^order * 4K */ + current_order_size = BUDDY_PAGE_SIZE * (1 << order); + list = pool->free_lists + order; + total_size += list->nr_free * current_order_size; - /* debug : print info about current order */ - kdebug("buddy memory chunk order: %d, size: 0x%lx, num: %d\n", - order, current_order_size, list->nr_free); - } - return total_size; + /* debug : print info about current order */ + kdebug("buddy memory chunk order: %d, size: 0x%lx, num: %d\n", + order, current_order_size, list->nr_free); + } + return total_size; } diff --git a/lab4/kernel/mm/mm.c b/lab4/kernel/mm/mm.c index 7b0feb2..4159a15 100644 --- a/lab4/kernel/mm/mm.c +++ b/lab4/kernel/mm/mm.c @@ -16,6 +16,7 @@ #include "buddy.h" #include "slab.h" +#include "page_table.h" extern unsigned long *img_end; @@ -51,6 +52,35 @@ unsigned long get_ttbr1(void) void map_kernel_space(vaddr_t va, paddr_t pa, size_t len) { // +#define IS_VALID (1UL << 0) +#define UXN (0x1UL << 54) +#define ACCESSED (0x1UL << 10) +#define INNER_SHARABLE (0x3UL << 8) + +#define SIZE_2M (2UL*1024*1024) +#define PAGE_SHIFT (12) +#define GET_PADDR_IN_PTE(entry) \ + (((u64)entry.table.next_table_addr) << PAGE_SHIFT) + + paddr_t addr_l0, addr_l1, addr_l2; + pte_t pte_l0, pte_l1; + u64 *table_l2; + + // 获得页表地址 + // 不妨假设 len 小于 1G 且属于同一块 + addr_l0 = get_ttbr1(); + pte_l0.pte = *((u64 *) phys_to_virt(addr_l0) + GET_L0_INDEX(va)); + addr_l1 = GET_PADDR_IN_PTE(pte_l0); + pte_l1.pte = *((u64 *) phys_to_virt(addr_l1) + GET_L1_INDEX(va)); + addr_l2 = GET_PADDR_IN_PTE(pte_l1); + table_l2 = (u64 *) phys_to_virt(addr_l2); + + // 设置页表 + u32 start_entry_idx = GET_L2_INDEX(va); + u32 end_entry_idx = GET_L2_INDEX((va + len)); + for (u32 idx = start_entry_idx; idx < end_entry_idx; ++idx) { + table_l2[idx] = (pa + idx * SIZE_2M) | UXN | ACCESSED | INNER_SHARABLE | NORMAL_MEMORY | IS_VALID; + } // } diff --git a/lab4/kernel/mm/page_table.c b/lab4/kernel/mm/page_table.c index 0109d93..b3376c9 100644 --- a/lab4/kernel/mm/page_table.c +++ b/lab4/kernel/mm/page_table.c @@ -162,7 +162,24 @@ static int get_next_ptp(ptp_t * cur_ptp, u32 level, vaddr_t va, int query_in_pgtbl(vaddr_t * pgtbl, vaddr_t va, paddr_t * pa, pte_t ** entry) { // + ptp_t * cur_ptp = (ptp_t *) pgtbl, *next_ptp; + int page_type; + // 遍历 L0-L3 + for (u32 cur_level = 0; cur_level < 4; cur_level++) { + page_type = get_next_ptp(cur_ptp, cur_level, va, &next_ptp, entry, false); + if (page_type < 0) { + // 无法映射 + return page_type; + } else if (page_type == BLOCK_PTP) { + // 遇到块项直接返回 + break; + } else { + // 遇到页表项,向下遍历 + cur_ptp = next_ptp; + } + } + *pa = GET_PADDR_IN_PTE((*entry)) | (va & PAGE_MASK); // return 0; } @@ -186,7 +203,40 @@ int map_range_in_pgtbl(vaddr_t * pgtbl, vaddr_t va, paddr_t pa, size_t len, vmr_prop_t flags) { // - + vaddr_t va_start = va, va_end = va + len, va_cur; + ptp_t * cur_ptp, *next_ptp; + int page_type; + u32 cur_level; + pte_t *entry; + u64 cur_pfn; + // 遍历所有页 + cur_pfn = pa >> PAGE_SHIFT; + va_start &= ~PAGE_MASK; + va_end &= ~PAGE_MASK; + if (va_end < va + len) { + va_end++; // 有不完整的一页 + } + for (va_cur = va_start; va_cur < va_end; va_cur += PAGE_SIZE) { + // 创建一页 + cur_ptp = (ptp_t *) pgtbl; + for (cur_level = 0; cur_level < 4; cur_level++) { + page_type = get_next_ptp(cur_ptp, cur_level, va_cur, &next_ptp, &entry, true); + if (page_type < 0) { + // 无法映射 + return page_type; + } else if (page_type == BLOCK_PTP) { + // 目前只支持页映射,遇到块项直接返回 + return -ENOMAPPING; + } else { + // 遇到页表项,向下遍历 + cur_ptp = next_ptp; + } + } + // 配置页 + set_pte_flags(entry, flags, USER_PTE); + entry->l3_page.pfn = cur_pfn++; + } + flush_tlb(); // return 0; } @@ -207,7 +257,40 @@ int map_range_in_pgtbl(vaddr_t * pgtbl, vaddr_t va, paddr_t pa, int unmap_range_in_pgtbl(vaddr_t * pgtbl, vaddr_t va, size_t len) { // - + vaddr_t va_start = va, va_end = va + len, va_cur; + ptp_t * cur_ptp, *next_ptp; + int page_type; + u32 cur_level; + pte_t *entry; + // 遍历所有页 + va_start &= ~PAGE_MASK; + va_end &= ~PAGE_MASK; + if (va_end < va + len) { + va_end++; // 有不完整的一页 + } + for (va_cur = va_start; va_cur < va_end; va_cur += PAGE_SIZE) { + // 创建一页 + cur_ptp = (ptp_t *) pgtbl; + for (cur_level = 0; cur_level < 4; cur_level++) { + page_type = get_next_ptp(cur_ptp, cur_level, va, &next_ptp, &entry, false); + if (page_type < 0) { + // 无法映射 + break; + } else if (page_type == BLOCK_PTP) { + // 目前只支持页映射,遇到块项直接返回 + return -ENOMAPPING; + } else { + // 遇到页表项,向下遍历 + cur_ptp = next_ptp; + } + } + if (cur_level != 4) { + continue; + } + // 配置页 + entry->pte = 0; + } + flush_tlb(); // return 0; } diff --git a/lab4/kernel/mm/vm_syscall.c b/lab4/kernel/mm/vm_syscall.c index d80b561..44c93a2 100644 --- a/lab4/kernel/mm/vm_syscall.c +++ b/lab4/kernel/mm/vm_syscall.c @@ -348,6 +348,37 @@ u64 sys_handle_brk(u64 addr) * */ + if (vmspace->heap_vmr != NULL) { + retval = vmspace->heap_vmr->start + vmspace->heap_vmr->size; + } else { + retval = vmspace->user_current_heap; + } + + if (addr == 0) { + // 初始化堆 + if (vmspace->heap_vmr != NULL) { + // 已经初始化 + return -EINVAL; + } + + // 创建堆 PMO 对象 + pmo = obj_alloc(TYPE_PMO, sizeof(*pmo)); + if (!pmo) { + return -ENOMEM; + } + pmo_init(pmo, PMO_ANONYM, 0, 0); + + // 初始化堆映射 + vmspace->heap_vmr = init_heap_vmr(vmspace, vmspace->user_current_heap, pmo); + } else if (vmspace->heap_vmr != NULL && addr > retval) { + // 增长堆 + vmspace->heap_vmr->size = addr - vmspace->heap_vmr->start; + retval = addr; + } else if (vmspace->heap_vmr != NULL && addr < retval) { + // 缩减堆 + retval = -EINVAL; + } + /* * return origin heap addr on failure; * return new heap addr on success. diff --git a/lab4/kernel/monitor.c b/lab4/kernel/monitor.c index 00dd7b5..0f951b9 100644 --- a/lab4/kernel/monitor.c +++ b/lab4/kernel/monitor.c @@ -15,6 +15,9 @@ #include #include +#include + +extern char kernel_stack[PLAT_CPU_NUM][KERNEL_STACK_SIZE]; static inline __attribute__ ((always_inline)) u64 read_fp() @@ -30,6 +33,21 @@ int stack_backtrace() printk("Stack backtrace:\n"); // Your code here. + u64 *fp, *preFp; + fp = read_fp(); + // until stack end + while (true) { + preFp = *fp; + // entry frame + if (preFp == 0) + break; + printk("LR %lx FP %lx Args", *(preFp + 1), preFp); + for (int i = 0; i < 5; i++) { + printk(" %lx", *(fp + 2 + i)); + } + printk("\n"); + fp = preFp; + } return 0; } diff --git a/lab4/kernel/process/process.c b/lab4/kernel/process/process.c index fdd8ec2..bfe3f8f 100644 --- a/lab4/kernel/process/process.c +++ b/lab4/kernel/process/process.c @@ -247,21 +247,26 @@ void process_create_root(char *bin_name) char *binary = NULL; int ret; + // 从内存硬盘读取相关文件,使用 CPIO 格式 ret = ramdisk_read_file(bin_name, &binary); BUG_ON(ret < 0); BUG_ON(binary == NULL); + // 创建 PCB 并设置自身 Cap root_process = process_create(); + // 创建主线程与其 Cap thread_cap = thread_create_main(root_process, ROOT_THREAD_STACK_BASE, ROOT_THREAD_STACK_SIZE, ROOT_THREAD_PRIO, TYPE_ROOT, smp_get_cpu_id(), binary, bin_name); + // 将主线程 Cap 加入进程 root_thread = obj_get(root_process, thread_cap, TYPE_THREAD); /* Enqueue: put init thread into the ready queue */ BUG_ON(sched_enqueue(root_thread)); obj_put(root_thread); + current_thread = root_thread; } /* syscalls */ diff --git a/lab4/kernel/process/thread.c b/lab4/kernel/process/thread.c index df354bf..84b716b 100644 --- a/lab4/kernel/process/thread.c +++ b/lab4/kernel/process/thread.c @@ -175,6 +175,15 @@ static u64 load_binary(struct process *process, * page aligned segment size. Take care of the page alignment when allocating * and mapping physical memory. */ + // 段实际数据大小 + seg_sz = elf->p_headers[i].p_filesz; + // 段虚拟地址 + p_vaddr = elf->p_headers[i].p_vaddr; + // 段映射结果大小,其实不太需要对齐,因为之后的逻辑已经处理了 + seg_map_sz = ROUND_UP(elf->p_headers[i].p_memsz, PAGE_SIZE); + if (ROUND_DOWN(p_vaddr, PAGE_SIZE) + seg_map_sz < p_vaddr + elf->p_headers[i].p_memsz) { + seg_map_sz += PAGE_SIZE; + } pmo = obj_alloc(TYPE_PMO, sizeof(*pmo)); if (!pmo) { @@ -193,9 +202,19 @@ static u64 load_binary(struct process *process, * You should copy data from the elf into the physical memory in pmo. * The physical address of a pmo can be get from pmo->start. */ + const char *section_data; + char *alloc_section; + + // 复制段内存 + section_data = bin + elf->p_headers[i].p_offset; + alloc_section = (char *) phys_to_virt(pmo->start); + kdebug("Copy segment[%d] from addr %lx -> %lx, len = %d\n", i, section_data, alloc_section, seg_sz); + memcpy(alloc_section, section_data, seg_sz); flags = PFLAGS2VMRFLAGS(elf->p_headers[i].p_flags); + kdebug("Map segment[%d] from paddr %lx -> %lx, len = %d\n", + i, pmo->start, ROUND_DOWN(p_vaddr, PAGE_SIZE), seg_map_sz); ret = vmspace_map_range(vmspace, ROUND_DOWN(p_vaddr, PAGE_SIZE), seg_map_sz, flags, pmo); @@ -251,10 +270,12 @@ int thread_create_main(struct process *process, u64 stack_base, u64 stack; u64 pc; + // 创建虚拟地址空间 init_vmspace = obj_get(process, VMSPACE_OBJ_ID, TYPE_VMSPACE); obj_put(init_vmspace); /* Allocate and setup a user stack for the init thread */ + // 创建用户栈 PMO 对象,并设置 Cap stack_pmo = obj_alloc(TYPE_PMO, sizeof(*stack_pmo)); if (!stack_pmo) { ret = -ENOMEM; @@ -267,11 +288,13 @@ int thread_create_main(struct process *process, u64 stack_base, goto out_free_obj_pmo; } + // 映射线程用户栈 ret = vmspace_map_range(init_vmspace, stack_base, stack_size, VMR_READ | VMR_WRITE, stack_pmo); BUG_ON(ret != 0); /* init thread */ + // 初始化线程对象 thread = obj_alloc(TYPE_THREAD, sizeof(*thread)); if (!thread) { ret = -ENOMEM; @@ -281,15 +304,19 @@ int thread_create_main(struct process *process, u64 stack_base, /* Fill the parameter of the thread struct */ stack = stack_base + stack_size; + // 加载程序各 ELF 段 pc = load_binary(process, init_vmspace, bin_start, &meta); + // 设置栈 prepare_env((char *)phys_to_virt(stack_pmo->start) + stack_size, stack, &meta, bin_name); stack -= ENV_SIZE_ON_STACK; + // 创建线程上下文 ret = thread_init(thread, process, stack, pc, prio, type, aff); BUG_ON(ret != 0); + // 取得线程 Cap thread_cap = cap_alloc(process, thread, 0); if (thread_cap < 0) { ret = thread_cap; @@ -297,6 +324,7 @@ int thread_create_main(struct process *process, u64 stack_base, } /* L1 icache & dcache have no coherence */ + // 清空 L1 缓存 flush_idcache(); // return thread; diff --git a/lab4/kernel/sched/context.c b/lab4/kernel/sched/context.c index c7c7ff2..9fb5fa9 100644 --- a/lab4/kernel/sched/context.c +++ b/lab4/kernel/sched/context.c @@ -57,6 +57,12 @@ void init_thread_ctx(struct thread *thread, u64 stack, u64 func, u32 prio, */ /* Fill the context of the thread */ + // 栈寄存器 + thread->thread_ctx->ec.reg[SP_EL0] = stack; + // PC 计数器 + thread->thread_ctx->ec.reg[ELR_EL1] = func; + // 状态字寄存器 + thread->thread_ctx->ec.reg[SPSR_EL1] = SPSR_EL1_EL0t; /* Set thread type */ thread->thread_ctx->type = type; diff --git a/lab4/kernel/sched/sched.c b/lab4/kernel/sched/sched.c index b29a8e3..b58b343 100644 --- a/lab4/kernel/sched/sched.c +++ b/lab4/kernel/sched/sched.c @@ -129,13 +129,13 @@ u64 switch_context(void) * Return the correct value in order to make eret_to_thread work correctly * in main.c */ - return 0; + return (u64) &target_ctx->ec; } /* SYSCALL functions */ /** - * Lab4 + * Lab4 * Finish the sys_yield function */ void sys_yield(void) @@ -144,9 +144,9 @@ void sys_yield(void) int sched_init(struct sched_ops *sched_ops) { - BUG_ON(sched_ops == NULL); + BUG_ON(sched_ops == NULL); - cur_sched_ops = sched_ops; - cur_sched_ops->sched_init(); - return 0; + cur_sched_ops = sched_ops; + cur_sched_ops->sched_init(); + return 0; } diff --git a/lab4/kernel/syscall/syscall.c b/lab4/kernel/syscall/syscall.c index de80bdf..8493508 100644 --- a/lab4/kernel/syscall/syscall.c +++ b/lab4/kernel/syscall/syscall.c @@ -31,22 +31,25 @@ void sys_putc(char ch) * Lab3: Your code here * Send ch to the screen in anyway as your like */ + uart_send(ch); } u32 sys_getc(void) { - return uart_recv(); + return uart_recv(); } -/* +/* * Lab4 * Finish the sys_get_cpu_id syscall */ u32 sys_get_cpu_id(void) { - return -1; + return -1; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winitializer-overrides" /* * Lab3: Your code here * Update the syscall table as you like to redirect syscalls @@ -70,7 +73,7 @@ const void *syscall_table[NR_SYSCALL] = { [SYS_cap_copy_from] = sys_cap_copy_from, [SYS_set_affinity] = sys_set_affinity, [SYS_get_affinity] = sys_get_affinity, - /* + /* * Lab4 * Add syscall */ @@ -87,3 +90,4 @@ const void *syscall_table[NR_SYSCALL] = { [SYS_debug] = sys_debug }; +#pragma clang diagnostic pop diff --git a/lab4/kernel/syscall/syscall_num.h b/lab4/kernel/syscall/syscall_num.h index 763823e..7a3425d 100644 --- a/lab4/kernel/syscall/syscall_num.h +++ b/lab4/kernel/syscall/syscall_num.h @@ -14,10 +14,10 @@ #define NR_SYSCALL 256 -void sys_exit(void); -void sys_create_pmo(void); -void sys_map_pmo(void); -void sys_handle_brk(void); +void sys_exit(int ret); +int sys_create_pmo(u64 size, u64 type); +int sys_map_pmo(u64 target_process_cap, u64 pmo_cap, u64 addr, u64 perm); +u64 sys_handle_brk(u64 addr); /* lab3 syscalls finished */ void sys_yield(void); diff --git a/lab4/user/lib/libmain.c b/lab4/user/lib/libmain.c index 7cfcab6..9c6da65 100644 --- a/lab4/user/lib/libmain.c +++ b/lab4/user/lib/libmain.c @@ -13,5 +13,6 @@ void _start_c(long *p) * Lab3: Your code here * Complete the main function */ + usys_exit(ret); return; } diff --git a/lab4/user/lib/syscall.c b/lab4/user/lib/syscall.c index 0bc95c9..22e8185 100644 --- a/lab4/user/lib/syscall.c +++ b/lab4/user/lib/syscall.c @@ -13,7 +13,28 @@ u64 syscall(u64 sys_no, u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, * And finally use svc to execute the system call. After syscall returned, don't forget * to move return value from x0 to the ret variable of this function */ - return ret; + + __asm __volatile("mov x9, %0"::"r"(sys_no)); + + // 参数 +#define SET_ARG(n) __asm __volatile("mov x"#n", %0"::"r"(arg##n)); + SET_ARG(0); + SET_ARG(1); + SET_ARG(2); + SET_ARG(3); + SET_ARG(4); + SET_ARG(5); + SET_ARG(6); + SET_ARG(7); + + // 系统调用 + __asm __volatile("mov x8, x9"); + __asm ("svc #0"); + + // 返回值 + __asm __volatile("mov %0, x0":"=r"(ret)); + + return ret; } /* @@ -22,25 +43,27 @@ u64 syscall(u64 sys_no, u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, */ void usys_putc(char ch) { + syscall(SYS_putc, ch, 0, 0, 0, 0, 0, 0, 0, 0); } void usys_exit(int ret) { + syscall(SYS_exit, ret, 0, 0, 0, 0, 0, 0, 0, 0); } int usys_create_pmo(u64 size, u64 type) { - return 0; + return (int) syscall(SYS_create_pmo, size, type, 0, 0, 0, 0, 0, 0, 0); } int usys_map_pmo(u64 process_cap, u64 pmo_cap, u64 addr, u64 rights) { - return 0; + return (int) syscall(SYS_map_pmo, process_cap, pmo_cap, addr, rights, 0, 0, 0, 0, 0); } u64 usys_handle_brk(u64 addr) { - return 0; + return syscall(SYS_handle_brk, addr, 0, 0, 0, 0, 0, 0, 0, 0); } /* Here finishes all syscalls need by lab3 */