Skip to content
Open
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
79 changes: 61 additions & 18 deletions kernel/app/init-example/app/init.cc
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,12 @@ void test_tls()
y = 2*y;
TEST_EQ(x, 2048);
TEST_EQ(y, 4096);

std::atomic<int> sync(0);

auto threadFun = [] (void *data) -> void* {
auto sync = reinterpret_cast<std::atomic<int>*>(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);
Expand All @@ -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");
}

Expand Down Expand Up @@ -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(){
Expand Down Expand Up @@ -368,12 +383,14 @@ void test_omp(){
mythos::Mutex mutex;
void* thread_main(void* ctx)
{
auto sync = reinterpret_cast<std::atomic<int>*>(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;
}

Expand All @@ -382,35 +399,56 @@ void test_ExecutionContext()
MLOG_INFO(mlog::app, "Test ExecutionContext");
mythos::ExecutionContext ec1(capAlloc());
mythos::ExecutionContext ec2(capAlloc());
mythos::Frame stateFrame(capAlloc());
std::atomic<int> sync1(0);
std::atomic<int> 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);
}

for (volatile int i=0; i<100000; i++) {
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");
}

Expand All @@ -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);
Expand Down
11 changes: 8 additions & 3 deletions kernel/boot/init-loader-amd64/boot/load_init.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@


namespace mythos {

Event<boot::InitLoader&> event::initLoader;

namespace boot {

InitLoader::InitLoader(char* image)
Expand Down Expand Up @@ -140,6 +140,10 @@ optional<void> 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<void>(Error::SUCCESS);
if (res) res = csSet(init::EXAMPLE_FACTORY, factory::example);
Expand Down Expand Up @@ -277,8 +281,9 @@ optional<void> 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);
Expand Down
19 changes: 12 additions & 7 deletions kernel/cpu/fpu-amd64/cpu/fpu.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ 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;


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;
Expand Down Expand Up @@ -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
Expand All @@ -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];
Expand Down Expand Up @@ -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]));
}
Expand All @@ -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
Expand Down Expand Up @@ -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

Expand Down
3 changes: 2 additions & 1 deletion kernel/cpu/fpu-amd64/cpu/fpu.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
45 changes: 5 additions & 40 deletions kernel/cpu/kernel-entry-amd64/cpu/irq_entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
14 changes: 6 additions & 8 deletions kernel/cpu/kernel-entry-amd64/cpu/kernel_entry.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading