~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm64/kvm/hyp/nvhe/psci-relay.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /arch/arm64/kvm/hyp/nvhe/psci-relay.c (Version linux-6.11.5) and /arch/i386/kvm/hyp/nvhe/psci-relay.c (Version linux-4.19.319)


** Warning: Cannot open xref database.

  1 // SPDX-License-Identifier: GPL-2.0-only            1 
  2 /*                                                
  3  * Copyright (C) 2020 - Google LLC                
  4  * Author: David Brazdil <dbrazdil@google.com>    
  5  */                                               
  6                                                   
  7 #include <asm/kvm_asm.h>                          
  8 #include <asm/kvm_hyp.h>                          
  9 #include <asm/kvm_mmu.h>                          
 10 #include <linux/arm-smccc.h>                      
 11 #include <linux/kvm_host.h>                       
 12 #include <uapi/linux/psci.h>                      
 13                                                   
 14 #include <nvhe/memory.h>                          
 15 #include <nvhe/trap_handler.h>                    
 16                                                   
 17 void kvm_hyp_cpu_entry(unsigned long r0);         
 18 void kvm_hyp_cpu_resume(unsigned long r0);        
 19                                                   
 20 void __noreturn __host_enter(struct kvm_cpu_co    
 21                                                   
 22 /* Config options set by the host. */             
 23 struct kvm_host_psci_config __ro_after_init kv    
 24                                                   
 25 #define INVALID_CPU_ID  UINT_MAX                  
 26                                                   
 27 struct psci_boot_args {                           
 28         atomic_t lock;                            
 29         unsigned long pc;                         
 30         unsigned long r0;                         
 31 };                                                
 32                                                   
 33 #define PSCI_BOOT_ARGS_UNLOCKED         0         
 34 #define PSCI_BOOT_ARGS_LOCKED           1         
 35                                                   
 36 #define PSCI_BOOT_ARGS_INIT                       
 37         ((struct psci_boot_args){                 
 38                 .lock = ATOMIC_INIT(PSCI_BOOT_    
 39         })                                        
 40                                                   
 41 static DEFINE_PER_CPU(struct psci_boot_args, c    
 42 static DEFINE_PER_CPU(struct psci_boot_args, s    
 43                                                   
 44 #define is_psci_0_1(what, func_id)                
 45         (kvm_host_psci_config.psci_0_1_ ## wha    
 46          (func_id) == kvm_host_psci_config.fun    
 47                                                   
 48 static bool is_psci_0_1_call(u64 func_id)         
 49 {                                                 
 50         return (is_psci_0_1(cpu_suspend, func_    
 51                 is_psci_0_1(cpu_on, func_id) |    
 52                 is_psci_0_1(cpu_off, func_id)     
 53                 is_psci_0_1(migrate, func_id))    
 54 }                                                 
 55                                                   
 56 static bool is_psci_0_2_call(u64 func_id)         
 57 {                                                 
 58         /* SMCCC reserves IDs 0x00-1F with the    
 59         return (PSCI_0_2_FN(0) <= func_id && f    
 60                (PSCI_0_2_FN64(0) <= func_id &&    
 61 }                                                 
 62                                                   
 63 static unsigned long psci_call(unsigned long f    
 64                                unsigned long a    
 65 {                                                 
 66         struct arm_smccc_res res;                 
 67                                                   
 68         arm_smccc_1_1_smc(fn, arg0, arg1, arg2    
 69         return res.a0;                            
 70 }                                                 
 71                                                   
 72 static unsigned long psci_forward(struct kvm_c    
 73 {                                                 
 74         return psci_call(cpu_reg(host_ctxt, 0)    
 75                          cpu_reg(host_ctxt, 2)    
 76 }                                                 
 77                                                   
 78 static unsigned int find_cpu_id(u64 mpidr)        
 79 {                                                 
 80         unsigned int i;                           
 81                                                   
 82         /* Reject invalid MPIDRs */               
 83         if (mpidr & ~MPIDR_HWID_BITMASK)          
 84                 return INVALID_CPU_ID;            
 85                                                   
 86         for (i = 0; i < NR_CPUS; i++) {           
 87                 if (cpu_logical_map(i) == mpid    
 88                         return i;                 
 89         }                                         
 90                                                   
 91         return INVALID_CPU_ID;                    
 92 }                                                 
 93                                                   
 94 static __always_inline bool try_acquire_boot_a    
 95 {                                                 
 96         return atomic_cmpxchg_acquire(&args->l    
 97                                       PSCI_BOO    
 98                                       PSCI_BOO    
 99                 PSCI_BOOT_ARGS_UNLOCKED;          
100 }                                                 
101                                                   
102 static __always_inline void release_boot_args(    
103 {                                                 
104         atomic_set_release(&args->lock, PSCI_B    
105 }                                                 
106                                                   
107 static int psci_cpu_on(u64 func_id, struct kvm    
108 {                                                 
109         DECLARE_REG(u64, mpidr, host_ctxt, 1);    
110         DECLARE_REG(unsigned long, pc, host_ct    
111         DECLARE_REG(unsigned long, r0, host_ct    
112                                                   
113         unsigned int cpu_id;                      
114         struct psci_boot_args *boot_args;         
115         struct kvm_nvhe_init_params *init_para    
116         int ret;                                  
117                                                   
118         /*                                        
119          * Find the logical CPU ID for the giv    
120          * the set of CPUs that were online at    
121          * Booting other CPUs is rejected beca    
122          * checked against the finalized capab    
123          * by doing the feature checks in hyp.    
124          */                                       
125         cpu_id = find_cpu_id(mpidr);              
126         if (cpu_id == INVALID_CPU_ID)             
127                 return PSCI_RET_INVALID_PARAMS    
128                                                   
129         boot_args = per_cpu_ptr(&cpu_on_args,     
130         init_params = per_cpu_ptr(&kvm_init_pa    
131                                                   
132         /* Check if the target CPU is already     
133         if (!try_acquire_boot_args(boot_args))    
134                 return PSCI_RET_ALREADY_ON;       
135                                                   
136         boot_args->pc = pc;                       
137         boot_args->r0 = r0;                       
138         wmb();                                    
139                                                   
140         ret = psci_call(func_id, mpidr,           
141                         __hyp_pa(&kvm_hyp_cpu_    
142                         __hyp_pa(init_params))    
143                                                   
144         /* If successful, the lock will be rel    
145         if (ret != PSCI_RET_SUCCESS)              
146                 release_boot_args(boot_args);     
147                                                   
148         return ret;                               
149 }                                                 
150                                                   
151 static int psci_cpu_suspend(u64 func_id, struc    
152 {                                                 
153         DECLARE_REG(u64, power_state, host_ctx    
154         DECLARE_REG(unsigned long, pc, host_ct    
155         DECLARE_REG(unsigned long, r0, host_ct    
156                                                   
157         struct psci_boot_args *boot_args;         
158         struct kvm_nvhe_init_params *init_para    
159                                                   
160         boot_args = this_cpu_ptr(&suspend_args    
161         init_params = this_cpu_ptr(&kvm_init_p    
162                                                   
163         /*                                        
164          * No need to acquire a lock before wr    
165          * can only suspend itself. Racy CPU_O    
166          */                                       
167         boot_args->pc = pc;                       
168         boot_args->r0 = r0;                       
169                                                   
170         /*                                        
171          * Will either return if shallow sleep    
172          * point if it is a deep sleep state.     
173          */                                       
174         return psci_call(func_id, power_state,    
175                          __hyp_pa(&kvm_hyp_cpu    
176                          __hyp_pa(init_params)    
177 }                                                 
178                                                   
179 static int psci_system_suspend(u64 func_id, st    
180 {                                                 
181         DECLARE_REG(unsigned long, pc, host_ct    
182         DECLARE_REG(unsigned long, r0, host_ct    
183                                                   
184         struct psci_boot_args *boot_args;         
185         struct kvm_nvhe_init_params *init_para    
186                                                   
187         boot_args = this_cpu_ptr(&suspend_args    
188         init_params = this_cpu_ptr(&kvm_init_p    
189                                                   
190         /*                                        
191          * No need to acquire a lock before wr    
192          * can only suspend itself. Racy CPU_O    
193          */                                       
194         boot_args->pc = pc;                       
195         boot_args->r0 = r0;                       
196                                                   
197         /* Will only return on error. */          
198         return psci_call(func_id,                 
199                          __hyp_pa(&kvm_hyp_cpu    
200                          __hyp_pa(init_params)    
201 }                                                 
202                                                   
203 asmlinkage void __noreturn __kvm_host_psci_cpu    
204 {                                                 
205         struct psci_boot_args *boot_args;         
206         struct kvm_cpu_context *host_ctxt;        
207                                                   
208         host_ctxt = host_data_ptr(host_ctxt);     
209                                                   
210         if (is_cpu_on)                            
211                 boot_args = this_cpu_ptr(&cpu_    
212         else                                      
213                 boot_args = this_cpu_ptr(&susp    
214                                                   
215         cpu_reg(host_ctxt, 0) = boot_args->r0;    
216         write_sysreg_el2(boot_args->pc, SYS_EL    
217                                                   
218         if (is_cpu_on)                            
219                 release_boot_args(boot_args);     
220                                                   
221         __host_enter(host_ctxt);                  
222 }                                                 
223                                                   
224 static unsigned long psci_0_1_handler(u64 func    
225 {                                                 
226         if (is_psci_0_1(cpu_off, func_id) || i    
227                 return psci_forward(host_ctxt)    
228         if (is_psci_0_1(cpu_on, func_id))         
229                 return psci_cpu_on(func_id, ho    
230         if (is_psci_0_1(cpu_suspend, func_id))    
231                 return psci_cpu_suspend(func_i    
232                                                   
233         return PSCI_RET_NOT_SUPPORTED;            
234 }                                                 
235                                                   
236 static unsigned long psci_0_2_handler(u64 func    
237 {                                                 
238         switch (func_id) {                        
239         case PSCI_0_2_FN_PSCI_VERSION:            
240         case PSCI_0_2_FN_CPU_OFF:                 
241         case PSCI_0_2_FN64_AFFINITY_INFO:         
242         case PSCI_0_2_FN64_MIGRATE:               
243         case PSCI_0_2_FN_MIGRATE_INFO_TYPE:       
244         case PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU    
245                 return psci_forward(host_ctxt)    
246         /*                                        
247          * SYSTEM_OFF/RESET should not return     
248          * Allow it so as to stay robust to br    
249          */                                       
250         case PSCI_0_2_FN_SYSTEM_OFF:              
251         case PSCI_0_2_FN_SYSTEM_RESET:            
252                 return psci_forward(host_ctxt)    
253         case PSCI_0_2_FN64_CPU_SUSPEND:           
254                 return psci_cpu_suspend(func_i    
255         case PSCI_0_2_FN64_CPU_ON:                
256                 return psci_cpu_on(func_id, ho    
257         default:                                  
258                 return PSCI_RET_NOT_SUPPORTED;    
259         }                                         
260 }                                                 
261                                                   
262 static unsigned long psci_1_0_handler(u64 func    
263 {                                                 
264         switch (func_id) {                        
265         case PSCI_1_0_FN_PSCI_FEATURES:           
266         case PSCI_1_0_FN_SET_SUSPEND_MODE:        
267         case PSCI_1_1_FN64_SYSTEM_RESET2:         
268                 return psci_forward(host_ctxt)    
269         case PSCI_1_0_FN64_SYSTEM_SUSPEND:        
270                 return psci_system_suspend(fun    
271         default:                                  
272                 return psci_0_2_handler(func_i    
273         }                                         
274 }                                                 
275                                                   
276 bool kvm_host_psci_handler(struct kvm_cpu_cont    
277 {                                                 
278         unsigned long ret;                        
279                                                   
280         switch (kvm_host_psci_config.version)     
281         case PSCI_VERSION(0, 1):                  
282                 if (!is_psci_0_1_call(func_id)    
283                         return false;             
284                 ret = psci_0_1_handler(func_id    
285                 break;                            
286         case PSCI_VERSION(0, 2):                  
287                 if (!is_psci_0_2_call(func_id)    
288                         return false;             
289                 ret = psci_0_2_handler(func_id    
290                 break;                            
291         default:                                  
292                 if (!is_psci_0_2_call(func_id)    
293                         return false;             
294                 ret = psci_1_0_handler(func_id    
295                 break;                            
296         }                                         
297                                                   
298         cpu_reg(host_ctxt, 0) = ret;              
299         cpu_reg(host_ctxt, 1) = 0;                
300         cpu_reg(host_ctxt, 2) = 0;                
301         cpu_reg(host_ctxt, 3) = 0;                
302         return true;                              
303 }                                                 
304                                                   

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php