diff --git a/kernel/app/init-example/app/init.cc b/kernel/app/init-example/app/init.cc index b2602826..84c0b493 100644 --- a/kernel/app/init-example/app/init.cc +++ b/kernel/app/init-example/app/init.cc @@ -208,8 +208,12 @@ void test_tls() y = 2*y; TEST_EQ(x, 2048); TEST_EQ(y, 4096); + + std::atomic sync(0); auto threadFun = [] (void *data) -> void* { + auto sync = reinterpret_cast*>(data); + sync->store(1); MLOG_INFO(mlog::app, "main thread TLS:", DVARhex(readFS(0)), DVARhex(readFS(0x28))); TEST_EQ(x, 1024); TEST_EQ(y, 2048); @@ -220,20 +224,31 @@ void test_tls() y = y*2; TEST_EQ(x, 2048); TEST_EQ(y, 4096); + sync->store(2); return nullptr; }; mythos::ExecutionContext ec1(capAlloc()); auto tls = mythos::setupNewTLS(); + mythos::Frame stateFrame(capAlloc()); + auto res2 = stateFrame.create(pl, kmem, 4096, 4096).wait(); + TEST(res2); MLOG_INFO(mlog::app, "test_EC: create ec1 TLS", DVARhex(tls)); ASSERT(tls != nullptr); auto res1 = ec1.create(kmem).as(myAS).cs(myCS).sched(mythos::init::SCHEDULERS_START + 1) - .prepareStack(thread1stack_top).startFun(threadFun, nullptr, ec1.cap()) + .state(stateFrame.cap(),0) + .prepareStack(thread1stack_top) + .startFun(threadFun, &sync, ec1.cap()) .suspended(false).fs(tls) .invokeVia(pl).wait(); TEST(res1); TEST(ec1.setFSGS(pl,(uint64_t) tls, 0).wait()); mythos::syscall_signal(ec1.cap()); + MLOG_INFO(mlog::app, "waiting for EC to finish..."); + while (sync.load() != 2) {} // @todo should call mythos::syscall_yield() + // delete ec1, stateFrame; cannot delete the allocated TLS :-/ + capAlloc.free(stateFrame, pl); + capAlloc.free(ec1, pl); MLOG_INFO(mlog::app, "End test tls"); } @@ -331,14 +346,14 @@ void* threadMain(void* arg){ } void test_pthreads(){ - MLOG_INFO(mlog::app, "Test Pthreads"); - pthread_t p; - - auto tmp = pthread_create(&p, NULL, &threadMain, NULL); - MLOG_INFO(mlog::app, "pthread_create returned", DVAR(tmp)); - pthread_join(p, NULL); - - MLOG_INFO(mlog::app, "End Test Pthreads"); + MLOG_INFO(mlog::app, "Test Pthreads"); + pthread_t p; + + auto tmp = pthread_create(&p, NULL, &threadMain, NULL); + MLOG_INFO(mlog::app, "pthread_create returned", DVAR(tmp)); + pthread_join(p, NULL); + + MLOG_INFO(mlog::app, "End Test Pthreads"); } void test_omp(){ @@ -368,12 +383,14 @@ void test_omp(){ mythos::Mutex mutex; void* thread_main(void* ctx) { + auto sync = reinterpret_cast*>(ctx); MLOG_INFO(mlog::app, "hello thread!", DVAR(ctx)); mutex << [ctx]() { MLOG_INFO(mlog::app, "thread in mutex", DVAR(ctx)); }; mythos::ISysretHandler::handle(mythos::syscall_wait()); MLOG_INFO(mlog::app, "thread resumed from wait", DVAR(ctx)); + sync->store(2); return 0; } @@ -382,25 +399,34 @@ void test_ExecutionContext() MLOG_INFO(mlog::app, "Test ExecutionContext"); mythos::ExecutionContext ec1(capAlloc()); mythos::ExecutionContext ec2(capAlloc()); + mythos::Frame stateFrame(capAlloc()); + std::atomic sync1(0); + std::atomic sync2(0); { MLOG_INFO(mlog::app, "test_EC: create ec1"); mythos::PortalLock pl(portal); // future access will fail if the portal is in use already + auto res3 = stateFrame.create(pl, kmem, 2*4096, 4096).wait(); + TEST(res3); auto tls1 = mythos::setupNewTLS(); ASSERT(tls1 != nullptr); - auto res1 = ec1.create(kmem).as(myAS).cs(myCS).sched(mythos::init::SCHEDULERS_START) - .prepareStack(thread1stack_top).startFun(&thread_main, nullptr, ec1.cap()) - .suspended(false).fs(tls1) - .invokeVia(pl).wait(); + auto res1 = ec1.create(kmem).as(myAS).cs(myCS).sched(mythos::init::SCHEDULERS_START+1) + .state(stateFrame.cap(), 0) + .prepareStack(thread1stack_top) + .startFun(&thread_main, &sync1, ec1.cap()) + .suspended(false).fs(tls1) + .invokeVia(pl).wait(); TEST(res1); MLOG_INFO(mlog::app, "test_EC: create ec2"); auto tls2 = mythos::setupNewTLS(); ASSERT(tls2 != nullptr); auto res2 = ec2.create(kmem).as(myAS).cs(myCS).sched(mythos::init::SCHEDULERS_START+1) - .prepareStack(thread2stack_top).startFun(&thread_main, nullptr, ec2.cap()) - .suspended(false).fs(tls2) - .invokeVia(pl).wait(); + .state(stateFrame.cap(), 4096) + .prepareStack(thread2stack_top) + .startFun(&thread_main, &sync2, ec2.cap()) + .suspended(false).fs(tls2) + .invokeVia(pl).wait(); TEST(res2); } @@ -408,9 +434,21 @@ void test_ExecutionContext() for (volatile int j=0; j<1000; j++) {} } - MLOG_INFO(mlog::app, "sending notifications"); + MLOG_INFO(mlog::app, " sending notifications"); mythos::syscall_signal(ec1.cap()); mythos::syscall_signal(ec2.cap()); + MLOG_INFO(mlog::app, " waiting for EC1 to finish..."); + while (sync1.load() != 2) {} // @todo should call mythos::syscall_yield() + MLOG_INFO(mlog::app, " waiting for EC2 to finish..."); + while (sync2.load() != 2) {} // @todo should call mythos::syscall_yield() + + { + MLOG_INFO(mlog::app, "test_EC: delete ECs and state frame"); + mythos::PortalLock pl(portal); // future access will fail if the portal is in use already + capAlloc.free(stateFrame, pl); + capAlloc.free(ec1, pl); + capAlloc.free(ec2, pl); + } MLOG_INFO(mlog::app, "End Test ExecutionContext"); } @@ -421,10 +459,15 @@ void test_InterruptControl() { mythos::PortalLock pl(portal); // future access will fail if the portal is in use already mythos::ExecutionContext ec(capAlloc()); + mythos::Frame stateFrame(capAlloc()); + auto res2 = stateFrame.create(pl, kmem, 4096, 4096).wait(); + TEST(res2); auto tls = mythos::setupNewTLS(); ASSERT(tls != nullptr); auto res1 = ec.create(kmem).as(myAS).cs(myCS).sched(mythos::init::SCHEDULERS_START + 2) - .prepareStack(thread3stack_top).startFun(&thread_main, nullptr, ec.cap()) + .state(stateFrame.cap(), 0) + .prepareStack(thread3stack_top) + .startFun(&thread_main, nullptr, ec.cap()) .suspended(false).fs(tls) .invokeVia(pl).wait(); TEST(res1); diff --git a/kernel/boot/init-loader-amd64/boot/load_init.cc b/kernel/boot/init-loader-amd64/boot/load_init.cc index d7fe9e31..13ee544f 100644 --- a/kernel/boot/init-loader-amd64/boot/load_init.cc +++ b/kernel/boot/init-loader-amd64/boot/load_init.cc @@ -47,9 +47,9 @@ namespace mythos { - + Event event::initLoader; - + namespace boot { InitLoader::InitLoader(char* image) @@ -140,6 +140,10 @@ optional InitLoader::initCSpace() res = memMapper.installPML4(init::PML4); if (!res) RETHROW(res); + MLOG_INFO(mlog::boot, "... create state frame for init thread in cap", init::STATE_FRAME); + auto stateFrameCap = memMapper.createFrame(init::STATE_FRAME, 4096, 4096); + if (!stateFrameCap) RETHROW(stateFrameCap); + MLOG_INFO(mlog::boot, "... create example factory in cap", init::EXAMPLE_FACTORY); res = optional(Error::SUCCESS); if (res) res = csSet(init::EXAMPLE_FACTORY, factory::example); @@ -277,8 +281,9 @@ optional InitLoader::createEC(uintptr_t ipc_vaddr) if (res) res = ec->setCapSpace(capAlloc.get(init::CSPACE)); if (res) res = ec->setAddressSpace(capAlloc.get(init::PML4)); if (res) res = ec->setSchedulingContext(capAlloc.get(init::SCHEDULERS_START)); + if (res) res = ec->setStateFrame(capAlloc.get(init::STATE_FRAME), 0, true); if (!res) RETHROW(res); - ec->getThreadState().rdi = ipc_vaddr; + ec->setRegParams(ipc_vaddr); // will be in rdi ec->setEntryPoint(_img.header()->entry); ec->setTrapped(false); RETURN(Error::SUCCESS); diff --git a/kernel/cpu/fpu-amd64/cpu/fpu.cc b/kernel/cpu/fpu-amd64/cpu/fpu.cc index 227340c2..0bbdcaee 100644 --- a/kernel/cpu/fpu-amd64/cpu/fpu.cc +++ b/kernel/cpu/fpu-amd64/cpu/fpu.cc @@ -41,7 +41,7 @@ static uint32_t xstate_sizes[x86::XFeature::MAX]; static uint32_t xstate_comp_offsets[x86::XFeature::MAX]; enum FpuMode { FSAVE, FXSAVE, XSAVE, XSAVEOPT, XSAVES }; -static char const * const fpuModeNames[] = +static char const * const fpuModeNames[] = {"FSAVE", "FXSAVE", "XSAVE", "XSAVEOPT", "XSAVES"}; static FpuMode fpu_mode = FSAVE; @@ -49,7 +49,7 @@ static FpuMode fpu_mode = FSAVE; static void fpu_setup_xstate() { // ask cpuid for supported features - xfeatures_mask = x86::getXFeaturesMask(); + xfeatures_mask = x86::getXFeaturesMask(); mlog::boot.detail("xsave features from cpuid 0xd", DVARhex(xfeatures_mask)); // and then disable features not supported by the processor if (!x86::hasFPU()) xfeatures_mask.fp = false; @@ -88,7 +88,7 @@ static void fpu_setup_xstate() } PANIC(fpu_xstate_size <= sizeof(x86::FpuState)); //do_extra_xstate_size_checks(); - // for PT: update_regset_xstate_info(fpu_user_xstate_size, xfeatures_mask & ~XFEATURE_MASK_SUPERVISOR); + // for PT: update_regset_xstate_info(fpu_user_xstate_size, xfeatures_mask & ~XFEATURE_MASK_SUPERVISOR); // get the offsets and sizes of the state space xstate_offsets[0] = 0; // legacy FPU state @@ -100,7 +100,7 @@ static void fpu_setup_xstate() auto last_good_offset = offsetof(x86::XRegs, extended_state_area); // beginnning of the "extended state" for (uint8_t idx = 2; idx < x86::XFeature::MAX; idx++) { if (!xfeatures_mask.enabled(idx)) continue; - xstate_offsets[idx] = (!x86::isXFeatureSupervisor(idx)) ? x86::getXFeatureOffset(idx) : 0; + xstate_offsets[idx] = (!x86::isXFeatureSupervisor(idx)) ? x86::getXFeatureOffset(idx) : 0; xstate_sizes[idx] = x86::getXFeatureSize(idx); OOPS_MSG(last_good_offset <= xstate_offsets[idx], "cpu has misordered xstate"); last_good_offset = xstate_offsets[idx]; @@ -132,7 +132,7 @@ static void fpu_setup_xstate() char const* names[] = {"x87", "mmx/sse", "ymm", "bndregs", "bndcsr", "opmask", "zmm_hi256", "hi16_zmm", "pt", "pkru"}; for (uint8_t idx = 0; idx < x86::XFeature::MAX; idx++) { if (!xfeatures_mask.enabled(idx)) continue; - mlog::boot.detail("we support XSAVE feature", idx, names[idx], + mlog::boot.detail("we support XSAVE feature", idx, names[idx], DVARhex(xstate_offsets[idx]), DVAR(xstate_sizes[idx]), DVARhex(xstate_comp_offsets[idx]), DVAR(xstate_comp_sizes[idx])); } @@ -144,8 +144,8 @@ void FpuState::initBSP() mlog::boot.info("has x87 FPU:", DVAR(x86::hasMMX()), DVAR(x86::hasAVX()), DVAR(x86::hasAVX()&&x86::hasAVX512F()), DVAR(x86::hasXSAVE()), - DVAR(x86::hasXSAVE()&&x86::hasXSAVEC()), - DVAR(x86::hasXSAVE()&&x86::hasXSAVEOPT()), + DVAR(x86::hasXSAVE()&&x86::hasXSAVEC()), + DVAR(x86::hasXSAVE()&&x86::hasXSAVEOPT()), DVAR(x86::hasXSAVE()&&x86::hasXSAVES())); // initialise MXCR feature mask for fxsr @@ -276,6 +276,11 @@ void FpuState::clear() memcpy(&state, &fpu_init_state, fpu_xstate_size); } +size_t FpuState::size() +{ + return fpu_xstate_size; +} + } // namespace cpu } // namespace mythos diff --git a/kernel/cpu/fpu-amd64/cpu/fpu.hh b/kernel/cpu/fpu-amd64/cpu/fpu.hh index 1760ff10..4c0c0d71 100644 --- a/kernel/cpu/fpu-amd64/cpu/fpu.hh +++ b/kernel/cpu/fpu-amd64/cpu/fpu.hh @@ -44,13 +44,14 @@ namespace mythos { /** called during bootup on each processor. */ static void initAP(); + static size_t size(); void clear(); void save(); void restore(); public: - x86::FpuState state; + x86::FpuState state; }; } // namespace cpu diff --git a/kernel/cpu/kernel-entry-amd64/cpu/irq_entry.S b/kernel/cpu/kernel-entry-amd64/cpu/irq_entry.S index dee17b06..25b1c665 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/mythos/init/mythos/init.hh b/kernel/mythos/init/mythos/init.hh index 150e8e00..2712ae74 100644 --- a/kernel/mythos/init/mythos/init.hh +++ b/kernel/mythos/init/mythos/init.hh @@ -39,6 +39,7 @@ namespace init { PML4, EC, PORTAL, + STATE_FRAME, EXAMPLE_FACTORY, MEMORY_REGION_FACTORY, EXECUTION_CONTEXT_FACTORY, 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..48a2926c 100644 --- a/kernel/mythos/invocation/mythos/protocol/ExecutionContext.hh +++ b/kernel/mythos/invocation/mythos/protocol/ExecutionContext.hh @@ -46,17 +46,21 @@ 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, bool initializeState) + : InvocationBase(label,getLength(this)), stateOffset(stateOffset), initializeState(initializeState) { 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; + bool initializeState; }; struct Amd64Registers { @@ -118,16 +122,23 @@ 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}; + bool initializeState = {true}; 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 21c21e57..55fae02e 100644 --- a/kernel/objects/execution-context/objects/ExecutionContext.cc +++ b/kernel/objects/execution-context/objects/ExecutionContext.cc @@ -38,26 +38,19 @@ 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(); } void ExecutionContext::setFlagsSuspend(flag_t f) { - auto prev = setFlags(f | DONT_PREEMPT); + auto prev = setFlags(f | DONT_PREEMPT); // cleared by resume() MLOG_DETAIL(mlog::ec, "set flag", DVAR(this), DVARhex(f), DVARhex(prev), DVARhex(flags.load()), isReady()); - if (needPreemption(prev) && !isReady()) { - auto place = currentPlace.load(); - ASSERT(place != nullptr); - /// @todo is place->preempt() sufficient without waiting? - if (place) synchronousAt(place) << [this]() { + auto place = currentPlace.load(); + if (needPreemption(prev) && place != nullptr) { + // place->preempt() is insufficient because the synchronous unbind() has to wait until suspending has finished + synchronousAt(place) << [this]() { MLOG_DETAIL(mlog::ec, "suspended", DVAR(this)); }; } @@ -80,13 +73,16 @@ namespace mythos { MLOG_INFO(mlog::ec, "setAddressSpace", DVAR(this), DVAR(pme)); TypedCap obj(pme); if (!obj) RETHROW(obj); - if (!obj->getPageMapInfo(obj.cap()).isRootMap()) THROW(Error::INVALID_CAPABILITY); - RETURN(_as.set(this, *pme, obj.cap())); + auto info = obj->getPageMapInfo(obj.cap()); + if (!info.isRootMap()) THROW(Error::INVALID_CAPABILITY); + + RETURN(_as.set(this, *pme, obj.cap(), info.table.physint())); } - void ExecutionContext::bind(optional) + void ExecutionContext::bind(optional, uint64_t tableAddr) { - MLOG_INFO(mlog::ec, "setAddressSpace bind", DVAR(this)); + MLOG_INFO(mlog::ec, "setAddressSpace bind", DVAR(this), DVARhex(tableAddr)); + page_table = PhysPtr(tableAddr); clearFlagsResume(NO_AS); } @@ -94,6 +90,7 @@ namespace mythos { { MLOG_INFO(mlog::ec, "setAddressSpace unbind", DVAR(this)); setFlagsSuspend(NO_AS); + page_table = PhysPtr(); } optional ExecutionContext::setSchedulingContext(optional sce) @@ -117,7 +114,7 @@ namespace mythos { if (place != nullptr) { // save my state place->run(t->set([this, msg, sce](Tasklet*){ - this->fpuState.save(); + this->state->fpuState.save(); TypedCap obj(sce); if (!obj) { msg->replyResponse(obj.state()); @@ -133,13 +130,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); @@ -159,13 +150,51 @@ namespace mythos { TypedCap obj(cse); if (!obj) RETHROW(obj); RETURN(_cs.set(this, *cse, obj.cap())); + } + + optional ExecutionContext::setStateFrame(optional framecapref, uint32_t offset, bool initializeState) + { + MLOG_INFO(mlog::ec, "setStateFrame", DVAR(this), DVAR(framecapref)); + TypedCap