From 1676132dd8b344a13934d318a2a250c078dad1cf Mon Sep 17 00:00:00 2001 From: Randolf Rotta Date: Tue, 17 Dec 2019 18:45:26 +0100 Subject: [PATCH 01/13] unified return to user for saver handling of %rip, fixed value for %rflags --- kernel/cpu/kernel-entry-amd64/cpu/irq_entry.S | 45 ++--------- .../kernel-entry-amd64/cpu/kernel_entry.hh | 14 ++-- .../kernel-entry-amd64/cpu/syscall_entry.S | 81 ++++++++++++++----- .../objects/ExecutionContext.cc | 21 +++-- .../objects/ExecutionContext.hh | 5 +- .../objects/SchedulingContext.cc | 13 ++- 6 files changed, 90 insertions(+), 89 deletions(-) diff --git a/kernel/cpu/kernel-entry-amd64/cpu/irq_entry.S b/kernel/cpu/kernel-entry-amd64/cpu/irq_entry.S index dee17b06..e95eb0ea 100644 --- a/kernel/cpu/kernel-entry-amd64/cpu/irq_entry.S +++ b/kernel/cpu/kernel-entry-amd64/cpu/irq_entry.S @@ -134,14 +134,16 @@ interrupt_common: movq $0, TS_MAYSYSRET(%rax) // might be on the NMI stack, but everything is stored safely - // in the ThreadState, thus we can switch to the bigger kernel - // stack now + // in the ThreadState, thus we can switch to the bigger kernel + // stack now /// @todo check whether we actually could end up on the NMI stack when coming from user mode!!! mov %gs:kernel_stack, %rsp mov %rax, %rdi // 1. argument: pointer to thread_state xor %rbp, %rbp pushq $0 // fake return address - jmp irq_entry_user + jmp irq_entry_user // @todo as a call + // @todo call try to return to user via scheduler + // @todo call sleep if nothing to return to interrupt_kernel: xchg %bx, %bx @@ -181,40 +183,3 @@ interrupt_kernel: pop %rcx add $(2*8), %rsp // pop irqno and error code iretq - -.global irq_return_user -.type irq_return_user, @function -irq_return_user: - xchg %bx, %bx - mov $IA32_FS_BASE, %rcx - mov TS_FS_BASE(%rdi), %eax - mov (TS_FS_BASE+4)(%rdi), %edx - wrmsr // restore user's FS base - mov $IA32_KERNEL_GS_BASE, %rcx - mov TS_GS_BASE(%rdi), %eax - mov (TS_GS_BASE+4)(%rdi), %edx - wrmsr // prepare user's GS base for swapgs - // create fake interrupt frame on the kernel stack - pushq $(SEGMENT_USER_DS+3) // SS - user data segment with bottom 2 bits set for ring 3 - pushq TS_RSP(%rdi) // RSP - user stack from 2nd parameter - pushq TS_RFLAGS(%rdi) // RFLAGS - pushq $(SEGMENT_USER_CS+3) // CS - user code segment with bottom 2 bits set for ring 3 - pushq TS_RIP(%rdi) // RIP - Instruction pointer after iretq - // restore all other register - mov TS_RAX(%rdi), %rax - mov TS_RBX(%rdi), %rbx - mov TS_RCX(%rdi), %rcx - mov TS_RDX(%rdi), %rdx - mov TS_RSI(%rdi), %rsi - mov TS_RBP(%rdi), %rbp - mov TS_R8(%rdi), %r8 - mov TS_R9(%rdi), %r9 - mov TS_R10(%rdi), %r10 - mov TS_R11(%rdi), %r11 - mov TS_R12(%rdi), %r12 - mov TS_R13(%rdi), %r13 - mov TS_R14(%rdi), %r14 - mov TS_R15(%rdi), %r15 - mov TS_RDI(%rdi), %rdi - swapgs // restore user's GS base - iretq // return to user mode and enable interrupts via rflags IF field diff --git a/kernel/cpu/kernel-entry-amd64/cpu/kernel_entry.hh b/kernel/cpu/kernel-entry-amd64/cpu/kernel_entry.hh index bf2f3f38..011cf523 100644 --- a/kernel/cpu/kernel-entry-amd64/cpu/kernel_entry.hh +++ b/kernel/cpu/kernel-entry-amd64/cpu/kernel_entry.hh @@ -71,20 +71,18 @@ namespace mythos { /** high-level syscall handler, must be defined by another module, used by syscall_entry.S */ NORETURN void syscall_entry_cxx(ThreadState*) SYMBOL("syscall_entry_cxx"); - /** return from syscall to user, defined in syscall_entry.S, reads state from thread_state */ - NORETURN void syscall_return(ThreadState*) SYMBOL("syscall_return"); + namespace internal { + /** return from syscall or interrupt to user, defined in syscall_entry.S, reads state from thread_state */ + NORETURN void return_to_user_asm(ThreadState*) SYMBOL("return_to_user_asm"); + } // namespace internal /** high-level irq handler when entering from user mode, must be * defined by another module, used by irq_entry.S */ NORETURN void irq_entry_user(ThreadState*) SYMBOL("irq_entry_user"); - /** return from interrupt to user, defined in irq_entry.S, reads state from thread_state */ - NORETURN void irq_return_user(ThreadState*) SYMBOL("irq_return_user"); - NORETURN inline void return_to_user() { - ThreadState* s = thread_state.get(); - if (s->maySysret && s->rip < 0x7FFFFFFFFFFF) syscall_return(s); - else irq_return_user(s); + // @todo handle case of nullptr -> sleep ??? + internal::return_to_user_asm(thread_state.get()); } /** Layout of the kernel's execution state on the interrupted kernel's stack. diff --git a/kernel/cpu/kernel-entry-amd64/cpu/syscall_entry.S b/kernel/cpu/kernel-entry-amd64/cpu/syscall_entry.S index c04edcc0..cc969807 100644 --- a/kernel/cpu/kernel-entry-amd64/cpu/syscall_entry.S +++ b/kernel/cpu/kernel-entry-amd64/cpu/syscall_entry.S @@ -24,6 +24,7 @@ * Copyright 2016 Randolf Rotta, Robert Kuban, Maik Krüger, and contributors, BTU Cottbus-Senftenberg */ #include "cpu/thread-state-layout.h" +#include "cpu/gdt-layout.h" .extern thread_state .extern kernel_stack @@ -61,11 +62,14 @@ syscall_entry: mov %rax, %rdi // 1. argument: pointer to thread_state xor %rbp, %rbp pushq $0 // fake return address - jmp syscall_entry_cxx + jmp syscall_entry_cxx // @todo as a call + // @todo call try to return to user via scheduler + // @todo call sleep if nothing to return to -.global syscall_return -.type syscall_return, @function -syscall_return: +.global return_to_user_asm +.type return_to_user_asm, @function +// RDI: ThreadState* +return_to_user_asm: mov $IA32_FS_BASE, %rcx mov TS_FS_BASE(%rdi), %eax mov (TS_FS_BASE+4)(%rdi), %edx @@ -74,24 +78,59 @@ syscall_return: mov TS_GS_BASE(%rdi), %eax mov (TS_GS_BASE+4)(%rdi), %edx wrmsr // prepare user's GS base for swapgs - mov TS_RBP(%rdi), %rbp - /// @todo may use xor %reg,%reg to zero the unpreserved registers + + // check for save and fast sysret, otherwise do iret + // maysysret is nonzero and rip < 0x7FFFFFFFFFFF + movabs $0x7ffffffffffe,%rax + mov TS_RIP(%rdi), %rcx // instruction pointer + cmp %rax, %rcx + setbe %al + movzbl %al, %eax + test %rax, TS_MAYSYSRET(%rdi) // flag for "came from syscall" + je return_from_irq + /// @todo reorder thread-state-layout to reflect reduced register passing - //mov TS_RBX(%rdi), %rbx - //mov TS_R12(%rdi), %r12 - //mov TS_R13(%rdi), %r13 - //mov TS_R14(%rdi), %r14 - //mov TS_R15(%rdi), %r15 + xor %rbx, %rbx + xor %r12, %r12 + xor %r13, %r13 + xor %r14, %r14 + xor %r15, %r15 // skip rcx (rcx contains user's rip) - //mov TS_RAX(%rdi), %rax // may contain a return value now - //mov TS_RDX(%rdi), %rdx - mov TS_RSI(%rdi), %rsi - //mov TS_R8(%rdi), %r8 - //mov TS_R9(%rdi), %r9 - //mov TS_R10(%rdi), %r10 - mov TS_RFLAGS(%rdi), %r11 // rflags - mov TS_RIP(%rdi), %rcx // instruction pointer - mov TS_RSP(%rdi), %rsp // stack - mov TS_RDI(%rdi), %rdi + xor %rax, %rax + xor %rdx, %rdx + mov TS_RSI(%rdi), %rsi // return value: user context + xor %r8, %r8 + xor %r9, %r9 + xor %r10, %r10 + mov $0x000200, %r11 // don't trust the user's rflags, enforce interrupt enable flag + mov TS_RBP(%rdi), %rbp // stack frame base pointer + mov TS_RSP(%rdi), %rsp // top of stack + mov TS_RDI(%rdi), %rdi // return value: state or error code swapgs // restore user's GS base sysretq + +return_from_irq: + // create fake interrupt frame on the kernel stack + pushq $(SEGMENT_USER_DS+3) // SS - user data segment with bottom 2 bits set for ring 3 + pushq TS_RSP(%rdi) // RSP - user stack from 2nd parameter + pushq $0x000200 // RFLAGS - don't trust the user's rflags, enforce interrupt enable flag + pushq $(SEGMENT_USER_CS+3) // CS - user code segment with bottom 2 bits set for ring 3 + pushq %rcx // RIP - Instruction pointer after iretq + // restore all other register + mov TS_RAX(%rdi), %rax + mov TS_RBX(%rdi), %rbx + mov TS_RCX(%rdi), %rcx + mov TS_RDX(%rdi), %rdx + mov TS_RSI(%rdi), %rsi + mov TS_RBP(%rdi), %rbp + mov TS_R8(%rdi), %r8 + mov TS_R9(%rdi), %r9 + mov TS_R10(%rdi), %r10 + mov TS_R11(%rdi), %r11 + mov TS_R12(%rdi), %r12 + mov TS_R13(%rdi), %r13 + mov TS_R14(%rdi), %r14 + mov TS_R15(%rdi), %r15 + mov TS_RDI(%rdi), %rdi + swapgs // restore user's GS base + iretq // return to user mode and enable interrupts via rflags IF field diff --git a/kernel/objects/execution-context/objects/ExecutionContext.cc b/kernel/objects/execution-context/objects/ExecutionContext.cc index 21c21e57..34fa75b1 100644 --- a/kernel/objects/execution-context/objects/ExecutionContext.cc +++ b/kernel/objects/execution-context/objects/ExecutionContext.cc @@ -38,13 +38,9 @@ namespace mythos { ExecutionContext::ExecutionContext(IAsyncFree* memory) - : flags(0) - , memory(memory) + : memory(memory) { - setFlags(IS_TRAPPED + NO_AS + NO_SCHED - + DONT_PREEMPT + NOT_LOADED + NOT_RUNNING); threadState.clear(); - threadState.rflags = x86::FLAG_IF; // ensure that interrupts are enabled in user mode fpuState.clear(); } @@ -306,7 +302,7 @@ namespace mythos { threadState.fs_base = fs; threadState.gs_base = gs; MLOG_DETAIL(mlog::ec, "set fs/gs", DVAR(this), DVARhex(fs), DVARhex(gs)); - + RETURN(Error::SUCCESS); } @@ -415,9 +411,10 @@ namespace mythos { case SYSCALL_WAIT: { auto prevState = setFlags(IN_WAIT | IS_WAITING); - MLOG_INFO(mlog::syscall, "wait", DVARhex(prevState)); - if (!notificationQueue.empty() || (prevState & IS_NOTIFIED)) + MLOG_DETAIL(mlog::syscall, "wait", DVARhex(prevState)); + if (!notificationQueue.empty() || (prevState & IS_NOTIFIED)) { clearFlags(IS_WAITING); // because of race with notifier + } break; } @@ -447,7 +444,9 @@ namespace mythos { mlog::Logger user("user"); // userctx => address in users virtual memory. Yes, we fully trust the user :( // portal => string length - mlog::sink->write((char const*)userctx, portal); + char str[300]; + memcpy(str, reinterpret_cast(userctx), (portal<300) ? portal : 300); + mlog::sink->write(str, portal); code = uint64_t(Error::SUCCESS); break; } @@ -510,7 +509,7 @@ namespace mythos { if (prevWait & IN_WAIT) { // clear IS_NOTIFIED only if the user mode was waiting for it // we won't clear it twice without a second wait() system call - clearFlags(IS_NOTIFIED); + clearFlags(IS_NOTIFIED); // return a notification event if any auto e = notificationQueue.pull(); @@ -522,7 +521,7 @@ namespace mythos { threadState.rsi = 0; threadState.rdi = uint64_t(Error::NO_MESSAGE); } - MLOG_DETAIL(mlog::ec, DVAR(this), "return one notification", + MLOG_DETAIL(mlog::ec, DVAR(this), "return one notification", DVARhex(threadState.rsi), DVAR(threadState.rdi)); } diff --git a/kernel/objects/execution-context/objects/ExecutionContext.hh b/kernel/objects/execution-context/objects/ExecutionContext.hh index d912da87..65555d1d 100644 --- a/kernel/objects/execution-context/objects/ExecutionContext.hh +++ b/kernel/objects/execution-context/objects/ExecutionContext.hh @@ -67,7 +67,8 @@ namespace mythos { NOT_LOADED = 1<<8, // CPU state is not loaded DONT_PREEMPT = 1<<9, // somebody else will send the preemption NOT_RUNNING = 1<<10, // EC is not running - BLOCK_MASK = IS_WAITING | IS_TRAPPED | NO_AS | NO_SCHED | REGISTER_ACCESS + BLOCK_MASK = IS_WAITING | IS_TRAPPED | NO_AS | NO_SCHED | REGISTER_ACCESS, + INIT_FLAGS = IS_TRAPPED | NO_AS | NO_SCHED | DONT_PREEMPT | NOT_LOADED | NOT_RUNNING }; ExecutionContext(IAsyncFree* memory); @@ -157,7 +158,7 @@ namespace mythos { private: async::NestedMonitorDelegating monitor; INotifiable::list_t notificationQueue; - std::atomic flags; + std::atomic flags = {INIT_FLAGS}; CapRef _as; CapRef _cs; CapRef _sched; diff --git a/kernel/objects/scheduling-context/objects/SchedulingContext.cc b/kernel/objects/scheduling-context/objects/SchedulingContext.cc index c94da9cb..b32dcf33 100644 --- a/kernel/objects/scheduling-context/objects/SchedulingContext.cc +++ b/kernel/objects/scheduling-context/objects/SchedulingContext.cc @@ -34,10 +34,10 @@ namespace mythos { - void SchedulingContext::bind(handle_t*) + void SchedulingContext::bind(handle_t*) { } - + void SchedulingContext::unbind(handle_t* ec) { ASSERT(ec != nullptr); @@ -51,16 +51,14 @@ namespace mythos { ASSERT(ec != nullptr); MLOG_INFO(mlog::sched, "ready", DVAR(ec->get())); - // do nothing if it is the current execution context - auto current = current_handle.load(); - if (current == ec) return; /// @todo can this actually happen? - // add to the ready queue readyQueue.remove(ec); /// @todo do not need to remove if already on the queue, just do nothing then. This needs additional information in handle_t of LinkedList readyQueue.push(ec); // wake up the hardware thread if it has no execution context running - if (current == nullptr) home->preempt(); + // or if if current ec got ready in case of race with failed ec->resume() + auto current = current_handle.load(); + if (current == nullptr || current == ec) home->preempt(); } void SchedulingContext::tryRunUser() @@ -77,6 +75,7 @@ namespace mythos { current->get()->loadState(); } current->get()->resume(); // if it returns, the ec is blocked + // note: the ec can become ready again here. Solved in ready() current_handle.store(nullptr); } MLOG_DETAIL(mlog::sched, "try from ready list"); From e77ffedafde577a20f030eecb9f756b9eedf6b68 Mon Sep 17 00:00:00 2001 From: Randolf Rotta Date: Tue, 17 Dec 2019 20:20:34 +0100 Subject: [PATCH 02/13] prepared ExecutionContext for user-space state frame; improved CapRef to pass a 64bit val from set() to bind(); initialized more of the invocation buf, this is likely at the wrong place --- .../mythos/invocation/mythos/InvocationBuf.hh | 8 ++- .../mythos/protocol/ExecutionContext.hh | 21 +++++--- .../capability-utils/objects/CapRef.cc | 4 +- .../capability-utils/objects/CapRef.hh | 20 +++---- .../objects/ExecutionContext.cc | 52 ++++++++++++++----- .../objects/ExecutionContext.hh | 42 +++++++++++---- .../objects/InterruptControl.hh | 4 +- kernel/objects/portal/objects/Portal.cc | 9 ++-- kernel/objects/portal/objects/Portal.hh | 7 ++- .../kobject/runtime/ExecutionContext.hh | 47 +++++++++-------- 10 files changed, 137 insertions(+), 77 deletions(-) diff --git a/kernel/mythos/invocation/mythos/InvocationBuf.hh b/kernel/mythos/invocation/mythos/InvocationBuf.hh index 5b95c33b..08574c0b 100644 --- a/kernel/mythos/invocation/mythos/InvocationBuf.hh +++ b/kernel/mythos/invocation/mythos/InvocationBuf.hh @@ -48,8 +48,12 @@ namespace mythos{ InvocationBase() : tag(0) {} InvocationBase(uint16_t label) : tag(0) { tag.label = label; } - InvocationBase(uint16_t label, uint8_t length, unsigned extraCaps=0) - : tag(0) { tag = tag.label(label).length(length).extra_caps(extraCaps); } + InvocationBase(uint16_t label, uint8_t length, unsigned extraCaps=0) + : tag(0) + { + tag = tag.label(label).length(length).extra_caps(extraCaps); + ASSERT(extraCaps <= 6); + } Tag tag; // 1x 4byte CapPtr dstPtr = null_cap; // 1x 4byte diff --git a/kernel/mythos/invocation/mythos/protocol/ExecutionContext.hh b/kernel/mythos/invocation/mythos/protocol/ExecutionContext.hh index c8d21d44..b51556b6 100644 --- a/kernel/mythos/invocation/mythos/protocol/ExecutionContext.hh +++ b/kernel/mythos/invocation/mythos/protocol/ExecutionContext.hh @@ -46,17 +46,20 @@ namespace mythos { struct Configure : public InvocationBase { typedef InvocationBase response_type; constexpr static uint16_t label = (proto<<8) + CONFIGURE; - Configure(CapPtr as, CapPtr cs, CapPtr sched) - : InvocationBase(label,getLength(this)) + Configure(CapPtr as, CapPtr cs, CapPtr sched, CapPtr state, uint32_t stateOffset) + : InvocationBase(label,getLength(this)), stateOffset(stateOffset) { addExtraCap(as); addExtraCap(cs); addExtraCap(sched); + addExtraCap(state); } CapPtr as() const { return this->capPtrs[0]; } CapPtr cs() const { return this->capPtrs[1]; } CapPtr sched() const { return this->capPtrs[2]; } + CapPtr state() const { return this->capPtrs[3]; } + uint32_t stateOffset; }; struct Amd64Registers { @@ -118,16 +121,22 @@ namespace mythos { struct Create : public KernelMemory::CreateBase { typedef InvocationBase response_type; - Create(CapPtr dst, CapPtr factory) - : CreateBase(dst, factory, getLength(this), 3), start(false) { } + Create(CapPtr dst, CapPtr factory) + : CreateBase(dst, factory, getLength(this), 4) + { + as(null_cap); cs(null_cap); sched(null_cap); state(null_cap); + } Amd64Registers regs; - bool start; + bool start = {false}; + uint32_t stateOffset = {0}; CapPtr as() const { return this->capPtrs[2]; } CapPtr cs() const { return this->capPtrs[3]; } CapPtr sched() const { return this->capPtrs[4]; } + CapPtr state() const { return this->capPtrs[5]; } void as(CapPtr c) { this->capPtrs[2] = c; } void cs(CapPtr c) { this->capPtrs[3] = c; } - void sched(CapPtr c) { this->capPtrs[4] =c; } + void sched(CapPtr c) { this->capPtrs[4] = c; } + void state(CapPtr c) { this->capPtrs[5] = c; } }; template diff --git a/kernel/objects/capability-utils/objects/CapRef.cc b/kernel/objects/capability-utils/objects/CapRef.cc index d37b9422..643e3e35 100644 --- a/kernel/objects/capability-utils/objects/CapRef.cc +++ b/kernel/objects/capability-utils/objects/CapRef.cc @@ -34,7 +34,7 @@ namespace mythos { cap::resetReference(this->entry); } - optional CapRefBase::set(void* subject, CapEntry& src, Cap srcCap) + optional CapRefBase::set(void* subject, CapEntry& src, Cap srcCap, uint64_t extra) { this->reset(); RETURN(cap::setReference( @@ -43,7 +43,7 @@ namespace mythos { src, srcCap, [=](){ this->orig.store(srcCap.asReference().value()); - this->binding(subject, srcCap.asReference()); + this->binding(subject, srcCap.asReference(), extra); })); } diff --git a/kernel/objects/capability-utils/objects/CapRef.hh b/kernel/objects/capability-utils/objects/CapRef.hh index 119f83ef..b093e891 100644 --- a/kernel/objects/capability-utils/objects/CapRef.hh +++ b/kernel/objects/capability-utils/objects/CapRef.hh @@ -36,7 +36,7 @@ namespace mythos { /** * * Subject is the owner of the CapRef instance. - */ + */ class CapRefBase : protected IKernelObject { @@ -56,14 +56,14 @@ namespace mythos { Cap cap() const { return Cap(this->orig.load()); } protected: - optional set(void* subject, CapEntry& src, Cap srcCap); + optional set(void* subject, CapEntry& src, Cap srcCap, uint64_t extra); /** called during successful write to the reference. * * Users should override this method in order to set cached values * and state flags. Mutual exclusion is ensured by the @c CapRef. */ - virtual void binding(void* subject, Cap obj) = 0; + virtual void binding(void* subject, Cap obj, uint64_t extra) = 0; /** called during the revocation or reset of the reference. * @@ -86,7 +86,7 @@ namespace mythos { { public: template - static void binding(Subject *s, Object const& o) { s->bind(o); } + static void binding(Subject *s, Object const& o, uint64_t extra) { s->bind(o, extra); } template static void unbinding(Subject *s, Object const& o) { s->unbind(o); } @@ -102,11 +102,11 @@ namespace mythos { virtual ~CapRef() {} - optional set(Subject* subject, CapEntry* src, Cap srcCap) - { return CapRefBase::set(subject, *src, srcCap); } + optional set(Subject* subject, CapEntry* src, Cap srcCap, uint64_t extra=0) + { return CapRefBase::set(subject, *src, srcCap, extra); } - optional set(Subject* subject, CapEntry& src, Cap srcCap) - { return CapRefBase::set(subject, src, srcCap); } + optional set(Subject* subject, CapEntry& src, Cap srcCap, uint64_t extra=0) + { return CapRefBase::set(subject, src, srcCap, extra); } optional get() const { Cap obj = Cap(this->orig.load()); @@ -115,9 +115,9 @@ namespace mythos { } protected: - void binding(void* subject, Cap orig) override { + void binding(void* subject, Cap orig, uint64_t extra) override { ASSERT(orig.isUsable()); - Revoker::binding(static_cast(subject), orig.getPtr()->cast()); + Revoker::binding(static_cast(subject), orig.getPtr()->cast(), extra); } void unbinding(void* subject, Cap orig) override { diff --git a/kernel/objects/execution-context/objects/ExecutionContext.cc b/kernel/objects/execution-context/objects/ExecutionContext.cc index 34fa75b1..21c81a9b 100644 --- a/kernel/objects/execution-context/objects/ExecutionContext.cc +++ b/kernel/objects/execution-context/objects/ExecutionContext.cc @@ -52,7 +52,7 @@ namespace mythos { if (needPreemption(prev) && !isReady()) { auto place = currentPlace.load(); ASSERT(place != nullptr); - /// @todo is place->preempt() sufficient without waiting? + // place->preempt() is insufficient because the synchronous unbind() has to wait until suspending has finished if (place) synchronousAt(place) << [this]() { MLOG_DETAIL(mlog::ec, "suspended", DVAR(this)); }; @@ -80,7 +80,7 @@ namespace mythos { RETURN(_as.set(this, *pme, obj.cap())); } - void ExecutionContext::bind(optional) + void ExecutionContext::bind(optional, uint64_t) { MLOG_INFO(mlog::ec, "setAddressSpace bind", DVAR(this)); clearFlagsResume(NO_AS); @@ -129,13 +129,7 @@ namespace mythos { } } - Error ExecutionContext::unsetSchedulingContext() - { - _sched.reset(); - return Error::SUCCESS; - } - - void ExecutionContext::bind(optional) + void ExecutionContext::bind(optional, uint64_t) { MLOG_INFO(mlog::ec, "setScheduler bind", DVAR(this)); clearFlagsResume(NO_SCHED); @@ -155,7 +149,31 @@ namespace mythos { TypedCap obj(cse); if (!obj) RETHROW(obj); RETURN(_cs.set(this, *cse, obj.cap())); + } + + optional ExecutionContext::setStateFrame(optional framecapref, uint32_t offset) + { + MLOG_INFO(mlog::ec, "setStateFrame", DVAR(this), DVAR(framecapref)); + TypedCap