Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions examples/real_mode_print_hello_world.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ def after_execution_cb(sess: bochscpu.Session, cpu_id: int, insn: int):
logging.debug(f"[CPU#{cpu_id}] after PC={sess.cpu.rip:#08x}")


def cnear_branch_not_taken_cb(sess: bochscpu.Session, cpu_id: int, before: int, after: int):
logging.debug(f"in cnear_branch_not_taken_cb, {cpu_id=:#x} {before=:#x} {after=:#x}")
def cnear_branch_not_taken_cb(
sess: bochscpu.Session, cpu_id: int, before: int, after: int
):
logging.debug(
f"in cnear_branch_not_taken_cb, {cpu_id=:#x} {before=:#x} {after=:#x}"
)


def cnear_branch_taken_cb(sess: bochscpu.Session, cpu_id: int, before: int, after: int):
Expand All @@ -39,12 +43,12 @@ def interrupt_cb(sess: bochscpu.Session, cpu_id: int, int_num: int):
logging.debug(f"in interrupt_cb, {cpu_id=} received {int_num=:#x}")
mode = sess.cpu.state.rax >> 8
match int_num, mode:
case 0x10, 0x0e:
case 0x10, 0x0E:
#
# This is the main juice of the emulated interruption
# ref: https://en.wikipedia.org/wiki/INT_10H
#
char = chr(sess.cpu.state.rax & 0xff)
char = chr(sess.cpu.state.rax & 0xFF)
print(f"{char}", end="")

#
Expand All @@ -65,7 +69,9 @@ def exception_cb(
):
match (vector, error_code):
case _:
logging.warning(f"[CPU#{cpu_id}] Received exception({bochscpu.cpu.ExceptionType(vector)}, {error_code=:d}) ")
logging.warning(
f"[CPU#{cpu_id}] Received exception({bochscpu.cpu.ExceptionType(vector)}, {error_code=:d}) "
)
sess.stop()


Expand All @@ -78,7 +84,9 @@ def emulate(code_str: str, data: bytes):
assert isinstance(code, list)
code = bytes(code)
logging.debug(f"Compiled {len(code)} bytes")
code = code.ljust(PAGE_SIZE, b"\xcc") # Make sure we hit an exception, helpful for debug
code = code.ljust(
PAGE_SIZE, b"\xcc"
) # Make sure we hit an exception, helpful for debug
assert len(code) == PAGE_SIZE

#
Expand Down Expand Up @@ -110,7 +118,7 @@ def emulate(code_str: str, data: bytes):
_cs = bochscpu.Segment()
_cs.base = code_gpa
_cs.limit = PAGE_SIZE
_cs.selector = 6 << 3| 0 << 2 | 0 # DescriptorTable[6], TI=0->GDT, RPL=0
_cs.selector = 6 << 3 | 0 << 2 | 0 # DescriptorTable[6], TI=0->GDT, RPL=0
cs_attr = bochscpu.cpu.SegmentFlags()
cs_attr.P = True
cs_attr.E = True
Expand All @@ -126,8 +134,8 @@ def emulate(code_str: str, data: bytes):
_ss = bochscpu.Segment()
_ss.present = True
_ss.base = stack_gpa
_ss.limit = PAGE_SIZE >> 4 # Granularity is 16b (D off)
_ss.selector = 8 << 3| 0 << 2 | 0 # DescriptorTable[8], TI=0->GDT, RPL=0
_ss.limit = PAGE_SIZE >> 4 # Granularity is 16b (D off)
_ss.selector = 8 << 3 | 0 << 2 | 0 # DescriptorTable[8], TI=0->GDT, RPL=0
ss_attr = bochscpu.cpu.SegmentFlags()
ss_attr.P = True
ss_attr.DB = False
Expand All @@ -144,7 +152,7 @@ def emulate(code_str: str, data: bytes):
_ds.present = True
_ds.base = data_gpa
_ds.limit = PAGE_SIZE
_ds.selector = 10 << 3| 0 << 2 | 0 # DescriptorTable[10], TI=0->GDT, RPL=0
_ds.selector = 10 << 3 | 0 << 2 | 0 # DescriptorTable[10], TI=0->GDT, RPL=0
ds_attr = bochscpu.cpu.SegmentFlags()
ds_attr.P = True
ds_attr.E = False
Expand Down
53 changes: 44 additions & 9 deletions examples/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,26 @@ def clflush_cb(sess: bochscpu.Session, cpu_id: int, lin_addr: int, phy_addr: int
pass


def cnear_branch_not_taken_cb(sess: bochscpu.Session, cpu_id: int, branch_ip: int, new_ip: int):
def cnear_branch_not_taken_cb(
sess: bochscpu.Session, cpu_id: int, branch_ip: int, new_ip: int
):
pass


def cnear_branch_taken_cb(sess: bochscpu.Session, cpu_id: int, branch_ip: int, new_ip: int):
def cnear_branch_taken_cb(
sess: bochscpu.Session, cpu_id: int, branch_ip: int, new_ip: int
):
pass


def far_branch_cb(
sess: bochscpu.Session, cpu_id: int, what: int, prev_cs: int, prev_ip: int, new_cs: int, new_ip: int
sess: bochscpu.Session,
cpu_id: int,
what: int,
prev_cs: int,
prev_ip: int,
new_cs: int,
new_ip: int,
):
pass

Expand All @@ -87,7 +97,13 @@ def interrupt_cb(sess: bochscpu.Session, cpu_id: int, int_num: int):


def lin_access_cb(
sess: bochscpu.Session, cpu_id: int, lin: int, phy: int, len: int, memtype: int, rw: int
sess: bochscpu.Session,
cpu_id: int,
lin: int,
phy: int,
len: int,
memtype: int,
rw: int,
):
pass

Expand All @@ -97,7 +113,13 @@ def mwait_cb(sess: bochscpu.Session, cpu_id: int, addr: int, len: int, flags: in


def opcode_cb(
sess: bochscpu.Session, cpu_id: int, insn: int, opcode: int, len: int, is32: bool, is64: bool
sess: bochscpu.Session,
cpu_id: int,
insn: int,
opcode: int,
len: int,
is32: bool,
is64: bool,
):
pass

Expand All @@ -106,11 +128,15 @@ def outp_cb(sess: bochscpu.Session, cpu_id: int, len: int, val: int):
pass


def phy_access_cb(sess: bochscpu.Session, cpu_id: int, lin: int, phy: int, len: int, rw: int):
def phy_access_cb(
sess: bochscpu.Session, cpu_id: int, lin: int, phy: int, len: int, rw: int
):
pass


def prefetch_hint_cb(sess: bochscpu.Session, cpu_id: int, what: int, seg: int, offset: int):
def prefetch_hint_cb(
sess: bochscpu.Session, cpu_id: int, what: int, seg: int, offset: int
):
pass


Expand All @@ -126,7 +152,9 @@ def tlb_cntrl_cb(sess: bochscpu.Session, cpu_id: int, what: int, new_cr_value: i
pass


def ucnear_branch_cb(sess: bochscpu.Session, cpu_id: int, what: int, branch_ip: int, new_branch_ip: int):
def ucnear_branch_cb(
sess: bochscpu.Session, cpu_id: int, what: int, branch_ip: int, new_branch_ip: int
):
pass


Expand All @@ -152,7 +180,7 @@ def emulate():
# page fault handler
#
sess = bochscpu.Session()
sess.missing_page_handler = missing_page_cb
sess.missing_page_handler = bochscpu.utils.callbacks.missing_page_cb

#
# Create a CPU state and assign it to the session. The different x86 modes can be set
Expand Down Expand Up @@ -202,6 +230,13 @@ def emulate():
hook.vmexit = vmexit_cb
hook.wrmsr = wrmsr_cb

#
# Since 0.2.0 you can use the helper `callbacks` helper module to quickly install default
# callbacks as such:
#
# bochscpu.utils.callbacks.install_default_callbacks(hook)
#

#
# Create the hook chain
#
Expand Down
15 changes: 14 additions & 1 deletion python/bochscpu/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,17 @@
#
# `_bochscpu` is the C++ module
#
from ._bochscpu import Hook, InstructionType, Segment, Session, State, GlobalSegment # type: ignore
from ._bochscpu import ( # type: ignore
OpcodeOperationType,
HookType,
OpcodeOperationType,
PrefetchType,
CacheControlType,
TlbControlType,
InstructionType,
Segment,
GlobalSegment,
Hook,
State,
Session,
)
71 changes: 65 additions & 6 deletions python/bochscpu/_bochscpu/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,33 @@ class GlobalSegment:
"""
...

class TlbControlType(Enum):
"""Class TlbControlType"""

INSTR_MOV_CR0: TlbControlType
INSTR_MOV_CR3: TlbControlType
INSTR_MOV_CR4: TlbControlType
INSTR_TASK_SWITCH: TlbControlType
INSTR_CONTEXT_SWITCH: TlbControlType
INSTR_INVLPG: TlbControlType
INSTR_INVEPT: TlbControlType
INSTR_INVVPID: TlbControlType
INSTR_INVPCID: TlbControlType

class CacheControlType(Enum):
"""Class CacheControlType"""

INSTR_INVD: CacheControlType
INSTR_WBINVD: CacheControlType

class PrefetchType(Enum):
"""Class PrefetchType"""

INSTR_PREFETCH_NTA: PrefetchType
INSTR_PREFETCH_T0: PrefetchType
INSTR_PREFETCH_T1: PrefetchType
INSTR_PREFETCH_T2: PrefetchType

class HookType(Enum):
"""
<attribute '__doc__' of 'HookType' objects>
Expand Down Expand Up @@ -890,6 +917,16 @@ class Session:
"""

def __init__(self) -> None: ...
def run(self, hooks: list[bochscpu.Hook]) -> None:
"""
Start the execution
"""
...
def stop(self) -> None:
"""
Stop the execution
"""
...
@property
def cpu(self) -> bochscpu._bochscpu.cpu.Cpu:
"""
Expand All @@ -899,23 +936,45 @@ class Session:
@property
def missing_page_handler(self) -> Callable[[int, None], None]:
"""
Set the missing page callback
Get the missing page callback
"""
...
@missing_page_handler.setter
def missing_page_handler(self) -> Callable[[int, None], None]:
"""
Get the missing page callback
Set the missing page callback
"""
...
def run(self, arg: list[bochscpu._bochscpu.Hook], /) -> None:
@property
def auxiliaries(self) -> Callable[[list[int], None], None]:
"""
Start the execution with a set of hooks
Get the auxiliary variable array
"""
...
def stop(self) -> None:
@auxiliaries.setter
def auxiliaries(self) -> Callable[[list[int], None], None]:
"""
Stop the execution
Set the auxiliary variable array
"""
...
def set_auxiliary_variable(self, index: int, value: int) -> bool:
"""
Set an auxiliary variable
"""
...
def get_auxiliary_variable(self, index: int) -> int:
"""
Get an auxiliary variable
"""
...
def __setitem__(self, index: int, value: int) -> bool:
"""
Alias for `set_auxiliary_variable`
"""
...
def __getitem__(self, index: int) -> int:
"""
Alias for `get_auxiliary_variable`
"""
...

Expand Down
2 changes: 1 addition & 1 deletion python/bochscpu/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import bochscpu.memory
import bochscpu._bochscpu as _bochscpu

from . import cpu
from . import cpu, callbacks

PAGE_SIZE = bochscpu.memory.page_size()

Expand Down
Loading