bool km_page_create(struct km *mem_dst, unsigned long address, page_prot_t prot) { pte_t entry; unsigned long page = 0; struct km_walk_ctx dst_ctx; KM_WALK_INIT(mem_dst, &dst_ctx); if (unlikely(km_walk_to(&dst_ctx, address) == false)) goto err; /* Create 模式应该看不到任何内容,否则可以理解被别人刚刚处理成功 */ if (km_pte_read(&dst_ctx)) goto err; page = km_page_alloc(); if (!page) goto err; entry = page | km_arch_get_flags(prot); km_pte_write(&dst_ctx, entry); /* 不需要flush tlb,因为新的page在tlb中是不存在的 */ return true; err: if (page) km_page_dealloc(page); return false; }
static uintptr_t km_map_aligned(uintptr_t paddr, size_t size, unsigned int flags) { uintptr_t vaddr; size_t align; uintptr_t offs; ASSERT(ALIGN_DOWN(paddr, FRAME_SIZE) == paddr); ASSERT(ALIGN_UP(size, FRAME_SIZE) == size); /* Enforce natural or at least PAGE_SIZE alignment. */ align = ispwr2(size) ? size : (1U << (fnzb(size) + 1)); vaddr = km_page_alloc(size, max(PAGE_SIZE, align)); page_table_lock(AS_KERNEL, true); for (offs = 0; offs < size; offs += PAGE_SIZE) { page_mapping_insert(AS_KERNEL, vaddr + offs, paddr + offs, flags); } page_table_unlock(AS_KERNEL, true); return vaddr; }
bool km_page_create_cow(struct km *mem_dst, unsigned long address) { pte_t entry; unsigned long page = 0; struct km_walk_ctx dst_ctx; KM_WALK_INIT(mem_dst, &dst_ctx); if (unlikely(km_walk_to(&dst_ctx, address) == false)) goto err; /* 必须有内容,否则就不应该Cow */ if (!km_pte_read(&dst_ctx)) goto err; page = km_page_alloc(); if (!page) goto err; //TODO: Non identical map if (page >= CONFIG_HAL_KERNEL_MEM_LEN) goto err; memcpy((void*)HAL_GET_BASIC_KADDRESS(page), (void*)KM_PAGE_ROUND_ALIGN(address), PAGE_SIZE); entry = page | km_arch_get_flags(KM_PROT_READ | KM_PROT_WRITE); km_pte_write_force(&dst_ctx, entry); /* Must flush, because we are changing the entry */ km_arch_flush_page(mem_dst, address); return true; err: if (page) km_page_dealloc(page); return false; }