diff --git a/.gitignore b/.gitignore index 5b39ef3..41d64dc 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,8 @@ *.so *.dylib *.dll +*.pyd +*.pyc # Fortran module files *.mod diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..9109b58 --- /dev/null +++ b/docs/README.md @@ -0,0 +1 @@ +# `bochscpu-python` diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/api/.pages b/docs/api/.pages new file mode 100644 index 0000000..db48efa --- /dev/null +++ b/docs/api/.pages @@ -0,0 +1,4 @@ +title: API Reference +nav: + - Overview: README.md + - ... diff --git a/docs/api/README.md b/docs/api/README.md new file mode 100644 index 0000000..433e1f5 --- /dev/null +++ b/docs/api/README.md @@ -0,0 +1,20 @@ + + +# API Overview + +## Modules + +- No modules + +## Classes + +- No classes + +## Functions + +- No functions + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/docs/api/bochscpu.Hook.md b/docs/api/bochscpu.Hook.md new file mode 100644 index 0000000..bce2343 --- /dev/null +++ b/docs/api/bochscpu.Hook.md @@ -0,0 +1,169 @@ + + +# class `Hook` +Class Hook + + +--- + +### property Hook.after_execution + +Callback for Bochs `after_execution` callback + +--- + +### property Hook.before_execution + +Callback for Bochs `before_execution` callback + +--- + +### property Hook.cache_cntrl + +Callback for Bochs `cache_cntrl` callback + +--- + +### property Hook.clflush + +Callback for Bochs `clflush` callback + +--- + +### property Hook.cnear_branch_not_taken + +Callback for Bochs `cnear_branch_not_taken` callback + +--- + +### property Hook.cnear_branch_taken + +Callback for Bochs `cnear_branch_taken` callback + +--- + +### property Hook.ctx + +A raw pointer to the Session object + +--- + +### property Hook.exception + +Callback for Bochs `exception` callback + +--- + +### property Hook.far_branch + +Callback for Bochs `far_branch` callback + +--- + +### property Hook.hlt + +Callback for Bochs `hlt` callback + +--- + +### property Hook.hw_interrupt + +Callback for Bochs `hw_interrupt` callback + +--- + +### property Hook.inp + +Callback for Bochs `inp` callback + +--- + +### property Hook.inp2 + +Callback for Bochs `inp2` callback + +--- + +### property Hook.interrupt + +Callback for Bochs `interrupt` callback + +--- + +### property Hook.lin_access + +Callback for Bochs `lin_access` callback + +--- + +### property Hook.mwait + +Callback for Bochs `mwait` callback + +--- + +### property Hook.opcode + +Callback for Bochs `opcode` callback + +--- + +### property Hook.outp + +Callback for Bochs `outp` callback + +--- + +### property Hook.phy_access + +Callback for Bochs `phy_access` callback + +--- + +### property Hook.prefetch_hint + +Callback for Bochs `prefetch_hint` callback + +--- + +### property Hook.repeat_iteration + +Callback for Bochs `repeat_iteration` callback + +--- + +### property Hook.reset + +Callback for Bochs `reset` callback + +--- + +### property Hook.tlb_cntrl + +Callback for Bochs `tlb_cntrl` callback + +--- + +### property Hook.ucnear_branch + +Callback for Bochs `ucnear_branch` callback + +--- + +### property Hook.vmexit + +Callback for Bochs `vmexit` callback + +--- + +### property Hook.wrmsr + +Callback for Bochs `wrmsr` callback + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/docs/api/bochscpu.InstructionType.md b/docs/api/bochscpu.InstructionType.md new file mode 100644 index 0000000..ff08742 --- /dev/null +++ b/docs/api/bochscpu.InstructionType.md @@ -0,0 +1,15 @@ + + +# class `InstructionType` + + + + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/docs/api/bochscpu.Segment.md b/docs/api/bochscpu.Segment.md new file mode 100644 index 0000000..dc5ce42 --- /dev/null +++ b/docs/api/bochscpu.Segment.md @@ -0,0 +1,43 @@ + + +# class `Segment` +Segment class + + +--- + +### property Segment.attr + +Get/Set the Segment `attr` attribute + +--- + +### property Segment.base + +Get/Set the Segment `base` attribute + +--- + +### property Segment.limit + +Get/Set the Segment `limit` attribute + +--- + +### property Segment.present + +Get/Set the Segment `present` attribute + +--- + +### property Segment.selector + +Get/Set the Segment `selector` attribute + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/docs/api/bochscpu.Session.md b/docs/api/bochscpu.Session.md new file mode 100644 index 0000000..fe12d7d --- /dev/null +++ b/docs/api/bochscpu.Session.md @@ -0,0 +1,33 @@ + + +# class `Session` +Class session + + +--- + +### property Session.cpu + +Get the CPU associated to the session + +--- + +### property Session.missing_page_handler + +Set the missing page callback + + +--- + +### handler Session.run + +--- + +### handler Session.stop + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/docs/api/bochscpu.State.md b/docs/api/bochscpu.State.md new file mode 100644 index 0000000..867db68 --- /dev/null +++ b/docs/api/bochscpu.State.md @@ -0,0 +1,385 @@ + + +# class `State` +Class State + + +--- + +### property State.apic_base + +Get/Set the register `apic_base` in the current state + +--- + +### property State.cr0 + +Get/Set the register `cr0` in the current state + +--- + +### property State.cr2 + +Get/Set the register `cr2` in the current state + +--- + +### property State.cr3 + +Get/Set the register `cr3` in the current state + +--- + +### property State.cr4 + +Get/Set the register `cr4` in the current state + +--- + +### property State.cr8 + +Get/Set the register `cr8` in the current state + +--- + +### property State.cs + +Get/Set the register `cs` in the current state + +--- + +### property State.cstar + +Get/Set the register `cstar` in the current state + +--- + +### property State.dr0 + +Get/Set the register `dr0` in the current state + +--- + +### property State.dr1 + +Get/Set the register `dr1` in the current state + +--- + +### property State.dr2 + +Get/Set the register `dr2` in the current state + +--- + +### property State.dr3 + +Get/Set the register `dr3` in the current state + +--- + +### property State.dr6 + +Get/Set the register `dr6` in the current state + +--- + +### property State.dr7 + +Get/Set the register `dr7` in the current state + +--- + +### property State.ds + +Get/Set the register `ds` in the current state + +--- + +### property State.efer + +Get/Set the register `efer` in the current state + +--- + +### property State.es + +Get/Set the register `es` in the current state + +--- + +### property State.fpcw + +Get/Set the register `fpcw` in the current state + +--- + +### property State.fpop + +Get/Set the register `fpop` in the current state + +--- + +### property State.fpst + +Get/Set the register `fpst` in the current state + +--- + +### property State.fpsw + +Get/Set the register `fpsw` in the current state + +--- + +### property State.fptw + +Get/Set the register `fptw` in the current state + +--- + +### property State.fs + +Get/Set the register `fs` in the current state + +--- + +### property State.gdtr + +Get/Set the register `gdtr` in the current state + +--- + +### property State.gs + +Get/Set the register `gs` in the current state + +--- + +### property State.idtr + +Get/Set the register `idtr` in the current state + +--- + +### property State.kernel_gs_base + +Get/Set the register `kernel_gs_base` in the current state + +--- + +### property State.ldtr + +Get/Set the register `ldtr` in the current state + +--- + +### property State.lstar + +Get/Set the register `lstar` in the current state + +--- + +### property State.mxcsr + +Get/Set the register `mxcsr` in the current state + +--- + +### property State.mxcsr_mask + +Get/Set the register `mxcsr_mask` in the current state + +--- + +### property State.pat + +Get/Set the register `pat` in the current state + +--- + +### property State.r10 + +Get/Set the register `r10` in the current state + +--- + +### property State.r11 + +Get/Set the register `r11` in the current state + +--- + +### property State.r12 + +Get/Set the register `r12` in the current state + +--- + +### property State.r13 + +Get/Set the register `r13` in the current state + +--- + +### property State.r14 + +Get/Set the register `r14` in the current state + +--- + +### property State.r15 + +Get/Set the register `r15` in the current state + +--- + +### property State.r8 + +Get/Set the register `r8` in the current state + +--- + +### property State.r9 + +Get/Set the register `r9` in the current state + +--- + +### property State.rax + +Get/Set the register `rax` in the current state + +--- + +### property State.rbp + +Get/Set the register `rbp` in the current state + +--- + +### property State.rbx + +Get/Set the register `rbx` in the current state + +--- + +### property State.rcx + +Get/Set the register `rcx` in the current state + +--- + +### property State.rdi + +Get/Set the register `rdi` in the current state + +--- + +### property State.rdx + +Get/Set the register `rdx` in the current state + +--- + +### property State.rflags + +Get/Set the register `rflags` in the current state + +--- + +### property State.rip + +Get/Set the register `rip` in the current state + +--- + +### property State.rsi + +Get/Set the register `rsi` in the current state + +--- + +### property State.rsp + +Get/Set the register `rsp` in the current state + +--- + +### property State.seed + +Get/Set the seed in the current state + +--- + +### property State.sfmask + +Get/Set the register `sfmask` in the current state + +--- + +### property State.ss + +Get/Set the register `ss` in the current state + +--- + +### property State.star + +Get/Set the register `star` in the current state + +--- + +### property State.sysenter_cs + +Get/Set the register `sysenter_cs` in the current state + +--- + +### property State.sysenter_eip + +Get/Set the register `sysenter_eip` in the current state + +--- + +### property State.sysenter_esp + +Get/Set the register `sysenter_esp` in the current state + +--- + +### property State.tr + +Get/Set the register `tr` in the current state + +--- + +### property State.tsc + +Get/Set the register `tsc` in the current state + +--- + +### property State.tsc_aux + +Get/Set the register `tsc_aux` in the current state + +--- + +### property State.xcr0 + +Get/Set the register `xcr0` in the current state + +--- + +### property State.zmm + +Get/Set the register `zmm` in the current state + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/docs/api/bochscpu._bochscpu.md b/docs/api/bochscpu._bochscpu.md new file mode 100644 index 0000000..8b1c24d --- /dev/null +++ b/docs/api/bochscpu._bochscpu.md @@ -0,0 +1,727 @@ + + +# module `bochscpu._bochscpu` +The native `bochscpu` module + +**Global Variables** +--------------- +- **memory** +- **cpu** +- **BX_INSTR_IS_JMP** +- **BOCHSCPU_INSTR_IS_JMP_INDIRECT** +- **BOCHSCPU_INSTR_IS_CALL** +- **BOCHSCPU_INSTR_IS_CALL_INDIRECT** +- **BOCHSCPU_INSTR_IS_RET** +- **BOCHSCPU_INSTR_IS_IRET** +- **BOCHSCPU_INSTR_IS_INT** +- **BOCHSCPU_INSTR_IS_SYSCALL** +- **BOCHSCPU_INSTR_IS_SYSRET** +- **BOCHSCPU_INSTR_IS_SYSENTER** +- **BOCHSCPU_INSTR_IS_SYSEXIT** +- **BOCHSCPU_HOOK_MEM_READ** +- **BOCHSCPU_HOOK_MEM_WRITE** +- **BOCHSCPU_HOOK_MEM_EXECUTE** +- **BOCHSCPU_HOOK_MEM_RW** +- **BOCHSCPU_HOOK_TLB_CR0** +- **BOCHSCPU_HOOK_TLB_CR3** +- **BOCHSCPU_HOOK_TLB_CR4** +- **BOCHSCPU_HOOK_TLB_TASKSWITCH** +- **BOCHSCPU_HOOK_TLB_CONTEXTSWITCH** +- **BOCHSCPU_HOOK_TLB_INVLPG** +- **BOCHSCPU_HOOK_TLB_INVEPT** +- **BOCHSCPU_HOOK_TLB_INVVPID** +- **BOCHSCPU_HOOK_TLB_INVPCID** +- **BOCHSCPU_OPCODE_ERROR** +- **BOCHSCPU_OPCODE_INSERTED** + + +--- + +## class `GlobalSegment` +GlobalSegment class + + +--- + +#### property GlobalSegment.base + +Get/Set the GlobalSegment `base` attribute + +--- + +#### property GlobalSegment.limit + +Get/Set the GlobalSegment `limit` attribute + + + + +--- + +## class `Hook` +Class Hook + + +--- + +#### property Hook.after_execution + +Callback for Bochs `after_execution` callback + +--- + +#### property Hook.before_execution + +Callback for Bochs `before_execution` callback + +--- + +#### property Hook.cache_cntrl + +Callback for Bochs `cache_cntrl` callback + +--- + +#### property Hook.clflush + +Callback for Bochs `clflush` callback + +--- + +#### property Hook.cnear_branch_not_taken + +Callback for Bochs `cnear_branch_not_taken` callback + +--- + +#### property Hook.cnear_branch_taken + +Callback for Bochs `cnear_branch_taken` callback + +--- + +#### property Hook.ctx + +A raw pointer to the Session object + +--- + +#### property Hook.exception + +Callback for Bochs `exception` callback + +--- + +#### property Hook.far_branch + +Callback for Bochs `far_branch` callback + +--- + +#### property Hook.hlt + +Callback for Bochs `hlt` callback + +--- + +#### property Hook.hw_interrupt + +Callback for Bochs `hw_interrupt` callback + +--- + +#### property Hook.inp + +Callback for Bochs `inp` callback + +--- + +#### property Hook.inp2 + +Callback for Bochs `inp2` callback + +--- + +#### property Hook.interrupt + +Callback for Bochs `interrupt` callback + +--- + +#### property Hook.lin_access + +Callback for Bochs `lin_access` callback + +--- + +#### property Hook.mwait + +Callback for Bochs `mwait` callback + +--- + +#### property Hook.opcode + +Callback for Bochs `opcode` callback + +--- + +#### property Hook.outp + +Callback for Bochs `outp` callback + +--- + +#### property Hook.phy_access + +Callback for Bochs `phy_access` callback + +--- + +#### property Hook.prefetch_hint + +Callback for Bochs `prefetch_hint` callback + +--- + +#### property Hook.repeat_iteration + +Callback for Bochs `repeat_iteration` callback + +--- + +#### property Hook.reset + +Callback for Bochs `reset` callback + +--- + +#### property Hook.tlb_cntrl + +Callback for Bochs `tlb_cntrl` callback + +--- + +#### property Hook.ucnear_branch + +Callback for Bochs `ucnear_branch` callback + +--- + +#### property Hook.vmexit + +Callback for Bochs `vmexit` callback + +--- + +#### property Hook.wrmsr + +Callback for Bochs `wrmsr` callback + + + + +--- + +## class `HookType` + + + + + + + + +--- + +## class `InstructionType` + + + + + + + + +--- + +## class `OpcodeOperationType` + + + + + + + + +--- + +## class `Segment` +Segment class + + +--- + +#### property Segment.attr + +Get/Set the Segment `attr` attribute + +--- + +#### property Segment.base + +Get/Set the Segment `base` attribute + +--- + +#### property Segment.limit + +Get/Set the Segment `limit` attribute + +--- + +#### property Segment.present + +Get/Set the Segment `present` attribute + +--- + +#### property Segment.selector + +Get/Set the Segment `selector` attribute + + + + +--- + +## class `Session` +Class session + + +--- + +#### property Session.cpu + +Get the CPU associated to the session + +--- + +#### property Session.missing_page_handler + +Set the missing page callback + + +--- + +#### handler Session.run + +--- + +#### handler Session.stop + + + +--- + +## class `State` +Class State + + +--- + +#### property State.apic_base + +Get/Set the register `apic_base` in the current state + +--- + +#### property State.cr0 + +Get/Set the register `cr0` in the current state + +--- + +#### property State.cr2 + +Get/Set the register `cr2` in the current state + +--- + +#### property State.cr3 + +Get/Set the register `cr3` in the current state + +--- + +#### property State.cr4 + +Get/Set the register `cr4` in the current state + +--- + +#### property State.cr8 + +Get/Set the register `cr8` in the current state + +--- + +#### property State.cs + +Get/Set the register `cs` in the current state + +--- + +#### property State.cstar + +Get/Set the register `cstar` in the current state + +--- + +#### property State.dr0 + +Get/Set the register `dr0` in the current state + +--- + +#### property State.dr1 + +Get/Set the register `dr1` in the current state + +--- + +#### property State.dr2 + +Get/Set the register `dr2` in the current state + +--- + +#### property State.dr3 + +Get/Set the register `dr3` in the current state + +--- + +#### property State.dr6 + +Get/Set the register `dr6` in the current state + +--- + +#### property State.dr7 + +Get/Set the register `dr7` in the current state + +--- + +#### property State.ds + +Get/Set the register `ds` in the current state + +--- + +#### property State.efer + +Get/Set the register `efer` in the current state + +--- + +#### property State.es + +Get/Set the register `es` in the current state + +--- + +#### property State.fpcw + +Get/Set the register `fpcw` in the current state + +--- + +#### property State.fpop + +Get/Set the register `fpop` in the current state + +--- + +#### property State.fpst + +Get/Set the register `fpst` in the current state + +--- + +#### property State.fpsw + +Get/Set the register `fpsw` in the current state + +--- + +#### property State.fptw + +Get/Set the register `fptw` in the current state + +--- + +#### property State.fs + +Get/Set the register `fs` in the current state + +--- + +#### property State.gdtr + +Get/Set the register `gdtr` in the current state + +--- + +#### property State.gs + +Get/Set the register `gs` in the current state + +--- + +#### property State.idtr + +Get/Set the register `idtr` in the current state + +--- + +#### property State.kernel_gs_base + +Get/Set the register `kernel_gs_base` in the current state + +--- + +#### property State.ldtr + +Get/Set the register `ldtr` in the current state + +--- + +#### property State.lstar + +Get/Set the register `lstar` in the current state + +--- + +#### property State.mxcsr + +Get/Set the register `mxcsr` in the current state + +--- + +#### property State.mxcsr_mask + +Get/Set the register `mxcsr_mask` in the current state + +--- + +#### property State.pat + +Get/Set the register `pat` in the current state + +--- + +#### property State.r10 + +Get/Set the register `r10` in the current state + +--- + +#### property State.r11 + +Get/Set the register `r11` in the current state + +--- + +#### property State.r12 + +Get/Set the register `r12` in the current state + +--- + +#### property State.r13 + +Get/Set the register `r13` in the current state + +--- + +#### property State.r14 + +Get/Set the register `r14` in the current state + +--- + +#### property State.r15 + +Get/Set the register `r15` in the current state + +--- + +#### property State.r8 + +Get/Set the register `r8` in the current state + +--- + +#### property State.r9 + +Get/Set the register `r9` in the current state + +--- + +#### property State.rax + +Get/Set the register `rax` in the current state + +--- + +#### property State.rbp + +Get/Set the register `rbp` in the current state + +--- + +#### property State.rbx + +Get/Set the register `rbx` in the current state + +--- + +#### property State.rcx + +Get/Set the register `rcx` in the current state + +--- + +#### property State.rdi + +Get/Set the register `rdi` in the current state + +--- + +#### property State.rdx + +Get/Set the register `rdx` in the current state + +--- + +#### property State.rflags + +Get/Set the register `rflags` in the current state + +--- + +#### property State.rip + +Get/Set the register `rip` in the current state + +--- + +#### property State.rsi + +Get/Set the register `rsi` in the current state + +--- + +#### property State.rsp + +Get/Set the register `rsp` in the current state + +--- + +#### property State.seed + +Get/Set the seed in the current state + +--- + +#### property State.sfmask + +Get/Set the register `sfmask` in the current state + +--- + +#### property State.ss + +Get/Set the register `ss` in the current state + +--- + +#### property State.star + +Get/Set the register `star` in the current state + +--- + +#### property State.sysenter_cs + +Get/Set the register `sysenter_cs` in the current state + +--- + +#### property State.sysenter_eip + +Get/Set the register `sysenter_eip` in the current state + +--- + +#### property State.sysenter_esp + +Get/Set the register `sysenter_esp` in the current state + +--- + +#### property State.tr + +Get/Set the register `tr` in the current state + +--- + +#### property State.tsc + +Get/Set the register `tsc` in the current state + +--- + +#### property State.tsc_aux + +Get/Set the register `tsc_aux` in the current state + +--- + +#### property State.xcr0 + +Get/Set the register `xcr0` in the current state + +--- + +#### property State.zmm + +Get/Set the register `zmm` in the current state + + + + +--- + +## class `Zmm` + + + + + +--- + +#### property Zmm.q + +(self) -> list[int] + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/docs/bochscpu.Hook.md b/docs/bochscpu.Hook.md new file mode 100644 index 0000000..bce2343 --- /dev/null +++ b/docs/bochscpu.Hook.md @@ -0,0 +1,169 @@ + + +# class `Hook` +Class Hook + + +--- + +### property Hook.after_execution + +Callback for Bochs `after_execution` callback + +--- + +### property Hook.before_execution + +Callback for Bochs `before_execution` callback + +--- + +### property Hook.cache_cntrl + +Callback for Bochs `cache_cntrl` callback + +--- + +### property Hook.clflush + +Callback for Bochs `clflush` callback + +--- + +### property Hook.cnear_branch_not_taken + +Callback for Bochs `cnear_branch_not_taken` callback + +--- + +### property Hook.cnear_branch_taken + +Callback for Bochs `cnear_branch_taken` callback + +--- + +### property Hook.ctx + +A raw pointer to the Session object + +--- + +### property Hook.exception + +Callback for Bochs `exception` callback + +--- + +### property Hook.far_branch + +Callback for Bochs `far_branch` callback + +--- + +### property Hook.hlt + +Callback for Bochs `hlt` callback + +--- + +### property Hook.hw_interrupt + +Callback for Bochs `hw_interrupt` callback + +--- + +### property Hook.inp + +Callback for Bochs `inp` callback + +--- + +### property Hook.inp2 + +Callback for Bochs `inp2` callback + +--- + +### property Hook.interrupt + +Callback for Bochs `interrupt` callback + +--- + +### property Hook.lin_access + +Callback for Bochs `lin_access` callback + +--- + +### property Hook.mwait + +Callback for Bochs `mwait` callback + +--- + +### property Hook.opcode + +Callback for Bochs `opcode` callback + +--- + +### property Hook.outp + +Callback for Bochs `outp` callback + +--- + +### property Hook.phy_access + +Callback for Bochs `phy_access` callback + +--- + +### property Hook.prefetch_hint + +Callback for Bochs `prefetch_hint` callback + +--- + +### property Hook.repeat_iteration + +Callback for Bochs `repeat_iteration` callback + +--- + +### property Hook.reset + +Callback for Bochs `reset` callback + +--- + +### property Hook.tlb_cntrl + +Callback for Bochs `tlb_cntrl` callback + +--- + +### property Hook.ucnear_branch + +Callback for Bochs `ucnear_branch` callback + +--- + +### property Hook.vmexit + +Callback for Bochs `vmexit` callback + +--- + +### property Hook.wrmsr + +Callback for Bochs `wrmsr` callback + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/docs/examples.md b/docs/examples.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/gallery.md b/docs/gallery.md new file mode 100644 index 0000000..affd84c --- /dev/null +++ b/docs/gallery.md @@ -0,0 +1,9 @@ +# Screenshots + + +## Fibonacci (long mode) + +![image](https://i.imgur.com/YvXg2Tz.png) + +## Windows user-mode dump emulation (long mode) + diff --git a/docs/install.md b/docs/install.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..204dd3e --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,2 @@ +mkdocs-material +lazydocs diff --git a/examples/long_mode_emulate_windows_udump.py b/examples/long_mode_emulate_windows_udump.py index 2aac730..f22d100 100644 --- a/examples/long_mode_emulate_windows_udump.py +++ b/examples/long_mode_emulate_windows_udump.py @@ -147,14 +147,21 @@ def switch_to_thread(state: bochscpu.State, thread: udmp_parser.Thread): _cs.base = 0 _cs.limit = 0xFFFF_FFFF _cs.selector = thread.Context.SegCs - _cs.attr = 0x22FB - _cs.present = True + _cs_attr = bochscpu.cpu.SegmentFlags() + _cs_attr.A = True + _cs_attr.R = True + _cs_attr.E = True + _cs_attr.S = True + _cs_attr.P = True + _cs_attr.L = True + _cs.attr = int(_cs_attr) + _ds = bochscpu.Segment() _ds.base = 0 _ds.limit = 0xFFFF_FFFF _ds.selector = thread.Context.SegDs _ds.attr = 0xCF3 - _ds.present = True + _es = bochscpu.Segment() _es.base = 0 _es.limit = 0xFFFF_FFFF diff --git a/examples/real_mode_print_hello.py b/examples/real_mode_print_hello.py index 4da651e..aea70de 100644 --- a/examples/real_mode_print_hello.py +++ b/examples/real_mode_print_hello.py @@ -1,100 +1,170 @@ -import logging -import os - -import keystone -import bochscpu -import bochscpu.cpu -import bochscpu.memory - - -def hexdump( - source: bytes, length: int = 0x10, separator: str = ".", base: int = 0x00 -) -> str: - result = [] - align = 0x8 * 2 + 2 - - for i in range(0, len(source), length): - chunk = bytearray(source[i : i + length]) - hexa = " ".join(map(lambda x: f"{x:02X}", chunk)) - text = "".join([chr(b) if 0x20 <= b < 0x7F else separator for b in chunk]) - result.append(f"{base + i:#0{align}x} {hexa:<{3 * length}} {text}") - return os.linesep.join(result) - - -def missing_page_cb(gpa: int): - raise Exception(f"missing_page_cb({gpa=:#x})") - - -def after_execution_cb(sess: bochscpu.Session, cpu_id: int, insn: int): - logging.info(f"[CPU#{cpu_id}] {insn=}") - - -def exception_cb( - sess: bochscpu.Session, - cpu_id: int, - vector: int, - error_code: int, -): - v = bochscpu.cpu.ExceptionType(vector) - match (vector, error_code): - case _: - logging.warning(f"cpu#{cpu_id} received exception({v}, {error_code=:d}) ") - sess.stop() - - -if __name__ == "__main__": - logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.DEBUG) - - # - # Use Keystone to compile the assembly - # - ks = keystone.Ks(keystone.KS_ARCH_X86, keystone.KS_MODE_16) - code_str = """ -mov ah, 0xe -mov al, 0x41 -int 0x16 -hlt -""" - code, _ = ks.asm(code_str) - assert isinstance(code, list) - code = bytes(code) - logging.debug(f"Compiled {len(code)} bytes") - code = code.ljust(510, b"\x00") + b"\x55\xaa" - - # print(hexdump(code)) - - # - # Expose the code to bochs - # - hva = bochscpu.memory.allocate_host_page() - gpa = 0x0000_7000 - bochscpu.memory.page_insert(gpa, hva) - bochscpu.memory.phy_write(gpa, code) - - # - # Create the VM with the desired callbacks - # - sess = bochscpu.Session() - sess.missing_page_handler = missing_page_cb - - state = bochscpu.State() - state.cr0 = 0 - state.cr4 = 0 - state.rsp = gpa + bochscpu.memory.page_size() // 2 - state.rip = gpa - sess.cpu.state = state - - h = bochscpu.Hook() - h.exception = exception_cb - h.after_execution = after_execution_cb - - sess.run( - [ - h, - ] - ) - - # - # Cleanup - # - bochscpu.memory.release_host_page(hva) +import logging +import os + +import keystone +import bochscpu +import bochscpu.cpu +import bochscpu.memory +import bochscpu.utils + + +def hexdump( + source: bytes, length: int = 0x10, separator: str = ".", base: int = 0x00 +) -> str: + result = [] + align = length + 2 + + for i in range(0, len(source), length): + chunk = bytearray(source[i : i + length]) + hexa = " ".join(map(lambda x: f"{x:02X}", chunk)) + text = "".join([chr(b) if 0x20 <= b < 0x7F else separator for b in chunk]) + result.append(f"{base + i:#0{align}x} {hexa:<{3 * length}} {text}") + return os.linesep.join(result) + + +def missing_page_cb(gpa: int): + raise Exception(f"missing_page_cb({gpa=:#x})") + + +def before_execution_cb(sess: bochscpu.Session, cpu_id: int, _: int): + logging.info(f"[CPU#{cpu_id}] before PC={sess.cpu.rip:#x}") + + +def after_execution_cb(sess: bochscpu.Session, cpu_id: int, _: int): + logging.info(f"[CPU#{cpu_id}] after PC={sess.cpu.rip:#x}") + + +def phy_access_cb(sess, cpu_id, a2, a3, a4, a5): + logging.debug(f"[CPU#{cpu_id}] {a2=:#x}") + + +def reset_cb(sess, a1, a2): + print(f"{a1=:} {a2=:}") + + +def interrupt_cb(sess, a1, a2): + print(f"{a1=:} {a2=:}") + + +def hw_interrupt_cb(sess, a1, a2, a3, a4): + print(f"{a1=:} {a2=:}") + + +def exception_cb( + sess: bochscpu.Session, + cpu_id: int, + vector: int, + error_code: int, +): + v = bochscpu.cpu.ExceptionType(vector) + match (vector, error_code): + case _: + logging.warning(f"cpu#{cpu_id} received exception({v}, {error_code=:d}) ") + sess.stop() + + +if __name__ == "__main__": + logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.DEBUG) + + # + # Use Keystone to compile the assembly + # + ks = keystone.Ks(keystone.KS_ARCH_X86, keystone.KS_MODE_16) + code_str = """ +loop: +jmp loop + +hlt +""" + code, _ = ks.asm(code_str) + assert isinstance(code, list) + code = bytes(code) + logging.debug(f"Compiled {len(code)} bytes") + code = code.ljust(510, b"\x00") + b"\x55\xaa" + + # print(hexdump(code)) + + # + # Create the code page + # + code_hva = bochscpu.memory.allocate_host_page() + code_gpa = 0x000_7000 + bochscpu.memory.page_insert(code_gpa, code_hva) + bochscpu.memory.phy_write(code_gpa + 0xC00, code) + + # _cs = bochscpu.Segment() + # _cs.base = 0 + # _cs.limit = 0x0000_0FFF + # _cs.selector = 0x0000 + # cs_attr = bochscpu.cpu.SegmentFlags() + # cs_attr.P = True + # cs_attr.E = True + # cs_attr.DB = False + # cs_attr.G = False + # _cs.attr = int(cs_attr) + # _cs.present = True + + # _ds = bochscpu.Segment() + # _ds.base = 0 + # _ds.limit = 0x0000_0FFF + # _ds.selector = 0x0000 + # ds_attr = bochscpu.cpu.SegmentFlags() + # ds_attr.P = True + # ds_attr.E = False + # ds_attr.DB = False + # ds_attr.G = False + # _ds.attr = int(ds_attr) + # _ds.present = True + + # _ss = bochscpu.Segment() + # _ss.present = True + # _ss.base = 0 + # _ss.selector = 0x0000 + # _ss.limit = 0x0000_7FFF + # ss_attr = bochscpu.cpu.SegmentFlags() + # ss_attr.D = True + # ss_attr.W = True + # ss_attr.G = False + # _ss.attr = int(ss_attr) + + # + # Create the VM with the desired callbacks + # + sess = bochscpu.Session() + sess.missing_page_handler = missing_page_cb + + state = bochscpu.State() + bochscpu.cpu.set_real_mode(state) + + # + # Assign segment to the state, CS and SS are always required + # + # state.cs = _cs + # state.ss = _ss + + state.rsp = 0x7000 + state.rip = 0x7C00 + + # bochscpu.utils.dump_registers(state) + + sess.cpu.state = state + + h = bochscpu.Hook() + h.exception = exception_cb + h.before_execution = before_execution_cb + h.after_execution = after_execution_cb + h.phy_access = phy_access_cb + h.reset = reset_cb + h.interrupt = interrupt_cb + h.hw_interrupt = hw_interrupt_cb + + sess.run( + [ + h, + ] + ) + + # + # Cleanup + # + bochscpu.memory.release_host_page(code_hva) diff --git a/examples/template.py b/examples/template.py new file mode 100644 index 0000000..9a8711e --- /dev/null +++ b/examples/template.py @@ -0,0 +1,121 @@ +# +# This snippet does nothing, but can be used as a template for quickly build stuff from bochscpu +# +import logging + +import bochscpu +import bochscpu.cpu +import bochscpu.memory +import bochscpu.utils + + +# +# Callbacks +# +def missing_page_cb(gpa: int): + """Edit this function to change the page fault behavior + Args: + gpa (int): the physical address of where the page fault occured + """ + raise RuntimeError(f"missing_page_cb({gpa=:#x})") + + +def before_execution_cb(sess: bochscpu.Session, cpu_id: int, _: int): + logging.debug(f"[CPU#{cpu_id}] before PC={sess.cpu.rip:#x}") + + +def after_execution_cb(sess: bochscpu.Session, cpu_id: int, _: int): + logging.debug(f"[CPU#{cpu_id}] after PC={sess.cpu.rip:#x}") + + +def phy_access_cb(sess: bochscpu.Session, cpu_id, a2, a3, a4, a5): + logging.debug(f"[CPU#{cpu_id}] {a2=:#x}") + + +def reset_cb(sess: bochscpu.Session, a1, a2): + logging.debug(f"{a1=:} {a2=:}") + + +def interrupt_cb(sess: bochscpu.Session, a1, a2): + logging.debug(f"{a1=:} {a2=:}") + + +def hw_interrupt_cb(sess: bochscpu.Session, a1, a2, a3, a4): + logging.debug(f"{a1=:} {a2=:} {a3=:} {a4=:} ") + + +def exception_cb( + sess: bochscpu.Session, + cpu_id: int, + vector: int, + error_code: int, +): + v = bochscpu.cpu.ExceptionType(vector) + match (vector, error_code): + case _: + logging.warning(f"cpu#{cpu_id} received exception({v}, {error_code=:d}) ") + sess.stop() + + +def run(): + # + # Allocate a page on host, expose it to bochs, and fill it up + # + code_hva = bochscpu.memory.allocate_host_page() + code_gpa = 0x0000_7000 + bochscpu.memory.page_insert(code_gpa, code_hva) + bochscpu.memory.phy_write(code_gpa, b"\xcc" * bochscpu.memory.page_size()) + + # + # Create a session. A session **MUST** have at least a callback pointing to a custom + # page fault handler + # + sess = bochscpu.Session() + sess.missing_page_handler = missing_page_cb + + # + # Create a CPU state and assign it to the session. The different x86 modes can be set + # thanks to helpers located in `bochscpu.cpu.set_XXXX_mode` where XXXX can be: + # - real + # - virtual8086 + # - protected + # - long + # + state = bochscpu.State() + bochscpu.cpu.set_real_mode(state) + state.rip = code_gpa + state.rsp = code_gpa + 0x0800 + sess.cpu.state = state + + # + # Define one (or several) chains of callbacks and bind them to the session + # + hook = bochscpu.Hook() + hook.exception = exception_cb + hook.before_execution = before_execution_cb + hook.after_execution = after_execution_cb + hook.phy_access = phy_access_cb + hook.reset = reset_cb + hook.interrupt = interrupt_cb + hook.hw_interrupt = hw_interrupt_cb + + # + # Let it go + # + sess.run( + [ + hook, + ] + ) + + # + # With the execution finished, you can read the final state of the CPU + # + final_state = sess.cpu.state + print(f"RIP={final_state.rip:#x}") + bochscpu.memory.release_host_page(code_hva) + + +if __name__ == "__main__": + logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.INFO) + run() diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..29b5352 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,21 @@ +site_name: Python bindings for `bochscpu` +theme: + name: material + font: + text: Roboto + code: Roboto Mono + features: + - navigation.instant + - navigation.tabs + + +nav: +- Home: README.md +- Gallery: gallery.md +- Setup: + - Installation: install.md + - Building: build.md +- Usage: + - Basic Examples: examples.md +- Development: + - API: api/README.md diff --git a/python/bochscpu/_bochscpu/cpu/__init__.pyi b/python/bochscpu/_bochscpu/cpu/__init__.pyi index 6bd8e8f..1ea8548 100644 --- a/python/bochscpu/_bochscpu/cpu/__init__.pyi +++ b/python/bochscpu/_bochscpu/cpu/__init__.pyi @@ -10,6 +10,7 @@ class ControlRegister: @ref AMD Manual Vol 2 - 3-9 (EFER) """ + def __init__(self, initial_value: int = 0) -> None: ... @property def AM(self) -> bool: """ @@ -338,8 +339,9 @@ class ControlRegister: def x87(self) -> bool: """Get x87 CR4 Flag""" ... - def __init__(self) -> None: ... def __int__(self) -> int: ... + def __repr__(self) -> str: ... + def __str__(self) -> str: ... class ControlRegisterFlag(Flag): """ @@ -395,12 +397,6 @@ class ControlRegisterFlag(Flag): VME: ControlRegisterFlag """ Virtual-8086 Mode Extensions R/W """ - def __init__(*args, **kwargs): - """ - Initialize self. See help(type(self)) for accurate signature. - """ - ... - class FlagRegisterFlag(Flag): ID: FlagRegisterFlag """ID Flag R/W""" @@ -448,6 +444,7 @@ class FlagRegisterFlag(Flag): """Carry Flag R/W""" class FlagRegister: + def __init__(self, initial_value: int = 0) -> None: ... @property def ID(self) -> bool: """Get ID Flag R/W""" @@ -601,6 +598,8 @@ class FlagRegister: """Set Carry Flag R/W""" ... def __int__(self) -> int: ... + def __repr__(self) -> str: ... + def __str__(self) -> str: ... class FeatureRegisterFlag(Flag): TCE: FeatureRegisterFlag @@ -621,6 +620,7 @@ class FeatureRegisterFlag(Flag): """System Call Extensions R/W""" class FeatureRegister: + def __init__(self, initial_value: int = 0) -> None: ... @property def TCE(self) -> bool: """Get Translation Cache Extension R/W""" @@ -686,6 +686,156 @@ class FeatureRegister: """Set System Call Extensions R/W""" ... def __int__(self) -> int: ... + def __repr__(self) -> str: ... + def __str__(self) -> str: ... + +class SegmentRegisterFlag(Enum): + """SegmentRegisterFlag class""" + + RPL0: SegmentRegisterFlag + """Low-bit for Requested Privilege Level""" + RPL1: SegmentRegisterFlag + """High-bit for Requested Privilege Level""" + +class SegmentFlag(Enum): + """SegmentFlag class""" + + A: SegmentFlag + """Accessed""" + R: SegmentFlag + """Readable - CS only""" + W: SegmentFlag + """Writable - DS/ES/FS/SS only""" + C: SegmentFlag + """Conforming""" + D: SegmentFlag + """Expend-down (Data)""" + E: SegmentFlag + """Executable - CS only (1) otherwise (0)""" + S: SegmentFlag + """SegmentType - CS/SS only (1)""" + DPL0: SegmentFlag + """Low-bit for Descriptor Privilege Level""" + DPL1: SegmentFlag + """High-bit for Descriptor Privilege Level""" + P: SegmentFlag + """Present""" + AVL: SegmentFlag + """Available bit""" + L: SegmentFlag + """Long bit - CS only""" + DB: SegmentFlag + """(32b) Default-Operand Size (D) Bit - CS only (1)""" + G: SegmentFlag + """Granularity (G) Bit - CS only""" + +class SegmentFlags: + """SegmentFlags class""" + + @property + def A(self) -> bool: + """Get Accessed bit""" + ... + @A.setter + def A(self, value: bool): + """Set Accessed bit""" + ... + @property + def R(self) -> bool: + """Get Readable - CS only""" + ... + @R.setter + def R(self, value: bool): + """Set Readable - CS only""" + ... + @property + def W(self) -> bool: + """Get Writable - DS/ES/FS/SS only""" + ... + @W.setter + def W(self, value: bool): + """Set Writable - DS/ES/FS/SS only""" + ... + @property + def D(self) -> bool: + """Get Expand-Down bit""" + ... + @D.setter + def D(self, value: bool): + """Set Expand-Down bit""" + ... + @property + def C(self) -> bool: + """Get Conforming bit""" + ... + @C.setter + def C(self, value: bool): + """Set Conforming bit""" + ... + @property + def E(self) -> bool: + """Get Executable bit - CS only (1) otherwise (0)""" + ... + @E.setter + def E(self, value: bool): + """Set Executable bit - CS only (1) otherwise (0)""" + ... + @property + def S(self) -> bool: + """Get SegmentType - CS/SS only (1)""" + ... + @S.setter + def S(self, value: bool): + """Set SegmentType - CS/SS only (1)""" + ... + @property + def DPL(self) -> int: + """Get Descriptor Privilege Level""" + ... + @DPL.setter + def DPL(self, value: int): + """Set Descriptor Privilege Level""" + ... + @property + def P(self) -> bool: + """Get Present bit""" + ... + @P.setter + def P(self, value: bool): + """Set Present bit""" + ... + @property + def AVL(self) -> bool: + """AvailGet able bit""" + @AVL.setter + def AVL(self, value: bool): + """Set Available bit""" + ... + @property + def L(self) -> bool: + """Get Long bit - CS only""" + @L.setter + def L(self, value: bool): + """Set Long bit - CS only""" + ... + @property + def DB(self) -> bool: + """Get (32b) Default-Operand Size (D) Bit - CS only (1)""" + @DB.setter + def DB(self, value: bool): + """(Set 32b) Default-Operand Size (D) Bit - CS only (1)""" + ... + @property + def G(self) -> bool: + """Get Granularity (G) Bit - CS only""" + @G.setter + def G(self, value: bool): + """Set Granularity (G) Bit - CS only""" + ... + def __int__(self) -> int: ... + def __repr__(self) -> str: ... + def __str__(self) -> str: ... + def __init__(self, initial_value: int = 0) -> None: ... class ExceptionType(Enum): DivideError: ExceptionType diff --git a/python/bochscpu/cpu/__init__.py b/python/bochscpu/cpu/__init__.py index 590f599..23c3da8 100644 --- a/python/bochscpu/cpu/__init__.py +++ b/python/bochscpu/cpu/__init__.py @@ -2,6 +2,12 @@ from bochscpu._bochscpu.cpu import * # type: ignore +import bochscpu.cpu + +# +# Globally using AMD Vol 2 - Figure 1-6 Operating Modes of the AMD64 Architecture +# + def set_long_mode(state: State): """ @@ -39,14 +45,19 @@ def set_long_mode(state: State): def set_real_mode(state: State): + """Set the CPU state to Protected Mode. CR0, CR4, and EFER will be overwritten. + + Args: + state (State): _description_ + """ cr0 = ControlRegister() - cr0.PE = False # Enable protected mode + cr0.PE = False cr4 = ControlRegister() cr4.PAE = False - efer = FeatureRegister() - efer.LME = False + efer = FeatureRegister(0) + efer.LMA = False state.cr0 = int(cr0) state.cr4 = int(cr4) @@ -54,20 +65,53 @@ def set_real_mode(state: State): return -# TODO virtual 8086, 32b compat +def set_virtual8086_mode(state: State): + """Set the CPU state to Protected Mode. CR0, CR4, EFER and RFLAGS will be + overwritten. + + Args: + state (State): _description_ + """ + cr0 = ControlRegister() + cr0.PE = True + + cr4 = ControlRegister() + cr4.PAE = False + + efer = FeatureRegister() + efer.LMA = False + + rflags = FlagRegister() + rflags.VM = True + + state.cr0 = int(cr0) + state.cr4 = int(cr4) + state.efer = int(efer) + state.rflags = int(rflags) + return def set_protected_mode(state: State): + """Set the CPU state to Protected Mode. CR0, CR4, EFER and RFLAGS will be + overwritten. + + Args: + state (State): _description_ + """ cr0 = ControlRegister() - cr0.PE = True # Enable protected mode + cr0.PE = True cr4 = ControlRegister() cr4.PAE = False efer = FeatureRegister() - efer.LME = False + efer.LMA = False + + rflags = FlagRegister() + rflags.VM = False state.cr0 = int(cr0) state.cr4 = int(cr4) state.efer = int(efer) + state.rflags = int(rflags) return diff --git a/python/bochscpu/utils/__init__.py b/python/bochscpu/utils/__init__.py index b3010a8..f1ce160 100644 --- a/python/bochscpu/utils/__init__.py +++ b/python/bochscpu/utils/__init__.py @@ -15,6 +15,7 @@ def dump_registers(state: _bochscpu.State, include_kernel: bool = False): state (_bochscpu.State): _description_ include_kernel (bool): _description_ """ + # TODO adjust registers depending on cpu mode print( f""" rax={state.rax:016x} rbx={state.rbx:016x} rcx={state.rcx:016x} diff --git a/python/inc/bochscpu.hpp b/python/inc/bochscpu.hpp index 05d8408..244dbb9 100644 --- a/python/inc/bochscpu.hpp +++ b/python/inc/bochscpu.hpp @@ -236,6 +236,34 @@ exception_cb(context_t* ctx, uint32_t cpu_id, unsigned vector, unsigned error_co namespace Cpu { +enum class SegmentRegisterFlag : uint16_t +{ + RPL0 = 0, // Low-bit for Requested Privilege Level + RPL1 = 1, // High-bit for Requested Privilege Level +}; + + +enum class SegmentFlag : uint16_t +{ + /// CS - AMD Manual Vol2 - 4.7.2 + /// DS - AMD Manual Vol2 - 4.7.3 + A = 0, // Accessed bit + R = 1, // Readable bit - CS only + W = 1, // Writable bit - DS/ES/FS/SS only + C = 2, // Conforming bit + D = 2, // Expend-down (Data) + E = 3, // Executable bit (Code - 1) + S = 4, // SegmentType bit - CS/SS only (1) + DPL0 = 5, // Low-bit for Descriptor Privilege Level + DPL1 = 6, // High-bit for Descriptor Privilege Level + P = 7, // Present bit + AVL = 12, // Available bit + L = 13, // Long bit - CS only + DB = 14, // (32b) Default-Operand Size (D) Bit - CS only (1) + G = 15, // Granularity (G) Bit - CS only +}; + + enum class ControlRegisterFlag : uint64_t { /// CR0 - AMD Manual Vol2 - 3.1.1 @@ -322,19 +350,22 @@ struct ControlRegister : std::bitset<64> { }; - struct FlagRegister : std::bitset<64> { - FlagRegister() - { - set((int)FlagRegisterFlag::Reserved1, true); - } }; struct FeatureRegister : std::bitset<64> { }; +struct SegmentRegisterFlags : std::bitset<2> +{ +}; + +struct SegmentFlags : std::bitset<16> +{ +}; + static uint32_t g_sessionId = 0; diff --git a/python/src/bochscpu_callbacks.cpp b/python/src/bochscpu_callbacks.cpp index e187269..7bd9312 100644 --- a/python/src/bochscpu_callbacks.cpp +++ b/python/src/bochscpu_callbacks.cpp @@ -33,7 +33,6 @@ before_execution_cb(context_t* ctx, uint32_t cpu_id, void* insn) ExecuteCallback(ctx, before_execution, cpu_id, insn); } - void after_execution_cb(context_t* ctx, uint32_t cpu_id, void* insn) { diff --git a/python/src/bochscpu_cpu.cpp b/python/src/bochscpu_cpu.cpp index 96d73ca..2a813fd 100644 --- a/python/src/bochscpu_cpu.cpp +++ b/python/src/bochscpu_cpu.cpp @@ -1,11 +1,41 @@ #include #include +#include + +#include #include "bochscpu.hpp" namespace nb = nanobind; using namespace nb::literals; +#define GenericGetterSetterStatic(cls, name, enum_cls, desc, value) \ + def_prop_rw( \ + #name, \ + [](cls const& x) \ + { \ + return x.test((int)enum_cls::name); \ + }, \ + [](cls& x, bool b) \ + { \ + x.set((int)enum_cls::name, value); \ + }, \ + desc) + +#define GenericGetterSetter(cls, name, enum_cls, desc) \ + def_prop_rw( \ + #name, \ + [](cls const& x) \ + { \ + return x.test((int)enum_cls::name); \ + }, \ + [](cls& x, bool b) \ + { \ + x.set((int)enum_cls::name, b); \ + }, \ + desc) + + /// /// @brief BochsCPU CPU submodule Python interface /// @@ -77,314 +107,81 @@ bochscpu_cpu_module(nb::module_& base_module) .export_values(); + +#define GetterSetter(name, desc) \ + GenericGetterSetter(BochsCPU::Cpu::ControlRegister, name, BochsCPU::Cpu::ControlRegisterFlag, desc) + nb::class_(m, "ControlRegister") .def(nb::init<>()) - .def_prop_rw( - "PG", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::PG); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::PG, onoff); - }) - .def_prop_rw( - "CD", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::CD); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::CD, onoff); - }) - .def_prop_rw( - "NW", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::NW); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::NW, onoff); - }) - .def_prop_rw( - "AM", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::AM); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::AM, onoff); - }) - .def_prop_rw( - "WP", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::WP); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::WP, onoff); - }) - .def_prop_rw( - "NE", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::NE); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::NE, onoff); - }) - .def_prop_rw( - "ET", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::ET); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::ET, onoff); - }) - .def_prop_rw( - "TS", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::TS); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::TS, onoff); - }) - .def_prop_rw( - "EM", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::EM); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::EM, onoff); - }) - .def_prop_rw( - "MP", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::MP); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::MP, onoff); - }) - .def_prop_rw( - "PE", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::PE); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::PE, onoff); - }) + .def(nb::init()) - .def_prop_rw( - "OSXSAVE", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::OSXSAVE); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::OSXSAVE, onoff); - }) - .def_prop_rw( - "FSGSBASE", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::FSGSBASE); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::FSGSBASE, onoff); - }) - .def_prop_rw( - "OSXMMEXCPT", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::OSXMMEXCPT); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::OSXMMEXCPT, onoff); - }) - .def_prop_rw( - "OSFXSR", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::OSFXSR); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::OSFXSR, onoff); - }) - .def_prop_rw( - "PCE", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::PCE); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::PCE, onoff); - }) - .def_prop_rw( - "PGE", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::PGE); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::PGE, onoff); - }) - .def_prop_rw( - "MCE", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::MCE); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::MCE, onoff); - }) - .def_prop_rw( - "PAE", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::PAE); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::PAE, onoff); - }) - .def_prop_rw( - "PSE", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::PSE); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::PSE, onoff); - }) - .def_prop_rw( - "DE", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::DE); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::DE, onoff); - }) - .def_prop_rw( - "TSD", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::TSD); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::TSD, onoff); - }) - .def_prop_rw( - "PVI", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::PVI); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::PVI, onoff); - }) - .def_prop_rw( - "VME", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::VME); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::VME, onoff); - }) - .def_prop_rw( - "X", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::X); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::X, onoff); - }) - .def_prop_rw( - "LWP", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::LWP); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::LWP, onoff); - }) - .def_prop_rw( - "YMM", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::YMM); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::YMM, onoff); - }) - .def_prop_rw( - "SSE", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::SSE); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) - { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::SSE, onoff); - }) - .def_prop_rw( - "x87", - [](BochsCPU::Cpu::ControlRegister& cr) - { - return cr.test((int)BochsCPU::Cpu::ControlRegisterFlag::x87); - }, - [](BochsCPU::Cpu::ControlRegister& cr, bool onoff) + // cr0 + .GetterSetter(PG, "Paging R/W") + .GetterSetter(CD, "Cache Disable R/W") + .GetterSetter(NW, "Not Writethrough R/W") + .GetterSetter(AM, "Alignment Mask R/W") + .GetterSetter(WP, "Write Protect R/W") + .GetterSetter(NE, "Numeric Error R/W") + .GetterSetter(ET, "Extension Type R") + .GetterSetter(TS, "Task Switched R/W") + .GetterSetter(EM, "Emulation R/W") + .GetterSetter(MP, "Monitor Coprocessor R/W") + .GetterSetter(PE, "Protection Enabled R/W") + + // cr4 + .GetterSetter(OSXSAVE, "XSAVE and Processor Extended States Enable Bit R/W") + .GetterSetter(FSGSBASE, "Enable RDFSBASE, RDGSBASE, WRFSBASE, and WRGSBASE instructions R/W") + .GetterSetter(OSXMMEXCPT, "Operating System Unmasked Exception Support R/W") + .GetterSetter(OSFXSR, "Operating System FXSAVE/FXRSTOR Support R/W") + .GetterSetter(PCE, "Performance-Monitoring Counter Enable R/W") + .GetterSetter(PGE, "Page-Global Enable R/W") + .GetterSetter(MCE, "Machine Check Enable R/W") + .GetterSetter(PAE, "Physical-Address Extension R/W") + .GetterSetter(PSE, "Page Size Extensions R/W") + .GetterSetter(DE, "Debugging Extensions R/W") + .GetterSetter(TSD, "Time Stamp Disable R/W") + .GetterSetter(PVI, "Protected-Mode Virtual Interrupts R/W") + .GetterSetter(VME, "Virtual-8086 Mode Extensions R/W") + + // xcr0 + .GetterSetter(X, "Reserved specifically for XCR0 bit vector expansion. ") + .GetterSetter( + LWP, + "When set, Lightweight Profiling (LWP) extensions are enabled and XSAVE/XRSTOR supports LWP state " + "management.") + .GetterSetter( + YMM, + "When set, 256-bit SSE state management is supported by XSAVE/XRSTOR. Must be set to enable AVX " + "extensions.") + .GetterSetter( + SSE, + "When set, 128-bit SSE state management is supported by XSAVE/XRSTOR. This bit must be set if YMM is set. " + "Must be set to enable AVX extensions.") + .GetterSetter(x87, "x87 FPU state management is supported by XSAVE/XRSTOR. Must be set to 1.") + + .def( + "__repr__", + [](BochsCPU::Cpu::ControlRegister const& x) { - cr.set((int)BochsCPU::Cpu::ControlRegisterFlag::x87, true); // Always be One + return x.to_string(); }) .def( - "__repr__", - [](BochsCPU::Cpu::ControlRegister& cr) + "__str__", + [](BochsCPU::Cpu::ControlRegister const& x) { - return cr.to_string(); + return x.to_string(); }) .def( "__int__", - [](BochsCPU::Cpu::ControlRegister& cr) + [](BochsCPU::Cpu::ControlRegister const& x) { - return cr.to_ullong(); + return x.to_ullong(); }); +#undef GetterSetter + #pragma endregion -#pragma region FlagRegistrer +#pragma region FlagRegister nb::enum_(m, "FlagRegisterFlag") .value("ID", BochsCPU::Cpu::FlagRegisterFlag::ID, "ID Flag R/W") .value("VIP", BochsCPU::Cpu::FlagRegisterFlag::VIP, "Virtual Interrupt Pending R/W") @@ -410,92 +207,36 @@ bochscpu_cpu_module(nb::module_& base_module) .value("CF", BochsCPU::Cpu::FlagRegisterFlag::CF, "Carry Flag R/W") .export_values(); +#define GetterSetter(name, desc) \ + GenericGetterSetter(BochsCPU::Cpu::FlagRegister, name, BochsCPU::Cpu::FlagRegisterFlag, desc) + +#define GetterSetterStatic(name, desc, val) \ + GenericGetterSetterStatic(BochsCPU::Cpu::FlagRegister, name, BochsCPU::Cpu::FlagRegisterFlag, desc, val) + nb::class_(m, "FlagRegister") .def(nb::init<>()) - .def_prop_rw( - "ID", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::ID); - }, - [](BochsCPU::Cpu::FlagRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FlagRegisterFlag::ID, onoff); - }, - "ID Flag R/W") - .def_prop_rw( - "VIP", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::VIP); - }, - [](BochsCPU::Cpu::FlagRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FlagRegisterFlag::VIP, onoff); - }, - "Virtual Interrupt Pending R/W") - .def_prop_rw( - "VIF", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::VIF); - }, - [](BochsCPU::Cpu::FlagRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FlagRegisterFlag::VIF, onoff); - }, - "Virtual Interrupt Flag R/W") - .def_prop_rw( - "AC", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::AC); - }, - [](BochsCPU::Cpu::FlagRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FlagRegisterFlag::AC, onoff); - }, - "Alignment Check R/W") - .def_prop_rw( - "VM", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::VM); - }, - [](BochsCPU::Cpu::FlagRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FlagRegisterFlag::VM, onoff); - }, - "Virtual-8086 Mode R/W") - .def_prop_rw( - "RF", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::RF); - }, - [](BochsCPU::Cpu::FlagRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FlagRegisterFlag::RF, onoff); - }, - "Resume Flag R/W") - .def_prop_ro( - "Reserved4", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::Reserved4); - }, - "Read as Zero") - .def_prop_rw( - "NT", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::NT); - }, - [](BochsCPU::Cpu::FlagRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FlagRegisterFlag::NT, onoff); - }, - "Nested Task R/W") + .def(nb::init()) + .GetterSetter(ID, "ID Flag R/W") + .GetterSetter(VIP, "Virtual Interrupt Pending R/W") + .GetterSetter(VIF, "Virtual Interrupt Flag R/W") + .GetterSetter(AC, "Alignment Check R/W") + .GetterSetter(VM, "Virtual-8086 Mode R/W") + .GetterSetter(RF, "Resume Flag R/W") + .GetterSetterStatic(Reserved4, "Read as Zero", false) + .GetterSetter(NT, "Nested Task R/W") + .GetterSetter(OF, "Overflow Flag R/W") + .GetterSetter(DF, "Direction Flag R/W") + .GetterSetter(IF, "Interrupt Flag R/W") + .GetterSetter(TF, "Trap Flag R/W") + .GetterSetter(SF, "Sign Flag R/W") + .GetterSetter(ZF, "Zero Flag R/W") + .GetterSetterStatic(Reserved3, "Read as Zero", false) + .GetterSetter(AF, "Auxiliary Flag R/W") + .GetterSetterStatic(Reserved2, "Read as Zero", false) + .GetterSetter(PF, "Parity Flag R/W") + .GetterSetterStatic(Reserved1, "Read as One", true) + .GetterSetter(CF, "Carry Flag R/W") + .def_prop_rw( "IOPL", [](BochsCPU::Cpu::FlagRegister& fr) @@ -509,132 +250,28 @@ bochscpu_cpu_module(nb::module_& base_module) fr.set((int)BochsCPU::Cpu::FlagRegisterFlag::IOPL1, iopl & 1); }, "IOPL I/O Privilege Level R/W") - .def_prop_rw( - "OF", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::OF); - }, - [](BochsCPU::Cpu::FlagRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FlagRegisterFlag::OF, onoff); - }, - "Overflow Flag R/W") - .def_prop_rw( - "DF", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::DF); - }, - [](BochsCPU::Cpu::FlagRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FlagRegisterFlag::DF, onoff); - }, - "Direction Flag R/W") - .def_prop_rw( - "IF", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::IF); - }, - [](BochsCPU::Cpu::FlagRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FlagRegisterFlag::IF, onoff); - }, - "Interrupt Flag R/W") - .def_prop_rw( - "TF", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::TF); - }, - [](BochsCPU::Cpu::FlagRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FlagRegisterFlag::TF, onoff); - }, - "Trap Flag R/W") - .def_prop_rw( - "SF", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::SF); - }, - [](BochsCPU::Cpu::FlagRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FlagRegisterFlag::SF, onoff); - }, - "Sign Flag R/W") - .def_prop_rw( - "ZF", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::ZF); - }, - [](BochsCPU::Cpu::FlagRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FlagRegisterFlag::ZF, onoff); - }, - "Zero Flag R/W") - .def_prop_ro( - "Reserved3", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::Reserved3); - }, - "Read as Zero") - .def_prop_rw( - "AF", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::AF); - }, - [](BochsCPU::Cpu::FlagRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FlagRegisterFlag::AF, onoff); - }, - "Auxiliary Flag R/W") - .def_prop_ro( - "Reserved2", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::Reserved2); - }, - "Read as Zero") - .def_prop_rw( - "PF", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::PF); - }, - [](BochsCPU::Cpu::FlagRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FlagRegisterFlag::PF, onoff); - }, - "Parity Flag R/W") - .def_prop_ro( - "Reserved1", - [](BochsCPU::Cpu::FlagRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::Reserved1); - }, - "Read as One") - .def_prop_rw( - "CF", - [](BochsCPU::Cpu::FlagRegister& fr) + + .def( + "__repr__", + [](BochsCPU::Cpu::FlagRegister const& x) { - return fr.test((int)BochsCPU::Cpu::FlagRegisterFlag::CF); - }, - [](BochsCPU::Cpu::FlagRegister& fr, bool onoff) + return x.to_string(); + }) + .def( + "__str__", + [](BochsCPU::Cpu::FlagRegister const& x) { - fr.set((int)BochsCPU::Cpu::FlagRegisterFlag::CF, onoff); - }, - "Carry Flag R/W") + return x.to_string(); + }) .def( "__int__", - [](BochsCPU::Cpu::FlagRegister& fr) + [](BochsCPU::Cpu::FlagRegister const& x) { - return fr.to_ullong(); + return x.to_ullong(); }); +#undef GetterSetter +#undef GetterSetterStatic + #pragma endregion #pragma region FeatureRegister @@ -650,103 +287,136 @@ bochscpu_cpu_module(nb::module_& base_module) .value("SCE", BochsCPU::Cpu::FeatureRegisterFlag::SCE, "System Call Extensions R/W") .export_values(); + +#define GetterSetter(name, desc) \ + GenericGetterSetter(BochsCPU::Cpu::FeatureRegister, name, BochsCPU::Cpu::FeatureRegisterFlag, desc) + nb::class_(m, "FeatureRegister") .def(nb::init<>()) - - .def_prop_rw( - "TCE", - [](BochsCPU::Cpu::FeatureRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FeatureRegisterFlag::TCE); - }, - [](BochsCPU::Cpu::FeatureRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FeatureRegisterFlag::TCE, onoff); - }, - "Translation Cache Extension R/W") - .def_prop_rw( - "FFXSR", - [](BochsCPU::Cpu::FeatureRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FeatureRegisterFlag::FFXSR); - }, - [](BochsCPU::Cpu::FeatureRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FeatureRegisterFlag::FFXSR, onoff); - }, - "Fast FXSAVE/FXRSTOR R/W") - .def_prop_rw( - "LMSLE", - [](BochsCPU::Cpu::FeatureRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FeatureRegisterFlag::LMSLE); - }, - [](BochsCPU::Cpu::FeatureRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FeatureRegisterFlag::LMSLE, onoff); - }, - "Long Mode Segment Limit Enable R/W") - .def_prop_rw( - "SVME", - [](BochsCPU::Cpu::FeatureRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FeatureRegisterFlag::SVME); - }, - [](BochsCPU::Cpu::FeatureRegister& fr, bool onoff) - { - fr.set((int)BochsCPU::Cpu::FeatureRegisterFlag::SVME, onoff); - }, - "Secure Virtual Machine Enable R/W") - .def_prop_rw( - "NXE", - [](BochsCPU::Cpu::FeatureRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FeatureRegisterFlag::NXE); - }, - [](BochsCPU::Cpu::FeatureRegister& fr, bool onoff) + .def(nb::init()) + .GetterSetter(TCE, "Translation Cache Extension R/W") + .GetterSetter(FFXSR, "Fast FXSAVE/FXRSTOR R/W") + .GetterSetter(LMSLE, "Long Mode Segment Limit Enable R/W") + .GetterSetter(SVME, "Secure Virtual Machine Enable R/W") + .GetterSetter(NXE, "No-Execute Enable R/W") + .GetterSetter(LMA, "Long Mode Active R/W") + .GetterSetter(LME, "Long Mode Enable R/W") + .GetterSetter(SCE, "System Call Extensions R/W") + .def( + "__repr__", + [](BochsCPU::Cpu::FeatureRegister const& x) { - fr.set((int)BochsCPU::Cpu::FeatureRegisterFlag::NXE, onoff); - }, - "No-Execute Enable R/W") - .def_prop_rw( - "LMA", - [](BochsCPU::Cpu::FeatureRegister& fr) + return x.to_string(); + }) + .def( + "__str__", + [](BochsCPU::Cpu::FeatureRegister const& x) { - return fr.test((int)BochsCPU::Cpu::FeatureRegisterFlag::LMA); - }, - [](BochsCPU::Cpu::FeatureRegister& fr, bool onoff) + return x.to_string(); + }) + .def( + "__int__", + [](BochsCPU::Cpu::FeatureRegister const& x) { - fr.set((int)BochsCPU::Cpu::FeatureRegisterFlag::LMA, onoff); - }, - "Long Mode Active R/W") + return x.to_ullong(); + }); +#undef GetterSetter + +#pragma endregion + +#pragma region SegmentRegister + + nb::enum_(m, "SegmentRegisterFlag") + .value("RPL0", BochsCPU::Cpu::SegmentRegisterFlag::RPL0, "Low-bit for Requested Privilege Level") + .value("RPL1", BochsCPU::Cpu::SegmentRegisterFlag::RPL1, "High-bit for Requested Privilege Level") + .export_values(); + + nb::enum_(m, "SegmentFlag") + .value("A", BochsCPU::Cpu::SegmentFlag::A, "Accessed") + .value("R", BochsCPU::Cpu::SegmentFlag::R, "Readable - CS only") + .value("W", BochsCPU::Cpu::SegmentFlag::W, "Writable - DS/ES/FS/SS only") + .value("C", BochsCPU::Cpu::SegmentFlag::C, "Conforming") + .value("D", BochsCPU::Cpu::SegmentFlag::D, "Expand-down (Data)") + .value("E", BochsCPU::Cpu::SegmentFlag::E, "Executable - CS only (1) else (0)") + .value("S", BochsCPU::Cpu::SegmentFlag::S, "SegmentType - CS/SS only (1)") + .value("DPL0", BochsCPU::Cpu::SegmentFlag::DPL0, "Low-bit for Descriptor Privilege Level") + .value("DPL1", BochsCPU::Cpu::SegmentFlag::DPL1, "High-bit for Descriptor Privilege Level") + .value("P", BochsCPU::Cpu::SegmentFlag::P, "Present") + .value("AVL", BochsCPU::Cpu::SegmentFlag::AVL, "Available bit") + .value("L", BochsCPU::Cpu::SegmentFlag::L, "Long bit - CS only") + .value("DB", BochsCPU::Cpu::SegmentFlag::DB, "(32b) Default-Operand Size (D) Bit - CS only (1)") + .value("G", BochsCPU::Cpu::SegmentFlag::G, "Granularity (G) Bit - CS only") + .export_values(); + +#define GetterSetter(name, desc) \ + GenericGetterSetter(BochsCPU::Cpu::SegmentFlags, name, BochsCPU::Cpu::SegmentFlag, desc) + + nb::class_(m, "SegmentFlags") + .def(nb::init<>()) + .def(nb::init()) + .GetterSetter(A, "Accessed bit") + .GetterSetter(R, "Readable bit - CS only") + .GetterSetter(W, "Writable bit - DS/ES/FS/SS only") + .GetterSetter(C, "Conforming bit") + .GetterSetter(D, "Expand-down (Data)") + .GetterSetter(E, "Executable bit - CS only (1) otherwise (0)") + .GetterSetter(S, "SegmentType bit - CS/SS only (1)") + .GetterSetter(P, "Present bit") + .GetterSetter(AVL, "Available bit") + .GetterSetter(L, "Long bit - CS only") + .GetterSetter(DB, "(32b) Default-Operand Size (D) Bit - CS only (1)") + .GetterSetter(G, "Granularity (G) Bit - CS only") + .def_prop_rw( - "LME", - [](BochsCPU::Cpu::FeatureRegister& fr) + "DPL", + [](BochsCPU::Cpu::SegmentFlags& x) { - return fr.test((int)BochsCPU::Cpu::FeatureRegisterFlag::LME); + return int(x.test((int)BochsCPU::Cpu::SegmentFlag::DPL1)) << 1 | + int(x.test((int)BochsCPU::Cpu::SegmentFlag::DPL0)) << 0; }, - [](BochsCPU::Cpu::FeatureRegister& fr, bool onoff) + [](BochsCPU::Cpu::SegmentFlags& x, uint8_t dpl) { - fr.set((int)BochsCPU::Cpu::FeatureRegisterFlag::LME, onoff); + x.set((int)BochsCPU::Cpu::SegmentFlag::DPL1, dpl & 2); + x.set((int)BochsCPU::Cpu::SegmentFlag::DPL0, dpl & 1); }, - "Long Mode Enable R/W") - .def_prop_rw( - "SCE", - [](BochsCPU::Cpu::FeatureRegister& fr) - { - return fr.test((int)BochsCPU::Cpu::FeatureRegisterFlag::SCE); - }, - [](BochsCPU::Cpu::FeatureRegister& fr, bool onoff) + "IOPL I/O Privilege Level R/W") + + .def( + "__repr__", + [](BochsCPU::Cpu::SegmentFlags const& x) { - fr.set((int)BochsCPU::Cpu::FeatureRegisterFlag::SCE, onoff); - }, - "System Call Extensions R/W") + return x.to_string(); + }) + .def( + "__str__", + [](BochsCPU::Cpu::SegmentFlags const& x) + { + std::ostringstream ss; + ss << "SegmentFlags("; + // clang-format off + if ( x.test((int)BochsCPU::Cpu::SegmentFlag::G) ) ss << " G"; + if ( x.test((int)BochsCPU::Cpu::SegmentFlag::DB) ) ss << " DB"; + if ( x.test((int)BochsCPU::Cpu::SegmentFlag::AVL) ) ss << " AVL"; + if ( x.test((int)BochsCPU::Cpu::SegmentFlag::L) ) ss << " L"; + if ( x.test((int)BochsCPU::Cpu::SegmentFlag::P) ) ss << " P"; + if ( x.test((int)BochsCPU::Cpu::SegmentFlag::S) ) ss << " S"; + if ( x.test((int)BochsCPU::Cpu::SegmentFlag::E) ) ss << " E"; + if ( x.test((int)BochsCPU::Cpu::SegmentFlag::C) ) ss << " C"; + if ( x.test((int)BochsCPU::Cpu::SegmentFlag::W) ) ss << " W"; + if ( x.test((int)BochsCPU::Cpu::SegmentFlag::R) ) ss << " R"; + if ( x.test((int)BochsCPU::Cpu::SegmentFlag::A) ) ss << " A"; + // clang-format on + ss << " )"; + return ss.str(); + }) .def( "__int__", - [](BochsCPU::Cpu::FeatureRegister& fr) + [](BochsCPU::Cpu::SegmentFlags const& x) { - return fr.to_ullong(); + return x.to_ullong(); }); +#undef GetterSetter + #pragma endregion ///