mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-20 22:23:16 +00:00
parent
f3b03fa01b
commit
8b7f959451
@ -14,6 +14,9 @@
|
||||
#ifndef _CORE__KERNEL__CORE_INTERFACE_H_
|
||||
#define _CORE__KERNEL__CORE_INTERFACE_H_
|
||||
|
||||
/* base includes */
|
||||
#include <cpu/cpu_state.h>
|
||||
|
||||
/* base-internal includes */
|
||||
#include <base/internal/native_utcb.h>
|
||||
|
||||
@ -31,6 +34,7 @@ namespace Kernel {
|
||||
class Vm;
|
||||
class User_irq;
|
||||
using Native_utcb = Genode::Native_utcb;
|
||||
using Cpu_state = Genode::Cpu_state;
|
||||
template <typename T> class Core_object_identity;
|
||||
|
||||
/**
|
||||
@ -58,6 +62,10 @@ namespace Kernel {
|
||||
constexpr Call_arg call_id_new_obj() { return 121; }
|
||||
constexpr Call_arg call_id_delete_obj() { return 122; }
|
||||
constexpr Call_arg call_id_new_core_thread() { return 123; }
|
||||
constexpr Call_arg call_id_get_cpu_state() { return 124; }
|
||||
constexpr Call_arg call_id_set_cpu_state() { return 125; }
|
||||
constexpr Call_arg call_id_exception_state() { return 126; }
|
||||
constexpr Call_arg call_id_single_step() { return 127; }
|
||||
|
||||
/**
|
||||
* Invalidate TLB entries for the `pd` in region `addr`, `sz`
|
||||
@ -159,6 +167,42 @@ namespace Kernel {
|
||||
{
|
||||
call(call_id_ack_irq(), (Call_arg) &irq);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get CPU state
|
||||
*
|
||||
* \param thread pointer to thread kernel object
|
||||
* \param thread_state pointer to result CPU state object
|
||||
*/
|
||||
inline void get_cpu_state(Thread & thread, Cpu_state & cpu_state)
|
||||
{
|
||||
call(call_id_get_cpu_state(), (Call_arg)&thread, (Call_arg)&cpu_state);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set CPU state
|
||||
*
|
||||
* \param thread pointer to thread kernel object
|
||||
* \param thread_state pointer to CPU state object
|
||||
*/
|
||||
inline void set_cpu_state(Thread & thread, Cpu_state & cpu_state)
|
||||
{
|
||||
call(call_id_set_cpu_state(), (Call_arg)&thread, (Call_arg)&cpu_state);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enable/disable single-stepping
|
||||
*
|
||||
* \param thread pointer to thread kernel object
|
||||
* \param on enable or disable
|
||||
*/
|
||||
inline void single_step(Thread & thread, bool & on)
|
||||
{
|
||||
call(call_id_single_step(), (Call_arg)&thread, (Call_arg)&on);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _CORE__KERNEL__CORE_INTERFACE_H_ */
|
||||
|
@ -403,6 +403,7 @@ bool Thread::_restart()
|
||||
{
|
||||
assert(_state == ACTIVE || _state == AWAITS_RESTART);
|
||||
if (_state != AWAITS_RESTART) { return false; }
|
||||
_exception_state = NO_EXCEPTION;
|
||||
_become_active();
|
||||
return true;
|
||||
}
|
||||
@ -793,6 +794,34 @@ void Kernel::Thread::_call_invalidate_tlb()
|
||||
}
|
||||
|
||||
|
||||
void Thread::_call_get_cpu_state() {
|
||||
Thread &thread = *(Thread*)user_arg_1();
|
||||
Cpu_state &cpu_state = *(Cpu_state*)user_arg_2();
|
||||
cpu_state = *thread.regs;
|
||||
}
|
||||
|
||||
|
||||
void Thread::_call_set_cpu_state() {
|
||||
Thread &thread = *(Thread*)user_arg_1();
|
||||
Cpu_state &cpu_state = *(Cpu_state*)user_arg_2();
|
||||
static_cast<Cpu_state&>(*thread.regs) = cpu_state;
|
||||
}
|
||||
|
||||
|
||||
void Thread::_call_exception_state() {
|
||||
Thread &thread = *(Thread*)user_arg_1();
|
||||
Exception_state &exception_state = *(Exception_state*)user_arg_2();
|
||||
exception_state = thread.exception_state();
|
||||
}
|
||||
|
||||
|
||||
void Thread::_call_single_step() {
|
||||
Thread &thread = *(Thread*)user_arg_1();
|
||||
bool on = *(bool*)user_arg_2();
|
||||
Cpu::single_step(*thread.regs, on);
|
||||
}
|
||||
|
||||
|
||||
void Thread::_call()
|
||||
{
|
||||
try {
|
||||
@ -871,6 +900,10 @@ void Thread::_call()
|
||||
case call_id_new_obj(): _call_new_obj(); return;
|
||||
case call_id_delete_obj(): _call_delete_obj(); return;
|
||||
case call_id_suspend(): _call_suspend(); return;
|
||||
case call_id_get_cpu_state(): _call_get_cpu_state(); return;
|
||||
case call_id_set_cpu_state(): _call_set_cpu_state(); return;
|
||||
case call_id_exception_state(): _call_exception_state(); return;
|
||||
case call_id_single_step(): _call_single_step(); return;
|
||||
default:
|
||||
Genode::raw(*this, ": unknown kernel call");
|
||||
_die();
|
||||
@ -883,6 +916,7 @@ void Thread::_call()
|
||||
void Thread::_mmu_exception()
|
||||
{
|
||||
_become_inactive(AWAITS_RESTART);
|
||||
_exception_state = MMU_FAULT;
|
||||
Cpu::mmu_fault(*regs, _fault);
|
||||
_fault.ip = regs->ip;
|
||||
|
||||
@ -901,6 +935,25 @@ void Thread::_mmu_exception()
|
||||
}
|
||||
|
||||
|
||||
void Thread::_exception()
|
||||
{
|
||||
_become_inactive(AWAITS_RESTART);
|
||||
_exception_state = EXCEPTION;
|
||||
|
||||
if (_type != USER) {
|
||||
Genode::raw(*this, " raised an exception, which should never happen");
|
||||
_die();
|
||||
}
|
||||
|
||||
if (_pager && _pager->can_submit(1)) {
|
||||
_pager->submit(1);
|
||||
} else {
|
||||
Genode::raw(*this, " could not send signal to pager on exception");
|
||||
_die();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Thread::Thread(Board::Address_space_id_allocator &addr_space_id_alloc,
|
||||
Irq::Pool &user_irq_pool,
|
||||
Cpu_pool &cpu_pool,
|
||||
|
@ -59,6 +59,8 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
||||
|
||||
enum Type { USER, CORE, IDLE };
|
||||
|
||||
enum Exception_state { NO_EXCEPTION, MMU_FAULT, EXCEPTION };
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
@ -181,6 +183,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
||||
bool _paused { false };
|
||||
bool _cancel_next_await_signal { false };
|
||||
Type const _type;
|
||||
Exception_state _exception_state { NO_EXCEPTION };
|
||||
|
||||
Genode::Constructible<Tlb_invalidation> _tlb_invalidation {};
|
||||
Genode::Constructible<Destroy> _destroy {};
|
||||
@ -233,6 +236,11 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
||||
*/
|
||||
void _mmu_exception();
|
||||
|
||||
/**
|
||||
* Handle a non-mmu exception
|
||||
*/
|
||||
void _exception();
|
||||
|
||||
/**
|
||||
* Handle kernel-call request of the thread
|
||||
*/
|
||||
@ -294,6 +302,10 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
||||
void _call_timeout_max_us();
|
||||
void _call_time();
|
||||
void _call_suspend();
|
||||
void _call_get_cpu_state();
|
||||
void _call_set_cpu_state();
|
||||
void _call_exception_state();
|
||||
void _call_single_step();
|
||||
|
||||
template <typename T, typename... ARGS>
|
||||
void _call_new(ARGS &&... args)
|
||||
@ -468,6 +480,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
||||
Thread_fault fault() const { return _fault; }
|
||||
Genode::Native_utcb *utcb() { return _utcb; }
|
||||
Type type() const { return _type; }
|
||||
Exception_state exception_state() const { return _exception_state; }
|
||||
|
||||
Pd &pd() const
|
||||
{
|
||||
|
@ -61,9 +61,6 @@ void Pager_object::start_paging(Kernel_object<Kernel::Signal_receiver> & receive
|
||||
}
|
||||
|
||||
|
||||
void Pager_object::exception_handler(Signal_context_capability) { }
|
||||
|
||||
|
||||
void Pager_object::unresolved_page_fault_occurred() { }
|
||||
|
||||
|
||||
|
@ -105,6 +105,12 @@ class Core::Pager_object : private Object_pool<Pager_object>::Entry,
|
||||
Cpu_session_capability _cpu_session_cap;
|
||||
Thread_capability _thread_cap;
|
||||
|
||||
/**
|
||||
* User-level signal handler registered for this pager object via
|
||||
* 'Cpu_session::exception_handler()'.
|
||||
*/
|
||||
Signal_context_capability _exception_sigh { };
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -128,9 +134,24 @@ class Core::Pager_object : private Object_pool<Pager_object>::Entry,
|
||||
void wake_up();
|
||||
|
||||
/**
|
||||
* Unnecessary as base-hw doesn't use exception handlers
|
||||
* Assign user-level exception handler for the pager object
|
||||
*/
|
||||
void exception_handler(Signal_context_capability);
|
||||
void exception_handler(Signal_context_capability sigh)
|
||||
{
|
||||
_exception_sigh = sigh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify exception handler about the occurrence of an exception
|
||||
*/
|
||||
bool submit_exception_signal()
|
||||
{
|
||||
if (!_exception_sigh.valid()) return false;
|
||||
|
||||
Signal_transmitter transmitter(_exception_sigh);
|
||||
transmitter.submit();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install information that is necessary to handle page faults
|
||||
|
@ -210,15 +210,31 @@ Core::Pager_object &Platform_thread::pager()
|
||||
|
||||
Thread_state Platform_thread::state()
|
||||
{
|
||||
Thread_state bstate(*_kobj->regs);
|
||||
return Thread_state(bstate);
|
||||
Cpu_state cpu_state;
|
||||
Kernel::get_cpu_state(*_kobj, cpu_state);
|
||||
Thread_state state(cpu_state);
|
||||
|
||||
using Exception_state = Kernel::Thread::Exception_state;
|
||||
|
||||
switch (exception_state()) {
|
||||
case Exception_state::NO_EXCEPTION:
|
||||
break;
|
||||
case Exception_state::MMU_FAULT:
|
||||
state.unresolved_page_fault = true;
|
||||
break;
|
||||
case Exception_state::EXCEPTION:
|
||||
state.exception = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::state(Thread_state thread_state)
|
||||
{
|
||||
Cpu_state * cstate = static_cast<Cpu_state *>(&*_kobj->regs);
|
||||
*cstate = static_cast<Cpu_state>(thread_state);
|
||||
Cpu_state cpu_state(thread_state);
|
||||
Kernel::set_cpu_state(*_kobj, cpu_state);
|
||||
}
|
||||
|
||||
|
||||
|
@ -124,6 +124,22 @@ class Core::Platform_thread : Noncopyable
|
||||
*/
|
||||
~Platform_thread();
|
||||
|
||||
/**
|
||||
* Return information about current exception state
|
||||
*
|
||||
* This syscall wrapper is located here and not in
|
||||
* 'core_interface.h' because the 'Thread::Exception_state'
|
||||
* type is not known there.
|
||||
*/
|
||||
Kernel::Thread::Exception_state exception_state()
|
||||
{
|
||||
Kernel::Thread::Exception_state exception_state;
|
||||
using namespace Kernel;
|
||||
call(call_id_exception_state(), (Call_arg)&*_kobj,
|
||||
(Call_arg)&exception_state);
|
||||
return exception_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return information about current fault
|
||||
*/
|
||||
@ -158,12 +174,19 @@ class Core::Platform_thread : Noncopyable
|
||||
/**
|
||||
* Enable/disable single stepping
|
||||
*/
|
||||
void single_step(bool) { }
|
||||
void single_step(bool on) { Kernel::single_step(*_kobj, on); }
|
||||
|
||||
/**
|
||||
* Resume this thread
|
||||
*/
|
||||
void resume() { Kernel::resume_thread(*_kobj); }
|
||||
void resume()
|
||||
{
|
||||
if (exception_state() !=
|
||||
Kernel::Thread::Exception_state::NO_EXCEPTION)
|
||||
restart();
|
||||
|
||||
Kernel::resume_thread(*_kobj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CPU quota of the thread to 'quota'
|
||||
|
@ -43,6 +43,16 @@ void Pager_entrypoint::entry()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pt->exception_state() ==
|
||||
Kernel::Thread::Exception_state::EXCEPTION) {
|
||||
if (!po->submit_exception_signal())
|
||||
warning("unresolvable exception: "
|
||||
"pd='", pt->pd()->label(), "', "
|
||||
"thread='", pt->label(), "', "
|
||||
"ip=", Hex(pt->state().ip));
|
||||
continue;
|
||||
}
|
||||
|
||||
_fault = pt->fault_info();
|
||||
|
||||
/* try to resolve fault directly via local region managers */
|
||||
|
@ -120,6 +120,8 @@ struct Core::Arm_cpu : public Hw::Arm_cpu
|
||||
* Return kernel name of the executing CPU
|
||||
*/
|
||||
static unsigned executing_id() { return 0; }
|
||||
|
||||
static void single_step(Context &, bool) { };
|
||||
};
|
||||
|
||||
#endif /* _CORE__SPEC__ARM__CPU_SUPPORT_H_ */
|
||||
|
@ -75,6 +75,7 @@ struct Core::Cpu : Hw::Arm_64_cpu
|
||||
struct alignas(16) Context : Cpu_state
|
||||
{
|
||||
uint64_t pstate { };
|
||||
uint64_t mdscr_el1 { };
|
||||
uint64_t exception_type { RESET };
|
||||
Fpu_state fpu_state { };
|
||||
|
||||
@ -104,6 +105,12 @@ struct Core::Cpu : Hw::Arm_64_cpu
|
||||
|
||||
static void mmu_fault(Context &, Kernel::Thread_fault &);
|
||||
|
||||
static void single_step(Context ®s, bool on)
|
||||
{
|
||||
Cpu::Spsr::Ss::set(regs.pstate, on ? 1 : 0);
|
||||
Cpu::Mdscr::Ss::set(regs.mdscr_el1, on ? 1 : 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return kernel name of the executing CPU
|
||||
*/
|
||||
|
@ -35,10 +35,12 @@
|
||||
mrs x1, sp_el0
|
||||
mrs x2, elr_el1
|
||||
mrs x3, spsr_el1
|
||||
adr x4, .
|
||||
and x4, x4, #0xf80
|
||||
mrs x4, mdscr_el1
|
||||
adr x5, .
|
||||
and x5, x5, #0xf80
|
||||
stp x1, x2, [x0], #16
|
||||
stp x3, x4, [x0], #16
|
||||
stp xzr, x3, [x0], #16 /* ec will be updated later if needed */
|
||||
stp x4, x5, [x0], #16
|
||||
b _kernel_entry
|
||||
.balign 128
|
||||
.endr
|
||||
@ -91,11 +93,12 @@ _kernel_entry:
|
||||
mov sp, x1 /* reset stack */
|
||||
str x0, [sp, #-16] /* store cpu state pointer */
|
||||
add x1, x0, #8*31
|
||||
ldp x2, x3, [x1], #16 /* load sp, ip */
|
||||
ldr x4, [x1], #16 /* load pstate */
|
||||
ldp x2, x3, [x1], #16+8 /* load sp, ip, skip ec */
|
||||
ldp x4, x5, [x1], #16+8 /* load pstate, mdscr_el1, skip exception_type */
|
||||
msr sp_el0, x2
|
||||
msr elr_el1, x3
|
||||
msr spsr_el1, x4
|
||||
msr mdscr_el1, x5
|
||||
ldp q0, q1, [x1], #32
|
||||
ldp q2, q3, [x1], #32
|
||||
ldp q4, q5, [x1], #32
|
||||
|
@ -53,6 +53,11 @@ void Thread::exception(Cpu & cpu)
|
||||
case Cpu::Esr::Ec::DATA_ABORT_LOW_LEVEL:
|
||||
_mmu_exception();
|
||||
return;
|
||||
case Cpu::Esr::Ec::SOFTWARE_STEP_LOW_LEVEL: [[fallthrough]];
|
||||
case Cpu::Esr::Ec::BRK:
|
||||
regs->ec = Cpu::Esr::Ec::get(esr);
|
||||
_exception();
|
||||
return;
|
||||
default:
|
||||
Genode::raw("Unknown cpu exception EC=", Cpu::Esr::Ec::get(esr),
|
||||
" ISS=", Cpu::Esr::Iss::get(esr),
|
||||
|
@ -101,6 +101,8 @@ class Core::Cpu : public Hw::Riscv_cpu
|
||||
void switch_to(Mmu_context & context);
|
||||
static void mmu_fault(Context & c, Kernel::Thread_fault & f);
|
||||
|
||||
static void single_step(Context &, bool) { };
|
||||
|
||||
static unsigned executing_id() { return 0; }
|
||||
|
||||
static void clear_memory_region(addr_t const addr,
|
||||
|
@ -158,3 +158,12 @@ void Cpu::clear_memory_region(addr_t const addr, size_t const size, bool)
|
||||
memset((void*)addr, 0, size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Cpu::single_step(Context ®s, bool on)
|
||||
{
|
||||
if (on)
|
||||
regs.eflags |= Context::Eflags::EFLAGS_TF;
|
||||
else
|
||||
regs.eflags &= ~Context::Eflags::EFLAGS_TF;
|
||||
}
|
||||
|
@ -101,6 +101,7 @@ class Core::Cpu : public Hw::X86_64_cpu
|
||||
struct alignas(16) Context : Cpu_state, Kernel_stack, Fpu_context
|
||||
{
|
||||
enum Eflags {
|
||||
EFLAGS_TF = 1 << 8,
|
||||
EFLAGS_IF_SET = 1 << 9,
|
||||
EFLAGS_IOPL_3 = 3 << 12,
|
||||
};
|
||||
@ -134,6 +135,8 @@ class Core::Cpu : public Hw::X86_64_cpu
|
||||
|
||||
static void mmu_fault(Context & regs, Kernel::Thread_fault & fault);
|
||||
|
||||
static void single_step(Context ®s, bool on);
|
||||
|
||||
/**
|
||||
* Invalidate the whole TLB
|
||||
*/
|
||||
|
@ -147,9 +147,19 @@
|
||||
.align 8
|
||||
__idt:
|
||||
|
||||
/* first 128 entries */
|
||||
/* first 3 entries */
|
||||
.set isr_addr, ISR
|
||||
.rept 0x80
|
||||
.rept 3
|
||||
_idt_entry isr_addr IDT_FLAGS_PRIVILEGED
|
||||
.set isr_addr, isr_addr + ISR_ENTRY_SIZE
|
||||
.endr
|
||||
|
||||
/* int3 */
|
||||
_idt_entry isr_addr IDT_FLAGS_UNPRIVILEGED
|
||||
.set isr_addr, isr_addr + ISR_ENTRY_SIZE
|
||||
|
||||
/* entries 4-127 */
|
||||
.rept 124
|
||||
_idt_entry isr_addr IDT_FLAGS_PRIVILEGED
|
||||
.set isr_addr, isr_addr + ISR_ENTRY_SIZE
|
||||
.endr
|
||||
|
@ -30,9 +30,12 @@ void Thread::exception(Cpu & cpu)
|
||||
_mmu_exception();
|
||||
return;
|
||||
|
||||
case Cpu_state::DIVIDE_ERROR:
|
||||
case Cpu_state::DEBUG:
|
||||
case Cpu_state::BREAKPOINT:
|
||||
case Cpu_state::UNDEFINED_INSTRUCTION:
|
||||
Genode::raw(*this, ": undefined instruction at ip=", (void*)regs->ip);
|
||||
_die();
|
||||
case Cpu_state::GENERAL_PROTECTION:
|
||||
_exception();
|
||||
return;
|
||||
|
||||
case Cpu_state::SUPERVISOR_CALL:
|
||||
|
@ -79,11 +79,13 @@ struct Hw::Arm_64_cpu
|
||||
struct Ec : Bitfield<26, 6>
|
||||
{
|
||||
enum Exception {
|
||||
SVC = 0b010101,
|
||||
INST_ABORT_LOW_LEVEL = 0b100000,
|
||||
INST_ABORT_SAME_LEVEL = 0b100001,
|
||||
DATA_ABORT_LOW_LEVEL = 0b100100,
|
||||
DATA_ABORT_SAME_LEVEL = 0b100101,
|
||||
SVC = 0b010101,
|
||||
INST_ABORT_LOW_LEVEL = 0b100000,
|
||||
INST_ABORT_SAME_LEVEL = 0b100001,
|
||||
DATA_ABORT_LOW_LEVEL = 0b100100,
|
||||
DATA_ABORT_SAME_LEVEL = 0b100101,
|
||||
SOFTWARE_STEP_LOW_LEVEL = 0b110010,
|
||||
BRK = 0b111100,
|
||||
};
|
||||
};
|
||||
|
||||
@ -144,6 +146,11 @@ struct Hw::Arm_64_cpu
|
||||
SYSTEM_REGISTER(64, Mair_el1, mair_el1);
|
||||
SYSTEM_REGISTER(64, Mair_el2, mair_el2);
|
||||
|
||||
struct Mdscr : Genode::Register<64>
|
||||
{
|
||||
struct Ss : Bitfield<0, 1> {};
|
||||
};
|
||||
|
||||
SYSTEM_REGISTER(64, Mpidr, mpidr_el1,
|
||||
struct Aff0 : Bitfield<0, 8> {};
|
||||
struct Aff1 : Bitfield<8, 8> {};
|
||||
@ -179,12 +186,13 @@ struct Hw::Arm_64_cpu
|
||||
|
||||
struct Spsr : Genode::Register<64>
|
||||
{
|
||||
struct Sp : Bitfield<0, 1> {};
|
||||
struct El : Bitfield<2, 2> {};
|
||||
struct F : Bitfield<6, 1> {};
|
||||
struct I : Bitfield<7, 1> {};
|
||||
struct A : Bitfield<8, 1> {};
|
||||
struct D : Bitfield<9, 1> {};
|
||||
struct Sp : Bitfield<0, 1> {};
|
||||
struct El : Bitfield<2, 2> {};
|
||||
struct F : Bitfield<6, 1> {};
|
||||
struct I : Bitfield<7, 1> {};
|
||||
struct A : Bitfield<8, 1> {};
|
||||
struct D : Bitfield<9, 1> {};
|
||||
struct Ss : Bitfield<21, 1> {};
|
||||
};
|
||||
|
||||
SYSTEM_REGISTER(64, Spsr_el2, spsr_el2);
|
||||
|
@ -22,9 +22,15 @@ namespace Genode { struct Cpu_state; }
|
||||
|
||||
struct Genode::Cpu_state
|
||||
{
|
||||
enum Cpu_exception {
|
||||
SOFTWARE_STEP = 0x32,
|
||||
BREAKPOINT = 0x3c,
|
||||
};
|
||||
|
||||
addr_t r[31] { 0 }; /* general purpose register 0...30 */
|
||||
addr_t sp { 0 }; /* stack pointer */
|
||||
addr_t ip { 0 }; /* instruction pointer */
|
||||
addr_t ec { 0 }; /* exception class */
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__SPEC__ARM_64__CPU__CPU_STATE_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user