@@ -301,6 +301,102 @@ static void steal_time_dump(struct kvm_vm *vm, uint32_t vcpu_idx)
301301 pr_info ("\n" );
302302}
303303
304+ #elif defined(__loongarch__ )
305+
306+ /* steal_time must have 64-byte alignment */
307+ #define STEAL_TIME_SIZE ((sizeof(struct kvm_steal_time) + 63) & ~63)
308+ #define KVM_STEAL_PHYS_VALID BIT_ULL(0)
309+
310+ struct kvm_steal_time {
311+ __u64 steal ;
312+ __u32 version ;
313+ __u32 flags ;
314+ __u8 preempted ;
315+ __u8 pad [47 ];
316+ };
317+
318+ static void check_status (struct kvm_steal_time * st )
319+ {
320+ GUEST_ASSERT (!(READ_ONCE (st -> version ) & 1 ));
321+ GUEST_ASSERT_EQ (READ_ONCE (st -> flags ), 0 );
322+ GUEST_ASSERT_EQ (READ_ONCE (st -> preempted ), 0 );
323+ }
324+
325+ static void guest_code (int cpu )
326+ {
327+ uint32_t version ;
328+ struct kvm_steal_time * st = st_gva [cpu ];
329+
330+ memset (st , 0 , sizeof (* st ));
331+ GUEST_SYNC (0 );
332+
333+ check_status (st );
334+ WRITE_ONCE (guest_stolen_time [cpu ], st -> steal );
335+ version = READ_ONCE (st -> version );
336+ check_status (st );
337+ GUEST_SYNC (1 );
338+
339+ check_status (st );
340+ GUEST_ASSERT (version < READ_ONCE (st -> version ));
341+ WRITE_ONCE (guest_stolen_time [cpu ], st -> steal );
342+ check_status (st );
343+ GUEST_DONE ();
344+ }
345+
346+ static bool is_steal_time_supported (struct kvm_vcpu * vcpu )
347+ {
348+ int err ;
349+ uint64_t val ;
350+ struct kvm_device_attr attr = {
351+ .group = KVM_LOONGARCH_VCPU_CPUCFG ,
352+ .attr = CPUCFG_KVM_FEATURE ,
353+ .addr = (uint64_t )& val ,
354+ };
355+
356+ err = __vcpu_ioctl (vcpu , KVM_HAS_DEVICE_ATTR , & attr );
357+ if (err )
358+ return false;
359+
360+ err = __vcpu_ioctl (vcpu , KVM_GET_DEVICE_ATTR , & attr );
361+ if (err )
362+ return false;
363+
364+ return val & BIT (KVM_FEATURE_STEAL_TIME );
365+ }
366+
367+ static void steal_time_init (struct kvm_vcpu * vcpu , uint32_t i )
368+ {
369+ int err ;
370+ uint64_t st_gpa ;
371+ struct kvm_vm * vm = vcpu -> vm ;
372+ struct kvm_device_attr attr = {
373+ .group = KVM_LOONGARCH_VCPU_PVTIME_CTRL ,
374+ .attr = KVM_LOONGARCH_VCPU_PVTIME_GPA ,
375+ .addr = (uint64_t )& st_gpa ,
376+ };
377+
378+ /* ST_GPA_BASE is identity mapped */
379+ st_gva [i ] = (void * )(ST_GPA_BASE + i * STEAL_TIME_SIZE );
380+ sync_global_to_guest (vm , st_gva [i ]);
381+
382+ err = __vcpu_ioctl (vcpu , KVM_HAS_DEVICE_ATTR , & attr );
383+ TEST_ASSERT (err == 0 , "No PV stealtime Feature" );
384+
385+ st_gpa = (unsigned long )st_gva [i ] | KVM_STEAL_PHYS_VALID ;
386+ err = __vcpu_ioctl (vcpu , KVM_SET_DEVICE_ATTR , & attr );
387+ TEST_ASSERT (err == 0 , "Fail to set PV stealtime GPA" );
388+ }
389+
390+ static void steal_time_dump (struct kvm_vm * vm , uint32_t vcpu_idx )
391+ {
392+ struct kvm_steal_time * st = addr_gva2hva (vm , (ulong )st_gva [vcpu_idx ]);
393+
394+ ksft_print_msg ("VCPU%d:\n" , vcpu_idx );
395+ ksft_print_msg (" steal: %lld\n" , st -> steal );
396+ ksft_print_msg (" flags: %d\n" , st -> flags );
397+ ksft_print_msg (" version: %d\n" , st -> version );
398+ ksft_print_msg (" preempted: %d\n" , st -> preempted );
399+ }
304400#endif
305401
306402static void * do_steal_time (void * arg )
0 commit comments