Skip to content
Draft
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
65 changes: 57 additions & 8 deletions kernel/app/init-example/app/init.cc
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,53 @@ void test_process(){
MLOG_INFO(mlog::app, "Test process finished");
}

void pageMapPageFault(){
MLOG_INFO(mlog::app, "Trigger PageMap page fault");

mythos::PortalLock pl(portal);

mythos::PageMap pm4(capAlloc());

auto res = pm4.create(pl, kmem, 4).wait();
ASSERT(res);

MLOG_INFO(mlog::app, "Try to delete pm4 -> page fault");

capAlloc.free(pm4.cap(), pl);

MLOG_INFO(mlog::app, "If you can read this, you might have fixed the page fault?!");
}

void pageMapDeadlock(){
MLOG_INFO(mlog::app, "Trigger PageMap deadlock");

mythos::PortalLock pl(portal);

mythos::PageMap pm4(capAlloc());
mythos::PageMap pm3(capAlloc());
mythos::PageMap pm2(capAlloc());

auto res = pm4.create(pl, kmem, 4).wait();
ASSERT(res);
res = pm3.create(pl, kmem, 3).wait();
ASSERT(res);
res = pm2.create(pl, kmem, 2).wait();
ASSERT(res);

uintptr_t vaddr = 0x4000000;

pm4.installMap(pl, pm3, ((vaddr >> 39) & 0x1FF) << 39, 4,
mythos::protocol::PageMap::MapFlags().writable(true).configurable(true)).wait();
pm3.installMap(pl, pm2, ((vaddr >> 30) & 0x1FF) << 30, 3,
mythos::protocol::PageMap::MapFlags().writable(true).configurable(true)).wait();

MLOG_INFO(mlog::app, "Try to delete pm3 -> deadlock");

capAlloc.free(pm3.cap(), pl);

MLOG_INFO(mlog::app, "If you can read this, you might have fixed the deadlock?!");
}

void testCapMapDeletion(){
MLOG_INFO(mlog::app, "Test CapMap deletion");

Expand All @@ -540,21 +587,23 @@ int main()
mythos::syscall_debug(str, sizeof(str)-1);
MLOG_ERROR(mlog::app, "application is starting :)", DVARhex(info_ptr), DVARhex(initstack_top));

test_float();
test_Example();
test_Portal();
//test_float();
//test_Example();
//test_Portal();
test_heap(); // heap must be initialized for tls test
test_tls();
test_exceptions();
//test_tls();
//test_exceptions();
//test_InterruptControl();
//test_HostChannel(portal, 24*1024*1024, 2*1024*1024);
test_ExecutionContext();
test_pthreads();
test_Rapl();
test_processor_allocator();
//test_pthreads();
//test_Rapl();
//test_processor_allocator();
//test_process();
//test_CgaScreen();
testCapMapDeletion();
pageMapPageFault();
pageMapDeadlock();

char const end[] = "bye, cruel world!";
mythos::syscall_debug(end, sizeof(end)-1);
Expand Down
2 changes: 2 additions & 0 deletions kernel/boot/apboot-common/boot/DeployHWThread.hh
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "cpu/idle.hh"
#include "async/Place.hh"
#include "objects/DeleteBroadcast.hh"
#include "objects/PML4InvalidationBroadcastAmd64.hh"
#include "objects/SchedulingContext.hh"
#include "objects/InterruptControl.hh"
#include "boot/memory-layout.h"
Expand Down Expand Up @@ -78,6 +79,7 @@ struct DeployHWThread
{
idt.init();
DeleteBroadcast::init(); // depends on hwthread enumeration
PML4InvalidationBroadcast::init(); // depends on hwthread enumeration
}

void prepare(cpu::ThreadID threadID, cpu::ApicID apicID)
Expand Down
57 changes: 40 additions & 17 deletions kernel/objects/capability-spinning/objects/CapEntry.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,14 @@ namespace mythos {

void CapEntry::initRoot(Cap c)
{
MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this));
ASSERT(isKernelAddress(this));
ASSERT(c.isUsable());
ASSERT(cap().isEmpty());
Link loopLink(this);
MLOG_ERROR(mlog::cap, "this unlocks _next");
_next.store(loopLink.value());
MLOG_ERROR(mlog::cap, "this unlocks _prev");
_prev.store(loopLink.value());
_cap.store(c.value());
}
Expand All @@ -62,6 +65,7 @@ namespace mythos {

void CapEntry::reset()
{
MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this));
ASSERT(isUnlinked() || cap().isAllocated());
_prev.store(Link().value());
_next.store(Link().value());
Expand All @@ -80,32 +84,40 @@ namespace mythos {

optional<void> CapEntry::moveTo(CapEntry& other)
{
MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this), DVAR(other));
ASSERT(other.cap().isAllocated());
ASSERT(!other.isLinked());
lock_cap();
if (!lock_prev()) {
unlock_cap();
other.reset();
THROW(Error::GENERIC_ERROR);
}
lock();
lock_next();
auto thisCap = cap();
if (isRevoking() || !thisCap.isUsable()) {
other.reset();
unlock();
unlock_next();
unlock_prev();
unlock_cap();
THROW(Error::INVALID_CAPABILITY);
}

// using these values removes lock
auto next= Link(_next).withoutFlags();
auto prev= Link(_prev).withoutFlags();

next->setPrevPreserveFlags(&other);
other._next.store(next.value());
// deleted or revoking can not be set in other._prev
// deletion, deleted or revoking can not be set in other._prev
// as we allocated other for moving
other._prev.store(prev.value());
MLOG_ERROR(mlog::cap, "this unlocks prev");
prev->_next.store(Link(&other).value());
other.commit(thisCap);
MLOG_ERROR(mlog::cap, "this unlocks cap");
_prev.store(Link().value());
MLOG_ERROR(mlog::cap, "this unlocks next");
_next.store(Link().value());
_cap.store(Cap().value());
RETURN(Error::SUCCESS);
Expand All @@ -125,31 +137,42 @@ namespace mythos {
return true;
}

optional<void> CapEntry::unlink()
// fails if cap was changed concurrently
bool CapEntry::try_kill(Cap expected)
{
auto next = Link(_next).withoutFlags();
auto prev = Link(_prev).withoutFlags();
next->_prev.store(prev.value());
prev->_next.store(next.value());
_prev.store(Link().value());
CapValue expectedValue = expected.value();
MLOG_DETAIL(mlog::cap, this, ".try_kill", DVAR(expected));
if (!_cap.compare_exchange_strong(expectedValue, expected.asZombie().value())) {
// if the cap was just zombified by sb. else, thats okay
return (Cap(expectedValue).asZombie() == expected.asZombie());
} else return true;
}


optional<void> CapEntry::unlinkAndUnlockLinks()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be good to do all required locking here or in CapEntry's code instead of the external revoke operation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Splitting into locking and an ending operation (similar to a commit) allows us to use locked values to implement higher level operation. We can check if this is possible move locking into unlink after making sure we will not need that in the reworked revocation implementation.

Also, the external revoke operation is not just any operation and is bound to now details about the CapEntry/locking anyway.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we apply this acquire-commit design to the insertAfter operation as well? This might remove this one callback function via template argument in CapEntry.hh

{
MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this));
auto next = Link(_next);
auto prev = Link(_prev);
next->setPrevPreserveFlags(prev.ptr());
MLOG_ERROR(mlog::cap, "this unlocks _next of predecessor");
prev->_next.store(next.withoutFlags().value());
_prev.store(Link().withoutPtr().value());
MLOG_ERROR(mlog::cap, "this unlocks _next");
_next.store(Link().value());
RETURN(Error::SUCCESS);
}

Error CapEntry::try_lock_prev()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should return the predecessor's address because we will need it anyway, see comments on CapEntry class documentation below.

{
auto prev = Link(_prev).ptr();
MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this), DVAR(prev));
if (!prev) {
return Error::GENERIC_ERROR;
}
if (prev->try_lock()) {
if (Link(_prev.load()).ptr() == prev) {
return Error::SUCCESS;
} else { // my _prev has changed in the mean time
prev->unlock();
return Error::RETRY;
}
} else return Error::RETRY;
auto success = prev->try_lock_next(this);
ASSERT(Link(_prev.load()).ptr() == prev);
return success ? Error::SUCCESS : Error::RETRY;
}

bool CapEntry::lock_prev()
Expand Down
Loading