gz / rust-x86

Rust library to use x86 (amd64) specific functionality and registers.

Home Page:https://docs.rs/x86

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

x86 registers definition

Wenzel opened this issue · comments

Hi !

I'm considering using your crate to use a "standard" definition of x86 registers in my project.
My goal is to do Virtual Machine Introspection (VMI), and I would like to read the registers of a VM on Xen, KVM or VirtualBox with a Rust API (libmicrovmi)

I looked at your docs, but I couldn't find a structure that would define the x86 registers.
There is indeed a module that defines the MSR constants, but what I would like is a structure that would contains all x86 standard registers.

For example on the Libvmi (C) library:

/*
 * Commonly used x86 registers
 */
typedef struct x86_regs {
    uint64_t rax;
    uint64_t rcx;
    uint64_t rdx;
    uint64_t rbx;
    uint64_t rsp;
    uint64_t rbp;
    uint64_t rsi;
    uint64_t rdi;
    uint64_t r8;
    uint64_t r9;
    uint64_t r10;
    uint64_t r11;
    uint64_t r12;
    uint64_t r13;
    uint64_t r14;
    uint64_t r15;
    uint64_t rflags;
    uint64_t dr6;
    uint64_t dr7;
    uint64_t rip;
    uint64_t cr0;
    uint64_t cr2;
    uint64_t cr3;
    uint64_t cr4;
    uint64_t sysenter_cs;
    uint64_t sysenter_esp;
    uint64_t sysenter_eip;
    uint64_t msr_efer;
    uint64_t msr_star;
    uint64_t msr_lstar;
    uint64_t msr_pat;
    uint64_t msr_cstar;
    uint64_t fs_base;
    uint64_t fs_limit;
    uint64_t fs_sel;
    uint64_t fs_arbytes;
    uint64_t gs_base;
    uint64_t gs_limit;
    uint64_t gs_sel;
    uint64_t gs_arbytes;
    uint64_t cs_base;
    uint64_t cs_limit;
    uint64_t cs_sel;
    uint32_t cs_arbytes;
    uint64_t ss_base;
    uint64_t ss_limit;
    uint64_t ss_sel;
    uint64_t ss_arbytes;
    uint64_t ds_base;
    uint64_t ds_limit;
    uint64_t ds_sel;
    uint64_t ds_arbytes;
    uint64_t es_base;
    uint64_t es_limit;
    uint64_t es_sel;
    uint64_t es_arbytes;
    uint64_t shadow_gs;
    uint64_t idtr_base;
    uint64_t idtr_limit;
    uint64_t gdtr_base;
    uint64_t gdtr_limit;

    uint32_t _pad;
} x86_registers_t;

typedef struct arm_registers {
    uint64_t ttbr0;
    uint64_t ttbr1;
    uint64_t ttbcr;
    uint64_t pc;
    uint32_t cpsr;
    uint32_t _pad;
} arm_registers_t;

typedef struct registers {
    union {
        x86_registers_t x86;
        arm_registers_t arm;
    };
} registers_t;

Can you add such a structure to provide a standard definition of x86 registers in a crate ?
What do you think ?

Thank you for this crate !

Hi, Thanks for your interest in x86. I think that it would be possible to provide such a struct that essentially captures the CPU register state.
Ideally, I'd like this crate to be a close representation of what's in the SDM. Is there a definition in the SDM somewhere that talks about what is considered an "x86 standard register"? That would make it easier to define it (for example you currently don't include all MSR values as part of the struct).

Hi @gz,

Is there a definition in the SDM somewhere that talks about what is considered an "x86 standard register"?

I think the official term is general-purpose registers, excluding RIP and RFLAGS:
Capture d’écran de 2019-10-28 21-51-47

I have 3 questions:

  • If I include your crate in my project, does this mean it can only compile on an x86 processor ? My users will also be running ARM processor trying to introspect x86 emulators like QEMU or Bochs.
  • I'm fairly new to Rust, so I don't exactly know already how I can represent this structure in my program. In C it's easy, with a union that includes every possibility that your struct can represent. How can I achieve that in Rust ?
  • Are you part of the rust-osdev group ? I saw a similar crate hosted there:
    https://github.com/rust-osdev/x86_64

Thanks !

Hi @Wenzel,

Alright, so it looks like we could try to aggregate all these according to the SDM.

If I include your crate in my project, does this mean it can only compile on an x86 processor ? My users will also be running ARM processor trying to introspect x86 emulators like QEMU or Bochs.

Currently the x86 crate only compiles on x86 (32 bit and 64bit). There is no reason why it couldn't be made to compile (at least the struct definitions) for ARM based processors. But it will require to exclude all x86 specific functions from the compilation unit (by using cfg! annotations). I'd be ok with such an addition if it serves some benefit.

I'm fairly new to Rust, so I don't exactly know already how I can represent this structure in my program. In C it's easy, with a union that includes every possibility that your struct can represent. How can I achieve that in Rust?

The rust way would also be to have an enum:

enum Registers {
  X86(X86Registers)
  Arm(ArmRegisters)
}

and then do pattern matching on that Registers enum.

Are you part of the rust-osdev group ? I saw a similar crate hosted there: https://github.com/rust-osdev/x86_64

No, it seems to me that x86_64 was a hard-fork of this crate. I don't know about the intentions of crate x86-64 but it looks like it's more about trying to provide a safe interface for programming x86 hardware, whereas this crate is trying to provide a no-abstraction/unsafe interface to program x86 and leaves the decisions on how to make it safe to the user of the library.

For 32 bit x86 there is a standard order specified by the pusha instruction:
https://c9x.me/x86/html/file_module_x86_id_270.html
This microcoded instruction doesn't work for the 64 bit versions of the registers or for r8-r15 but there's an obvious order for those.