/* * Copyright (C) 2023-2025 Intel Corporation. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include void set_paging_supervisor(__unused uint64_t base, __unused uint64_t size) { } static struct page_pool ppt_page_pool; static void *ppt_mmu_top_addr; uint64_t init_satp; static uint64_t phys_mem_start; static uint64_t phys_mem_size; static struct mem_region rsvd_regions[MAX_FDT_RSVD_REGIONS]; static int nr_rsvd_regions; void init_phys_mem_range(void) { int i; #ifdef CONFIG_FDT_PARSE_ENABLED int ret; ret = fdt_get_phys_mem_region(get_host_fdt(), &phys_mem_start, &phys_mem_size); if (ret < 0) { panic("Failed to find memory information from FDT"); } fdt_get_rsvd_mem_regions(get_host_fdt(), rsvd_regions, &nr_rsvd_regions); #else /* TODO: Replace with macros generated from config tool */ phys_mem_start = PHYS_MEM_START; phys_mem_size = PHYS_MEM_SIZE; #endif pr_info("Physical Memory: [0x%lx-0x%lx]", phys_mem_start, phys_mem_start + phys_mem_size); for (i = 0; i < nr_rsvd_regions; i++) { pr_info("Reserved memory: [0x%lx-0x%lx]", rsvd_regions[i].addr, rsvd_regions[i].addr + rsvd_regions[i].size); } } /** * Riscv mmio memory layout is continuous and it support 1G huge * page by default, base on this, we assume it only consume one VPN3/2 page, * and preserve 4 VPN1 page to deal with memory map without 1G alignment. * for VPN0 page, we only preserve uart mmio related 2 pages. * * FIXME: The number need to be calculated according to the actual platform * memory layout, which is to be generated by config tool. */ #define PPT_VPN3_PAGE_NUM 1UL #define PPT_VPN2_PAGE_NUM 1UL #define PPT_VPN1_PAGE_NUM 4UL #define PPT_VPN0_PAGE_NUM 2UL #define PPT_PAGE_NUM_SUM (PPT_VPN3_PAGE_NUM + PPT_VPN2_PAGE_NUM + PPT_VPN1_PAGE_NUM + PPT_VPN0_PAGE_NUM) #define PPT_PAGE_NUM roundup(PPT_PAGE_NUM_SUM, 64U) DEFINE_PAGE_TABLES(ppt_pages, PPT_PAGE_NUM); DEFINE_PAGE_TABLE(ppt_pages_bitmap); static bool large_page_support(enum _page_table_level level, uint64_t __unused prot) { if (level == PGT_LVL1|| level == PGT_LVL2) return true; else return false; } static void ppt_flush_cache_pagewalk(const void* entry __attribute__((unused))) { } static uint64_t ppt_pgentry_present(uint64_t pte) { return pte & PAGE_V; } static inline void ppt_set_pgentry(uint64_t *pte, uint64_t page, uint64_t prot, enum _page_table_level __unused level, bool is_leaf, const struct pgtable *table) { uint64_t prot_tmp; if (!is_leaf) { prot_tmp = PAGE_V; } else { prot_tmp = prot; } make_pgentry(pte, page, prot_tmp, table); } static const struct pgtable ppt_pgtable = { .pool = &ppt_page_pool, .large_page_support = large_page_support, .pgentry_present = ppt_pgentry_present, .flush_cache_pagewalk = ppt_flush_cache_pagewalk, .set_pgentry = ppt_set_pgentry, }; /* TODO: need to formally get the value either from * config tool or from DTS runtime parsing. */ static uint64_t get_board_hv_device_start(void) { return 0UL; } /* TODO: need to formally get the value either from * config tool or from DTS runtime parsing. */ static uint64_t get_board_hv_device_size(void) { return 0x80000000UL; } static bool switch_satp(uint64_t satp_value) { /** * Here is to detect whether SV48 is supported * by the platform by writing the MODE in satp * register, which is a WARL field. According to * The RISC-V Instruction Set Manual volume II, * if satp is written with an unsupported MODE, * the entire write has no effect; no fields in * satp are modified. */ set_satp(satp_value); return (cpu_csr_read(CSR_SATP) == satp_value); } /** * TODO: need to detect existence of svpbmt extension to support PAGE_ATTR_IO * and PAGE_ATTR_PMA for mapping. */ static void init_hv_mapping(void) { uint64_t hva_base; int i; ppt_mmu_top_addr = (uint64_t *)alloc_page(&ppt_page_pool); /*TODO: The SUM bit in sstatus is 0, meaning SMAP is enabled * however, SMAP is provided by smepmp extension, we need to detect * its existence from DTS. */ pgtable_add_map((uint64_t *)ppt_mmu_top_addr, get_board_hv_device_start(), get_board_hv_device_start(), get_board_hv_device_size(), PAGE_V | PAGE_R | PAGE_W, &ppt_pgtable); /* Maps all physical memory */ pgtable_add_map((uint64_t *)ppt_mmu_top_addr, phys_mem_start, phys_mem_start, phys_mem_size, PAGE_V | PAGE_R | PAGE_W, &ppt_pgtable); /* Remove reserved region */ for (i = 0; i < nr_rsvd_regions; i++) { pgtable_modify_or_del_map((uint64_t *)ppt_mmu_top_addr, rsvd_regions[i].addr, rsvd_regions[i].size, 0UL, 0UL, &ppt_pgtable, MR_DEL); } /*TODO: Only map PAGE_X for text section*/ hva_base = get_hv_image_base(); pgtable_modify_or_del_map((uint64_t *)ppt_mmu_top_addr, hva_base, get_hv_image_size(), PAGE_X, 0UL, &ppt_pgtable, MR_MODIFY); init_satp = ((uint64_t)ppt_mmu_top_addr >> PAGE_SHIFT) | SATP_MODE_SV48; if (!switch_satp(init_satp)) { panic("Only support SV48 mode !"); } } void init_paging(void) { init_phys_mem_range(); init_page_pool(&ppt_page_pool, (uint64_t *)ppt_pages, (uint64_t *)ppt_pages_bitmap, PPT_PAGE_NUM); init_hv_mapping(); } void enable_paging(void) { set_satp(init_satp); } /* FIXME: Remove it when public API that maps host memory range is available */ void dummy_pgtable_add_map(uint64_t paddr_base, uint64_t vaddr_base, uint64_t size, uint64_t prot) { pgtable_add_map((uint64_t *)ppt_mmu_top_addr, paddr_base, vaddr_base, size, prot, &ppt_pgtable); }