diff --git a/source/arm11/hardware/mmu.c b/source/arm11/hardware/mmu.c index 47e78e9..e7ff3e5 100644 --- a/source/arm11/hardware/mmu.c +++ b/source/arm11/hardware/mmu.c @@ -18,6 +18,7 @@ #include "types.h" #include "mem_map.h" +#include "fb_assert.h" #include "arm11/hardware/scu.h" #include "arm11/start.h" #include "arm.h" @@ -28,8 +29,8 @@ #define PERM_PRIV_RW_USR_NA (0b000001u) #define PERM_PRIV_RW_USR_RO (0b000010u) #define PERM_PRIV_RW_USR_RW (0b000011u) -#define PERM_PRIV_RO_USR_NA (0b100001u) -#define PERM_PRIV_RO_USR_RO (0b100010u) +#define PERM_PRIV_RO_USR_NA (0b100001u) // Doesn't work for supersections +#define PERM_PRIV_RO_USR_RO (0b100010u) // Doesn't work for supersections // Predefined mem attributes. Only bits 0, 1 and 10-12 matter #define ATTR_STRONGLY_ORDERED (0b0000000000000u) // Always shared @@ -40,21 +41,50 @@ #define ATTR_NORM_WRITE_BACK_ALLOC (0b0010000000011u) #define ATTR_NONSHARED_DEVICE (0b0100000000000u) // Always non-shared -// Policies for custom normal mem attributes +// Policies for custom normal memory attributes #define POLI_NONCACHABLE_UNBUFFERED (0b00u) #define POLI_WRITE_BACK_ALLOC_BUFFERED (0b01u) #define POLI_WRITE_THROUGH_NO_ALLOC_BUFFERED (0b10u) // Behaves as noncacheable on ARM11 MPCore #define POLI_WRITE_BACK_NO_ALLOC_BUFFERED (0b11u) +// Make custom normal memory attributes #define CUSTOM_ATTR(outer, inner) (1u<<12 | (outer)<<10 | (inner)) -// Converts the attribute bits from L1 format to L2 format +// Converts the attribute bits from L1 format to L2 format. +// Required for mmuMapPages(). #define L1_TO_L2(attr) (((attr)>>6 | (attr)) & 0x73) /** - * @brief Maps up to 4096 1 MB sections of memory. + * @brief Maps up to 256 16 MiB sections of memory. Domain is always 0. + * + * @param[in] va The virtual address base. Must be aligned to 16 MB. + * @param[in] pa The physical address base. Must be aligned to 16 MB. + * @param[in] num The number of sections to map. + * @param[in] access The access permission bits. + * @param[in] xn If this memory should be marked as execute never. + * @param[in] attr Other attribute bits like caching. + */ +static void mmuMapSupersections(u32 va, u32 pa, u32 num, u8 access, bool xn, u32 attr) +{ + fb_assert(!(va & ~0xFF000000)); + fb_assert(!(pa & ~0xFF000000)); + fb_assert(num < 256); + + for(u32 i = 0; i < 0x1000000 * num; i += 0x1000000) + { + const u32 l1Ss = (va + i)>>20; + for(u32 n = 0; n < 16; n++) + { + ((u32*)A11_MMU_TABLES_BASE)[l1Ss + n] = (pa + i) | 1u<<18 | access<<10 | + xn<<4 | attr<<2 | 0b10u; + } + } +} + +/** + * @brief Maps up to 4096 1 MiB sections of memory. * * @param[in] va The virtual address base. Must be aligned to 1 MB. * @param[in] pa The physical address base. Must be aligned to 1 MB. @@ -65,17 +95,21 @@ * @param[in] xn If this memory should be marked as execute never. * @param[in] attr Other attribute bits like caching. */ -static void mmuMapSections(u32 va, u32 pa, u32 num, bool shared, u32 access, u8 domain, bool xn, u32 attr) +static void mmuMapSections(u32 va, u32 pa, u32 num, bool shared, u8 access, u8 domain, bool xn, u32 attr) { - for(u32 i = 0; i < 0x100000u * num; i += 0x100000u) + fb_assert(!(va & ~0xFFF00000)); + fb_assert(!(pa & ~0xFFF00000)); + fb_assert(num < 4096); + + for(u32 i = 0; i < 0x100000 * num; i += 0x100000) { - ((u32*)A11_MMU_TABLES_BASE)[(va + i)>>20] = (((pa + i) & 0xFFF00000u) | (u32)shared<<16 | access<<10 | - (u32)domain<<5 | (u32)xn<<4 | attr<<2 | 0b10u); + ((u32*)A11_MMU_TABLES_BASE)[(va + i)>>20] = (pa + i) | shared<<16 | access<<10 | + domain<<5 | xn<<4 | attr<<2 | 0b10u; } } /** - * @brief Maps up to 256 4 KB pages of memory. + * @brief Maps up to 256 4 KiB pages of memory. * @brief The mapped range must not cross the next section. * * @param[in] va The virtual address base. Must be aligned to 4 KB. @@ -88,14 +122,18 @@ * @param[in] xn If this memory should be marked as execute never. * @param[in] attr Other attribute bits like caching. */ -static void mmuMapPages(u32 va, u32 pa, u32 num, u32 *l2Table, bool shared, u32 access, u8 domain, bool xn, u32 attr) +static void mmuMapPages(u32 va, u32 pa, u32 num, u32 *l2Table, bool shared, u8 access, u8 domain, bool xn, u32 attr) { - ((u32*)A11_MMU_TABLES_BASE)[va>>20] = (((u32)l2Table & 0xFFFFFC00u) | (u32)domain<<5 | 0b01u); + fb_assert(!(va & ~0xFFFFF000)); + fb_assert(!(pa & ~0xFFFFF000)); + fb_assert(num < 256); + fb_assert(!((u32)l2Table & ~0xFFFFFC00)); - for(u32 i = 0; i < 0x1000u * num; i += 0x1000u) + ((u32*)A11_MMU_TABLES_BASE)[va>>20] = (u32)l2Table | domain<<5 | 0b01u; + + for(u32 i = 0; i < 0x1000 * num; i += 0x1000) { - l2Table[(va + i)>>12 & 0xFFu] = (((pa + i) & 0xFFFFF000u) | (u32)shared<<10 | - access<<4 | attr<<2 | 0b10u | (u32)xn); + l2Table[(va + i)>>12 & 0xFF] = ((pa + i) & 0xFFFFF000) | shared<<10 | access<<4 | attr<<2 | 0b10u | xn; } } @@ -105,8 +143,8 @@ __setTtbr0(A11_MMU_TABLES_BASE | 0x12); // Use the 16 KB L1 table only __setTtbcr(0); - // Domain 1 = client, remaining domains all = no access - __setDacr(4); + // Domain 0 = client, remaining domains all = no access + __setDacr(1); // Context ID Register (ASID = 0, PROCID = 0) __setCidr(0); @@ -115,52 +153,56 @@ if(!__getCpuId()) { // Clear L1 and L2 tables - clearMem((u32*)A11_MMU_TABLES_BASE, 0x4C00u); + clearMem((u32*)A11_MMU_TABLES_BASE, 0x4C00); // IO mem mapping mmuMapSections(IO_MEM_ARM9_ARM11, IO_MEM_ARM9_ARM11, 4, true, - PERM_PRIV_RW_USR_NA, 1, true, ATTR_SHARED_DEVICE); + PERM_PRIV_RW_USR_NA, 0, true, ATTR_SHARED_DEVICE); // MPCore private region mapping mmuMapPages(MPCORE_PRIV_REG_BASE, MPCORE_PRIV_REG_BASE, 2, - (u32*)(A11_MMU_TABLES_BASE + 0x4000u), false, PERM_PRIV_RW_USR_NA, - 1, true, L1_TO_L2(ATTR_NONSHARED_DEVICE)); + (u32*)(A11_MMU_TABLES_BASE + 0x4000), false, PERM_PRIV_RW_USR_NA, + 0, true, L1_TO_L2(ATTR_NONSHARED_DEVICE)); // VRAM mapping - mmuMapSections(VRAM_BASE, VRAM_BASE, 6, true, PERM_PRIV_RW_USR_NA, 1, true, ATTR_NORM_WRITE_TROUGH_NO_ALLOC); + mmuMapSections(VRAM_BASE, VRAM_BASE, 6, true, PERM_PRIV_RW_USR_NA, 0, true, ATTR_NORM_WRITE_TROUGH_NO_ALLOC); // AXIWRAM core 0/1 stack mapping - mmuMapPages(A11_C0_STACK_START, A11_C0_STACK_START, 4, (u32*)(A11_MMU_TABLES_BASE + 0x4400u), - true, PERM_PRIV_RW_USR_NA, 1, true, + mmuMapPages(A11_C0_STACK_START, A11_C0_STACK_START, 4, (u32*)(A11_MMU_TABLES_BASE + 0x4400), + true, PERM_PRIV_RW_USR_NA, 0, true, L1_TO_L2(CUSTOM_ATTR(POLI_WRITE_BACK_ALLOC_BUFFERED, POLI_WRITE_BACK_ALLOC_BUFFERED))); // AXIWRAM MMU table mapping - mmuMapPages(A11_MMU_TABLES_BASE, A11_MMU_TABLES_BASE, 5, (u32*)(A11_MMU_TABLES_BASE + 0x4400u), true, - PERM_PRIV_RO_USR_NA, 1, true, L1_TO_L2(ATTR_NORM_NONCACHABLE)); + mmuMapPages(A11_MMU_TABLES_BASE, A11_MMU_TABLES_BASE, 5, (u32*)(A11_MMU_TABLES_BASE + 0x4400), true, + PERM_PRIV_RO_USR_NA, 0, true, L1_TO_L2(ATTR_NORM_NONCACHABLE)); extern const u32 __start__[]; extern const u32 __text_pages__[]; extern const u32 __rodata_start__[]; extern const u32 __rodata_pages__[]; extern const u32 __data_start__[]; - const u32 dataPages = (FCRAM_BASE - (u32)__data_start__) / 0x1000; + const u32 dataPages = (AXIWRAM_BASE + AXIWRAM_SIZE - (u32)__data_start__) / 0x1000; // text - mmuMapPages((u32)__start__, (u32)__start__, (u32)__text_pages__, (u32*)(A11_MMU_TABLES_BASE + 0x4400u), - true, PERM_PRIV_RO_USR_NA, 1, false, + mmuMapPages((u32)__start__, (u32)__start__, (u32)__text_pages__, + (u32*)(A11_MMU_TABLES_BASE + 0x4400), true, PERM_PRIV_RO_USR_NA, 0, false, L1_TO_L2(CUSTOM_ATTR(POLI_WRITE_BACK_ALLOC_BUFFERED, POLI_WRITE_BACK_ALLOC_BUFFERED))); // rodata - mmuMapPages((u32)__rodata_start__, (u32)__rodata_start__, (u32)__rodata_pages__, (u32*)(A11_MMU_TABLES_BASE + 0x4400u), - true, PERM_PRIV_RO_USR_NA, 1, true, + mmuMapPages((u32)__rodata_start__, (u32)__rodata_start__, (u32)__rodata_pages__, + (u32*)(A11_MMU_TABLES_BASE + 0x4400), true, PERM_PRIV_RO_USR_NA, 0, true, L1_TO_L2(CUSTOM_ATTR(POLI_WRITE_BACK_ALLOC_BUFFERED, POLI_WRITE_BACK_ALLOC_BUFFERED))); // data, bss and heap - mmuMapPages((u32)__data_start__, (u32)__data_start__, dataPages, (u32*)(A11_MMU_TABLES_BASE + 0x4400u), - true, PERM_PRIV_RW_USR_NA, 1, true, + mmuMapPages((u32)__data_start__, (u32)__data_start__, dataPages, + (u32*)(A11_MMU_TABLES_BASE + 0x4400u), true, PERM_PRIV_RW_USR_NA, 0, true, L1_TO_L2(CUSTOM_ATTR(POLI_WRITE_BACK_ALLOC_BUFFERED, POLI_WRITE_BACK_ALLOC_BUFFERED))); + // FCRAM with New 3DS extension + //mmuMapSupersections(FCRAM_BASE, FCRAM_BASE, 16, PERM_PRIV_RW_USR_NA, true, + // CUSTOM_ATTR(POLI_WRITE_BACK_ALLOC_BUFFERED, POLI_WRITE_BACK_ALLOC_BUFFERED)); + // Map fastboot executable start to boot11 mirror (exception vectors) mmuMapPages(BOOT11_MIRROR2, (u32)__start__, 1, (u32*)(A11_MMU_TABLES_BASE + 0x4800u), true, - PERM_PRIV_RO_USR_NA, 1, false, + PERM_PRIV_RO_USR_NA, 0, false, L1_TO_L2(CUSTOM_ATTR(POLI_WRITE_BACK_ALLOC_BUFFERED, POLI_WRITE_BACK_ALLOC_BUFFERED))); // Invalidate tag RAMs before enabling SMP as recommended by the MPCore doc.