using identity_mapping_add & switching MMU state - how ?
Dave Martin
dave.martin at linaro.org
Thu Jun 2 12:22:07 EDT 2011
On Thu, Jun 02, 2011 at 04:44:02PM +0100, Frank Hofmann wrote:
> Hi,
>
>
> I'm trying to find a way to do an MMU off / on transition.
>
> What I want to do is to call cpu_do_resume() from the hibernation
> restore codepath.
>
> I've succeeded to make this work by adding a test whether the MMU is
> already on when cpu_resume_mmu() is called.
>
> I'm not sure that sort of thing is proper; hence I've been trying to
> find a way to disable the MMU before calling cpu_do_resume().
>
> Can't seem to get this to work though; even though I'm creating a
> separate MMU context that's given 1:1 mappings for all of kernel
> code/data, execution still hangs as soon as I enable the code
> section below that switches the MMU off.
I think Per Fransson has been working on this area for kexec.
Given the intrinsic scariness of code for turning MMUs off, I think
it would be best if there's a single common implementation which is
usable for hibernation and kexec, and any other code which needs
to do this (CPU hotplug?)
Maybe Per has some ideas on how to do that...
Cheers
---Dave
>
>
> What I have at the moment is code that looks like this:
>
> ==============================================================================
> [ ... ]
> unsigned long notrace __swsusp_arch_restore_image(void)
> {
> extern struct pbe *restore_pblist;
> struct pbe *pbe;
>
> /* __swsusp_pg_dir has been created using pgd_alloc(&init_mm); */
>
> cpu_switch_mm(__swsusp_pg_dir, &init_mm);
>
> for (pbe = restore_pblist; pbe; pbe = pbe->next)
> copy_page(pbe->orig_address, pbe->address);
>
> flush_tlb_all();
> flush_cache_all();
>
> identity_mapping_add(__swsusp_pg_dir, __pa(_stext), __pa(_etext));
> identity_mapping_add(__swsusp_pg_dir, __pa(_sdata), __pa(_edata));
>
> cpu_switch_mm(__swsusp_pg_dir, &init_mm);
>
> flush_tlb_all();
> flush_cache_all();
>
> cpu_proc_fin(); /* turns caches off */
>
> /* caller requires v:p offset to calculate physical addresses */
> return (unsigned long)(PHYS_OFFSET - PAGE_OFFSET);
> }
>
> [ ... ]
> ENTRY(swsusp_arch_resume)
> mov r2, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
> msr cpsr_c, r2
> /*
> * Switch stack to a nosavedata region to make sure image restore
> * doesn't clobber it underneath itself.
> */
> ldr sp, =(__swsusp_resume_stk + PAGE_SIZE / 2)
> bl __swsusp_arch_restore_image
>
> /*
> * Restore the CPU registers.
> */
> mov r1, r0
> ldr r0, =(__swsusp_arch_ctx + (NREGS * 4))
> /*
> * This is what I'm trying to switch off; yet, doing so makes things hang
> */
> #if 0
> ldr r2, =cpu_do_resume
> sub r2, r1 @ __pa()
> ldr r3, =.Lmmu_is_off
> sub r3, r1 @ __pa()
> sub r0, r1 @ __pa()
> ldr lr, =.Lpost_mmu
> mrc p15, 0, r1, c1, c0, 0
> bic r1, #CR_M
> mcr p15, 0, r1, c1, c0, 0 @ MMU OFF
>
> mrc p15, 0, r1, c2, c0, 0 @ queue a dependency on CP15
> sub pc, r3, r1, lsr #32 @ to local label, phys addr
> .ltorg
> .align 5
> .Lmmu_is_off:
> mov pc, r2 @ jump to phys cpu_v6_do_resume
> .Lpost_mmu:
> #else
> bl cpu_do_resume
> #endif
> ldr r0, =__swsusp_arch_ctx
> ldmia r0!, {r1-r11,lr} @ nonvolatile regs
> ldr sp, [r0] @ stack
> msr cpsr, r1
> msr spsr, r2
>
> mov r0, #0
> stmfd sp!, {r0, lr}
> bl cpu_init @ reinitialize other modes
> ldmfd sp!, {r0, pc}
> ENDPROC(swsusp_arch_resume)
> ==============================================================================
>
> I.e. it performs the steps:
>
> - flush all caches, tlbs
> - setup identity mappings for all kernel code & data
> - switch to a self-contained pagedir
> - flush again
> - finish cpu (disable caches)
> - switch MMU off, re-read config reg to force necessary wait,
> and jump to physical address of "self".
>
>
> As said, things work just fine if simply doing the "bl
> cpu_do_resume" and adding a "MMU already on" check to
> cpu_resume_mmu().
>
>
> I must be missing something there; I've been reading the ARM kexec
> postings,
>
> http://lists.infradead.org/pipermail/linux-arm-kernel/2010-July/020183.html
>
> for the basic idea, and used the style from smp.c (alloc a temporary
> pagedir, create identity mappings there). Still, there's something
> not quite right ...
>
>
> Any ideas what I'm missing ?
> Thanks,
>
> FrankH.
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
More information about the linux-arm-kernel
mailing list