-
Notifications
You must be signed in to change notification settings - Fork 641
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Memory mapping issues in ARM64 #351
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -502,6 +502,8 @@ int arm64_mmu_unmap(vaddr_t vaddr, size_t size, | |
} | ||
|
||
int arch_mmu_map(arch_aspace_t *aspace, vaddr_t vaddr, paddr_t paddr, uint count, uint flags) { | ||
const struct mmu_initial_mapping *map = mmu_initial_mappings; | ||
|
||
LTRACEF("vaddr 0x%lx paddr 0x%lx count %u flags 0x%x\n", vaddr, paddr, count, flags); | ||
|
||
DEBUG_ASSERT(aspace); | ||
|
@@ -521,6 +523,35 @@ int arch_mmu_map(arch_aspace_t *aspace, vaddr_t vaddr, paddr_t paddr, uint count | |
return NO_ERROR; | ||
|
||
int ret; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This routine is a bit problematic due to generally removing the ability to map things as uncached anywhere in practice, except as a hardware register. Is the problem that since the regular mapping still exists there can exist writeback cache lines that trash the uncached mapping (which seems possible) or that via the large mapping it can prefetch into it? In the latter case that generally seems harmless unless it's secure memory or whatnot, provided the memory is cleaned+invalidated (or just invalidated) prior to mapping it here. In that case the extra cached mapping can only at worse end up with a prefetch that ends up with a RO cache line. |
||
/* | ||
* arm64 doesn't recommend alias mapping with mismatched attributes. | ||
* Better check new mappings against mmu_initial_mapping and if | ||
* there is any mismatch found, better bail out than continue. | ||
*/ | ||
while (map->size > 0) { | ||
if (paddr >= map->phys && paddr < (map->phys + map->size)) { | ||
if ((flags & ARCH_MMU_FLAG_UNCACHED) && | ||
!(map->flags & MMU_INITIAL_MAPPING_FLAG_UNCACHED)) { | ||
printf("Mismatch attributes, uncached mapping failed\n"); | ||
return ERR_NOT_ALLOWED; | ||
} | ||
|
||
if ((flags & ARCH_MMU_FLAG_CACHED) && !(map->flags & MMU_INITIAL_MAPPING_FLAG_CACHED)) { | ||
printf("Mismatch attributes, cached mapping failed\n"); | ||
return ERR_NOT_ALLOWED; | ||
} | ||
|
||
if ((flags & ARCH_MMU_FLAG_UNCACHED_DEVICE) && | ||
!(map->flags & MMU_INITIAL_MAPPING_FLAG_DEVICE)) { | ||
printf("Mismatch attributes, device mapping failed\n"); | ||
return ERR_NOT_ALLOWED; | ||
} | ||
} | ||
|
||
map++; | ||
} | ||
|
||
if (aspace->flags & ARCH_ASPACE_FLAG_KERNEL) { | ||
ret = arm64_mmu_map(vaddr, paddr, count * PAGE_SIZE, | ||
mmu_flags_to_pte_attr(flags), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -370,10 +370,17 @@ status_t vmm_alloc_physical(vmm_aspace_t *aspace, const char *name, size_t size, | |
|
||
/* map all of the pages */ | ||
int err = arch_mmu_map(&aspace->arch_aspace, r->base, paddr, size / PAGE_SIZE, arch_mmu_flags); | ||
LTRACEF("arch_mmu_map returns %d\n", err); | ||
if (err) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These error catching routines here and below look good, can you split them into a separate commit so they can be taken independent of the meat of the change? |
||
printf("%s: arch_mmu_map returns %d\n", __func__, err); | ||
goto err_map; | ||
} | ||
|
||
ret = NO_ERROR; | ||
mutex_release(&vmm_lock); | ||
return NO_ERROR; | ||
|
||
err_map: | ||
list_delete(&r->node); | ||
free(r); | ||
err_alloc_region: | ||
mutex_release(&vmm_lock); | ||
return ret; | ||
|
@@ -435,8 +442,11 @@ status_t vmm_alloc_contiguous(vmm_aspace_t *aspace, const char *name, size_t siz | |
*ptr = (void *)r->base; | ||
|
||
/* map all of the pages */ | ||
arch_mmu_map(&aspace->arch_aspace, r->base, pa, size / PAGE_SIZE, arch_mmu_flags); | ||
// XXX deal with error mapping here | ||
err = arch_mmu_map(&aspace->arch_aspace, r->base, pa, size / PAGE_SIZE, arch_mmu_flags); | ||
if (err) { | ||
printf("%s: arch_mmu_map returns %d\n", __func__, err); | ||
goto err2; | ||
} | ||
|
||
vm_page_t *p; | ||
while ((p = list_remove_head_type(&page_list, vm_page_t, node))) { | ||
|
@@ -446,6 +456,9 @@ status_t vmm_alloc_contiguous(vmm_aspace_t *aspace, const char *name, size_t siz | |
mutex_release(&vmm_lock); | ||
return NO_ERROR; | ||
|
||
err2: | ||
list_delete(&r->node); | ||
free(r); | ||
err1: | ||
mutex_release(&vmm_lock); | ||
pmm_free(&page_list); | ||
|
@@ -521,8 +534,11 @@ status_t vmm_alloc(vmm_aspace_t *aspace, const char *name, size_t size, void **p | |
paddr_t pa = vm_page_to_paddr(p); | ||
DEBUG_ASSERT(IS_PAGE_ALIGNED(pa)); | ||
|
||
arch_mmu_map(&aspace->arch_aspace, va, pa, 1, arch_mmu_flags); | ||
// XXX deal with error mapping here | ||
err = arch_mmu_map(&aspace->arch_aspace, va, pa, 1, arch_mmu_flags); | ||
if (err) { | ||
printf("%s: arch_mmu_map returns %d\n", __func__, err); | ||
goto err2; | ||
} | ||
|
||
list_add_tail(&r->page_list, &p->node); | ||
|
||
|
@@ -532,6 +548,10 @@ status_t vmm_alloc(vmm_aspace_t *aspace, const char *name, size_t size, void **p | |
mutex_release(&vmm_lock); | ||
return NO_ERROR; | ||
|
||
err2: | ||
arch_mmu_unmap(&aspace->arch_aspace, r->base, count); | ||
list_delete(&r->node); | ||
free(r); | ||
err1: | ||
mutex_release(&vmm_lock); | ||
pmm_free(&page_list); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately this and the above code, in lkboot, rely on uncached mappings in order to properly work.