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
8 changes: 4 additions & 4 deletions api/arch/x86/paging.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,11 @@ namespace paging {
using namespace util::literals;
using namespace util::bitops;

/** Conversion from x86 paging flags to mem::Accessflags **/
os::mem::Access to_memflags(Flags f);
/** Conversion from x86 paging flags to mem::Permission flags **/
os::mem::Permission to_memflags(Flags f);
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's go with os::mem::Prot, os::mem::Protect or os::mem::Protection instead - which ever you prefer, aligning with Intel manual and mprotect terminology.

Copy link
Contributor Author

@mazunki mazunki Oct 22, 2025

Choose a reason for hiding this comment

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

I do prefer os::mem::Protection myself, if we have to align ourselves to PROT_* values. I was hoping to use our own constexpr semantics with more extended features. I would like to distinguish between "allow-all" and "undefined protections". There is no way of doing this with a traditional Protection bitmask, since PROT_NONE = 0. Keeping the same name could be confusing.

That is, Protection is the opposite of Permission. Also, related question: do protection flags work the same on all/most architectures?


/** Conversion from mem::Access flags to x86 paging flags **/
Flags to_x86(os::mem::Access prot);
/** Conversion from mem::Permission flags to x86 paging flags **/
Flags to_x86(os::mem::Permission prot);

/** Summary of currently mapped page- and page directories **/
struct Summary {
Expand Down
1 change: 1 addition & 0 deletions api/arch/x86/paging_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#ifndef X86_PAGING_UTILS
#define X86_PAGING_UTILS

#include "arch/x86/paging.hpp"
#include <iostream>
#include <map>

Expand Down
38 changes: 9 additions & 29 deletions api/kernel/memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,10 @@
#include <sstream>
#include <expects>
#include <kernel/memmap.hpp>
#include <sys/mman.hpp>

namespace os::mem {

/** POSIX mprotect compliant access bits **/
enum class Access : uint8_t {
none = 0,
read = 1,
write = 2,
execute = 4
};

using Raw_allocator = buddy::Alloc<false>;

/** Get default allocator for untyped allocations */
Expand Down Expand Up @@ -68,7 +61,7 @@ namespace os::mem {
* Virtual to physical memory mapping.
* For interfacing with the virtual memory API, e.g. mem::map / mem::protect.
**/
template <typename Fl = Access>
template <typename Fl = os::mem::Permission>
struct Mapping
{
static const size_t any_size;
Expand Down Expand Up @@ -126,7 +119,7 @@ namespace os::mem {
Map unmap(uintptr_t addr);

/** Get protection flags for page enclosing a given address */
Access flags(uintptr_t addr);
Permission flags(uintptr_t addr);

/** Determine active page size of a given linear address **/
uintptr_t active_page_size(uintptr_t addr);
Expand All @@ -142,20 +135,20 @@ namespace os::mem {
* might result in 513 4KiB pages or 1 2MiB page and 1 4KiB page getting
* protected.
**/
Map protect(uintptr_t linear, size_t len, Access flags = Access::read);
Map protect(uintptr_t linear, size_t len, Permission flags = Permission::Read); // TODO(mazunki): consider whether we should default to Read here

/**
* Set and return access flags for a given linear address range
* The range is expected to be mapped by a previous call to map.
**/
Access protect_range(uintptr_t linear, Access flags = Access::read);
Permission protect_range(uintptr_t linear, Permission flags = Permission::Read); // TODO(mazunki): consider whether we should default to Read here

/**
* Set and return access flags for a page starting at linear.
* @note : the page size can be any of the supported sizes and
* protection will apply for that whole page.
**/
Access protect_page(uintptr_t linear, Access flags = Access::read);
Permission protect_page(uintptr_t linear, Permission flags = Permission::Read); // TODO(mazunki): consider whether we should default to Read here


/** Get the physical address to which linear address is mapped **/
Expand All @@ -176,20 +169,6 @@ namespace os::mem {





// Enable bitwise ops on access flags
namespace util {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you remind me why you're breaking out a new header for this? The file is only 345 lines

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Mainly because most of api/kernel/memory.hpp involves mappings (at a quick glance). I don't think it's particularly big either. I created sys/mman.hpp intending it to correlate one-to-one with sys_mman(0p) but for C++. Do you disagree?

inline namespace bitops {
template<>
struct enable_bitmask_ops<os::mem::Access> {
using type = typename std::underlying_type<os::mem::Access>::type;
static constexpr bool enable = true;
};
}
}


namespace os::mem {

//
Expand Down Expand Up @@ -333,11 +312,12 @@ namespace os::mem {
virtual_move(uintptr_t src, size_t size, uintptr_t dst, const char* label)
{
using namespace util::bitops;
const auto flags = os::mem::Access::read | os::mem::Access::write;
const auto flags = os::mem::Permission::Data; // TODO(mazunki): shouldn't this inherit flags from @src?
// setup @dst as new virt area for @src
os::mem::map({dst, src, flags, size}, label);

// unpresent @src
os::mem::protect(src, size, os::mem::Access::none);
os::mem::protect(src, size, os::mem::Permission::Any); // TODO(mazunki): change to Permission::None when introduced
}
}

Expand Down
53 changes: 53 additions & 0 deletions api/sys/mman.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* provides namespaced types for `sys_mman(0p)` values
*/
#ifndef _SYS_MMAN_HPP
#define _SYS_MMAN_HPP

#include <cstdint>
#include <sys/mman.h>
#include <util/bitops.hpp>
#include <type_traits>

namespace os::mem {
enum class Flags : uint8_t {
None = 0,
Shared = MAP_SHARED,
Private = MAP_PRIVATE,
Fixed = MAP_FIXED,
Anonymous = MAP_ANONYMOUS,
};

enum class Permission : uint8_t { // TODO(mazunki): consider making Permission::{Read,Write,Execute} private or standalone class
Read = PROT_READ,
Write = PROT_WRITE,
Execute = PROT_EXEC,

Data = Read | Write,
Code = Read | Execute,

Any = 0, // TODO(mazunki): this should really be R|W|X; but requires some refactoring
RWX = Read|Write|Execute, // TODO(mazunki): temporary, remove me. references should use Permission::Any

// None = 0, // TODO(mazunki): implement this after Any is properly implemented (to avoid confusion with old Access::none which had a different meaning). should block all access (best used for unmapped stuff, potentially tests)
};
} // os::mmap


namespace util {
inline namespace bitops {
template<> struct enable_bitmask_ops<os::mem::Flags> {
using type = std::underlying_type<os::mem::Flags>::type;
static constexpr bool enable = true;
};
}

inline namespace bitops {
template<>
struct enable_bitmask_ops<os::mem::Permission> {
using type = typename std::underlying_type<os::mem::Permission>::type;
static constexpr bool enable = true;
};
}
}
#endif // _SYS_MMAN_HPP
19 changes: 17 additions & 2 deletions api/util/bitops.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,19 +115,34 @@ constexpr operator~(E flag){

// bool has_flag(flag)
template<typename E>
constexpr typename std::enable_if<enable_bitmask_ops<E>::enable, bool>::type
[[nodiscard]] constexpr typename std::enable_if<enable_bitmask_ops<E>::enable, bool>::type
has_flag(E flag){
using base_type = typename std::underlying_type<E>::type;
return static_cast<base_type>(flag);
}

// bool has_flag(field, flags)
template<typename E>
constexpr typename std::enable_if<enable_bitmask_ops<E>::enable, bool>::type
[[nodiscard]] constexpr typename std::enable_if<enable_bitmask_ops<E>::enable, bool>::type
has_flag(E field, E flags){
return (field & flags) == flags ;
}

// bool missing_flag(flag)
template<typename E>
[[nodiscard]] constexpr typename std::enable_if<enable_bitmask_ops<E>::enable, bool>::type
missing_flag(E flag){
using base_type = typename std::underlying_type<E>::type;
return static_cast<base_type>(flag) == 0;
}

// bool missing_flag(field, flags)
template<typename E>
[[nodiscard]] constexpr typename std::enable_if<enable_bitmask_ops<E>::enable, bool>::type
missing_flag(E field, E flags) noexcept {
return (field & flags) != flags;
}


// Enable for uint8_t
template<>
Expand Down
1 change: 1 addition & 0 deletions deps/musl/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ stdenv.mkDerivation rec {
patches = [
./patches/musl.patch
./patches/endian.patch
./patches/mmap.patch
];

passthru.linuxHeaders = linuxHeaders;
Expand Down
21 changes: 21 additions & 0 deletions deps/musl/patches/mmap.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
diff --git a/src/mman/mmap.c b/src/mman/mmap.c
index 43e5e029..43307692 100644
--- a/src/mman/mmap.c
+++ b/src/mman/mmap.c
@@ -36,4 +36,15 @@ void *__mmap(void *start, size_t len, int prot, int flags, int fd, off_t off)
return (void *)__syscall_ret(ret);
}

-weak_alias(__mmap, mmap);
+void *__includeos_mmap(void *start, size_t len, int prot, int flags, int fd, off_t off)
+{
+ long ret;
+ if (flags & MAP_FIXED) {
+ __vm_wait();
+ }
+ ret = __syscall(SYS_mmap, start, len, prot, flags, fd, off);
+
+ return (void *) ret;
+}
+
+weak_alias(__includeos_mmap, mmap);
2 changes: 1 addition & 1 deletion src/arch/i686/paging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ namespace mem {
}

template <>
const size_t Mapping<os::mem::Access>::any_size = 4096;
const size_t Mapping<os::mem::Permission>::any_size = 4096;
}
}
4 changes: 2 additions & 2 deletions src/arch/x86_64/ist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ static stack create_stack_virt(size_t size, const char* name)
// TODO randomize location / ask virtual memory allocator
const uintptr_t stack_area = 1ull << 46;

const mem::Access flags = mem::Access::read | mem::Access::write;
const mem::Permission flags = mem::Permission::Data;

// Virtual area
// Adds a guard page between each new stack
Expand All @@ -53,7 +53,7 @@ static stack create_stack_virt(size_t size, const char* name)

Expects(map);
Expects(mem::active_page_size(map.lin) == 4096);
Expects(mem::flags(map.lin - 1) == mem::Access::none
Expects(mem::flags(map.lin - 1) == mem::Permission::Any // TODO(mazunki): should this be Permission::None?
&& "Guard page should not present");

// Next stack starts after next page
Expand Down
Loading