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)
+
+
+
+## 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
///