[kernel] Add spinlocks to vm_space, frame_allocator
Also updated spinlock interface to be an object, and added a scoped lock object that uses it as well.
This commit is contained in:
@@ -32,8 +32,6 @@ struct cpu_data
|
|||||||
TSS *tss;
|
TSS *tss;
|
||||||
GDT *gdt;
|
GDT *gdt;
|
||||||
|
|
||||||
// Values from here on don't need to be in the asm version
|
|
||||||
kutil::spinlock::node spinner;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" cpu_data * _current_gsbase();
|
extern "C" cpu_data * _current_gsbase();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "kernel_memory.h"
|
|
||||||
#include "kutil/assert.h"
|
#include "kutil/assert.h"
|
||||||
#include "kutil/memory.h"
|
#include "kutil/memory.h"
|
||||||
|
|
||||||
#include "frame_allocator.h"
|
#include "frame_allocator.h"
|
||||||
#include "kernel_args.h"
|
#include "kernel_args.h"
|
||||||
#include "kernel_memory.h"
|
#include "kernel_memory.h"
|
||||||
@@ -17,8 +17,8 @@ frame_allocator::get()
|
|||||||
}
|
}
|
||||||
|
|
||||||
frame_allocator::frame_allocator(kernel::args::frame_block *frames, size_t count) :
|
frame_allocator::frame_allocator(kernel::args::frame_block *frames, size_t count) :
|
||||||
m_blocks(frames),
|
m_blocks {frames},
|
||||||
m_count(count)
|
m_count {count}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,6 +32,8 @@ bsf(uint64_t v)
|
|||||||
size_t
|
size_t
|
||||||
frame_allocator::allocate(size_t count, uintptr_t *address)
|
frame_allocator::allocate(size_t count, uintptr_t *address)
|
||||||
{
|
{
|
||||||
|
kutil::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
for (long i = m_count - 1; i >= 0; --i) {
|
for (long i = m_count - 1; i >= 0; --i) {
|
||||||
frame_block &block = m_blocks[i];
|
frame_block &block = m_blocks[i];
|
||||||
|
|
||||||
@@ -80,6 +82,8 @@ frame_allocator::allocate(size_t count, uintptr_t *address)
|
|||||||
void
|
void
|
||||||
frame_allocator::free(uintptr_t address, size_t count)
|
frame_allocator::free(uintptr_t address, size_t count)
|
||||||
{
|
{
|
||||||
|
kutil::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
kassert(address % frame_size == 0, "Trying to free a non page-aligned frame!");
|
kassert(address % frame_size == 0, "Trying to free a non page-aligned frame!");
|
||||||
|
|
||||||
if (!count)
|
if (!count)
|
||||||
@@ -116,6 +120,8 @@ frame_allocator::free(uintptr_t address, size_t count)
|
|||||||
void
|
void
|
||||||
frame_allocator::used(uintptr_t address, size_t count)
|
frame_allocator::used(uintptr_t address, size_t count)
|
||||||
{
|
{
|
||||||
|
kutil::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
kassert(address % frame_size == 0, "Trying to mark a non page-aligned frame!");
|
kassert(address % frame_size == 0, "Trying to mark a non page-aligned frame!");
|
||||||
|
|
||||||
if (!count)
|
if (!count)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
/// Allocator for physical memory frames
|
/// Allocator for physical memory frames
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "kutil/spinlock.h"
|
||||||
|
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
namespace args {
|
namespace args {
|
||||||
@@ -43,7 +44,9 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
frame_block *m_blocks;
|
frame_block *m_blocks;
|
||||||
long m_count;
|
size_t m_count;
|
||||||
|
|
||||||
|
kutil::spinlock m_lock;
|
||||||
|
|
||||||
frame_allocator() = delete;
|
frame_allocator() = delete;
|
||||||
frame_allocator(const frame_allocator &) = delete;
|
frame_allocator(const frame_allocator &) = delete;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ vm_space::vm_space(page_table *p) :
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
vm_space::vm_space() :
|
vm_space::vm_space() :
|
||||||
m_kernel(false)
|
m_kernel {false}
|
||||||
{
|
{
|
||||||
m_pml4 = page_table::get_table_page();
|
m_pml4 = page_table::get_table_page();
|
||||||
page_table *kpml4 = kernel_space().m_pml4;
|
page_table *kpml4 = kernel_space().m_pml4;
|
||||||
@@ -163,6 +163,7 @@ void
|
|||||||
vm_space::page_in(const vm_area &vma, uintptr_t offset, uintptr_t phys, size_t count)
|
vm_space::page_in(const vm_area &vma, uintptr_t offset, uintptr_t phys, size_t count)
|
||||||
{
|
{
|
||||||
using memory::frame_size;
|
using memory::frame_size;
|
||||||
|
kutil::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
uintptr_t base = 0;
|
uintptr_t base = 0;
|
||||||
if (!find_vma(vma, base))
|
if (!find_vma(vma, base))
|
||||||
@@ -190,6 +191,7 @@ void
|
|||||||
vm_space::clear(const vm_area &vma, uintptr_t offset, size_t count, bool free)
|
vm_space::clear(const vm_area &vma, uintptr_t offset, size_t count, bool free)
|
||||||
{
|
{
|
||||||
using memory::frame_size;
|
using memory::frame_size;
|
||||||
|
kutil::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
uintptr_t base = 0;
|
uintptr_t base = 0;
|
||||||
if (!find_vma(vma, base))
|
if (!find_vma(vma, base))
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "kutil/enum_bitfields.h"
|
#include "kutil/enum_bitfields.h"
|
||||||
|
#include "kutil/spinlock.h"
|
||||||
#include "kutil/vector.h"
|
#include "kutil/vector.h"
|
||||||
#include "page_table.h"
|
#include "page_table.h"
|
||||||
|
|
||||||
@@ -127,6 +128,8 @@ private:
|
|||||||
bool operator==(const struct area &o) const;
|
bool operator==(const struct area &o) const;
|
||||||
};
|
};
|
||||||
kutil::vector<area> m_areas;
|
kutil::vector<area> m_areas;
|
||||||
|
|
||||||
|
kutil::spinlock m_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
IS_BITFIELD(vm_space::fault_type);
|
IS_BITFIELD(vm_space::fault_type);
|
||||||
|
|||||||
@@ -4,17 +4,43 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace kutil {
|
namespace kutil {
|
||||||
namespace spinlock {
|
|
||||||
|
|
||||||
/// An MCS based spinlock node
|
/// An MCS based spinlock
|
||||||
struct node
|
class spinlock
|
||||||
{
|
{
|
||||||
bool locked;
|
public:
|
||||||
node *next;
|
spinlock();
|
||||||
|
~spinlock();
|
||||||
|
|
||||||
|
/// A node in the wait queue.
|
||||||
|
struct waiter
|
||||||
|
{
|
||||||
|
bool locked;
|
||||||
|
waiter *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
void acquire(waiter *w);
|
||||||
|
void release(waiter *w);
|
||||||
|
|
||||||
|
private:
|
||||||
|
waiter *m_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
void aquire(node *lock, node *waiter);
|
/// Scoped lock that owns a spinlock::waiter
|
||||||
void release(node *lock, node *waiter);
|
class scoped_lock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline scoped_lock(spinlock &lock) : m_lock(lock) {
|
||||||
|
m_lock.acquire(&m_waiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~scoped_lock() {
|
||||||
|
m_lock.release(&m_waiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
spinlock &m_lock;
|
||||||
|
spinlock::waiter m_waiter;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace spinlock
|
|
||||||
} // namespace kutil
|
} // namespace kutil
|
||||||
|
|||||||
@@ -1,48 +1,49 @@
|
|||||||
#include "kutil/spinlock.h"
|
#include "kutil/spinlock.h"
|
||||||
|
|
||||||
namespace kutil {
|
namespace kutil {
|
||||||
namespace spinlock {
|
|
||||||
|
|
||||||
static constexpr int memorder = __ATOMIC_SEQ_CST;
|
static constexpr int memorder = __ATOMIC_SEQ_CST;
|
||||||
|
|
||||||
|
spinlock::spinlock() : m_lock {nullptr} {}
|
||||||
|
spinlock::~spinlock() {}
|
||||||
|
|
||||||
void
|
void
|
||||||
aquire(node * &lock, node *waiter)
|
spinlock::acquire(waiter *w)
|
||||||
{
|
{
|
||||||
waiter->next = nullptr;
|
w->next = nullptr;
|
||||||
waiter->locked = true;
|
w->locked = true;
|
||||||
|
|
||||||
// Point the lock at this waiter
|
// Point the lock at this waiter
|
||||||
node *prev = __atomic_exchange_n(&lock, waiter, memorder);
|
waiter *prev = __atomic_exchange_n(&m_lock, w, memorder);
|
||||||
if (prev) {
|
if (prev) {
|
||||||
// If there was a previous waiter, wait for them to
|
// If there was a previous waiter, wait for them to
|
||||||
// unblock us
|
// unblock us
|
||||||
prev->next = waiter;
|
prev->next = w;
|
||||||
while (waiter->locked) {
|
while (w->locked) {
|
||||||
asm ("pause");
|
asm ("pause");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
waiter->locked = false;
|
w->locked = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
release(node * &lock, node *waiter)
|
spinlock::release(waiter *w)
|
||||||
{
|
{
|
||||||
if (!waiter->next) {
|
if (!w->next) {
|
||||||
// If we're still the last waiter, we're done
|
// If we're still the last waiter, we're done
|
||||||
if(__atomic_compare_exchange_n(&lock, &waiter, nullptr, false, memorder, memorder))
|
if(__atomic_compare_exchange_n(&m_lock, &w, nullptr, false, memorder, memorder))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for the subseqent waiter to tell us who they are
|
// Wait for the subseqent waiter to tell us who they are
|
||||||
while (!waiter->next) {
|
while (!w->next) {
|
||||||
asm ("pause");
|
asm ("pause");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unblock the subseqent waiter
|
// Unblock the subseqent waiter
|
||||||
waiter->next->locked = false;
|
w->next->locked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace spinlock
|
|
||||||
} // namespace kutil
|
} // namespace kutil
|
||||||
|
|||||||
Reference in New Issue
Block a user