ducky.cpu package

Module contents

class ducky.cpu.CPU(machine, cpuid, memory_controller, cores=1)[source]

Bases: ducky.interfaces.ISnapshotable, ducky.interfaces.IMachineWorker

boot()[source]
die(exc)[source]
halt()[source]
load_state(state)[source]
on_core_alive(core)[source]

Triggered when one of cores goes alive.

on_core_halted(core)[source]

Signal CPU that one of cores is no longer alive.

on_core_running(core)[source]

Signal CPU that one of cores is now running.

on_core_suspended(core)[source]

Signal CPU that one of cores is now suspended.

save_state(parent)[source]
suspend()[source]
wake_up()[source]
class ducky.cpu.CPUCore(coreid, cpu, memory_controller)[source]

Bases: ducky.interfaces.ISnapshotable, ducky.interfaces.IMachineWorker

This class represents the main workhorse, one of CPU cores. Reads instructions, executes them, has registers, caches, handles interrupts, ...

Parameters:
  • coreid (int) – id of this core. Usually, it’s its serial number but it has no special meaning.
  • cpu (ducky.cpu.CPU) – CPU that owns this core.
  • memory_controller (ducky.mm.MemoryController) – use this controller to access main memory.
FP()[source]
IP()[source]
REG(reg)[source]
SP()[source]
backtrace()[source]
boot()[source]
change_runnable_state(alive=None, running=None, idle=None)[source]
check_protected_ins()[source]

Raise AccessViolationError if core is not running in privileged mode.

This method should be used by instruction handlers that require privileged mode, e.g. protected instructions.

Raises:AccessViolationError – if the core is not in privileged mode
check_protected_port(port)[source]
create_frame()[source]

Create new call stack frame. Push IP and FP registers and set FP value to SP.

destroy_frame()[source]

Destroy current call frame. Pop FP and IP from stack, by popping FP restores previous frame.

Raises:CPUException – if current frame does not match last created frame.
die(exc)[source]
do_int(index)[source]

Handle software interrupt. Real software interrupts cause CPU state to be saved and new stack and register values are prepared by __enter_interrupt method, virtual interrupts are simply triggered without any prior changes of CPU state.

Parameters:index (int) – interrupt number
exit_interrupt()[source]

Restore CPU state after running a interrupt routine. Call frame is destroyed, registers are restored, stack is returned back to memory pool.

flags
halt()[source]
has_coprocessor(name)[source]
init_debug_set()[source]
irq(index)[source]
load_state(state)[source]
pop(*regs)[source]
push(*regs)[source]
raw_pop()[source]

Pop value from stack. 4 byte number is read from address in SP, then SP is incremented by four.

Returns:popped value
Return type:u32
raw_push(val)[source]

Push value on stack. SP is decremented by four, and value is written at this new address.

Parameters:val (u32) – value to be pushed
reset(new_ip=0)[source]

Reset core’s state. All registers are set to zero, all flags are set to zero, except HWINT flag which is set to one, and IP is set to requested value.

Parameters:new_ip (u32_t) – new IP value, defaults to zero
run()[source]
save_state(parent)[source]
step()[source]

Perform one “step” - fetch next instruction, increment IP, and execute instruction’s code (see inst_* methods)

suspend()[source]
wake_up()[source]
class ducky.cpu.CPUCoreState[source]

Bases: ducky.snapshot.SnapshotNode

exception ducky.cpu.CPUException(msg, core=None, ip=None)[source]

Bases: exceptions.Exception

Base class for CPU-related exceptions.

Parameters:
  • msg (string) – message describing exceptional state.
  • core (ducky.cpu.CPUCore) – CPU core that raised exception, if any.
  • ip (u32_t) – address of an instruction that caused exception, if any.
class ducky.cpu.CPUState(*fields)[source]

Bases: ducky.snapshot.SnapshotNode

get_core_state_by_id(coreid)[source]
get_core_states()[source]
class ducky.cpu.CoreFlags[source]

Bases: ducky.util.Flags

ducky.cpu.DEFAULT_CORE_INST_CACHE_SIZE = 256

Default size of core instruction cache, in instructions.

ducky.cpu.DEFAULT_IVT_ADDRESS = 0

Default IVT address

ducky.cpu.DEFAULT_PT_ADDRESS = 65536

Default PT address

class ducky.cpu.InstructionCache(mmu, size, *args, **kwargs)[source]

Bases: ducky.util.LRUCache

Simple instruction cache class, based on LRU dictionary, with a limited size.

Parameters:
  • core (ducky.cpu.CPUCore) – CPU core that owns this cache.
  • size (int) – maximal number of entries this cache can store.
get_object(addr)[source]

Read instruction from memory. This method is responsible for the real job of fetching instructions and filling the cache.

Parameters:addr (u24) – absolute address to read from
Returns:instruction
Return type:InstBinaryFormat_Master
get_object_jit(addr)[source]

Read instruction from memory. This method is responsible for the real job of fetching instructions and filling the cache.

Parameters:addr (u24) – absolute address to read from
Returns:instruction
Return type:InstBinaryFormat_Master
class ducky.cpu.InterruptVector(ip=0, sp=0)[source]

Bases: object

Interrupt vector table entry.

SIZE = 8
exception ducky.cpu.InvalidInstructionSetError(inst_set, *args, **kwargs)[source]

Bases: ducky.cpu.CPUException

Raised when switch to unknown or invalid instruction set is requested.

Parameters:inst_set (int) – instruction set id.
exception ducky.cpu.InvalidOpcodeError(opcode, *args, **kwargs)[source]

Bases: ducky.cpu.CPUException

Raised when unknown or invalid opcode is found in instruction.

Parameters:opcode (int) – wrong opcode.
class ducky.cpu.MMU(core, memory_controller)[source]

Bases: ducky.interfaces.ISnapshotable

Memory management unit (aka MMU) provides a single point handling all core’s memory operations. All memory reads and writes must go through this unit, which is then responsible for all translations, access control, and caching.

Parameters:
check_access(access, addr, align=None)[source]

Check attempted access against PTE. Be aware that each check can be turned off by configuration file.

Parameters:
  • accessread, write or execute.
  • addr (u24) – memory address.
  • align (int) – if set, operation is expected to be aligned to this boundary.
Raises:

ducky.errors.AccessViolationError – when access is denied.

full_read_u16(addr)[source]
full_read_u32(addr, not_execute=True)[source]
full_read_u8(addr)[source]
full_write_u16(addr, value)[source]
full_write_u32(addr, value)[source]
full_write_u8(addr, value)[source]
get_pte(addr)[source]

Find out PTE for particular physical address. If PTE is not in internal PTE cache, it is fetched from PTE table.

Parameters:addr (u24) – memory address.
halt()[source]
release_ptes()[source]
reset()[source]
set_access_methods()[source]

Set parent core’s memory-access methods to proper shortcuts.

class ducky.cpu.StackFrame(fp)[source]

Bases: object

ducky.cpu.cmd_bt(console, cmd)[source]

Print current backtrace

ducky.cpu.cmd_cont(console, cmd)[source]

Continue execution until next breakpoint is reached: cont

ducky.cpu.cmd_core_state(console, cmd)[source]

Print core state

ducky.cpu.cmd_next(console, cmd)[source]

Proceed to the next instruction in the same stack frame.

ducky.cpu.cmd_set_core(console, cmd)[source]

Set core address of default core used by control commands: sc <coreid>

ducky.cpu.cmd_step(console, cmd)[source]

Step one instruction forward

ducky.cpu.do_log_cpu_core_state(core, logger=None, disassemble=True, inst_set=None)[source]

Log state of a CPU core. Content of its registers, and other interesting or useful internal variables are logged.

Parameters:
  • core (ducky.cpu.CPUCore) – core whose state should be logged.
  • logger – called for each line of output to actualy log it. By default, core’s ducky.cpu.CPUCore.DEBUG() method is used.
ducky.cpu.log_cpu_core_state(*args, **kwargs)[source]

This is a wrapper for ducky.cpu.do_log_cpu_core_state function. Its main purpose is to be removed when debug mode is not set, therefore all debug calls of ducky.cpu.do_log_cpu_core_state will disappear from code, making such code effectively “quiet”.