Merge branch 'jh7110_debug' into prepare_for_master
This commit is contained in:
@@ -107,4 +107,4 @@ void KBuddyDestory(struct KBuddy* pbuddy);
|
||||
/*
|
||||
* Print current free pages for debug.
|
||||
*/
|
||||
void KFreePagesInfo(struct KBuddy* pbuddy);
|
||||
void KFreePagesInfo(struct KBuddy* pbuddy);
|
||||
|
||||
@@ -35,7 +35,7 @@ Modification:
|
||||
#define OUTPUT_LEVLE_DEBUG 1
|
||||
#define OUTPUT_LEVLE_ERROR 2
|
||||
|
||||
#define OUTPUT_LEVEL_TEST 3
|
||||
#define OUTPUT_LEVLE_TEST 3
|
||||
|
||||
#define OUTPUT_LEVLE OUTPUT_LEVLE_DEBUG
|
||||
// #define OUTPUT_LEVLE OUTPUT_LEVLE_LOG
|
||||
|
||||
@@ -56,6 +56,7 @@ struct MemSpace {
|
||||
|
||||
/* task memory resources */
|
||||
struct TopLevelPageDirectory pgdir; // [phy] vm pgtbl base address
|
||||
struct TopLevelPageDirectory pgdir_riscv; // [phy] vm pgtbl base address
|
||||
uintptr_t heap_base; // mem size of proc used(allocated by kernel)
|
||||
uintptr_t mem_size;
|
||||
/* task communication mem resources */
|
||||
|
||||
@@ -37,7 +37,11 @@ struct CPU {
|
||||
int cpuid;
|
||||
|
||||
struct Thread* task;
|
||||
#ifndef __riscv
|
||||
struct context* scheduler;
|
||||
#else
|
||||
struct context scheduler;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern struct CPU global_cpus[NR_CPU];
|
||||
|
||||
@@ -48,6 +48,19 @@ Modification:
|
||||
#define LEVEL3_PDE_ADDR(v) ALIGNDOWN(v, LEVEL3_PDE_SIZE)
|
||||
|
||||
#define TOPLEVLE_PAGEDIR_SIZE sizeof(uintptr_t) * NUM_TOPLEVEL_PDE
|
||||
|
||||
|
||||
//#define PAGE_SHIFT (12)
|
||||
#define _PAGE_PFN_SHIFT 10
|
||||
#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
|
||||
#define PFN_PGD(x) ((x) << _PAGE_PFN_SHIFT)
|
||||
#define PFN_PHYS(x) ((x) << PAGE_SHIFT)
|
||||
#define _PGD_PFN(x) ((x) >> _PAGE_PFN_SHIFT)
|
||||
#define PFN_PMD PFN_PGD
|
||||
#define _PMD_PFN _PGD_PFN
|
||||
#define PFN_PTE PFN_PGD
|
||||
#define _PTE_PFN _PGD_PFN
|
||||
|
||||
// clang-format on
|
||||
|
||||
struct PagerRightGroup {
|
||||
@@ -74,4 +87,5 @@ void load_kern_pgdir(struct TraceTag* mmu_driver_tag, struct TraceTag* intr_driv
|
||||
void secondary_cpu_load_kern_pgdir(struct TraceTag* mmu_driver_tag, struct TraceTag* intr_driver_tag);
|
||||
|
||||
extern struct XiziPageManager xizi_pager;
|
||||
bool module_pager_init(struct PagerRightGroup*);
|
||||
bool module_pager_init(struct PagerRightGroup*);
|
||||
|
||||
|
||||
@@ -96,10 +96,17 @@ int main(void)
|
||||
}
|
||||
|
||||
/* start first task */
|
||||
#ifndef __riscv
|
||||
char* init_task_param[2] = { "/app/shell", 0 };
|
||||
sys_spawn((char*)_binary_init_start, "shell", init_task_param);
|
||||
char* fs_server_task_param[2] = { "/app/fs_server", 0 };
|
||||
sys_spawn((char*)_binary_default_fs_start, "memfs", fs_server_task_param);
|
||||
#else
|
||||
char* fs_server_task_param[2] = { "/app/fs_server", 0 };
|
||||
sys_spawn((char*)_binary_default_fs_start, "memfs", fs_server_task_param);
|
||||
char* init_task_param[2] = { "/app/shell", 0 };
|
||||
sys_spawn((char*)_binary_init_start, "shell", init_task_param);
|
||||
#endif
|
||||
}
|
||||
/* start scheduler */
|
||||
struct SchedulerRightGroup scheduler_rights;
|
||||
|
||||
@@ -8,6 +8,9 @@ endif
|
||||
ifneq ($(findstring $(BOARD), imx6q-sabrelite zynq7000-zc702), )
|
||||
SRC_FILES:= kalloc.c pagetable.c pagetable_level2.c buddy.c object_allocator.c share_page.c
|
||||
endif
|
||||
ifneq ($(findstring $(BOARD), jh7110), )
|
||||
SRC_FILES := kalloc.c pagetable_riscv.c pagetable_riscv_level3.c buddy.c object_allocator.c share_page.c
|
||||
endif
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
||||
@@ -36,13 +36,18 @@ Modification:
|
||||
#include "actracer.h"
|
||||
#include "buddy.h"
|
||||
|
||||
|
||||
struct KBuddy kern_virtmem_buddy;
|
||||
struct KBuddy user_phy_freemem_buddy;
|
||||
|
||||
extern uintptr_t kernel_data_end[];
|
||||
bool module_phymem_init()
|
||||
{
|
||||
#ifndef __riscv
|
||||
uintptr_t kern_freemem_start = V2P(kernel_data_end);
|
||||
#else
|
||||
uintptr_t kern_freemem_start = V2P_LINK(kernel_data_end);
|
||||
#endif
|
||||
uintptr_t kern_freemem_end = PHY_USER_FREEMEM_BASE;
|
||||
uintptr_t user_freemem_start = PHY_USER_FREEMEM_BASE;
|
||||
uintptr_t user_freemem_end = PHY_MEM_STOP;
|
||||
@@ -58,7 +63,11 @@ char* kalloc(uintptr_t size)
|
||||
if (mem_alloc == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
#ifndef __riscv
|
||||
assert((uintptr_t)mem_alloc >= V2P(&kernel_data_end) && (uintptr_t)mem_alloc < PHY_USER_FREEMEM_BASE);
|
||||
#else
|
||||
assert((uintptr_t)mem_alloc >= V2P_LINK(&kernel_data_end) && (uintptr_t)mem_alloc < PHY_USER_FREEMEM_BASE);
|
||||
#endif
|
||||
mem_alloc = P2V(mem_alloc);
|
||||
if ((uintptr_t)mem_alloc < KERN_MEM_BASE) {
|
||||
DEBUG("Error Alloc: %x by size: %d (Caused by double free)\n", mem_alloc, size);
|
||||
|
||||
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* 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 pagetable.c
|
||||
* @brief build page table
|
||||
* @version 3.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2023.08.25
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: pagetable.c
|
||||
Description: build page table
|
||||
Others:
|
||||
History:
|
||||
1. Date: 2023-08-28
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. first version
|
||||
*************************************************/
|
||||
#include "memlayout.h"
|
||||
|
||||
#include "trap_common.h"
|
||||
|
||||
#include "assert.h"
|
||||
#include "buddy.h"
|
||||
#include "kalloc.h"
|
||||
#include "pagetable.h"
|
||||
|
||||
static struct PagerRightGroup right_group;
|
||||
struct MmuCommonDone* _p_pgtbl_mmu_access = NULL;
|
||||
|
||||
static bool _new_pgdir(struct TopLevelPageDirectory* pgdir)
|
||||
{
|
||||
void* new_pgdir_addr = 0;
|
||||
|
||||
if (UNLIKELY((new_pgdir_addr = kalloc(TOPLEVLE_PAGEDIR_SIZE)) == NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pgdir->pd_addr = new_pgdir_addr;
|
||||
|
||||
memset(new_pgdir_addr, 0, TOPLEVLE_PAGEDIR_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _map_pages(uintptr_t* pgdir, uintptr_t vaddr, uintptr_t paddr, intptr_t len, uintptr_t attr)
|
||||
{
|
||||
assert(len >= 0);
|
||||
vaddr = ALIGNDOWN(vaddr, LEVEL4_PTE_SIZE);
|
||||
paddr = ALIGNDOWN(paddr, LEVEL4_PTE_SIZE);
|
||||
uintptr_t vaddr_last = ALIGNDOWN(vaddr + len - 1, LEVEL4_PTE_SIZE);
|
||||
|
||||
while (true) {
|
||||
uintptr_t* pte = NULL;
|
||||
if ((pte = _page_walk(pgdir, vaddr, true)) == NULL) {
|
||||
ERROR("pte not found for vaddr %p.\n", vaddr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (UNLIKELY(*pte != 0)) {
|
||||
ERROR("remapping: vaddr: %p | paddr: %p | pte: %p |\n", vaddr, paddr, *pte);
|
||||
return false;
|
||||
}
|
||||
|
||||
*pte = PFN_PTE(PFN_DOWN(paddr)) | attr;
|
||||
|
||||
if (vaddr == vaddr_last) {
|
||||
break;
|
||||
}
|
||||
|
||||
vaddr += PAGE_SIZE;
|
||||
paddr += PAGE_SIZE;
|
||||
}
|
||||
|
||||
assert(vaddr == vaddr_last);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _unmap_pages(uintptr_t* pgdir, uintptr_t vaddr, int len)
|
||||
{
|
||||
assert(len >= 0);
|
||||
vaddr = ALIGNDOWN(vaddr, LEVEL4_PTE_SIZE);
|
||||
uintptr_t vaddr_last = ALIGNDOWN(vaddr + len - 1, LEVEL4_PTE_SIZE);
|
||||
|
||||
while (true) {
|
||||
uintptr_t* pte = NULL;
|
||||
if ((pte = _page_walk(pgdir, vaddr, false)) == NULL) {
|
||||
ERROR("pte not found for vaddr %p.\n", vaddr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*pte == 0) {
|
||||
ERROR("unmap a unmapped page, vaddr: %p, pte: %p\n", vaddr, *pte);
|
||||
return false;
|
||||
}
|
||||
|
||||
*pte = 0;
|
||||
|
||||
if (vaddr == vaddr_last) {
|
||||
break;
|
||||
}
|
||||
|
||||
vaddr += PAGE_SIZE;
|
||||
}
|
||||
|
||||
assert(vaddr == vaddr_last);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief map paddr to vaddr for given pgdir (user only)
|
||||
/// @param pgdir vaddr of pgdir
|
||||
/// @param vaddr
|
||||
/// @param paddr
|
||||
/// @param len
|
||||
/// @param is_dev
|
||||
/// @return
|
||||
static bool _map_user_pages(struct MemSpace* pmemspace, uintptr_t vaddr, uintptr_t paddr, int len, bool is_dev)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
if (len < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (UNLIKELY(vaddr >= USER_MEM_TOP)) {
|
||||
ERROR("mapping kernel space.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uintptr_t mem_attr = 0;
|
||||
if (LIKELY(!is_dev)) {
|
||||
_p_pgtbl_mmu_access->MmuUsrPteAttr(&mem_attr);
|
||||
} else {
|
||||
_p_pgtbl_mmu_access->MmuUsrDevPteAttr(&mem_attr);
|
||||
}
|
||||
|
||||
ret = _map_pages(pmemspace->pgdir.pd_addr, vaddr, paddr, (intptr_t)len, mem_attr);
|
||||
if (ret == false) {
|
||||
ERROR("mapping _map_pages fail.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// In order for the S-mode to access the memory of the U-mode, in the riscv architecture.
|
||||
if (LIKELY(!is_dev)) {
|
||||
_p_pgtbl_mmu_access->MmuKernPteAttr(&mem_attr);
|
||||
} else {
|
||||
_p_pgtbl_mmu_access->MmuDevPteAttr(&mem_attr);
|
||||
}
|
||||
|
||||
ret = _map_pages(pmemspace->pgdir_riscv.pd_addr, vaddr, paddr, (intptr_t)len, mem_attr);
|
||||
if (ret == false) {
|
||||
ERROR("mapping _map_pages riscv fail.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _map_customizable_page(struct MemSpace* pmemspace, uintptr_t vaddr, uintptr_t paddr, int len, uintptr_t attr)
|
||||
{
|
||||
if (len < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (UNLIKELY(vaddr >= USER_MEM_TOP)) {
|
||||
ERROR("mapping kernel space.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return _map_pages(pmemspace->pgdir.pd_addr, vaddr, paddr, (intptr_t)len, attr);
|
||||
}
|
||||
/// assume that a user pagedir is allocated from [0, size)
|
||||
/// if new_size > old_size, allocate more space,
|
||||
/// if old_size > new_size, free extra space, to avoid unnecessary alloc/free.
|
||||
static uintptr_t _resize_user_pgdir(struct MemSpace* pmemspace, uintptr_t old_size, uintptr_t new_size)
|
||||
{
|
||||
if (UNLIKELY(new_size > USER_MEM_TOP)) {
|
||||
ERROR("user size out of range.\n");
|
||||
return old_size;
|
||||
}
|
||||
if (UNLIKELY(new_size < old_size)) {
|
||||
/// @todo: free extra space.
|
||||
return old_size;
|
||||
}
|
||||
|
||||
uintptr_t cur_size = ALIGNUP(old_size, PAGE_SIZE);
|
||||
uintptr_t size_needed = ALIGNUP(new_size, PAGE_SIZE) - cur_size;
|
||||
|
||||
// char* new_page = kalloc(size_needed);
|
||||
char* new_page = kalloc_by_ownership(pmemspace->kernspace_mem_usage.tag, size_needed);
|
||||
if (new_page == NULL) {
|
||||
ERROR("No memory\n");
|
||||
return cur_size;
|
||||
}
|
||||
memset(new_page, 0, size_needed);
|
||||
if (!xizi_pager.map_pages(pmemspace, cur_size, V2P(new_page), size_needed, false)) {
|
||||
return cur_size;
|
||||
}
|
||||
|
||||
return new_size;
|
||||
}
|
||||
|
||||
/// @brief translate virt address to phy address with pgdir
|
||||
/// @param pgdir
|
||||
/// @param vaddr accept only page aligned address
|
||||
/// @return paddr of pgdir(vaddr); zero for unmapped addr
|
||||
static uintptr_t _address_translate(struct TopLevelPageDirectory* pgdir, uintptr_t vaddr)
|
||||
{
|
||||
assert(vaddr % PAGE_SIZE == 0);
|
||||
const uintptr_t* const pte = _page_walk(pgdir->pd_addr, vaddr, false);
|
||||
if (pte == NULL || *pte == 0) {
|
||||
return 0;
|
||||
}
|
||||
return (uintptr_t)PFN_PHYS(_PTE_PFN(*pte));
|
||||
}
|
||||
|
||||
static uintptr_t _cross_vspace_data_copy_in_page(struct TopLevelPageDirectory* pgdir, uintptr_t cross_dest, uintptr_t src, uintptr_t len)
|
||||
{
|
||||
uintptr_t cross_dest_end = cross_dest + len;
|
||||
assert(ALIGNUP(cross_dest, PAGE_SIZE) == ALIGNUP(cross_dest_end, PAGE_SIZE));
|
||||
|
||||
uintptr_t paddr = xizi_pager.address_translate(pgdir, ALIGNDOWN(cross_dest, PAGE_SIZE));
|
||||
uintptr_t offset = cross_dest - ALIGNDOWN(cross_dest, PAGE_SIZE);
|
||||
uintptr_t* vdest = (uintptr_t*)((uintptr_t)P2V(paddr) + offset);
|
||||
uintptr_t* vsrc = (uintptr_t*)src;
|
||||
memcpy(vdest, vsrc, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/// @brief copy data from src(kernel vspace) to dest of pgdir vspace
|
||||
/// @param pgdir
|
||||
/// @param cross_dest vaddress in pgdir
|
||||
/// @param src
|
||||
/// @param len
|
||||
/// @return
|
||||
static uintptr_t _cross_vspace_data_copy(struct TopLevelPageDirectory* pgdir, uintptr_t cross_dest, uintptr_t src, uintptr_t len)
|
||||
{
|
||||
uintptr_t len_to_top = ALIGNUP(cross_dest, PAGE_SIZE) - cross_dest;
|
||||
|
||||
uintptr_t copied_len = 0;
|
||||
while (copied_len < len) {
|
||||
uintptr_t current_copy_len = len_to_top >= len ? len : len_to_top;
|
||||
|
||||
current_copy_len = _cross_vspace_data_copy_in_page(pgdir, cross_dest, src, current_copy_len);
|
||||
|
||||
// update variables
|
||||
copied_len += current_copy_len;
|
||||
cross_dest += current_copy_len;
|
||||
src += current_copy_len;
|
||||
len_to_top = ALIGNDOWN(cross_dest + PAGE_SIZE, PAGE_SIZE) - ALIGNDOWN(cross_dest, PAGE_SIZE); // actually PAGE_SIZE
|
||||
assert(len_to_top == PAGE_SIZE);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
struct XiziPageManager xizi_pager = {
|
||||
.new_pgdir = _new_pgdir,
|
||||
.free_user_pgdir = _free_user_pgdir,
|
||||
.map_pages = _map_user_pages,
|
||||
.unmap_pages = _unmap_pages,
|
||||
|
||||
.resize_user_pgdir = _resize_user_pgdir,
|
||||
.address_translate = _address_translate,
|
||||
.cross_vspace_data_copy = _cross_vspace_data_copy,
|
||||
};
|
||||
|
||||
bool module_pager_init(struct PagerRightGroup* _right_group)
|
||||
{
|
||||
right_group = *_right_group;
|
||||
_p_pgtbl_mmu_access = AchieveResource(&right_group.mmu_driver_tag);
|
||||
return _p_pgtbl_mmu_access != NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int test_access_map_address(void)
|
||||
{
|
||||
unsigned long address = KERN_MEM_BASE + (PHY_MEM_STOP - PHY_MEM_BASE) - 4096;
|
||||
printf_early("%s to access 0x%lx\n", __func__, address);
|
||||
*(unsigned long *)address = 0x55;
|
||||
if(*(unsigned long *)address == 0x55) {
|
||||
printf_early("%s access 0x%lx done\n", __func__, address);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief kernel pagedir
|
||||
struct TopLevelPageDirectory kern_pgdir;
|
||||
|
||||
void load_kern_pgdir(struct TraceTag* mmu_driver_tag, struct TraceTag* intr_driver_tag)
|
||||
{
|
||||
if (mmu_driver_tag->meta == NULL) {
|
||||
ERROR("Invalid mmu driver tag.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_new_pgdir(&kern_pgdir)) {
|
||||
panic("cannot alloc kernel page directory");
|
||||
}
|
||||
|
||||
uintptr_t kern_attr = 0;
|
||||
_p_pgtbl_mmu_access->MmuKernPteAttr(&kern_attr);
|
||||
uintptr_t dev_attr = 0;
|
||||
_p_pgtbl_mmu_access->MmuDevPteAttr(&dev_attr);
|
||||
|
||||
|
||||
// kern mem link
|
||||
_map_pages((uintptr_t*)kern_pgdir.pd_addr, KERNEL_LINK_ADDR, PHY_MEM_BASE, (PHY_USER_FREEMEM_BASE - PHY_MEM_BASE), kern_attr);
|
||||
// kern mem
|
||||
_map_pages((uintptr_t*)kern_pgdir.pd_addr, KERN_MEM_BASE, PHY_MEM_BASE, (PHY_MEM_STOP - PHY_MEM_BASE), kern_attr);
|
||||
// dev mem
|
||||
_map_pages((uintptr_t*)kern_pgdir.pd_addr, DEV_VRTMEM_BASE, DEV_PHYMEM_BASE, DEV_MEM_SIZE, dev_attr);
|
||||
|
||||
_p_pgtbl_mmu_access->LoadPgdir((uintptr_t)V2P(kern_pgdir.pd_addr));
|
||||
#if 0
|
||||
test_access_map_address();
|
||||
#endif
|
||||
}
|
||||
|
||||
void secondary_cpu_load_kern_pgdir(struct TraceTag* mmu_driver_tag, struct TraceTag* intr_driver_tag)
|
||||
{
|
||||
_p_pgtbl_mmu_access->LoadPgdir((uintptr_t)V2P(kern_pgdir.pd_addr));
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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 pagetable_level3.c
|
||||
* @brief page walk and L2 pagetable
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.05.06
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: pagetable_level3.c
|
||||
Description: ok1028 image vector table
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. first version
|
||||
*************************************************/
|
||||
#include <stdint.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "memlayout.h"
|
||||
|
||||
#include "assert.h"
|
||||
#include "buddy.h"
|
||||
#include "kalloc.h"
|
||||
#include "pagetable.h"
|
||||
|
||||
uintptr_t* _page_walk(uintptr_t* pgdir, uintptr_t vaddr, bool alloc)
|
||||
{
|
||||
// get page table addr
|
||||
assert(pgdir != NULL);
|
||||
uintptr_t pde_attr = 0;
|
||||
_p_pgtbl_mmu_access->MmuPdeAttr(&pde_attr);
|
||||
|
||||
uintptr_t* l2_pde_ptr = (uintptr_t*)&pgdir[(vaddr >> LEVEL2_PDE_SHIFT) & (NUM_LEVEL2_PDE - 1)];
|
||||
|
||||
uintptr_t* l3_pde_vaddr;
|
||||
if (*l2_pde_ptr != 0) {
|
||||
uintptr_t l3_table_paddr = PFN_PHYS(_PGD_PFN(*l2_pde_ptr));
|
||||
l3_pde_vaddr = (uintptr_t*)P2V(l3_table_paddr);
|
||||
} else {
|
||||
if (!alloc || !(l3_pde_vaddr = (uintptr_t*)kalloc(sizeof(uintptr_t) * NUM_LEVEL3_PDE))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(l3_pde_vaddr, 0, sizeof(uintptr_t) * NUM_LEVEL3_PDE);
|
||||
*l2_pde_ptr = PFN_PGD(PFN_DOWN(V2P(l3_pde_vaddr))) | pde_attr;
|
||||
}
|
||||
|
||||
uintptr_t* l3_pde_ptr = (uintptr_t*)&l3_pde_vaddr[(vaddr >> LEVEL3_PDE_SHIFT) & (NUM_LEVEL3_PDE - 1)];
|
||||
|
||||
uintptr_t* l4_pte_vaddr;
|
||||
if (*l3_pde_ptr != 0) {
|
||||
uintptr_t l4_table_paddr = PFN_PHYS(_PMD_PFN(*l3_pde_ptr));
|
||||
l4_pte_vaddr = (uintptr_t*)P2V(l4_table_paddr);
|
||||
} else {
|
||||
if (!alloc || !(l4_pte_vaddr = (uintptr_t*)kalloc(sizeof(uintptr_t) * NUM_LEVEL4_PTE))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(l4_pte_vaddr, 0, sizeof(uintptr_t) * NUM_LEVEL4_PTE);
|
||||
*l3_pde_ptr = PFN_PMD(PFN_DOWN(V2P(l4_pte_vaddr))) | pde_attr;
|
||||
}
|
||||
|
||||
return &l4_pte_vaddr[LEVEL4_PTE_IDX(vaddr)];
|
||||
}
|
||||
|
||||
|
||||
void _free_user_pgdir(struct TopLevelPageDirectory* pgdir)
|
||||
{
|
||||
if (pgdir->pd_addr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uintptr_t end_idx = (USER_MEM_TOP >> LEVEL2_PDE_SHIFT) & (NUM_LEVEL2_PDE - 1);
|
||||
|
||||
for (uintptr_t l2_entry_idx = 0; l2_entry_idx < end_idx; l2_entry_idx++) {
|
||||
// free each level3 page table
|
||||
uintptr_t* l3_table_paddr = (uintptr_t*)PFN_PHYS(_PMD_PFN(pgdir->pd_addr[l2_entry_idx]));
|
||||
if (l3_table_paddr != NULL) {
|
||||
uintptr_t* l3_table_vaddr = P2V(l3_table_paddr);
|
||||
for (uintptr_t l3_entry_idx = 0; l3_entry_idx < NUM_LEVEL3_PDE; l3_entry_idx++) {
|
||||
uintptr_t* l4_table_paddr = (uintptr_t*)PFN_PHYS(_PTE_PFN(l3_table_vaddr[l3_entry_idx]));
|
||||
if (l4_table_paddr != NULL) {
|
||||
kfree(P2V(l4_table_paddr));
|
||||
}
|
||||
}
|
||||
kfree(P2V(l3_table_paddr));
|
||||
}
|
||||
}
|
||||
kfree((char*)pgdir->pd_addr);
|
||||
}
|
||||
@@ -99,7 +99,11 @@ void show_mem(void)
|
||||
{
|
||||
SHOWINFO_BORDER_LINE();
|
||||
|
||||
#ifndef __riscv
|
||||
uint64_t total = (PHY_MEM_STOP - V2P(kernel_data_end));
|
||||
#else
|
||||
uint64_t total = (PHY_MEM_STOP - V2P_LINK(kernel_data_end));
|
||||
#endif
|
||||
uint64_t user_dynamic_free = 0;
|
||||
uint64_t kernel_free = 0;
|
||||
for (int j = 0; j < MAX_BUDDY_ORDER; j++) {
|
||||
@@ -139,8 +143,13 @@ int sys_state(sys_state_option option, sys_state_info* info)
|
||||
{
|
||||
switch (option) {
|
||||
case SYS_STATE_MEMBLOCK_INFO: {
|
||||
#ifndef __riscv
|
||||
info->memblock_info.memblock_start = (uintptr_t)V2P(_binary_fs_img_start);
|
||||
info->memblock_info.memblock_end = (uintptr_t)V2P(_binary_fs_img_end);
|
||||
#else
|
||||
info->memblock_info.memblock_start = (uintptr_t)V2P_LINK(_binary_fs_img_start);
|
||||
info->memblock_info.memblock_end = (uintptr_t)V2P_LINK(_binary_fs_img_end);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case SYS_STATE_GET_HEAP_BASE:
|
||||
|
||||
@@ -54,6 +54,10 @@ int sys_new_thread(struct MemSpace* pmemspace, struct Thread* task, uintptr_t en
|
||||
arch_trapframe_set_sp_pc(task->thread_context.trapframe, loaded_sp.user_sp, (uintptr_t)entry);
|
||||
arch_set_main_params(task->thread_context.trapframe, loaded_sp.argc, loaded_sp.user_sp);
|
||||
|
||||
#ifdef __riscv
|
||||
arch_context_set_sp(task->thread_context.context, (uintptr_t)task->thread_context.trapframe);
|
||||
#endif
|
||||
|
||||
// init thread name
|
||||
char* last = NULL;
|
||||
for (last = name; *name; name++) {
|
||||
|
||||
@@ -143,6 +143,10 @@ uintptr_t* load_memspace(struct MemSpace* pmemspace, char* img_start)
|
||||
}
|
||||
/* copy kernel pagetable so that interrupt and syscall wont corrupt */
|
||||
memcpy(pmemspace->pgdir.pd_addr, kern_pgdir.pd_addr, TOPLEVLE_PAGEDIR_SIZE);
|
||||
#ifdef __riscv
|
||||
xizi_pager.new_pgdir(&pmemspace->pgdir_riscv);
|
||||
memcpy(pmemspace->pgdir_riscv.pd_addr, kern_pgdir.pd_addr, TOPLEVLE_PAGEDIR_SIZE);
|
||||
#endif
|
||||
|
||||
// read elf file by (header, section)
|
||||
uintptr_t load_size = 0;
|
||||
|
||||
@@ -136,12 +136,14 @@ int _task_return_sys_resources(struct Thread* ptask)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef __riscv
|
||||
extern void trap_return(void);
|
||||
__attribute__((optimize("O0"))) void task_prepare_enter()
|
||||
{
|
||||
xizi_leave_kernel();
|
||||
trap_return();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief this function changes task list without locking, so it must be called inside a lock critical area
|
||||
/// @param task
|
||||
@@ -250,7 +252,11 @@ static struct Thread* _new_thread(struct MemSpace* pmemspace)
|
||||
task->thread_context.task = task;
|
||||
memset((void*)task->thread_context.kern_stack_addr, 0x00, USER_STACK_SIZE);
|
||||
/// stack bottom
|
||||
#ifndef __riscv
|
||||
char* sp = (char*)task->thread_context.kern_stack_addr + USER_STACK_SIZE - 4;
|
||||
#else
|
||||
char* sp = (char*)task->thread_context.kern_stack_addr + USER_STACK_SIZE;
|
||||
#endif
|
||||
|
||||
/// 1. trap frame into stack, for process to nomally return by trap_return
|
||||
/// trapframe (user context)
|
||||
@@ -365,8 +371,15 @@ static void central_trans_task_state()
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __riscv
|
||||
uintptr_t riscv_kernel_satp = 0;
|
||||
#endif
|
||||
struct Thread* next_task_emergency = NULL;
|
||||
#ifndef __riscv
|
||||
extern void context_switch(struct context**, struct context*);
|
||||
#else
|
||||
extern void context_switch(struct context*, struct context*);
|
||||
#endif
|
||||
static void _scheduler(struct SchedulerRightGroup right_group)
|
||||
{
|
||||
struct MmuCommonDone* p_mmu_driver = AchieveResource(&right_group.mmu_driver_tag);
|
||||
@@ -396,8 +409,14 @@ static void _scheduler(struct SchedulerRightGroup right_group)
|
||||
// DEBUG_PRINTF("Thread %s(%d) to RUNNING\n", next_task->name, next_task->tid);
|
||||
task_state_set_running(next_task);
|
||||
cpu->task = next_task;
|
||||
|
||||
#ifdef __riscv
|
||||
riscv_kernel_satp = PFN_DOWN((uintptr_t)V2P(next_task->memspace->pgdir_riscv.pd_addr)) | SATP_MODE;
|
||||
#endif
|
||||
|
||||
assert(next_task->memspace->pgdir.pd_addr != NULL);
|
||||
p_mmu_driver->LoadPgdir((uintptr_t)V2P(next_task->memspace->pgdir.pd_addr));
|
||||
|
||||
context_switch(&cpu->scheduler, next_task->thread_context.context);
|
||||
central_trans_task_state();
|
||||
cpu->task = NULL;
|
||||
|
||||
@@ -48,15 +48,28 @@ Modification:
|
||||
#include "syscall.h"
|
||||
#include "task.h"
|
||||
|
||||
#ifndef __riscv
|
||||
extern void context_switch(struct context**, struct context*);
|
||||
#else
|
||||
extern void context_switch(struct context*, struct context*);
|
||||
#endif
|
||||
__attribute__((optimize("O0"))) void dabort_handler(struct trapframe* r)
|
||||
{
|
||||
#ifndef __riscv
|
||||
if (r->pc >= DEV_VRTMEM_BASE && is_spinlock_hold_by_current_cpu(&whole_kernel_lock)) {
|
||||
assert(is_spinlock_hold_by_current_cpu(&whole_kernel_lock));
|
||||
ERROR("dabort in kernel, current task: %s\n", cur_cpu()->task == NULL ? "NULL" : cur_cpu()->task->name);
|
||||
dabort_reason(r);
|
||||
panic("data abort exception\n");
|
||||
}
|
||||
#else
|
||||
if (r->epc >= DEV_VRTMEM_BASE && is_spinlock_hold_by_current_cpu(&whole_kernel_lock)) {
|
||||
assert(is_spinlock_hold_by_current_cpu(&whole_kernel_lock));
|
||||
ERROR("dabort in kernel, current task: %s\n", cur_cpu()->task == NULL ? "NULL" : cur_cpu()->task->name);
|
||||
dabort_reason(r);
|
||||
panic("data abort exception\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
struct Thread* cur_task = cur_cpu()->task;
|
||||
ERROR("dabort in user space: %s\n", cur_task->name);
|
||||
@@ -64,18 +77,31 @@ __attribute__((optimize("O0"))) void dabort_handler(struct trapframe* r)
|
||||
|
||||
xizi_enter_kernel();
|
||||
sys_exit(cur_task);
|
||||
#ifndef __riscv
|
||||
context_switch(&cur_task->thread_context.context, cur_cpu()->scheduler);
|
||||
#else
|
||||
context_switch(cur_task->thread_context.context, &cur_cpu()->scheduler);
|
||||
#endif
|
||||
panic("dabort end should never be reashed.\n");
|
||||
}
|
||||
|
||||
__attribute__((optimize("O0"))) void iabort_handler(struct trapframe* r)
|
||||
{
|
||||
#ifndef __riscv
|
||||
if (r->pc >= DEV_VRTMEM_BASE && is_spinlock_hold_by_current_cpu(&whole_kernel_lock)) {
|
||||
assert(is_spinlock_hold_by_current_cpu(&whole_kernel_lock));
|
||||
ERROR("iabort in kernel, current task: %s\n", cur_cpu()->task == NULL ? "NULL" : cur_cpu()->task->name);
|
||||
iabort_reason(r);
|
||||
panic("kernel prefetch abort exception\n");
|
||||
}
|
||||
#else
|
||||
if (r->epc >= DEV_VRTMEM_BASE && is_spinlock_hold_by_current_cpu(&whole_kernel_lock)) {
|
||||
assert(is_spinlock_hold_by_current_cpu(&whole_kernel_lock));
|
||||
ERROR("iabort in kernel, current task: %s\n", cur_cpu()->task == NULL ? "NULL" : cur_cpu()->task->name);
|
||||
iabort_reason(r);
|
||||
panic("kernel prefetch abort exception\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
struct Thread* cur_task = cur_cpu()->task;
|
||||
ERROR("iabort in user space: %s\n", cur_task->name);
|
||||
@@ -83,6 +109,10 @@ __attribute__((optimize("O0"))) void iabort_handler(struct trapframe* r)
|
||||
|
||||
xizi_enter_kernel();
|
||||
sys_exit(cur_task);
|
||||
#ifndef __riscv
|
||||
context_switch(&cur_task->thread_context.context, cur_cpu()->scheduler);
|
||||
#else
|
||||
context_switch(cur_task->thread_context.context, &cur_cpu()->scheduler);
|
||||
#endif
|
||||
panic("iabort end should never be reashed.\n");
|
||||
}
|
||||
|
||||
@@ -53,7 +53,11 @@ void default_interrupt_routine(int irq)
|
||||
ERROR("Interrupt %d has been asserted\n", irq);
|
||||
}
|
||||
|
||||
#ifndef __riscv
|
||||
extern void context_switch(struct context**, struct context*);
|
||||
#else
|
||||
extern void context_switch(struct context*, struct context*);
|
||||
#endif
|
||||
void intr_irq_dispatch(struct trapframe* tf)
|
||||
{
|
||||
xizi_enter_kernel();
|
||||
@@ -86,7 +90,11 @@ void intr_irq_dispatch(struct trapframe* tf)
|
||||
|
||||
assert(cur_cpu()->task == current_task && current_task->snode.state == RUNNING);
|
||||
if (!queue_is_empty(¤t_task->snode.state_trans_signal_queue)) {
|
||||
#ifndef __riscv
|
||||
context_switch(¤t_task->thread_context.context, cur_cpu()->scheduler);
|
||||
#else
|
||||
context_switch(current_task->thread_context.context, &cur_cpu()->scheduler);
|
||||
#endif
|
||||
}
|
||||
assert(current_task == cur_cpu()->task);
|
||||
|
||||
|
||||
@@ -45,7 +45,11 @@ bool swi_distributer_init(struct SwiDispatcherRightGroup* _right_group)
|
||||
return p_intr_driver != NULL;
|
||||
}
|
||||
|
||||
#ifndef __riscv
|
||||
extern void context_switch(struct context**, struct context*);
|
||||
#else
|
||||
extern void context_switch(struct context*, struct context*);
|
||||
#endif
|
||||
void software_irq_dispatch(struct trapframe* tf)
|
||||
{
|
||||
xizi_enter_kernel();
|
||||
@@ -54,19 +58,22 @@ void software_irq_dispatch(struct trapframe* tf)
|
||||
// get current task
|
||||
struct Thread* cur_task = cur_cpu()->task;
|
||||
/// @todo: Handle dead task
|
||||
|
||||
int syscall_num = -1;
|
||||
if (cur_task && cur_task->snode.state != DEAD) {
|
||||
cur_task->thread_context.trapframe = tf;
|
||||
// call syscall
|
||||
|
||||
int ret = arch_syscall(cur_task->thread_context.trapframe, &syscall_num);
|
||||
arch_set_return(tf, ret);
|
||||
}
|
||||
|
||||
assert(cur_cpu()->task == cur_task && cur_task->snode.state == RUNNING);
|
||||
if (!queue_is_empty(&cur_task->snode.state_trans_signal_queue)) {
|
||||
#ifndef __riscv
|
||||
context_switch(&cur_task->thread_context.context, cur_cpu()->scheduler);
|
||||
#else
|
||||
struct CPU* cpu = cur_cpu();
|
||||
context_switch(cur_task->thread_context.context, &cpu->scheduler);
|
||||
#endif
|
||||
}
|
||||
if (syscall_num == SYSCALL_EXIT) {
|
||||
panic("Exit reaches");
|
||||
@@ -74,4 +81,4 @@ void software_irq_dispatch(struct trapframe* tf)
|
||||
|
||||
assert(cur_task == cur_cpu()->task);
|
||||
xizi_leave_kernel();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user