[PATCH 1/3] arm64: mm: Support Common Not Private translations

Vladimir Murzin vladimir.murzin at arm.com
Tue Oct 10 05:50:26 PDT 2017


Hi James,

On 09/10/17 17:48, James Morse wrote:
> Hi Catalin, Vladimir,
> 
> On 09/10/17 16:23, Catalin Marinas wrote:
>> On Mon, Oct 09, 2017 at 01:55:32PM +0100, Vladimir Murzin wrote:
>>> This patch adds support for Common Not Private translations on
>>> different exceptions levels:
> 
>>> (2) For EL1 we postpone setting CNP till all cpus are up and rely on
>>>     cpufeature framework to 1) patch the code which is sensitive to
>>>     CNP and 2) update TTBR1_EL1 with CNP bit set. The only case where
>>>     TTBR1_EL1 can be reprogrammed is hibirnation, so the code there is
>>>     changed to save raw TTBR1_EL1 and blindly restore it on resume.
> 
>> Even if you do this when all the CPUs are up, that's not always true.
>> Starting with maxcpus=1 allows something like systemd to bring up new
>> CPUs once user space starts.
> 
> For secondary CPUs cpu_enable_cnp() will be called to set CNP on TTBR1_EL1. But
> what about cpuidle? This also resets the TTBR1_EL1 value.

Good point! I've missed it because reset happens via __enable_mmu, which has 
no idea about CnP.

Would something like below be sufficient?


diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c
index 1e3be90..03a02c4 100644
--- a/arch/arm64/kernel/suspend.c
+++ b/arch/arm64/kernel/suspend.c
@@ -46,6 +46,10 @@ void notrace __cpu_suspend_exit(void)
 	 */
 	cpu_uninstall_idmap();
 
+#ifdef CONFIG_ARM64_CNP
+	/* Restore CnP bit in TTBR1_EL1 */
+	cpu_replace_ttbr1(swapper_pg_dir);
+#endif
 	/*
 	 * PSTATE was not saved over suspend/resume, re-enable any detected
 	 * features that might not have been set correctly.

> 
> 
>> The problem we have is that we don't know
>> what the firmware is doing, whether it's setting CnP or not. Maybe we
>> should add some statement in Documentation/arm64/booting.txt that
>> firmware must not use CnP at all.
> 
> 
>>> diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
>>> index 095d3c1..1d056f3 100644
>>> --- a/arch/arm64/kernel/hibernate.c
>>> +++ b/arch/arm64/kernel/hibernate.c
>>> @@ -124,7 +124,7 @@ int arch_hibernation_header_save(void *addr, unsigned int max_size)
>>>  		return -EOVERFLOW;
>>>  
>>>  	arch_hdr_invariants(&hdr->invariants);
>>> -	hdr->ttbr1_el1		= __pa_symbol(swapper_pg_dir);
>>> +	hdr->ttbr1_el1		= read_sysreg(ttbr1_el1);
>>>  	hdr->reenter_kernel	= _cpu_resume;
>>>  
>>>  	/* We can't use __hyp_get_vectors() because kvm may still be loaded */
> 
>> Are all the CPUs up when coming out of hibernation and restoring
>> ttbr1_el1?
> 
> 'nonboot' CPUs are powered off around hibernate, so this only runs on one CPU.
> 
> Restoring with the CNP set like this will share all the TTBR1 mappings using the
> reserved ASID out of TTBR0. Hibernate then calls cpu_uninstall_idmap() via
> __cpu_suspend_exit(), which will restore the original ttbr0 value and CNP bit.
> 

Thanks for explanation!

Vladimir

> 
> Thanks,
> 
> James
> 




More information about the linux-arm-kernel mailing list