Map a single virtual address page to a physical address page in the page table. */
| 90 | |
| 91 | /* Map a single virtual address page to a physical address page in the page table. */ |
| 92 | static int _map_one_page(struct rt_aspace *aspace, void *va, void *pa, |
| 93 | size_t attr) |
| 94 | { |
| 95 | rt_ubase_t l1_off, l2_off, l3_off; |
| 96 | rt_ubase_t *mmu_l1, *mmu_l2, *mmu_l3; |
| 97 | |
| 98 | l1_off = GET_L1((size_t)va); |
| 99 | l2_off = GET_L2((size_t)va); |
| 100 | l3_off = GET_L3((size_t)va); |
| 101 | |
| 102 | mmu_l1 = ((rt_ubase_t *)aspace->page_table) + l1_off; |
| 103 | |
| 104 | if (PTE_USED(*mmu_l1)) |
| 105 | { |
| 106 | mmu_l2 = (rt_ubase_t *)PPN_TO_VPN(GET_PADDR(*mmu_l1), PV_OFFSET); |
| 107 | } |
| 108 | else |
| 109 | { |
| 110 | mmu_l2 = (rt_ubase_t *)rt_pages_alloc(0); |
| 111 | |
| 112 | if (mmu_l2) |
| 113 | { |
| 114 | rt_memset(mmu_l2, 0, PAGE_SIZE); |
| 115 | rt_hw_cpu_dcache_clean(mmu_l2, PAGE_SIZE); |
| 116 | *mmu_l1 = COMBINEPTE((rt_ubase_t)VPN_TO_PPN(mmu_l2, PV_OFFSET), |
| 117 | PAGE_DEFAULT_ATTR_NEXT); |
| 118 | rt_hw_cpu_dcache_clean(mmu_l1, sizeof(*mmu_l1)); |
| 119 | } |
| 120 | else |
| 121 | { |
| 122 | return -1; |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | if (PTE_USED(*(mmu_l2 + l2_off))) |
| 127 | { |
| 128 | RT_ASSERT(!PAGE_IS_LEAF(*(mmu_l2 + l2_off))); |
| 129 | mmu_l3 = |
| 130 | (rt_ubase_t *)PPN_TO_VPN(GET_PADDR(*(mmu_l2 + l2_off)), PV_OFFSET); |
| 131 | } |
| 132 | else |
| 133 | { |
| 134 | mmu_l3 = (rt_ubase_t *)rt_pages_alloc(0); |
| 135 | |
| 136 | if (mmu_l3) |
| 137 | { |
| 138 | rt_memset(mmu_l3, 0, PAGE_SIZE); |
| 139 | rt_hw_cpu_dcache_clean(mmu_l3, PAGE_SIZE); |
| 140 | *(mmu_l2 + l2_off) = |
| 141 | COMBINEPTE((rt_ubase_t)VPN_TO_PPN(mmu_l3, PV_OFFSET), |
| 142 | PAGE_DEFAULT_ATTR_NEXT); |
| 143 | rt_hw_cpu_dcache_clean(mmu_l2, sizeof(*mmu_l2)); |
| 144 | /* declares a reference to parent page table */ |
| 145 | rt_page_ref_inc((void *)mmu_l2, 0); |
| 146 | } |
| 147 | else |
| 148 | { |
| 149 | return -1; |
no test coverage detected