Compare commits

...

11 Commits

39 changed files with 486 additions and 86 deletions

View File

@ -1,9 +1,11 @@
set(glacier_files
status/error.cpp
string/string.cpp
string/string_builder.cpp
string/string_view.cpp
string/str_format.cpp
string/str_split.cpp
util/hash.cpp
)
add_library(glacier STATIC

View File

@ -7,35 +7,11 @@
#include "glacier/container/pair.h"
#include "glacier/status/error.h"
#include "glacier/string/string.h"
#include "glacier/util/hash.h"
namespace glcr {
template <typename T>
struct HashFunc {
uint64_t operator()(const T&);
};
template <>
struct HashFunc<uint64_t> {
uint64_t operator()(const uint64_t& value) {
// FIXME: Write a real hash function.
return 0xABBAABBAABBAABBA ^ value;
}
};
template <>
struct HashFunc<String> {
uint64_t operator()(const String& value) {
// FIXME: Write a real hash function.
uint64_t acc = 0;
for (uint64_t i = 0; i < value.length(); i++) {
acc += value[i];
}
return 0xABBAABBAABBAABBA ^ acc;
}
};
template <typename K, typename V, class H = HashFunc<K>>
template <typename K, typename V, class H = Hash<K>>
class HashMap {
public:
HashMap() = default;

View File

@ -0,0 +1,44 @@
#include "glacier/status/error.h"
namespace glcr {
StringView ErrorCodeToStr(ErrorCode code) {
switch (code) {
case OK:
return "OK";
case INVALID_ARGUMENT:
return "INVALID_ARGUMENT";
case NOT_FOUND:
return "NOT_FOUND";
case PERMISSION_DENIED:
return "PERMISSION_DENIED";
case NULL_PTR:
return "NULL_PTR";
case EMPTY:
return "EMPTY";
case ALREADY_EXISTS:
return "ALREADY_EXISTS";
case BUFFER_SIZE:
return "BUFFER_SIZE";
case FAILED_PRECONDITION:
return "FAILED_PRECONDITION";
case INTERNAL:
return "INTERNAL";
case UNIMPLEMENTED:
return "UNIMPLEMENTED";
case EXHAUSTED:
return "EXHAUSTED";
case INVALID_RESPONSE:
return "INVALID_RESPONSE";
case CAP_NOT_FOUND:
return "CAP_NOT_FOUND";
case CAP_WRONG_TYPE:
return "CAP_WRONG_TYPE";
case CAP_PERMISSION_DENIED:
return "CAP_PERMISSION_DENIED";
default:
return "UNKNOWN";
}
}
} // namespace glcr

View File

@ -2,6 +2,8 @@
#include <stdint.h>
#include "glacier/string/string_view.h"
namespace glcr {
enum ErrorCode : uint64_t {
@ -29,6 +31,8 @@ enum ErrorCode : uint64_t {
};
StringView ErrorCodeToStr(ErrorCode code);
#define RET_ERR(expr) \
{ \
glcr::ErrorCode _tmp_err = static_cast<glcr::ErrorCode>(expr); \

View File

@ -0,0 +1,63 @@
#pragma once
#include "status/error.h"
#include "string/string.h"
namespace glcr {
class Status {
public:
static Status Ok() { return {}; }
Status(ErrorCode code) : code_(code), message_() {}
Status(ErrorCode code, StringView message) : code_(code), message_(message) {}
explicit operator bool() { return ok(); }
bool ok() { return code_ == OK; }
ErrorCode code() { return code_; }
StringView message() { return message_; }
private:
ErrorCode code_;
String message_;
Status();
};
Status InvalidArgument(StringView message) {
return Status(INVALID_ARGUMENT, message);
}
Status NotFound(StringView message) { return Status(NOT_FOUND, message); }
Status PermissionDenied(StringView message) {
return Status(PERMISSION_DENIED, message);
}
Status NullPtr(StringView message) { return Status(NULL_PTR, message); }
Status Empty(StringView message) { return Status(EMPTY, message); }
Status AlreadyExists(StringView message) {
return Status(ALREADY_EXISTS, message);
}
Status BufferSize(StringView message) { return Status(BUFFER_SIZE, message); }
Status FailedPrecondition(StringView message) {
return Status(FAILED_PRECONDITION, message);
}
Status Internal(StringView message) { return Status(INTERNAL, message); }
Status Unimplemented(StringView message) {
return Status(UNIMPLEMENTED, message);
}
Status Exhausted(StringView message) { return Status(EXHAUSTED, message); }
Status InvalidResponse(StringView message) {
return Status(INVALID_RESPONSE, message);
}
} // namespace glcr

View File

@ -57,7 +57,7 @@ void StrFormatValue(StringBuilder& builder, const uint64_t& value,
template <>
void StrFormatValue(StringBuilder& builder, const ErrorCode& value,
StringView opts) {
StrFormatValue(builder, static_cast<uint64_t>(value), opts);
StrFormatValue(builder, ErrorCodeToStr(value), opts);
}
template <>

30
lib/glacier/util/hash.cpp Normal file
View File

@ -0,0 +1,30 @@
#include "util/hash.h"
#include "string/string.h"
namespace glcr {
namespace {
const uint64_t kFnvOffset = 0xcbf29ce484222325;
const uint64_t kFnvPrime = 0x100000001b3;
} // namespace
uint64_t Hash<uint64_t>::operator()(const uint64_t& value) {
uint64_t hash = kFnvOffset;
for (uint8_t i = 0; i < 8; i++) {
hash *= kFnvPrime;
hash ^= (value >> (8 * i)) & 0xFF;
}
return hash;
}
uint64_t Hash<String>::operator()(const String& value) {
uint64_t hash = kFnvOffset;
for (uint8_t i = 0; i < value.length(); i++) {
hash *= kFnvPrime;
hash ^= value[i];
}
return hash;
}
} // namespace glcr

27
lib/glacier/util/hash.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include <stdint.h>
namespace glcr {
// General purpose templated hash function.
// Currently the template speciializations
// implement FNV hashing:
// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
template <typename T>
struct Hash {
uint64_t operator()(const T&);
};
template <>
struct Hash<uint64_t> {
uint64_t operator()(const uint64_t&);
};
class String;
template <>
struct Hash<String> {
uint64_t operator()(const String&);
};
} // namespace glcr

View File

@ -10,6 +10,7 @@ add_library(mammoth STATIC
src/process.cpp
src/port_client.cpp
src/port_server.cpp
src/semaphore.cpp
src/thread.cpp
)

View File

@ -0,0 +1,15 @@
#pragma once
#include <ztypes.h>
class Semaphore {
public:
Semaphore();
~Semaphore();
void Wait();
void Signal();
private:
z_cap_t semaphore_cap_;
};

View File

@ -0,0 +1,11 @@
#include "mammoth/semaphore.h"
#include <zcall.h>
#include "mammoth/debug.h"
Semaphore::Semaphore() { check(ZSemaphoreCreate(&semaphore_cap_)); }
Semaphore::~Semaphore() { check(ZCapRelease(semaphore_cap_)); }
void Semaphore::Wait() { check(ZSemaphoreWait(semaphore_cap_)); }
void Semaphore::Signal() { check(ZSemaphoreSignal(semaphore_cap_)); }

View File

@ -2,16 +2,11 @@
## Yellowstone
- Store registered services in a hashmap.
- Requires: Adding hashmap to Glacier.
- Start the next service from a configuration file.
## Denali
- Migrate denali to a yunq definition.
- Requires: Adding async yunq servers (or more synchronization primitives)
- Add the ability to send multiple Ahci commands at once.
## VictoriaFalls
- Add a read file VFS service.

View File

@ -85,7 +85,7 @@ void AhciDevice::HandleIrq() {
for (uint64_t i = 0; i < 32; i++) {
if (commands_finished & (1 << i)) {
commands_issued_ &= ~(1 << i);
commands_[i]->Callback();
commands_[i]->SignalComplete();
}
}

View File

@ -7,11 +7,11 @@
Command::~Command() {}
DmaReadCommand::DmaReadCommand(uint64_t lba, uint64_t sector_cnt,
uint64_t paddr, Mutex& callback_mutex)
uint64_t paddr)
: lba_(lba),
sector_cnt_(sector_cnt),
paddr_(paddr),
callback_mutex_(callback_mutex) {}
callback_semaphore_() {}
DmaReadCommand::~DmaReadCommand() {}
@ -47,4 +47,6 @@ void DmaReadCommand::PopulatePrdt(PhysicalRegionDescriptor* prdt) {
prdt[0].region_address = paddr_;
prdt[0].byte_count = sector_cnt_ * 512;
}
void DmaReadCommand::Callback() { callback_mutex_.Release(); }
void DmaReadCommand::SignalComplete() { callback_semaphore_.Signal(); }
void DmaReadCommand::WaitComplete() { callback_semaphore_.Wait(); }

View File

@ -1,8 +1,8 @@
#pragma once
#include <mammoth/memory_region.h>
#include <mammoth/mutex.h>
#include <mammoth/response_context.h>
#include <mammoth/semaphore.h>
#include <stdint.h>
#include "ahci/ahci.h"
@ -12,24 +12,27 @@ class Command {
virtual ~Command();
virtual void PopulateFis(uint8_t* command_fis) = 0;
virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) = 0;
virtual void Callback() = 0;
virtual void WaitComplete() = 0;
virtual void SignalComplete() = 0;
};
class DmaReadCommand : public Command {
public:
DmaReadCommand(uint64_t lba, uint64_t sector_cnt, uint64_t dest_paddr,
Mutex& callback_mutex);
DmaReadCommand(uint64_t lba, uint64_t sector_cnt, uint64_t dest_paddr);
virtual ~DmaReadCommand() override;
void PopulateFis(uint8_t* command_fis) override;
void PopulatePrdt(PhysicalRegionDescriptor* prdt) override;
void Callback() override;
void WaitComplete() override;
void SignalComplete() override;
private:
uint64_t lba_;
uint64_t sector_cnt_;
uint64_t paddr_;
Mutex& callback_mutex_;
// TODO: Make this owned by the device so that we don't have to create a new
// one with the kernel every time a command is issued.
Semaphore callback_semaphore_;
};

View File

@ -15,19 +15,15 @@ glcr::ErrorOr<glcr::UniquePtr<DenaliServer>> DenaliServer::Create(
glcr::ErrorCode DenaliServer::HandleRead(const ReadRequest& req,
ReadResponse& resp) {
ASSIGN_OR_RETURN(AhciDevice * device, driver_.GetDevice(req.device_id()));
ASSIGN_OR_RETURN(Mutex mutex, Mutex::Create());
RET_ERR(mutex.Lock());
uint64_t paddr;
OwnedMemoryRegion region =
OwnedMemoryRegion::ContiguousPhysical(req.size() * 512, &paddr);
DmaReadCommand command(req.lba(), req.size(), paddr, mutex);
DmaReadCommand command(req.lba(), req.size(), paddr);
device->IssueCommand(&command);
// Wait for read operation to complete.
RET_ERR(mutex.Lock());
RET_ERR(mutex.Release());
command.WaitComplete();
resp.set_device_id(req.device_id());
resp.set_size(req.size());
@ -38,33 +34,31 @@ glcr::ErrorCode DenaliServer::HandleRead(const ReadRequest& req,
glcr::ErrorCode DenaliServer::HandleReadMany(const ReadManyRequest& req,
ReadResponse& resp) {
ASSIGN_OR_RETURN(AhciDevice * device, driver_.GetDevice(req.device_id()));
ASSIGN_OR_RETURN(Mutex mutex, Mutex::Create());
RET_ERR(mutex.Lock());
uint64_t region_paddr;
OwnedMemoryRegion region = OwnedMemoryRegion::ContiguousPhysical(
req.lba().size() * 512, &region_paddr);
auto& vec = req.lba();
uint64_t curr_run_start = 0;
for (uint64_t i = 0; i < vec.size(); i++) {
if (i + 1 < vec.size() && vec.at(i) + 1 == vec.at(i + 1)) {
continue;
if (req.lba().size() != req.sector_cnt().size()) {
return glcr::INVALID_ARGUMENT;
}
uint64_t lba = vec.at(curr_run_start);
uint64_t size = (i - curr_run_start) + 1;
uint64_t paddr = region_paddr + curr_run_start * 512;
DmaReadCommand command(lba, size, paddr, mutex);
uint64_t sector_cnt = 0;
for (uint64_t i = 0; i < req.sector_cnt().size(); i++) {
sector_cnt += req.sector_cnt().at(i);
}
uint64_t region_paddr;
OwnedMemoryRegion region =
OwnedMemoryRegion::ContiguousPhysical(sector_cnt * 512, &region_paddr);
for (uint64_t i = 0; i < req.lba().size(); i++) {
uint64_t lba = req.lba().at(i);
uint64_t size = req.sector_cnt().at(i);
DmaReadCommand command(lba, size, region_paddr);
device->IssueCommand(&command);
command.WaitComplete();
// Wait for read operation to complete.
RET_ERR(mutex.Lock());
curr_run_start = i + 1;
region_paddr += size * 512;
}
resp.set_device_id(req.device_id());
resp.set_size(req.lba().size());
resp.set_size(sector_cnt);
resp.set_memory(region.DuplicateCap());
return glcr::OK;
}

View File

@ -11,7 +11,10 @@ message ReadRequest {
message ReadManyRequest {
u64 device_id;
// FIXME: Add repeated message fields.
// Must be the same length.
repeated u64 lba;
repeated u64 sector_cnt;
}
message ReadResponse {

View File

@ -100,11 +100,21 @@ void ReadManyRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint
lba_.PushBack(bytes.At<uint64_t>(i));
}
// Parse sector_cnt.
auto sector_cnt_pointer = bytes.At<ExtPointer>(offset + header_size + (8 * 2));
sector_cnt_.Resize(sector_cnt_pointer.length / sizeof(uint64_t));
for (uint64_t i = offset + sector_cnt_pointer.offset;
i < offset + sector_cnt_pointer.offset + sector_cnt_pointer.length;
i += sizeof(uint64_t)) {
sector_cnt_.PushBack(bytes.At<uint64_t>(i));
}
}
uint64_t ReadManyRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const {
uint32_t next_extension = header_size + 8 * 2;
uint32_t next_extension = header_size + 8 * 3;
const uint32_t core_size = next_extension;
// Write device_id.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * 0), device_id());
@ -121,6 +131,19 @@ uint64_t ReadManyRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t off
uint32_t ext_offset = offset + lba_ptr.offset + (i * sizeof(uint64_t));
bytes.WriteAt<uint64_t>(ext_offset, lba().at(i));
}
// Write sector_cnt.
ExtPointer sector_cnt_ptr{
.offset = next_extension,
.length = (uint32_t)(sector_cnt().size() * sizeof(uint64_t)),
};
next_extension += sector_cnt_ptr.length;
bytes.WriteAt<ExtPointer>(offset + header_size + (8 * 2), sector_cnt_ptr);
for (uint64_t i = 0; i < sector_cnt().size(); i++) {
uint32_t ext_offset = offset + sector_cnt_ptr.offset + (i * sizeof(uint64_t));
bytes.WriteAt<uint64_t>(ext_offset, sector_cnt().at(i));
}
// The next extension pointer is the length of the message.
WriteHeader(bytes, offset, core_size, next_extension);
@ -129,7 +152,7 @@ uint64_t ReadManyRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t off
}
uint64_t ReadManyRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const {
uint32_t next_extension = header_size + 8 * 2;
uint32_t next_extension = header_size + 8 * 3;
const uint32_t core_size = next_extension;
uint64_t next_cap = 0;
// Write device_id.
@ -147,6 +170,19 @@ uint64_t ReadManyRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t off
uint32_t ext_offset = offset + lba_ptr.offset + (i * sizeof(uint64_t));
bytes.WriteAt<uint64_t>(ext_offset, lba().at(i));
}
// Write sector_cnt.
ExtPointer sector_cnt_ptr{
.offset = next_extension,
.length = (uint32_t)(sector_cnt().size() * sizeof(uint64_t)),
};
next_extension += sector_cnt_ptr.length;
bytes.WriteAt<ExtPointer>(offset + header_size + (8 * 2), sector_cnt_ptr);
for (uint64_t i = 0; i < sector_cnt().size(); i++) {
uint32_t ext_offset = offset + sector_cnt_ptr.offset + (i * sizeof(uint64_t));
bytes.WriteAt<uint64_t>(ext_offset, sector_cnt().at(i));
}
// The next extension pointer is the length of the message.
WriteHeader(bytes, offset, core_size, next_extension);

View File

@ -47,10 +47,13 @@ class ReadManyRequest {
void set_device_id(const uint64_t& value) { device_id_ = value; }
const glcr::Vector<uint64_t>& lba() const { return lba_; }
void add_lba(const uint64_t& value) { lba_.PushBack(value); }
const glcr::Vector<uint64_t>& sector_cnt() const { return sector_cnt_; }
void add_sector_cnt(const uint64_t& value) { sector_cnt_.PushBack(value); }
private:
uint64_t device_id_;
glcr::Vector<uint64_t> lba_;
glcr::Vector<uint64_t> sector_cnt_;
// Parses everything except for caps.
void ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset);

View File

@ -1,4 +1,5 @@
add_executable(teton
framebuffer/console.cpp
framebuffer/framebuffer.cpp
framebuffer/psf.cpp
teton.cpp

View File

@ -0,0 +1,44 @@
#include "framebuffer/console.h"
#include <mammoth/debug.h>
void Console::WriteChar(char c) {
if (c == '\n') {
CursorReturn();
return;
}
uint64_t row = cursor_pos_ / cols();
if (row >= rows()) {
crash("Unimplemented console scroll.", glcr::UNIMPLEMENTED);
}
uint64_t fb_row = row * (psf_.height() + 1);
uint64_t col = cursor_pos_ % cols();
uint64_t fb_col = col * (psf_.width() + 1);
uint8_t* glyph = psf_.glyph(c);
for (uint32_t r = fb_row; r < fb_row + psf_.height(); r++) {
for (uint32_t c = fb_col; c < fb_col + psf_.width(); c++) {
uint8_t glyph_offset = psf_.width() - (c - fb_col) - 1;
if ((glyph[r] & (1 << glyph_offset))) {
framebuf_.DrawPixel(r, c, 0xFFFFFFF);
} else {
framebuf_.DrawPixel(r, c, 0);
}
}
}
cursor_pos_++;
}
void Console::WriteString(glcr::StringView str) {
for (uint64_t i = 0; i < str.size(); i++) {
WriteChar(str[i]);
}
}
void Console::CursorReturn() {
cursor_pos_ -= cursor_pos_ % cols();
cursor_pos_ += cols();
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <glacier/string/string_view.h>
#include "framebuffer/framebuffer.h"
#include "framebuffer/psf.h"
class Console {
public:
explicit Console(Framebuffer& fb, Psf& psf) : framebuf_(fb), psf_(psf) {}
void WriteChar(char c);
void WriteString(glcr::StringView str);
uint32_t rows() { return framebuf_.height() / (psf_.height() + 1); }
uint32_t cols() { return framebuf_.width() / (psf_.width() + 1); }
private:
// TODO: Don't store a reference here.
Framebuffer& framebuf_;
Psf& psf_;
uint64_t cursor_pos_ = 0;
void CursorIncr();
void CursorReturn();
};

View File

@ -11,6 +11,9 @@ class Framebuffer {
void DrawGlyph(uint8_t* glyph);
uint64_t width() { return fb_info_.width(); }
uint64_t height() { return fb_info_.height(); }
private:
// FIXME: Implement Yunq copy or move so we
// don't have to store a reference here.

View File

@ -20,6 +20,8 @@ class Psf {
void DumpHeader();
uint32_t size() { return header_->numglyph; }
uint32_t width() { return header_->width; }
uint32_t height() { return header_->height; }
uint8_t* glyph(uint32_t index) {
return reinterpret_cast<uint8_t*>(psf_file_.vaddr() + header_->headersize +

View File

@ -3,6 +3,7 @@
#include <victoriafalls/victoriafalls.yunq.client.h>
#include <yellowstone/yellowstone.yunq.client.h>
#include "framebuffer/console.h"
#include "framebuffer/framebuffer.h"
#include "framebuffer/psf.h"
@ -22,12 +23,6 @@ uint64_t main(uint64_t init_port) {
Framebuffer fbuf(framebuffer);
for (uint64_t r = 0; r < 20; r++) {
for (uint64_t c = 0; c < 20; c++) {
fbuf.DrawPixel(r, c, 0x0000FF00);
}
}
// 2. Parse a font file.
GetEndpointRequest req;
@ -45,7 +40,11 @@ uint64_t main(uint64_t init_port) {
Psf psf(OwnedMemoryRegion::FromCapability(fresp.memory()));
psf.DumpHeader();
fbuf.DrawGlyph(psf.glyph('C'));
Console console(fbuf, psf);
console.WriteString("Hello World!\n");
for (uint8_t i = 0x20; i < 0x7E; i++) {
console.WriteChar(i);
}
// 3. Write a line to the screen.

View File

@ -78,14 +78,19 @@ glcr::ErrorOr<OwnedMemoryRegion> Ext2BlockReader::ReadBlocks(
const glcr::Vector<uint64_t>& block_list) {
ReadManyRequest req;
req.set_device_id(device_id_);
// FIXME: We should have better ergonomics for setting a repeated field in
// Yunq.
for (uint64_t i = 0; i < block_list.size(); i++) {
uint64_t sector = lba_offset_ + block_list.at(i) * SectorsPerBlock();
for (uint64_t j = 0; j < SectorsPerBlock(); j++) {
req.add_lba(sector + j);
uint64_t curr_start = lba_offset_ + block_list.at(i) * SectorsPerBlock();
uint64_t curr_run_len = 1;
while ((i + 1) < block_list.size() &&
block_list.at(i + 1) == block_list.at(i) + 1) {
i++;
curr_run_len++;
}
req.add_lba(curr_start);
req.add_sector_cnt(curr_run_len * SectorsPerBlock());
dbgln("Read {x}, {x}", curr_start, curr_run_len * SectorsPerBlock());
}
dbgln("Read many: {x}", req.lba().size());
ReadResponse resp;
RET_ERR(denali_.ReadMany(req, resp));
return OwnedMemoryRegion::FromCapability(resp.memory());

View File

@ -31,6 +31,7 @@ add_executable(zion
object/port.cpp
object/process.cpp
object/reply_port.cpp
object/semaphore.cpp
object/thread.cpp
scheduler/context_switch.s
scheduler/jump_user_space.s

View File

@ -6,8 +6,6 @@
- Reserve lower physical memory for hardware accesses as necessary.
- Return errors rather than panicking on allocation failure
- Return memory pages to the pool when a MemoryObject goes out of scope.
- Add diagnostics to inspect physical memory usage.
### Virtual Memory
@ -46,7 +44,6 @@
- Add different scheduling priorities.
- Add thread sleep capability.
- Add synchronization syscalls for userspace.
## Large Projects

View File

@ -64,5 +64,8 @@ SYS1(CapRelease, z_cap_t, cap);
SYS1(MutexCreate, z_cap_t*, mutex_cap);
SYS1(MutexLock, z_cap_t, mutex_cap);
SYS1(MutexRelease, z_cap_t, mutex_cap);
SYS1(SemaphoreCreate, z_cap_t*, semaphore_cap);
SYS1(SemaphoreWait, z_cap_t, semaphore_cap);
SYS1(SemaphoreSignal, z_cap_t, semaphore_cap);
SYS1(Debug, const char*, message);

View File

@ -60,6 +60,9 @@ const uint64_t kZionCapRelease = 0x71;
const uint64_t kZionMutexCreate = 0x80;
const uint64_t kZionMutexLock = 0x81;
const uint64_t kZionMutexRelease = 0x82;
const uint64_t kZionSemaphoreCreate = 0x83;
const uint64_t kZionSemaphoreWait = 0x84;
const uint64_t kZionSemaphoreSignal = 0x85;
// Debugging Calls.
const uint64_t kZionDebug = 0x1'0000;
@ -89,6 +92,9 @@ const uint64_t kZionPerm_SpawnThread = 0x200;
// Permissions on mutexes.
const uint64_t kZionPerm_Lock = 0x100;
const uint64_t kZionPerm_Release = 0x200;
// Permissions on semaphores.
const uint64_t kZionPerm_Wait = 0x100;
const uint64_t kZionPerm_Signal = 0x200;
const z_perm_t kZionPerm_None = 0;
const z_perm_t kZionPerm_All = -1;

View File

@ -75,6 +75,12 @@ extern "C" void interrupt_divide_by_zero(InterruptFrame* frame) {
panic("DIV0");
}
extern "C" void isr_invalid_opcode();
extern "C" void interrupt_invalid_opcode(InterruptFrame* frame) {
dbgln("RIP: {x}", frame->rip);
panic("INVALID OPCODE");
}
extern "C" void isr_protection_fault();
extern "C" void interrupt_protection_fault(InterruptFrame* frame) {
dbgln("General Protection Fault");
@ -183,6 +189,7 @@ extern "C" void interrupt_pci4(InterruptFrame*) {
void InitIdt() {
gIdt[0] = CreateDescriptor(isr_divide_by_zero);
gIdt[0x6] = CreateDescriptor(isr_invalid_opcode);
gIdt[0xD] = CreateDescriptor(isr_protection_fault);
gIdt[0xE] = CreateDescriptor(isr_page_fault);
gIdt[0x13] = CreateDescriptor(isr_fpe_fault);

View File

@ -56,6 +56,7 @@ isr_\name:
.endm
isr_handler divide_by_zero
isr_handler invalid_opcode
isr_handler protection_fault,1
isr_handler page_fault,1
isr_handler fpe_fault

View File

@ -15,6 +15,7 @@ class KernelObject : public glcr::RefCounted<KernelObject> {
ENDPOINT = 0x7,
REPLY_PORT = 0x8,
MUTEX = 0x9,
SEMAPHORE = 0x10,
};
virtual uint64_t TypeTag() = 0;

29
zion/object/semaphore.cpp Normal file
View File

@ -0,0 +1,29 @@
#include "object/semaphore.h"
#include "scheduler/scheduler.h"
glcr::RefPtr<Semaphore> Semaphore::Create() {
return glcr::AdoptPtr<Semaphore>(new Semaphore());
}
// FIXME: We almost certainly have some race conditions
// between this and unlock where we could end up with
// a thread in the blocked_threads_ queue while noone is holding the lock.
void Semaphore::Signal() {
__atomic_fetch_add(&lock_, 0x1, __ATOMIC_SEQ_CST);
if (blocked_threads_.size() > 0) {
auto thread = blocked_threads_.PopFront();
thread->SetState(Thread::RUNNABLE);
gScheduler->Enqueue(thread);
}
}
void Semaphore::Wait() {
while (lock_ == 0) {
auto thread = gScheduler->CurrentThread();
thread->SetState(Thread::BLOCKED);
blocked_threads_.PushBack(thread);
gScheduler->Yield();
}
__atomic_fetch_sub(&lock_, 0x1, __ATOMIC_SEQ_CST);
}

33
zion/object/semaphore.h Normal file
View File

@ -0,0 +1,33 @@
#pragma once
#include <glacier/container/intrusive_list.h>
#include <glacier/memory/ref_ptr.h>
#include "include/ztypes.h"
#include "object/kernel_object.h"
#include "object/thread.h"
class Semaphore;
template <>
struct KernelObjectTag<Semaphore> {
static const uint64_t type = KernelObject::SEMAPHORE;
};
class Semaphore : public KernelObject {
public:
uint64_t TypeTag() override { return KernelObject::SEMAPHORE; }
static uint64_t DefaultPermissions() {
return kZionPerm_Wait | kZionPerm_Signal;
}
static glcr::RefPtr<Semaphore> Create();
void Wait();
void Signal();
private:
uint8_t lock_ = 0;
glcr::IntrusiveList<Thread> blocked_threads_;
};

View File

@ -7,7 +7,7 @@
z_err_t ProcessExit(ZProcessExitReq* req) {
auto curr_thread = gScheduler->CurrentThread();
dbgln("Exit code: {x}", req->code);
dbgln("Exit code: {}", static_cast<glcr::ErrorCode>(req->code));
curr_thread->process().Exit();
panic("Returned from thread exit");
return glcr::UNIMPLEMENTED;

View File

@ -1,6 +1,7 @@
#include "syscall/synchronization.h"
#include "object/mutex.h"
#include "object/semaphore.h"
#include "scheduler/scheduler.h"
glcr::ErrorCode MutexCreate(ZMutexCreateReq* req) {
@ -22,10 +23,35 @@ glcr::ErrorCode MutexLock(ZMutexLockReq* req) {
glcr::ErrorCode MutexRelease(ZMutexReleaseReq* req) {
auto& curr_proc = gScheduler->CurrentProcess();
auto cap = curr_proc.GetCapability(req->mutex_cap);
// TODO: We may not want a separate permission for releasing the mutex.
RET_ERR(ValidateCapability<Mutex>(cap, kZionPerm_Release));
auto mutex = cap->obj<Mutex>();
mutex->Release();
return glcr::OK;
}
glcr::ErrorCode SemaphoreCreate(ZSemaphoreCreateReq* req) {
auto& curr_proc = gScheduler->CurrentProcess();
*req->semaphore_cap = curr_proc.AddNewCapability(Semaphore::Create());
return glcr::OK;
}
glcr::ErrorCode SemaphoreWait(ZSemaphoreWaitReq* req) {
auto& curr_proc = gScheduler->CurrentProcess();
auto cap = curr_proc.GetCapability(req->semaphore_cap);
RET_ERR(ValidateCapability<Semaphore>(cap, kZionPerm_Wait));
auto semaphore = cap->obj<Semaphore>();
semaphore->Wait();
return glcr::OK;
}
glcr::ErrorCode SemaphoreSignal(ZSemaphoreSignalReq* req) {
auto& curr_proc = gScheduler->CurrentProcess();
auto cap = curr_proc.GetCapability(req->semaphore_cap);
RET_ERR(ValidateCapability<Semaphore>(cap, kZionPerm_Signal));
auto semaphore = cap->obj<Semaphore>();
semaphore->Signal();
return glcr::OK;
}

View File

@ -7,3 +7,7 @@
glcr::ErrorCode MutexCreate(ZMutexCreateReq* req);
glcr::ErrorCode MutexLock(ZMutexLockReq* req);
glcr::ErrorCode MutexRelease(ZMutexReleaseReq* req);
glcr::ErrorCode SemaphoreCreate(ZSemaphoreCreateReq* req);
glcr::ErrorCode SemaphoreWait(ZSemaphoreWaitReq* req);
glcr::ErrorCode SemaphoreSignal(ZSemaphoreSignalReq* req);

View File

@ -88,6 +88,9 @@ extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req) {
CASE(MutexCreate);
CASE(MutexLock);
CASE(MutexRelease);
CASE(SemaphoreCreate);
CASE(SemaphoreWait);
CASE(SemaphoreSignal);
// syscall/debug.h
CASE(Debug);
default: