gz / rust-cpuid

cpuid library in rust.
https://docs.rs/raw-cpuid/
MIT License
150 stars 45 forks source link

Issuses on offset and size in extended state region #91

Closed Bonjourz closed 2 years ago

Bonjourz commented 2 years ago

Hi, I want to get the specific size and offset of a state component n (2 <= n <= 31) in the extended state by using the functions rust-cpuid lib provides. But it seems the library always returns the information (size and offset) of the first valid state component.

Here is the sample code:

pub fn extended_state_size_and_offset(level: u32) -> (u32, u32) {
    let cpuid = CpuId::new();
    let mut offset  = 0;
    let mut size = 0;
    if let Some(info) = cpuid.get_extended_state_info() {
        let extended_state_iter = info.iter();
        if let Some(extend_state) = extended_state_iter.next() {
            offset = extend_state.offset();
            size = extend_state.size();
        }
    }
    (offset, size)
}

The code above can only returns the size and offset of the first valid state component, and cannot returns the specific state component indexed by level.

Could you please help me to confirm whether such issue exists indeed? If so, I'm pleased to submit PR to fix the issue.

gz commented 2 years ago

hi @Bonjourz

I'm not sure I fully understand the issue with always returning the first offset and size. It seems to me in your code example that your code will return the last offset and size it finds e.g., there is no if level == idx that checks the provided argument?

Running the raw-cpuid binary on my machine, I'm getting:

Extended Register State (0x0d/0):
XCR0/IA32_XSS supported states:
┌────────┬─────────────────┬──┐
│XCR0    │              x87│✅│
│XCR0    │        SSE state│✅│
│XCR0    │        AVX state│✅│
│XCR0    │      MPX BNDREGS│❌│
│XCR0    │       MPX BNDCSR│❌│
│XCR0    │   AVX-512 opmask│❌│
│XCR0    │AVX-512 ZMM_Hi256│❌│
│XCR0    │ AVX-512 Hi16_ZMM│❌│
│IA32_XSS│               PT│❌│
│XCR0    │             PKRU│✅│
│IA32_XSS│              HDC│❌│
└────────┴─────────────────┴──┘
┌───────────────────────────────────┬───┐
│   bytes required by fields in XCR0│832│
│bytes required by XSAVE/XRSTOR area│896│
└───────────────────────────────────┴───┘
XSAVE features (0x0d/1):
┌───────────────────────────┬───┐
│       XSAVEOPT instruction│ ✅│
│         XSAVEC instruction│ ✅│
│         XGETBV instruction│ ✅│
│XSAVES/XRSTORS instructions│ ✅│
│     SAVE area size [Bytes]│832│
└───────────────────────────┴───┘
AVX/YMM features (0x0d/2):
┌────────────────────────────────────┬─────────────────┐
│             save state size [Bytes]│              256│
│              save state byte offset│              576│
│       supported in IA32_XSS or XCR0│XCR0 (user state)│
│64-byte alignment in compacted XSAVE│               ❌│
└────────────────────────────────────┴─────────────────┘
PKRU features (0x0d/9):
┌────────────────────────────────────┬─────────────────┐
│             save state size [Bytes]│               64│
│              save state byte offset│              832│
│       supported in IA32_XSS or XCR0│XCR0 (user state)│
│64-byte alignment in compacted XSAVE│               ❌│
└────────────────────────────────────┴─────────────────┘

and the "regular" cpuid binary gives:

   XSAVE features (0xd/0):
      XCR0 lower 32 bits valid bit field mask = 0x00000207
      XCR0 upper 32 bits valid bit field mask = 0x00000000
         XCR0 supported: x87 state            = true
         XCR0 supported: SSE state            = true
         XCR0 supported: AVX state            = true
         XCR0 supported: MPX BNDREGS          = false
         XCR0 supported: MPX BNDCSR           = false
         XCR0 supported: AVX-512 opmask       = false
         XCR0 supported: AVX-512 ZMM_Hi256    = false
         XCR0 supported: AVX-512 Hi16_ZMM     = false
         IA32_XSS supported: PT state         = false
         XCR0 supported: PKRU state           = true
         XCR0 supported: CET_U state          = false
         XCR0 supported: CET_S state          = false
         IA32_XSS supported: HDC state        = false
      bytes required by fields in XCR0        = 0x00000340 (832)
      bytes required by XSAVE/XRSTOR area     = 0x00000380 (896)
   XSAVE features (0xd/1):
      XSAVEOPT instruction                        = true
      XSAVEC instruction                          = true
      XGETBV instruction                          = true
      XSAVES/XRSTORS instructions                 = true
      SAVE area size in bytes                     = 0x00000340 (832)
      IA32_XSS lower 32 bits valid bit field mask = 0x00000000
      IA32_XSS upper 32 bits valid bit field mask = 0x00000000
   AVX/YMM features (0xd/2):
      AVX/YMM save state byte size             = 0x00000100 (256)
      AVX/YMM save state byte offset           = 0x00000240 (576)
      supported in IA32_XSS or XCR0            = XCR0 (user state)
      64-byte alignment in compacted XSAVE     = false
   PKRU features (0xd/9):
      PKRU save state byte size                = 0x00000040 (64)
      PKRU save state byte offset              = 0x00000340 (832)
      supported in IA32_XSS or XCR0            = XCR0 (user state)
      64-byte alignment in compacted XSAVE     = false
gz commented 2 years ago

hi @Bonjourz I'm sorry, I missed that you're calling .iter() and .next() just once which explains what you're seeing. In this case, the fix is to use extended_state as an iterator that you're supposed to loop through, e.g.,:

for extended_state in extended_state_iter {
    println!("{:?}", extended_state);
}

You can also fine an example in the cpuid binary sources.

Bonjourz commented 2 years ago

Hi, @gz , it seems I'm not familiar with the usage of Iterator trait in Rust. Now the issue is fixed. Thanks for your detailed explanation!