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 */