diff options
-rw-r--r-- | arch/sh/kernel/head_32.S | 169 |
1 files changed, 92 insertions, 77 deletions
diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S index ee954d1b8cc6..e93320135cda 100644 --- a/arch/sh/kernel/head_32.S +++ b/arch/sh/kernel/head_32.S @@ -86,7 +86,96 @@ ENTRY(_stext) #endif #if defined(CONFIG_PMB) && !defined(CONFIG_PMB_LEGACY) +/* + * Reconfigure the initial PMB mappings setup by the hardware. + * + * When we boot in 32-bit MMU mode there are 2 PMB entries already + * setup for us. + * + * Entry VPN PPN V SZ C UB WT + * --------------------------------------------------------------- + * 0 0x80000000 0x00000000 1 512MB 1 0 1 + * 1 0xA0000000 0x00000000 1 512MB 0 0 0 + * + * But we reprogram them here because we want complete control over + * our address space and the initial mappings may not map PAGE_OFFSET + * to __MEMORY_START (or even map all of our RAM). + * + * Once we've setup cached and uncached mappings we clear the rest of the + * PMB entries. This clearing also deals with the fact that PMB entries + * can persist across reboots. The PMB could have been left in any state + * when the reboot occurred, so to be safe we clear all entries and start + * with with a clean slate. + * + * The uncached mapping is constructed using the smallest possible + * mapping with a single unbufferable page. Only the kernel text needs to + * be covered via the uncached mapping so that certain functions can be + * run uncached. + * + * Drivers and the like that have previously abused the 1:1 identity + * mapping are unsupported in 32-bit mode and must specify their caching + * preference when page tables are constructed. + * + * This frees up the P2 space for more nefarious purposes. + * + * Register utilization is as follows: + * + * r0 = PMB_DATA data field + * r1 = PMB_DATA address field + * r2 = PMB_ADDR data field + * r3 = PMB_ADDR address field + * r4 = PMB_E_SHIFT + * r5 = remaining amount of RAM to map + * r6 = PMB mapping size we're trying to use + * r7 = cached_to_uncached + * r8 = scratch register + * r9 = scratch register + * r10 = number of PMB entries we've setup + */ + + mov.l .LMMUCR, r1 /* Flush the TLB */ + mov.l @r1, r0 + or #MMUCR_TI, r0 + mov.l r0, @r1 + + mov.l .LMEMORY_SIZE, r5 + mov r5, r7 + + mov #PMB_E_SHIFT, r0 + mov #0x1, r4 + shld r0, r4 + mov.l .LFIRST_DATA_ENTRY, r0 + mov.l .LPMB_DATA, r1 + mov.l .LFIRST_ADDR_ENTRY, r2 + mov.l .LPMB_ADDR, r3 + + mov #0, r10 + + /* + * Uncached mapping + */ + mov #(PMB_SZ_16M >> 2), r9 + shll2 r9 + + mov #(PMB_UB >> 8), r8 + shll8 r8 + + or r0, r8 + or r9, r8 + mov.l r8, @r1 + mov r2, r8 + add r7, r8 + mov.l r8, @r3 + + add r4, r1 + add r4, r3 + add #1, r10 + +/* + * Iterate over all of the available sizes from largest to + * smallest for constructing the cached mapping. + */ #define __PMB_ITER_BY_SIZE(size) \ .L##size: \ mov #(size >> 4), r6; \ @@ -115,26 +204,6 @@ ENTRY(_stext) /* Increment number of PMB entries */ \ add #1, r10; \ \ - /* \ - * Uncached mapping \ - */ \ - mov #(PMB_UB >> 8), r8; \ - shll8 r8; \ - \ - or r0, r8; \ - or r9, r8; \ - mov.l r8, @r1; \ - mov r2, r8; \ - add r7, r8; \ - mov.l r8, @r3; \ - \ - /* Increment to the next PMB_DATA entry */ \ - add r4, r1; \ - /* Increment to the next PMB_ADDR entry */ \ - add r4, r3; \ - /* Increment number of PMB entries */ \ - add #1, r10; \ - \ sub r6, r5; \ add r6, r0; \ add r6, r2; \ @@ -142,68 +211,14 @@ ENTRY(_stext) bra .L##size; \ 9999: - /* - * Reconfigure the initial PMB mappings setup by the hardware. - * - * When we boot in 32-bit MMU mode there are 2 PMB entries already - * setup for us. - * - * Entry VPN PPN V SZ C UB WT - * --------------------------------------------------------------- - * 0 0x80000000 0x00000000 1 512MB 1 0 1 - * 1 0xA0000000 0x00000000 1 512MB 0 0 0 - * - * But we reprogram them here because we want complete control over - * our address space and the initial mappings may not map PAGE_OFFSET - * to __MEMORY_START (or even map all of our RAM). - * - * Once we've setup cached and uncached mappings for all of RAM we - * clear the rest of the PMB entries. - * - * This clearing also deals with the fact that PMB entries can persist - * across reboots. The PMB could have been left in any state when the - * reboot occurred, so to be safe we clear all entries and start with - * with a clean slate. - */ - - mov.l .LMMUCR, r1 /* Flush the TLB */ - mov.l @r1, r0 - or #MMUCR_TI, r0 - mov.l r0, @r1 - - mov.l .LMEMORY_SIZE, r5 - mov r5, r7 - - mov #PMB_E_SHIFT, r0 - mov #0x1, r4 - shld r0, r4 - - mov.l .LFIRST_DATA_ENTRY, r0 - mov.l .LPMB_DATA, r1 - mov.l .LFIRST_ADDR_ENTRY, r2 - mov.l .LPMB_ADDR, r3 - - mov #0, r10 - - /* - * r0 = PMB_DATA data field - * r1 = PMB_DATA address field - * r2 = PMB_ADDR data field - * r3 = PMB_ADDR address field - * r4 = PMB_E_SHIFT - * r5 = remaining amount of RAM to map - * r6 = PMB mapping size we're trying to use - * r7 = cached_to_uncached - * r8 = scratch register - * r9 = scratch register - * r10 = number of PMB entries we've setup - */ __PMB_ITER_BY_SIZE(512) __PMB_ITER_BY_SIZE(128) __PMB_ITER_BY_SIZE(64) __PMB_ITER_BY_SIZE(16) - /* Update cached_to_uncached */ + /* + * Now that we can access it, update cached_to_uncached. + */ mov.l .Lcached_to_uncached, r0 mov.l r7, @r0 |