kernel/arm: add memory barriers for page table ops
Introduce memory barriers according to ARMARM, section G.5.3 TLB maintenance operations and barriers Sequence for mapping memory in (both L1 and L2): * DSB * Invalidate i-cache (TODO) * Insert new entry in page directory / page table * DSB * ISB Sequence for mapping memory out: * Remove page table entry * DSB * Invalidate TLB entry * DSB * ISB Sequence for updating a page table entry: * Update page table entry * DSB * Invalidate TLB entry * Invalidate branch predictor (TODO) * DSB * ISB Note: i-cache invalidation and branch predictor invalidation is not implemented yet as this commit focuses on implementing memory barriers. Change-Id: I192fa80f6b43117236a4be6fa8c988afca90e015 Reviewed-on: https://review.haiku-os.org/c/haiku/+/5241 Tested-by: Commit checker robot <[email protected]> Reviewed-by: Fredrik Holmqvist <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
cf5f513b3b
commit
83f755b5d8
@@ -11,23 +11,9 @@
|
|||||||
// TODO: Could be 32-bits sometimes?
|
// TODO: Could be 32-bits sometimes?
|
||||||
|
|
||||||
|
|
||||||
#if __ARM_ARCH__ <= 5
|
|
||||||
#define isb() __asm__ __volatile__("" : : : "memory")
|
|
||||||
#define dsb() __asm__ __volatile__("mcr p15, 0, %0, c7, c10, 4" \
|
|
||||||
: : "r" (0) : "memory")
|
|
||||||
#define dmb() __asm__ __volatile__("" : : : "memory")
|
|
||||||
#elif __ARM_ARCH__ == 6
|
|
||||||
#define isb() __asm__ __volatile__("mcr p15, 0, %0, c7, c5, 4" \
|
|
||||||
: : "r" (0) : "memory")
|
|
||||||
#define dsb() __asm__ __volatile__("mcr p15, 0, %0, c7, c10, 4" \
|
|
||||||
: : "r" (0) : "memory")
|
|
||||||
#define dmb() __asm__ __volatile__("mcr p15, 0, %0, c7, c10, 5" \
|
|
||||||
: : "r" (0) : "memory")
|
|
||||||
#else /* ARMv7+ */
|
|
||||||
#define isb() __asm__ __volatile__("isb" : : : "memory")
|
#define isb() __asm__ __volatile__("isb" : : : "memory")
|
||||||
#define dsb() __asm__ __volatile__("dsb" : : : "memory")
|
#define dsb() __asm__ __volatile__("dsb" : : : "memory")
|
||||||
#define dmb() __asm__ __volatile__("dmb" : : : "memory")
|
#define dmb() __asm__ __volatile__("dmb" : : : "memory")
|
||||||
#endif
|
|
||||||
|
|
||||||
#define set_ac()
|
#define set_ac()
|
||||||
#define clear_ac()
|
#define clear_ac()
|
||||||
@@ -98,6 +84,7 @@ extern addr_t arm_get_fp(void);
|
|||||||
extern int mmu_read_c1(void);
|
extern int mmu_read_c1(void);
|
||||||
extern int mmu_write_c1(int val);
|
extern int mmu_write_c1(int val);
|
||||||
|
|
||||||
|
void arch_cpu_invalidate_TLB_page(addr_t page);
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
arch_cpu_pause(void)
|
arch_cpu_pause(void)
|
||||||
|
|||||||
@@ -117,34 +117,70 @@ arch_cpu_memory_write_barrier(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
arch_cpu_invalidate_TLB_page(addr_t page)
|
||||||
|
{
|
||||||
|
// ensure visibility of the update to translation table walks
|
||||||
|
dsb();
|
||||||
|
|
||||||
|
// TLBIMVAIS(page)
|
||||||
|
asm volatile ("mcr p15, 0, %0, c8, c3, 1"
|
||||||
|
: : "r" (page));
|
||||||
|
|
||||||
|
// ensure completion of TLB invalidation
|
||||||
|
dsb();
|
||||||
|
isb();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
arch_cpu_invalidate_TLB_range(addr_t start, addr_t end)
|
arch_cpu_invalidate_TLB_range(addr_t start, addr_t end)
|
||||||
{
|
{
|
||||||
|
// ensure visibility of the update to translation table walks
|
||||||
|
dsb();
|
||||||
|
|
||||||
int32 num_pages = end / B_PAGE_SIZE - start / B_PAGE_SIZE;
|
int32 num_pages = end / B_PAGE_SIZE - start / B_PAGE_SIZE;
|
||||||
while (num_pages-- >= 0) {
|
while (num_pages-- >= 0) {
|
||||||
asm volatile ("mcr p15, 0, %[c8format], c8, c6, 1"
|
asm volatile ("mcr p15, 0, %[c8format], c8, c6, 1"
|
||||||
: : [c8format] "r" (start) );
|
: : [c8format] "r" (start) );
|
||||||
start += B_PAGE_SIZE;
|
start += B_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure completion of TLB invalidation
|
||||||
|
dsb();
|
||||||
|
isb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages)
|
arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages)
|
||||||
{
|
{
|
||||||
|
// ensure visibility of the update to translation table walks
|
||||||
|
dsb();
|
||||||
|
|
||||||
for (int i = 0; i < num_pages; i++) {
|
for (int i = 0; i < num_pages; i++) {
|
||||||
asm volatile ("mcr p15, 0, %[c8format], c8, c6, 1":
|
asm volatile ("mcr p15, 0, %[c8format], c8, c6, 1":
|
||||||
: [c8format] "r" (pages[i]) );
|
: [c8format] "r" (pages[i]) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure completion of TLB invalidation
|
||||||
|
dsb();
|
||||||
|
isb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
arch_cpu_global_TLB_invalidate(void)
|
arch_cpu_global_TLB_invalidate(void)
|
||||||
{
|
{
|
||||||
|
// ensure visibility of the update to translation table walks
|
||||||
|
dsb();
|
||||||
|
|
||||||
uint32 Rd = 0;
|
uint32 Rd = 0;
|
||||||
asm volatile ("mcr p15, 0, %[c8format], c8, c7, 0"
|
asm volatile ("mcr p15, 0, %[c8format], c8, c7, 0"
|
||||||
: : [c8format] "r" (Rd) );
|
: : [c8format] "r" (Rd) );
|
||||||
|
|
||||||
|
// ensure completion of TLB invalidation
|
||||||
|
dsb();
|
||||||
|
isb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -185,8 +185,7 @@ ARMPagingMethod32Bit::PhysicalPageSlotPool::Map(phys_addr_t physicalAddress,
|
|||||||
| ARM_MMU_L2_FLAG_B | ARM_MMU_L2_FLAG_C
|
| ARM_MMU_L2_FLAG_B | ARM_MMU_L2_FLAG_C
|
||||||
| ARM_MMU_L2_FLAG_AP_KRW | ARM_MMU_L2_FLAG_XN;
|
| ARM_MMU_L2_FLAG_AP_KRW | ARM_MMU_L2_FLAG_XN;
|
||||||
|
|
||||||
arch_cpu_invalidate_TLB_range(virtualAddress, virtualAddress + B_PAGE_SIZE);
|
arch_cpu_invalidate_TLB_page(virtualAddress);
|
||||||
// invalidate_TLB(virtualAddress);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -396,12 +395,12 @@ ARMPagingMethod32Bit::MapEarly(kernel_args* args, addr_t virtualAddress,
|
|||||||
"pgtable. phys=%#" B_PRIxPHYSADDR ", virt=%#" B_PRIxADDR "\n",
|
"pgtable. phys=%#" B_PRIxPHYSADDR ", virt=%#" B_PRIxADDR "\n",
|
||||||
pgtable_phys, pgtable_virt);
|
pgtable_phys, pgtable_virt);
|
||||||
|
|
||||||
|
// zero it out in it's new mapping
|
||||||
|
memset((void*)pgtable_virt, 0, B_PAGE_SIZE);
|
||||||
|
|
||||||
// put it in the pgdir
|
// put it in the pgdir
|
||||||
e = &fKernelVirtualPageDirectory[index];
|
e = &fKernelVirtualPageDirectory[index];
|
||||||
PutPageTableInPageDir(e, pgtable_phys, attributes);
|
PutPageTableInPageDir(e, pgtable_phys, attributes);
|
||||||
|
|
||||||
// zero it out in it's new mapping
|
|
||||||
memset((void*)pgtable_virt, 0, B_PAGE_SIZE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
phys_addr_t ptEntryPhys = fKernelVirtualPageDirectory[index] & ARM_PDE_ADDRESS_MASK;
|
phys_addr_t ptEntryPhys = fKernelVirtualPageDirectory[index] & ARM_PDE_ADDRESS_MASK;
|
||||||
@@ -493,14 +492,12 @@ ARMPagingMethod32Bit::IsKernelPageAccessible(addr_t virtualAddress,
|
|||||||
ARMPagingMethod32Bit::PutPageTableInPageDir(page_directory_entry* entry,
|
ARMPagingMethod32Bit::PutPageTableInPageDir(page_directory_entry* entry,
|
||||||
phys_addr_t pgtablePhysical, uint32 attributes)
|
phys_addr_t pgtablePhysical, uint32 attributes)
|
||||||
{
|
{
|
||||||
|
dsb();
|
||||||
|
|
||||||
*entry = (pgtablePhysical & ARM_PDE_ADDRESS_MASK) | ARM_MMU_L1_TYPE_COARSE;
|
*entry = (pgtablePhysical & ARM_PDE_ADDRESS_MASK) | ARM_MMU_L1_TYPE_COARSE;
|
||||||
// TODO: we ignore the attributes of the page table - for compatibility
|
|
||||||
// with BeOS we allow having user accessible areas in the kernel address
|
dsb();
|
||||||
// space. This is currently being used by some drivers, mainly for the
|
isb();
|
||||||
// frame buffer. Our current real time data implementation makes use of
|
|
||||||
// this fact, too.
|
|
||||||
// We might want to get rid of this possibility one day, especially if
|
|
||||||
// we intend to port it to a platform that does not support this.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -517,6 +514,9 @@ ARMPagingMethod32Bit::PutPageTableEntryInTable(page_table_entry* entry,
|
|||||||
|
|
||||||
// put it in the page table
|
// put it in the page table
|
||||||
*(volatile page_table_entry*)entry = page;
|
*(volatile page_table_entry*)entry = page;
|
||||||
|
|
||||||
|
dsb();
|
||||||
|
isb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user