@@ -19,6 +19,12 @@ use vmm_sys_util::ioctl::{ioctl, ioctl_with_mut_ref, ioctl_with_ref};
19
19
#[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
20
20
use vmm_sys_util:: ioctl:: { ioctl_with_mut_ptr, ioctl_with_ptr, ioctl_with_val} ;
21
21
22
+ /// Helper method to obtain the size of the register through its id
23
+ #[ cfg( any( target_arch = "arm" , target_arch = "aarch64" ) ) ]
24
+ fn reg_size ( reg_id : u64 ) -> usize {
25
+ 2_usize . pow ( ( ( reg_id & KVM_REG_SIZE_MASK ) >> KVM_REG_SIZE_SHIFT ) as u32 )
26
+ }
27
+
22
28
/// Reasons for vCPU exits.
23
29
///
24
30
/// The exit reasons are mapped to the `KVM_EXIT_*` defines in the
@@ -1162,45 +1168,61 @@ impl VcpuFd {
1162
1168
/// # Arguments
1163
1169
///
1164
1170
/// * `reg_id` - ID of the register for which we are setting the value.
1165
- /// * `data` - value for the specified register.
1171
+ /// * `data` - byte slice where the register value will be written to.
1172
+ ///
1173
+ /// # Note
1174
+ ///
1175
+ /// `data` should be equal or bigger then the register size
1176
+ /// oterwise function will return EINVAL error
1166
1177
#[ cfg( any( target_arch = "arm" , target_arch = "aarch64" ) ) ]
1167
- pub fn set_one_reg ( & self , reg_id : u64 , data : u128 ) -> Result < ( ) > {
1168
- let data_ptr = & data as * const _ ;
1178
+ pub fn set_one_reg ( & self , reg_id : u64 , data : & [ u8 ] ) -> Result < usize > {
1179
+ let reg_size = reg_size ( reg_id) ;
1180
+ if data. len ( ) < reg_size {
1181
+ return Err ( errno:: Error :: new ( libc:: EINVAL ) ) ;
1182
+ }
1169
1183
let onereg = kvm_one_reg {
1170
1184
id : reg_id,
1171
- addr : data_ptr as u64 ,
1185
+ addr : data . as_ptr ( ) as u64 ,
1172
1186
} ;
1173
1187
// SAFETY: This is safe because we allocated the struct and we know the kernel will read
1174
1188
// exactly the size of the struct.
1175
1189
let ret = unsafe { ioctl_with_ref ( self , KVM_SET_ONE_REG ( ) , & onereg) } ;
1176
1190
if ret < 0 {
1177
1191
return Err ( errno:: Error :: last ( ) ) ;
1178
1192
}
1179
- Ok ( ( ) )
1193
+ Ok ( reg_size )
1180
1194
}
1181
1195
1182
- /// Returns the value of the specified vCPU register.
1196
+ /// Writes the value of the specified vCPU register into provided buffer .
1183
1197
///
1184
1198
/// The id of the register is encoded as specified in the kernel documentation
1185
1199
/// for `KVM_GET_ONE_REG`.
1186
1200
///
1187
1201
/// # Arguments
1188
1202
///
1189
1203
/// * `reg_id` - ID of the register.
1204
+ /// * `data` - byte slice where the register value will be written to.
1205
+ /// # Note
1206
+ ///
1207
+ /// `data` should be equal or bigger then the register size
1208
+ /// oterwise function will return EINVAL error
1190
1209
#[ cfg( any( target_arch = "arm" , target_arch = "aarch64" ) ) ]
1191
- pub fn get_one_reg ( & self , reg_id : u64 ) -> Result < u128 > {
1192
- let mut reg_value = 0 ;
1210
+ pub fn get_one_reg ( & self , reg_id : u64 , data : & mut [ u8 ] ) -> Result < usize > {
1211
+ let reg_size = reg_size ( reg_id) ;
1212
+ if data. len ( ) < reg_size {
1213
+ return Err ( errno:: Error :: new ( libc:: EINVAL ) ) ;
1214
+ }
1193
1215
let mut onereg = kvm_one_reg {
1194
1216
id : reg_id,
1195
- addr : & mut reg_value as * mut _ as u64 ,
1217
+ addr : data . as_ptr ( ) as u64 ,
1196
1218
} ;
1197
1219
// SAFETY: This is safe because we allocated the struct and we know the kernel will read
1198
1220
// exactly the size of the struct.
1199
1221
let ret = unsafe { ioctl_with_mut_ref ( self , KVM_GET_ONE_REG ( ) , & mut onereg) } ;
1200
1222
if ret < 0 {
1201
1223
return Err ( errno:: Error :: last ( ) ) ;
1202
1224
}
1203
- Ok ( reg_value )
1225
+ Ok ( reg_size )
1204
1226
}
1205
1227
1206
1228
/// Notify the guest about the vCPU being paused.
@@ -2044,15 +2066,18 @@ mod tests {
2044
2066
2045
2067
// Set the PC to the guest address where we loaded the code.
2046
2068
vcpu_fd
2047
- . set_one_reg ( core_reg_base + 2 * 32 , guest_addr as u128 )
2069
+ . set_one_reg ( core_reg_base + 2 * 32 , & ( guest_addr as u128 ) . to_le_bytes ( ) )
2048
2070
. unwrap ( ) ;
2049
2071
2050
2072
// Set x8 and x9 to the addresses the guest test code needs
2051
2073
vcpu_fd
2052
- . set_one_reg ( core_reg_base + 2 * 8 , guest_addr as u128 + 0x10000 )
2074
+ . set_one_reg (
2075
+ core_reg_base + 2 * 8 ,
2076
+ & ( guest_addr as u128 + 0x10000 ) . to_le_bytes ( ) ,
2077
+ )
2053
2078
. unwrap ( ) ;
2054
2079
vcpu_fd
2055
- . set_one_reg ( core_reg_base + 2 * 9 , mmio_addr as u128 )
2080
+ . set_one_reg ( core_reg_base + 2 * 9 , & ( mmio_addr as u128 ) . to_le_bytes ( ) )
2056
2081
. unwrap ( ) ;
2057
2082
2058
2083
loop {
@@ -2389,12 +2414,16 @@ mod tests {
2389
2414
let data: u128 = 0 ;
2390
2415
let reg_id: u64 = 0 ;
2391
2416
2392
- assert ! ( vcpu. set_one_reg( reg_id, data) . is_err( ) ) ;
2417
+ assert ! ( vcpu. set_one_reg( reg_id, & data. to_le_bytes ( ) ) . is_err( ) ) ;
2393
2418
// Exercising KVM_SET_ONE_REG by trying to alter the data inside the PSTATE register (which is a
2394
2419
// specific aarch64 register).
2420
+ // This regiseter is 64 bit wide (8 bytes).
2395
2421
const PSTATE_REG_ID : u64 = 0x6030_0000_0010_0042 ;
2396
- vcpu. set_one_reg ( PSTATE_REG_ID , data)
2422
+ vcpu. set_one_reg ( PSTATE_REG_ID , & data. to_le_bytes ( ) )
2397
2423
. expect ( "Failed to set pstate register" ) ;
2424
+
2425
+ // Trying to set 8 byte register with 7 bytes must fail.
2426
+ assert ! ( vcpu. set_one_reg( PSTATE_REG_ID , & [ 0_u8 ; 7 ] ) . is_err( ) ) ;
2398
2427
}
2399
2428
2400
2429
#[ test]
@@ -2420,14 +2449,17 @@ mod tests {
2420
2449
PSR_MODE_EL1H | PSR_A_BIT | PSR_F_BIT | PSR_I_BIT | PSR_D_BIT ;
2421
2450
let data: u128 = PSTATE_FAULT_BITS_64 as u128 ;
2422
2451
const PSTATE_REG_ID : u64 = 0x6030_0000_0010_0042 ;
2423
- vcpu. set_one_reg ( PSTATE_REG_ID , data)
2452
+ vcpu. set_one_reg ( PSTATE_REG_ID , & data. to_le_bytes ( ) )
2424
2453
. expect ( "Failed to set pstate register" ) ;
2425
2454
2426
- assert_eq ! (
2427
- vcpu. get_one_reg( PSTATE_REG_ID )
2428
- . expect( "Failed to get pstate register" ) ,
2429
- PSTATE_FAULT_BITS_64 as u128
2430
- ) ;
2455
+ let mut bytes = [ 0_u8 ; 16 ] ;
2456
+ vcpu. get_one_reg ( PSTATE_REG_ID , & mut bytes)
2457
+ . expect ( "Failed to get pstate register" ) ;
2458
+ let data = u128:: from_le_bytes ( bytes) ;
2459
+ assert_eq ! ( data, PSTATE_FAULT_BITS_64 as u128 ) ;
2460
+
2461
+ // Trying to get 8 byte register with 7 bytes must fail.
2462
+ assert ! ( vcpu. get_one_reg( PSTATE_REG_ID , & mut [ 0_u8 ; 7 ] ) . is_err( ) ) ;
2431
2463
}
2432
2464
2433
2465
#[ test]
0 commit comments