mirror of
https://github.com/justinian/jsix.git
synced 2025-12-09 16:04:32 -08:00
[util] Remove enum_bitfields
The enum_bitfields system never worked quite right, and always had edge cases where name resolution for the SFINAE would fail. Move everything over to use util::bitset, which can be constexpr and boils down to inline integer bitops in release mode. Improved util::bitset itself, moving the array-backed base implementation into a new util::sized_bitset, and making the single-inttype backed implementation the base case. Also added a distinction between | or |= (which work with real bit values) and + or += (which work with bit indexes).
This commit is contained in:
@@ -22,7 +22,7 @@ read_string(util::buffer &data)
|
||||
static void
|
||||
read_descriptor(descriptor &e, util::buffer &data)
|
||||
{
|
||||
e.flags = static_cast<desc_flags>(*util::read<uint16_t>(data));
|
||||
e.flags = util::bitset16 {*util::read<uint16_t>(data)};
|
||||
e.path = read_string(data);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <bootproto/bootconfig.h>
|
||||
#include <util/bitset.h>
|
||||
#include <util/counted.h>
|
||||
|
||||
namespace uefi {
|
||||
@@ -14,7 +15,7 @@ namespace boot {
|
||||
using desc_flags = bootproto::desc_flags;
|
||||
|
||||
struct descriptor {
|
||||
desc_flags flags;
|
||||
util::bitset16 flags;
|
||||
wchar_t const *path;
|
||||
};
|
||||
|
||||
@@ -27,7 +28,7 @@ public:
|
||||
/// Constructor. Loads bootconfig from the given buffer.
|
||||
bootconfig(util::buffer data, uefi::boot_services *bs);
|
||||
|
||||
inline uint16_t flags() const { return m_flags; }
|
||||
inline util::bitset16 flags() const { return m_flags; }
|
||||
inline const descriptor & kernel() const { return m_kernel; }
|
||||
inline const descriptor & init() const { return m_init; }
|
||||
inline const wchar_t * initrd() const { return m_initrd; }
|
||||
@@ -35,7 +36,7 @@ public:
|
||||
inline const descriptors & panics() { return m_panics; }
|
||||
|
||||
private:
|
||||
uint16_t m_flags;
|
||||
util::bitset16 m_flags;
|
||||
descriptor m_kernel;
|
||||
descriptor m_init;
|
||||
descriptors m_panics;
|
||||
|
||||
@@ -110,7 +110,7 @@ parse_program(const wchar_t *name, util::const_buffer data, bootproto::program &
|
||||
section.phys_addr = elf.base() + seg.offset;
|
||||
section.virt_addr = seg.vaddr;
|
||||
section.size = seg.mem_size;
|
||||
section.type = static_cast<bootproto::section_flags>(seg.flags);
|
||||
section.type = seg.flags;
|
||||
|
||||
if (seg.mem_size != seg.file_size)
|
||||
section.phys_addr = allocate_bss(seg);
|
||||
@@ -128,8 +128,6 @@ load_program(
|
||||
paging::pager &pager,
|
||||
bool verify)
|
||||
{
|
||||
using util::bits::has;
|
||||
|
||||
status_line status(L"Loading program", name);
|
||||
|
||||
elf::file elf {data};
|
||||
@@ -155,8 +153,8 @@ load_program(
|
||||
|
||||
pager.map_pages(phys_addr, seg.vaddr,
|
||||
memory::bytes_to_pages(seg.mem_size),
|
||||
has(seg.flags, elf::segment_flags::write),
|
||||
has(seg.flags, elf::segment_flags::exec));
|
||||
seg.flags.get(elf::segment_flags::write),
|
||||
seg.flags.get(elf::segment_flags::exec));
|
||||
}
|
||||
|
||||
return elf.entrypoint();
|
||||
|
||||
@@ -82,9 +82,8 @@ load_resources(
|
||||
util::buffer kernel = loader::load_file(disk, bc.kernel().path);
|
||||
uintptr_t kentry = loader::load_program(kernel, L"jsix kernel", pager, true);
|
||||
|
||||
args->flags = static_cast<bootproto::boot_flags>(bc.flags());
|
||||
args->flags = bc.flags();
|
||||
|
||||
namespace bits = util::bits;
|
||||
using bootproto::desc_flags;
|
||||
|
||||
bool has_panic = false;
|
||||
@@ -96,7 +95,7 @@ load_resources(
|
||||
// Find the screen-specific panic handler first to
|
||||
// give it priority
|
||||
for (const descriptor &d : bc.panics()) {
|
||||
if (bits::has(d.flags, desc_flags::graphical)) {
|
||||
if (d.flags.get(desc_flags::graphical)) {
|
||||
panic = loader::load_file(disk, d.path);
|
||||
has_panic = true;
|
||||
break;
|
||||
@@ -106,7 +105,7 @@ load_resources(
|
||||
|
||||
if (!has_panic) {
|
||||
for (const descriptor &d : bc.panics()) {
|
||||
if (!bits::has(d.flags, desc_flags::graphical)) {
|
||||
if (d.flags.get(desc_flags::graphical)) {
|
||||
panic = loader::load_file(disk, d.path);
|
||||
has_panic = true;
|
||||
break;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <util/enum_bitfields.h>
|
||||
#include <util/bitset.h>
|
||||
#include <util/misc.h> // for byteswap32
|
||||
|
||||
namespace acpi {
|
||||
@@ -62,32 +62,31 @@ struct gas
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
enum class fadt_flags : uint32_t
|
||||
enum class fadt_flags
|
||||
{
|
||||
wbinvd = 0x00000001,
|
||||
wbinvd_flush = 0x00000002,
|
||||
proc_c1 = 0x00000004,
|
||||
p_lvl2_up = 0x00000008,
|
||||
pwr_button = 0x00000010,
|
||||
slp_button = 0x00000020,
|
||||
fix_rtc = 0x00000040,
|
||||
rtc_s4 = 0x00000080,
|
||||
tmr_val_ext = 0x00000100,
|
||||
dck_cap = 0x00000200,
|
||||
reset_reg_sup = 0x00000400,
|
||||
sealed_case = 0x00000800,
|
||||
headless = 0x00001000,
|
||||
cpu_sw_slp = 0x00002000,
|
||||
pci_exp_wak = 0x00004000,
|
||||
use_plat_clock = 0x00008000,
|
||||
s4_rtc_sts_val = 0x00010000,
|
||||
remote_pwr_cap = 0x00020000,
|
||||
apic_cluster = 0x00040000,
|
||||
apic_physical = 0x00080000,
|
||||
hw_reduced_acpi = 0x00100000,
|
||||
low_pwr_s0_idle = 0x00200000
|
||||
wbinvd,
|
||||
wbinvd_flush,
|
||||
proc_c1,
|
||||
p_lvl2_up,
|
||||
pwr_button,
|
||||
slp_button,
|
||||
fix_rtc,
|
||||
rtc_s4,
|
||||
tmr_val_ext,
|
||||
dck_cap,
|
||||
reset_reg_sup,
|
||||
sealed_case,
|
||||
headless,
|
||||
cpu_sw_slp,
|
||||
pci_exp_wak,
|
||||
use_plat_clock,
|
||||
s4_rtc_sts_val,
|
||||
remote_pwr_cap,
|
||||
apic_cluster,
|
||||
apic_physical,
|
||||
hw_reduced_acpi,
|
||||
low_pwr_s0_idle
|
||||
};
|
||||
is_bitfield(fadt_flags);
|
||||
|
||||
struct fadt
|
||||
{
|
||||
@@ -134,7 +133,7 @@ struct fadt
|
||||
|
||||
uint16_t iapc_boot_arch;
|
||||
uint8_t reserved1;
|
||||
fadt_flags flags;
|
||||
util::bitset32 flags;
|
||||
|
||||
gas reset_reg;
|
||||
uint8_t reset_value;
|
||||
|
||||
@@ -71,21 +71,19 @@ lapic::get_id()
|
||||
}
|
||||
|
||||
void
|
||||
lapic::send_ipi(ipi mode, isr vector, uint8_t dest)
|
||||
lapic::send_ipi(util::bitset32 mode, isr vector, uint8_t dest)
|
||||
{
|
||||
// Wait until the APIC is ready to send
|
||||
ipi_wait();
|
||||
|
||||
uint32_t command =
|
||||
static_cast<uint32_t>(vector) |
|
||||
static_cast<uint32_t>(mode);
|
||||
uint32_t command = util::bitset32::from(vector) | mode;
|
||||
|
||||
apic_write(m_base, lapic_icr_high, static_cast<uint32_t>(dest) << 24);
|
||||
apic_write(m_base, lapic_icr_low, command);
|
||||
}
|
||||
|
||||
void
|
||||
lapic::send_ipi_broadcast(ipi mode, bool self, isr vector)
|
||||
lapic::send_ipi_broadcast(util::bitset32 mode, bool self, isr vector)
|
||||
{
|
||||
// Wait until the APIC is ready to send
|
||||
ipi_wait();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/// Classes to control both local and I/O APICs.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <util/enum_bitfields.h>
|
||||
#include <util/bitset.h>
|
||||
|
||||
#include "interrupts.h"
|
||||
|
||||
@@ -33,33 +33,30 @@ public:
|
||||
/// Get the local APIC's ID
|
||||
uint8_t get_id();
|
||||
|
||||
enum class ipi : uint32_t
|
||||
enum class ipi_flags
|
||||
{
|
||||
// Delivery modes
|
||||
fixed = 0x0000,
|
||||
smi = 0x0200,
|
||||
nmi = 0x0400,
|
||||
init = 0x0500,
|
||||
startup = 0x0600,
|
||||
|
||||
// Flags
|
||||
deassert = 0x0000,
|
||||
assert = 0x4000,
|
||||
edge = 0x0000, ///< edge-triggered
|
||||
level = 0x8000, ///< level-triggered
|
||||
logical = 11,
|
||||
pending = 12,
|
||||
assert = 14,
|
||||
level = 15,
|
||||
};
|
||||
|
||||
// IPI flags based on delivery mode (bits 8-10)
|
||||
static constexpr util::bitset32 ipi_fixed = 0;
|
||||
static constexpr util::bitset32 ipi_init = 0x500;
|
||||
static constexpr util::bitset32 ipi_sipi = 0x600;
|
||||
|
||||
/// Send an inter-processor interrupt.
|
||||
/// \arg mode The sending mode
|
||||
/// \arg vector The interrupt vector
|
||||
/// \arg dest The APIC ID of the destination
|
||||
void send_ipi(ipi mode, isr vector, uint8_t dest);
|
||||
void send_ipi(util::bitset32 mode, isr vector, uint8_t dest);
|
||||
|
||||
/// Send an inter-processor broadcast interrupt to all other CPUs
|
||||
/// \arg mode The sending mode
|
||||
/// \arg self If true, include this CPU in the broadcast
|
||||
/// \arg vector The interrupt vector
|
||||
void send_ipi_broadcast(ipi mode, bool self, isr vector);
|
||||
void send_ipi_broadcast(util::bitset32 mode, bool self, isr vector);
|
||||
|
||||
/// Wait for an IPI to finish sending. This is done automatically
|
||||
/// before sending another IPI with send_ipi().
|
||||
@@ -145,6 +142,3 @@ private:
|
||||
uint8_t m_id;
|
||||
uint8_t m_version;
|
||||
};
|
||||
|
||||
is_bitfield(lapic::ipi);
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ cpu_early_init(cpu_data *cpu)
|
||||
set_xcr0(xcr0_val);
|
||||
|
||||
// Set initial floating point state
|
||||
const util::bitset32 mxcsr_val {
|
||||
const util::bitset32 mxcsr_val = util::bitset32::of(
|
||||
mxcsr::DAZ,
|
||||
mxcsr::IM,
|
||||
mxcsr::DM,
|
||||
@@ -126,8 +126,7 @@ cpu_early_init(cpu_data *cpu)
|
||||
mxcsr::OM,
|
||||
mxcsr::UM,
|
||||
mxcsr::PM,
|
||||
mxcsr::FTZ,
|
||||
};
|
||||
mxcsr::FTZ);
|
||||
asm ( "ldmxcsr %0" :: "m"(mxcsr_val) );
|
||||
|
||||
// Install the GS base pointint to the cpu_data
|
||||
|
||||
@@ -22,6 +22,9 @@ static constexpr uint8_t tss_index = 6; // Note that this takes TWO GDT en
|
||||
static util::no_construct<GDT> __g_bsp_gdt_storage;
|
||||
GDT &g_bsp_gdt = __g_bsp_gdt_storage.value;
|
||||
|
||||
static constexpr util::bitset8 ring3 = util::bitset8::of( GDT::type::ring1, GDT::type::ring2 );
|
||||
static constexpr util::bitset8 rw = util::bitset8::of( GDT::type::read_write );
|
||||
static constexpr util::bitset8 rwx = util::bitset8::of( GDT::type::read_write, GDT::type::execute );
|
||||
|
||||
GDT::GDT(TSS *tss) :
|
||||
m_tss(tss)
|
||||
@@ -32,13 +35,13 @@ GDT::GDT(TSS *tss) :
|
||||
m_ptr.base = &m_entries[0];
|
||||
|
||||
// Kernel CS/SS - always 64bit
|
||||
set(kern_cs_index, 0, 0xfffff, true, type::read_write | type::execute);
|
||||
set(kern_ss_index, 0, 0xfffff, true, type::read_write);
|
||||
set(kern_cs_index, 0, 0xfffff, true, rwx);
|
||||
set(kern_ss_index, 0, 0xfffff, true, rw);
|
||||
|
||||
// User CS32/SS/CS64 - layout expected by SYSRET
|
||||
set(user_cs32_index, 0, 0xfffff, false, type::ring3 | type::read_write | type::execute);
|
||||
set(user_ss_index, 0, 0xfffff, true, type::ring3 | type::read_write);
|
||||
set(user_cs64_index, 0, 0xfffff, true, type::ring3 | type::read_write | type::execute);
|
||||
set(user_cs32_index, 0, 0xfffff, false, ring3 | rwx);
|
||||
set(user_ss_index, 0, 0xfffff, true, ring3 | rw);
|
||||
set(user_cs64_index, 0, 0xfffff, true, ring3 | rwx);
|
||||
|
||||
set_tss(tss);
|
||||
}
|
||||
@@ -61,7 +64,7 @@ GDT::install() const
|
||||
}
|
||||
|
||||
void
|
||||
GDT::set(uint8_t i, uint32_t base, uint64_t limit, bool is64, type t)
|
||||
GDT::set(uint8_t i, uint32_t base, uint64_t limit, bool is64, util::bitset8 t)
|
||||
{
|
||||
m_entries[i].limit_low = limit & 0xffff;
|
||||
m_entries[i].size = (limit >> 16) & 0xf;
|
||||
@@ -71,7 +74,9 @@ GDT::set(uint8_t i, uint32_t base, uint64_t limit, bool is64, type t)
|
||||
m_entries[i].base_mid = (base >> 16) & 0xff;
|
||||
m_entries[i].base_high = (base >> 24) & 0xff;
|
||||
|
||||
m_entries[i].type = t | type::system | type::present;
|
||||
static constexpr util::bitset8 sp = util::bitset8::of( type::system, type::present );
|
||||
m_entries[i].type = t;
|
||||
m_entries[i].type |= sp;
|
||||
}
|
||||
|
||||
struct tss_descriptor
|
||||
@@ -79,7 +84,7 @@ struct tss_descriptor
|
||||
uint16_t limit_low;
|
||||
uint16_t base_00;
|
||||
uint8_t base_16;
|
||||
GDT::type type;
|
||||
util::bitset8 type;
|
||||
uint8_t size;
|
||||
uint8_t base_24;
|
||||
uint32_t base_32;
|
||||
@@ -102,11 +107,9 @@ GDT::set_tss(TSS *tss)
|
||||
tssd.base_32 = (base >> 32) & 0xffffffff;
|
||||
tssd.reserved = 0;
|
||||
|
||||
tssd.type =
|
||||
type::accessed |
|
||||
type::execute |
|
||||
type::ring3 |
|
||||
type::present;
|
||||
static constexpr util::bitset8 tss_mark =
|
||||
util::bitset8::of(type::accessed, type::execute, type::present);
|
||||
tssd.type = ring3 | tss_mark;
|
||||
|
||||
memcpy(&m_entries[tss_index], &tssd, sizeof(tss_descriptor));
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/// Definitions relating to a CPU's GDT table
|
||||
|
||||
#include <stdint.h>
|
||||
#include <util/enum_bitfields.h>
|
||||
#include <util/bitset.h>
|
||||
|
||||
class TSS;
|
||||
|
||||
@@ -25,21 +25,20 @@ public:
|
||||
/// \arg index Which entry to print, or -1 for all entries
|
||||
void dump(unsigned index = -1) const;
|
||||
|
||||
enum class type : uint8_t
|
||||
enum class type
|
||||
{
|
||||
accessed = 0x01,
|
||||
read_write = 0x02,
|
||||
conforming = 0x04,
|
||||
execute = 0x08,
|
||||
system = 0x10,
|
||||
ring1 = 0x20,
|
||||
ring2 = 0x40,
|
||||
ring3 = 0x60,
|
||||
present = 0x80
|
||||
accessed,
|
||||
read_write,
|
||||
conforming,
|
||||
execute,
|
||||
system,
|
||||
ring1,
|
||||
ring2,
|
||||
present
|
||||
};
|
||||
|
||||
private:
|
||||
void set(uint8_t i, uint32_t base, uint64_t limit, bool is64, type t);
|
||||
void set(uint8_t i, uint32_t base, uint64_t limit, bool is64, util::bitset8 t);
|
||||
void set_tss(TSS *tss);
|
||||
|
||||
struct descriptor
|
||||
@@ -47,7 +46,7 @@ private:
|
||||
uint16_t limit_low;
|
||||
uint16_t base_low;
|
||||
uint8_t base_mid;
|
||||
type type;
|
||||
util::bitset8 type;
|
||||
uint8_t size;
|
||||
uint8_t base_high;
|
||||
} __attribute__ ((packed, align(8)));
|
||||
@@ -63,5 +62,3 @@ private:
|
||||
|
||||
ptr m_ptr;
|
||||
};
|
||||
|
||||
is_bitfield(GDT::type);
|
||||
|
||||
@@ -126,8 +126,7 @@ isr_handler(cpu_state *regs)
|
||||
// The zero page is always invalid
|
||||
if (cr2 > mem::frame_size) {
|
||||
bool user = cr2 < mem::kernel_offset;
|
||||
vm_space::fault_type ft =
|
||||
static_cast<vm_space::fault_type>(regs->errorcode);
|
||||
util::bitset8 ft = regs->errorcode;
|
||||
|
||||
vm_space &space = user
|
||||
? obj::process::current().space()
|
||||
|
||||
@@ -54,7 +54,7 @@ kernel_main(bootproto::args *args)
|
||||
bsp_late_init();
|
||||
|
||||
using bootproto::boot_flags;
|
||||
bool enable_test = util::bits::has(args->flags, boot_flags::test);
|
||||
bool enable_test = args->flags.get(boot_flags::test);
|
||||
syscall_initialize(enable_test);
|
||||
|
||||
device_manager &devices = device_manager::get();
|
||||
@@ -95,12 +95,15 @@ load_init_server(bootproto::program &program, uintptr_t modules_address)
|
||||
|
||||
vm_space &space = p->space();
|
||||
for (const auto § : program.sections) {
|
||||
vm_flags flags =
|
||||
((sect.type && section_flags::execute) ? vm_flags::exec : vm_flags::none) |
|
||||
((sect.type && section_flags::write) ? vm_flags::write : vm_flags::none);
|
||||
util::bitset32 flags = util::bitset32::of(vm_flags::exact);
|
||||
if (sect.type.get(section_flags::execute))
|
||||
flags.set(vm_flags::exec);
|
||||
|
||||
if (sect.type.get(section_flags::write))
|
||||
flags.set(vm_flags::write);
|
||||
|
||||
obj::vm_area *vma = new obj::vm_area_fixed(sect.phys_addr, sect.size, flags);
|
||||
space.add(sect.virt_addr, vma, obj::vm_flags::exact);
|
||||
space.add(sect.virt_addr, vma, flags);
|
||||
}
|
||||
|
||||
uint64_t iopl = (3ull << 12);
|
||||
|
||||
@@ -20,7 +20,8 @@ extern "C" {
|
||||
|
||||
using bootproto::allocation_register;
|
||||
|
||||
using obj::vm_flags;
|
||||
inline constexpr util::bitset32 vm_flag_write = util::bitset32::of(obj::vm_flags::write);
|
||||
inline constexpr util::bitset32 vm_flag_exact = util::bitset32::of(obj::vm_flags::exact);
|
||||
|
||||
// These objects are initialized _before_ global constructors are called,
|
||||
// so we don't want them to have global constructors at all, lest they
|
||||
@@ -53,7 +54,7 @@ obj::vm_area_guarded g_kernel_buffers {
|
||||
mem::buffers_offset,
|
||||
mem::kernel_buffer_pages,
|
||||
mem::buffers_size,
|
||||
vm_flags::write};
|
||||
vm_flag_write};
|
||||
|
||||
void * operator new(size_t size) { return g_kernel_heap.allocate(size); }
|
||||
void * operator new [] (size_t size) { return g_kernel_heap.allocate(size); }
|
||||
@@ -97,30 +98,30 @@ memory_initialize_pre_ctors(bootproto::args &kargs)
|
||||
|
||||
// Create the heap space and heap allocator
|
||||
obj::vm_area *heap = new (&g_kernel_heap_area)
|
||||
obj::vm_area_untracked(mem::heap_size, vm_flags::write);
|
||||
obj::vm_area_untracked(mem::heap_size, vm_flag_write);
|
||||
|
||||
obj::vm_area *heap_map = new (&g_kernel_heapmap_area)
|
||||
obj::vm_area_untracked(mem::heapmap_size, vm_flags::write);
|
||||
obj::vm_area_untracked(mem::heapmap_size, vm_flag_write);
|
||||
|
||||
vm.add(mem::heap_offset, heap, vm_flags::exact);
|
||||
vm.add(mem::heapmap_offset, heap_map, vm_flags::exact);
|
||||
vm.add(mem::heap_offset, heap, vm_flag_exact);
|
||||
vm.add(mem::heapmap_offset, heap_map, vm_flag_exact);
|
||||
|
||||
new (&g_kernel_heap) heap_allocator {mem::heap_offset, mem::heap_size, mem::heapmap_offset};
|
||||
|
||||
// Set up the log area and logger
|
||||
size_t log_buffer_size = log::log_pages * arch::frame_size;
|
||||
obj::vm_area *logs = new (&g_kernel_log_area)
|
||||
obj::vm_area_ring(log_buffer_size, vm_flags::write);
|
||||
vm.add(mem::logs_offset, logs, vm_flags::exact);
|
||||
obj::vm_area_ring(log_buffer_size, vm_flag_write);
|
||||
vm.add(mem::logs_offset, logs, vm_flag_exact);
|
||||
|
||||
new (&g_logger) log::logger(
|
||||
util::buffer::from(mem::logs_offset, log_buffer_size));
|
||||
|
||||
// Set up the capability tables
|
||||
obj::vm_area *caps = new (&g_cap_table_area)
|
||||
obj::vm_area_untracked(mem::caps_size, vm_flags::write);
|
||||
obj::vm_area_untracked(mem::caps_size, vm_flag_write);
|
||||
|
||||
vm.add(mem::caps_offset, caps, vm_flags::exact);
|
||||
vm.add(mem::caps_offset, caps, vm_flag_exact);
|
||||
|
||||
new (&g_cap_table) cap_table {mem::caps_offset};
|
||||
|
||||
@@ -128,8 +129,8 @@ memory_initialize_pre_ctors(bootproto::args &kargs)
|
||||
mem::stacks_offset,
|
||||
mem::kernel_stack_pages,
|
||||
mem::stacks_size,
|
||||
vm_flags::write};
|
||||
vm.add(mem::stacks_offset, &g_kernel_stacks, vm_flags::exact);
|
||||
vm_flag_write};
|
||||
vm.add(mem::stacks_offset, &g_kernel_stacks, vm_flag_exact);
|
||||
|
||||
// Clean out any remaning bootloader page table entries
|
||||
for (unsigned i = 0; i < arch::kernel_root_index; ++i)
|
||||
@@ -140,7 +141,7 @@ void
|
||||
memory_initialize_post_ctors(bootproto::args &kargs)
|
||||
{
|
||||
vm_space &vm = vm_space::kernel_space();
|
||||
vm.add(mem::buffers_offset, &g_kernel_buffers, vm_flags::exact);
|
||||
vm.add(mem::buffers_offset, &g_kernel_buffers, vm_flag_exact);
|
||||
|
||||
g_frame_allocator.free(
|
||||
get_physical_page(kargs.page_tables.pointer),
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
/// Definition of thread kobject types
|
||||
|
||||
#include <j6/cap_flags.h>
|
||||
#include <util/enum_bitfields.h>
|
||||
#include <util/linked_list.h>
|
||||
#include <util/spinlock.h>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace obj {
|
||||
|
||||
using mem::frame_size;
|
||||
|
||||
vm_area::vm_area(size_t size, vm_flags flags) :
|
||||
vm_area::vm_area(size_t size, util::bitset32 flags) :
|
||||
m_size {size},
|
||||
m_flags {flags},
|
||||
m_spaces {m_vector_static, 0, static_size},
|
||||
@@ -62,7 +62,7 @@ vm_area::can_resize(size_t size)
|
||||
return true;
|
||||
}
|
||||
|
||||
vm_area_fixed::vm_area_fixed(uintptr_t start, size_t size, vm_flags flags) :
|
||||
vm_area_fixed::vm_area_fixed(uintptr_t start, size_t size, util::bitset32 flags) :
|
||||
m_start {start},
|
||||
vm_area {size, flags}
|
||||
{
|
||||
@@ -70,7 +70,7 @@ vm_area_fixed::vm_area_fixed(uintptr_t start, size_t size, vm_flags flags) :
|
||||
|
||||
vm_area_fixed::~vm_area_fixed()
|
||||
{
|
||||
if (m_flags && vm_flags::mmio)
|
||||
if (m_flags.get(vm_flags::mmio))
|
||||
return;
|
||||
|
||||
size_t pages = mem::page_count(m_size);
|
||||
@@ -94,7 +94,7 @@ vm_area_fixed::get_page(uintptr_t offset, uintptr_t &phys, bool alloc)
|
||||
return true;
|
||||
}
|
||||
|
||||
vm_area_untracked::vm_area_untracked(size_t size, vm_flags flags) :
|
||||
vm_area_untracked::vm_area_untracked(size_t size, util::bitset32 flags) :
|
||||
vm_area {size, flags}
|
||||
{
|
||||
}
|
||||
@@ -127,7 +127,7 @@ vm_area_untracked::add_to(vm_space *space)
|
||||
}
|
||||
|
||||
|
||||
vm_area_open::vm_area_open(size_t size, vm_flags flags) :
|
||||
vm_area_open::vm_area_open(size_t size, util::bitset32 flags) :
|
||||
m_mapped {nullptr},
|
||||
vm_area {size, flags}
|
||||
{
|
||||
@@ -154,7 +154,7 @@ vm_area_open::add_existing(uintptr_t offset, uintptr_t phys)
|
||||
}
|
||||
|
||||
|
||||
vm_area_guarded::vm_area_guarded(uintptr_t start, size_t buf_pages, size_t size, vm_flags flags) :
|
||||
vm_area_guarded::vm_area_guarded(uintptr_t start, size_t buf_pages, size_t size, util::bitset32 flags) :
|
||||
m_pages {buf_pages + 1}, // Sections are N+1 pages for the leading guard page
|
||||
m_stacks {start, m_pages*mem::frame_size},
|
||||
vm_area_open {size, flags}
|
||||
@@ -191,7 +191,7 @@ vm_area_guarded::get_page(uintptr_t offset, uintptr_t &phys, bool alloc)
|
||||
return vm_area_open::get_page(offset, phys, alloc);
|
||||
}
|
||||
|
||||
vm_area_ring::vm_area_ring(size_t size, vm_flags flags) :
|
||||
vm_area_ring::vm_area_ring(size_t size, util::bitset32 flags) :
|
||||
vm_area_open {size * 2, flags},
|
||||
m_bufsize {size}
|
||||
{
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <j6/cap_flags.h>
|
||||
#include <util/bitset.h>
|
||||
#include <util/vector.h>
|
||||
#include <util/enum_bitfields.h>
|
||||
|
||||
#include "block_allocator.h"
|
||||
#include "objects/kobject.h"
|
||||
@@ -17,16 +17,15 @@ class vm_space;
|
||||
|
||||
namespace obj {
|
||||
|
||||
enum class vm_flags : uint32_t
|
||||
enum class vm_flags
|
||||
{
|
||||
#define VM_FLAG(name, v) name = v,
|
||||
#include <j6/tables/vm_flags.inc>
|
||||
#undef VM_FLAG
|
||||
driver_mask = 0x00ff'ffff, ///< flags allowed via syscall for drivers
|
||||
user_mask = 0x000f'ffff, ///< flags allowed via syscall for non-drivers
|
||||
};
|
||||
is_bitfield(vm_flags);
|
||||
|
||||
inline constexpr util::bitset32 vm_driver_mask = 0x00ff'ffff; ///< flags allowed via syscall for drivers
|
||||
inline constexpr util::bitset32 vm_user_mask = 0x000f'ffff; ///< flags allowed via syscall for non-drivers
|
||||
|
||||
/// Virtual memory areas allow control over memory allocation
|
||||
class vm_area :
|
||||
@@ -40,7 +39,7 @@ public:
|
||||
/// Constructor.
|
||||
/// \arg size Initial virtual size of the memory area
|
||||
/// \arg flags Flags for this memory area
|
||||
vm_area(size_t size, vm_flags flags = vm_flags::none);
|
||||
vm_area(size_t size, util::bitset32 flags = 0);
|
||||
|
||||
virtual ~vm_area();
|
||||
|
||||
@@ -48,7 +47,7 @@ public:
|
||||
inline size_t size() const { return m_size; }
|
||||
|
||||
/// Get the flags set for this area
|
||||
inline vm_flags flags() const { return m_flags; }
|
||||
inline util::bitset32 flags() const { return m_flags; }
|
||||
|
||||
/// Track that this area was added to a vm_space
|
||||
/// \arg space The space to add this area to
|
||||
@@ -83,7 +82,7 @@ protected:
|
||||
bool can_resize(size_t size);
|
||||
|
||||
size_t m_size;
|
||||
vm_flags m_flags;
|
||||
util::bitset32 m_flags;
|
||||
util::vector<vm_space*> m_spaces;
|
||||
|
||||
// Initial static space for m_spaces - most areas will never grow
|
||||
@@ -103,7 +102,7 @@ public:
|
||||
/// \arg start Starting physical address of this area
|
||||
/// \arg size Size of the physical memory area
|
||||
/// \arg flags Flags for this memory area
|
||||
vm_area_fixed(uintptr_t start, size_t size, vm_flags flags = vm_flags::none);
|
||||
vm_area_fixed(uintptr_t start, size_t size, util::bitset32 flags = 0);
|
||||
virtual ~vm_area_fixed();
|
||||
|
||||
virtual size_t resize(size_t size) override;
|
||||
@@ -122,7 +121,7 @@ public:
|
||||
/// Constructor.
|
||||
/// \arg size Initial virtual size of the memory area
|
||||
/// \arg flags Flags for this memory area
|
||||
vm_area_open(size_t size, vm_flags flags);
|
||||
vm_area_open(size_t size, util::bitset32 flags);
|
||||
virtual ~vm_area_open();
|
||||
|
||||
virtual bool get_page(uintptr_t offset, uintptr_t &phys, bool alloc = true) override;
|
||||
@@ -144,7 +143,7 @@ public:
|
||||
/// Constructor.
|
||||
/// \arg size Initial virtual size of the memory area
|
||||
/// \arg flags Flags for this memory area
|
||||
vm_area_untracked(size_t size, vm_flags flags);
|
||||
vm_area_untracked(size_t size, util::bitset32 flags);
|
||||
virtual ~vm_area_untracked();
|
||||
|
||||
virtual bool add_to(vm_space *space) override;
|
||||
@@ -166,7 +165,7 @@ public:
|
||||
uintptr_t start,
|
||||
size_t sec_pages,
|
||||
size_t size,
|
||||
vm_flags flags);
|
||||
util::bitset32 flags);
|
||||
|
||||
virtual ~vm_area_guarded();
|
||||
|
||||
@@ -194,7 +193,7 @@ public:
|
||||
/// \arg size Virtual size of the ring buffer. Note that
|
||||
/// the VMA size will be double this value.
|
||||
/// \arg flags Flags for this memory area
|
||||
vm_area_ring(size_t size, vm_flags flags);
|
||||
vm_area_ring(size_t size, util::bitset32 flags);
|
||||
virtual ~vm_area_ring();
|
||||
|
||||
virtual bool get_page(uintptr_t offset, uintptr_t &phys, bool alloc = true) override;
|
||||
|
||||
@@ -14,10 +14,7 @@ free_page_header * page_table::s_page_cache = nullptr;
|
||||
util::spinlock page_table::s_lock;
|
||||
constexpr size_t page_table::entry_sizes[4];
|
||||
|
||||
|
||||
constexpr page_table::flag table_flags =
|
||||
page_table::flag::present |
|
||||
page_table::flag::write;
|
||||
inline constexpr util::bitset64 table_flags = page_flags::present | page_flags::write;
|
||||
|
||||
|
||||
page_table::iterator::iterator(uintptr_t virt, page_table *pml4) :
|
||||
@@ -140,9 +137,9 @@ page_table::iterator::ensure_table(level l)
|
||||
uintptr_t phys = reinterpret_cast<uintptr_t>(table) & ~linear_offset;
|
||||
|
||||
uint64_t &parent = entry(l - 1);
|
||||
flag flags = table_flags;
|
||||
util::bitset64 flags = table_flags;
|
||||
if (m_index[0] < arch::kernel_root_index)
|
||||
flags |= flag::user;
|
||||
flags.set(flag::user);
|
||||
|
||||
m_table[unsigned(l)] = table;
|
||||
parent = (phys & ~0xfffull) | flags;
|
||||
|
||||
@@ -4,11 +4,33 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <arch/memory.h>
|
||||
#include <util/enum_bitfields.h>
|
||||
#include <util/bitset.h>
|
||||
#include <util/spinlock.h>
|
||||
|
||||
struct free_page_header;
|
||||
|
||||
namespace page_flags {
|
||||
inline constexpr util::bitset64 none = 0x0000;
|
||||
inline constexpr util::bitset64 present = 0x0001; /// Entry is present in the table
|
||||
inline constexpr util::bitset64 write = 0x0002; /// Section may be written
|
||||
inline constexpr util::bitset64 user = 0x0004; /// User-accessible
|
||||
inline constexpr util::bitset64 pat0 = 0x0008; /// PAT selector bit 0
|
||||
inline constexpr util::bitset64 pat1 = 0x0010; /// PAT selector bit 1
|
||||
inline constexpr util::bitset64 accessed = 0x0020; /// Entry has been accessed
|
||||
inline constexpr util::bitset64 dirty = 0x0040; /// Page has been written to
|
||||
inline constexpr util::bitset64 page = 0x0080; /// Entry is a large page
|
||||
inline constexpr util::bitset64 pat2 = 0x0080; /// PAT selector bit 2 on PT entries
|
||||
inline constexpr util::bitset64 global = 0x0100; /// Entry is not PCID-specific
|
||||
inline constexpr util::bitset64 pat2_lg = 0x1000; /// PAT selector bit 2 on large/huge pages
|
||||
|
||||
inline constexpr util::bitset64 wb = 0;
|
||||
inline constexpr util::bitset64 wt = pat0;
|
||||
inline constexpr util::bitset64 uc_ = pat1;
|
||||
inline constexpr util::bitset64 uc = pat0 | pat1;
|
||||
inline constexpr util::bitset64 wc = pat0 | pat1 | pat2;
|
||||
inline constexpr util::bitset64 wc_lg = pat0 | pat1 | pat2_lg;
|
||||
} // page_flags
|
||||
|
||||
/// Struct to allow easy accessing of a memory page being used as a page table.
|
||||
struct page_table
|
||||
{
|
||||
@@ -16,27 +38,19 @@ struct page_table
|
||||
enum class level : unsigned { pml4, pdp, pd, pt, page };
|
||||
|
||||
/// Page entry flags
|
||||
enum class flag : uint64_t
|
||||
enum class flag
|
||||
{
|
||||
none = 0x0000,
|
||||
present = 0x0001, /// Entry is present in the table
|
||||
write = 0x0002, /// Section may be written
|
||||
user = 0x0004, /// User-accessible
|
||||
pat0 = 0x0008, /// PAT selector bit 0
|
||||
pat1 = 0x0010, /// PAT selector bit 1
|
||||
accessed = 0x0020, /// Entry has been accessed
|
||||
dirty = 0x0040, /// Page has been written to
|
||||
page = 0x0080, /// Entry is a large page
|
||||
pat2 = 0x0080, /// PAT selector bit 2 on PT entries
|
||||
global = 0x0100, /// Entry is not PCID-specific
|
||||
pat2_lg = 0x1000, /// PAT selector bit 2 on large/huge pages
|
||||
|
||||
wb = none,
|
||||
wt = pat0,
|
||||
uc_ = pat1,
|
||||
uc = pat0 | pat1,
|
||||
wc = pat0 | pat1 | pat2,
|
||||
wc_lg = pat0 | pat1 | pat2_lg,
|
||||
present = 0, /// Entry is present in the table
|
||||
write = 1, /// Section may be written
|
||||
user = 2, /// User-accessible
|
||||
pat0 = 3, /// PAT selector bit 0
|
||||
pat1 = 4, /// PAT selector bit 1
|
||||
accessed = 5, /// Entry has been accessed
|
||||
dirty = 6, /// Page has been written to
|
||||
page = 7, /// Entry is a large page
|
||||
pat2 = 7, /// PAT selector bit 2 on PT entries
|
||||
global = 8, /// Entry is not PCID-specific
|
||||
pat2_lg = 12, /// PAT selector bit 2 on large/huge pages
|
||||
};
|
||||
|
||||
/// Helper for getting the next level value
|
||||
@@ -194,5 +208,3 @@ inline bool operator<(page_table::level a, page_table::level b) {
|
||||
|
||||
inline page_table::level& operator++(page_table::level& l) { l = l + 1; return l; }
|
||||
inline page_table::level& operator--(page_table::level& l) { l = l - 1; return l; }
|
||||
|
||||
is_bitfield(page_table::flag);
|
||||
|
||||
@@ -339,5 +339,5 @@ scheduler::maybe_schedule(TCB *t)
|
||||
return;
|
||||
|
||||
current_cpu().apic->send_ipi(
|
||||
lapic::ipi::fixed, isr::ipiSchedule, cpu->id);
|
||||
lapic::ipi_fixed, isr::ipiSchedule, cpu->id);
|
||||
}
|
||||
|
||||
@@ -57,8 +57,11 @@ start(cpu_data &bsp, void *kpml4)
|
||||
// Copy the startup code somwhere the real mode trampoline can run
|
||||
uintptr_t addr = 0x8000; // TODO: find a valid address, rewrite addresses
|
||||
isr vector = static_cast<isr>(addr >> 12);
|
||||
obj::vm_area *vma = new obj::vm_area_fixed(addr, 0x1000, vm_flags::write);
|
||||
vm_space::kernel_space().add(addr, vma, obj::vm_flags::exact);
|
||||
|
||||
constexpr util::bitset32 flags = util::bitset32::of(vm_flags::write, vm_flags::exact);
|
||||
obj::vm_area *vma = new obj::vm_area_fixed(addr, 0x1000, flags);
|
||||
vm_space::kernel_space().add(addr, vma, flags);
|
||||
|
||||
memcpy(
|
||||
reinterpret_cast<void*>(addr),
|
||||
reinterpret_cast<void*>(&ap_startup),
|
||||
@@ -67,7 +70,7 @@ start(cpu_data &bsp, void *kpml4)
|
||||
size_t free_stack_count = 0;
|
||||
|
||||
lapic &apic = *bsp.apic;
|
||||
lapic::ipi mode = lapic::ipi::init | lapic::ipi::level | lapic::ipi::assert;
|
||||
util::bitset32 mode = lapic::ipi_init + lapic::ipi_flags::level + lapic::ipi_flags::assert;
|
||||
apic.send_ipi_broadcast(mode, false, static_cast<isr>(0));
|
||||
|
||||
for (uint8_t id : ids) {
|
||||
@@ -90,7 +93,7 @@ start(cpu_data &bsp, void *kpml4)
|
||||
size_t current_count = ap_startup_count;
|
||||
log::verbose(logs::boot, "Starting AP %d: stack %llx", cpu->index, stack_end);
|
||||
|
||||
lapic::ipi startup = lapic::ipi::startup | lapic::ipi::assert;
|
||||
util::bitset32 startup = lapic::ipi_sipi + lapic::ipi_flags::assert;
|
||||
|
||||
apic.send_ipi(startup, vector, id);
|
||||
for (unsigned i = 0; i < 20; ++i) {
|
||||
|
||||
@@ -67,12 +67,11 @@ system_map_phys(system *self, j6_handle_t * area, uintptr_t phys, size_t size, u
|
||||
{
|
||||
// TODO: check to see if frames are already used? How would that collide with
|
||||
// the bootloader's allocated pages already being marked used?
|
||||
if (!(flags & vm_flags::mmio))
|
||||
util::bitset32 f = flags & vm_driver_mask;
|
||||
if (!f.get(vm_flags::mmio))
|
||||
frame_allocator::get().used(phys, mem::page_count(size));
|
||||
|
||||
vm_flags vmf = (static_cast<vm_flags>(flags) & vm_flags::driver_mask);
|
||||
construct_handle<vm_area_fixed>(area, phys, size, vmf);
|
||||
|
||||
construct_handle<vm_area_fixed>(area, phys, size, f);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ namespace syscalls {
|
||||
j6_status_t
|
||||
vma_create(j6_handle_t *self, size_t size, uint32_t flags)
|
||||
{
|
||||
vm_flags f = vm_flags::user_mask & flags;
|
||||
if (util::bits::has(f, vm_flags::ring))
|
||||
util::bitset32 f = flags & vm_user_mask;
|
||||
if (f.get(vm_flags::ring))
|
||||
construct_handle<vm_area_ring>(self, size, f);
|
||||
else
|
||||
construct_handle<vm_area_open>(self, size, f);
|
||||
@@ -26,8 +26,8 @@ j6_status_t
|
||||
vma_create_map(j6_handle_t *self, size_t size, uintptr_t *base, uint32_t flags)
|
||||
{
|
||||
vm_area *a = nullptr;
|
||||
vm_flags f = vm_flags::user_mask & flags;
|
||||
if (util::bits::has(f, vm_flags::ring))
|
||||
util::bitset32 f = flags & vm_user_mask;
|
||||
if (f.get(vm_flags::ring))
|
||||
a = construct_handle<vm_area_ring>(self, size, f);
|
||||
else
|
||||
a = construct_handle<vm_area_open>(self, size, f);
|
||||
@@ -40,7 +40,7 @@ j6_status_t
|
||||
vma_map(vm_area *self, process *proc, uintptr_t *base, uint32_t flags)
|
||||
{
|
||||
vm_space &space = proc ? proc->space() : process::current().space();
|
||||
vm_flags f = vm_flags::user_mask & flags;
|
||||
util::bitset32 f = flags & vm_user_mask;
|
||||
*base = space.add(*base, self, f);
|
||||
return *base ? j6_status_ok : j6_err_collision;
|
||||
}
|
||||
|
||||
@@ -55,9 +55,9 @@ vm_space::vm_space() :
|
||||
obj::vm_area *sysc = new obj::vm_area_fixed(
|
||||
g_sysconf_phys,
|
||||
sizeof(system_config),
|
||||
vm_flags::none);
|
||||
0);
|
||||
|
||||
add(sysconf_user_address, sysc, vm_flags::exact);
|
||||
add(sysconf_user_address, sysc, util::bitset32::of(vm_flags::exact));
|
||||
}
|
||||
|
||||
vm_space::~vm_space()
|
||||
@@ -81,7 +81,7 @@ vm_space::kernel_space()
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
vm_space::add(uintptr_t base, obj::vm_area *area, obj::vm_flags flags)
|
||||
vm_space::add(uintptr_t base, obj::vm_area *area, util::bitset32 flags)
|
||||
{
|
||||
if (!base)
|
||||
base = min_auto_address;
|
||||
@@ -89,7 +89,7 @@ vm_space::add(uintptr_t base, obj::vm_area *area, obj::vm_flags flags)
|
||||
uintptr_t end = base + area->size();
|
||||
|
||||
//TODO: optimize find/insert
|
||||
bool exact = util::bits::has(flags, j6_vm_flag_exact);
|
||||
bool exact = flags.get(vm_flags::exact);
|
||||
for (size_t i = 0; i < m_areas.count(); ++i) {
|
||||
const vm_space::area &a = m_areas[i];
|
||||
uintptr_t aend = a.base + a.area->size();
|
||||
@@ -192,7 +192,7 @@ vm_space::copy_from(const vm_space &source, const obj::vm_area &vma)
|
||||
|
||||
while (count--) {
|
||||
uint64_t &e = dit.entry(page_table::level::pt);
|
||||
if (e & page_table::flag::present) {
|
||||
if (util::bitset64::from(e) & page_flags::present) {
|
||||
// TODO: handle clobbering mapping
|
||||
}
|
||||
e = sit.entry(page_table::level::pt);
|
||||
@@ -210,11 +210,11 @@ vm_space::page_in(const obj::vm_area &vma, uintptr_t offset, uintptr_t phys, siz
|
||||
return;
|
||||
|
||||
uintptr_t virt = base + offset;
|
||||
page_table::flag flags =
|
||||
page_table::flag::present |
|
||||
(m_kernel ? page_table::flag::none : page_table::flag::user) |
|
||||
((vma.flags() && vm_flags::write) ? page_table::flag::write : page_table::flag::none) |
|
||||
((vma.flags() && vm_flags::write_combine) ? page_table::flag::wc : page_table::flag::none);
|
||||
util::bitset64 flags =
|
||||
page_flags::present |
|
||||
(m_kernel ? page_flags::none : page_flags::user) |
|
||||
(vma.flags().get(vm_flags::write) ? page_flags::write : page_flags::none) |
|
||||
(vma.flags().get(vm_flags::write_combine) ? page_flags::wc : page_flags::none);
|
||||
|
||||
page_table::iterator it {virt, m_pml4};
|
||||
|
||||
@@ -222,7 +222,7 @@ vm_space::page_in(const obj::vm_area &vma, uintptr_t offset, uintptr_t phys, siz
|
||||
uint64_t &entry = it.entry(page_table::level::pt);
|
||||
entry = (phys + i * frame_size) | flags;
|
||||
log::spam(logs::paging, "Setting entry for %016llx: %016llx [%04llx]",
|
||||
it.vaddress(), (phys + i * frame_size), flags);
|
||||
it.vaddress(), (phys + i * frame_size), flags.value());
|
||||
++it;
|
||||
}
|
||||
}
|
||||
@@ -247,11 +247,11 @@ vm_space::clear(const obj::vm_area &vma, uintptr_t offset, size_t count, bool fr
|
||||
while (count--) {
|
||||
uint64_t &e = it.entry(page_table::level::pt);
|
||||
uintptr_t phys = e & ~0xfffull;
|
||||
util::bitset64 flags = e;
|
||||
|
||||
if (e & page_table::flag::present) {
|
||||
uint64_t orig = e;
|
||||
if (flags & page_flags::present) {
|
||||
e = 0;
|
||||
if (orig & page_table::flag::accessed) {
|
||||
if (flags & page_flags::accessed) {
|
||||
auto *addr = reinterpret_cast<const uint8_t *>(it.vaddress());
|
||||
asm ( "invlpg %0" :: "m"(*addr) : "memory" );
|
||||
}
|
||||
@@ -290,11 +290,11 @@ vm_space::lock(const obj::vm_area &vma, uintptr_t offset, size_t count)
|
||||
while (count--) {
|
||||
uint64_t &e = it.entry(page_table::level::pt);
|
||||
uintptr_t phys = e & ~0xfffull;
|
||||
util::bitset64 flags = e;
|
||||
|
||||
if (e & page_table::flag::present) {
|
||||
uint64_t orig = e;
|
||||
if (flags & page_flags::present) {
|
||||
e = locked_page_tag;
|
||||
if (orig & page_table::flag::accessed) {
|
||||
if (flags & page_flags::accessed) {
|
||||
auto *addr = reinterpret_cast<const uint8_t *>(it.vaddress());
|
||||
asm ( "invlpg %0" :: "m"(*addr) : "memory" );
|
||||
}
|
||||
@@ -338,10 +338,10 @@ vm_space::initialize_tcb(TCB &tcb)
|
||||
}
|
||||
|
||||
bool
|
||||
vm_space::handle_fault(uintptr_t addr, fault_type fault)
|
||||
vm_space::handle_fault(uintptr_t addr, util::bitset8 fault)
|
||||
{
|
||||
// TODO: Handle more fult types
|
||||
if (fault && fault_type::present)
|
||||
if (fault.get(fault_type::present))
|
||||
return false;
|
||||
|
||||
uintptr_t page = (addr & ~0xfffull);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <j6/flags.h>
|
||||
#include <util/enum_bitfields.h>
|
||||
#include <util/bitset.h>
|
||||
#include <util/spinlock.h>
|
||||
#include <util/vector.h>
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
/// \arg area The area to add
|
||||
/// \arg flags Flags for the operation (exact, clobber, etc)
|
||||
/// \returns The base address the area was added at
|
||||
uintptr_t add(uintptr_t base, obj::vm_area *area, obj::vm_flags flags);
|
||||
uintptr_t add(uintptr_t base, obj::vm_area *area, util::bitset32 flags);
|
||||
|
||||
/// Remove a virtual memory area from this address space
|
||||
/// \arg area The area to remove
|
||||
@@ -88,15 +88,6 @@ public:
|
||||
/// Set this space as the current active space
|
||||
void activate() const;
|
||||
|
||||
enum class fault_type : uint8_t {
|
||||
none = 0x00,
|
||||
present = 0x01,
|
||||
write = 0x02,
|
||||
user = 0x04,
|
||||
reserved = 0x08,
|
||||
fetch = 0x10
|
||||
};
|
||||
|
||||
/// Allocate pages into virtual memory. May allocate less than requested.
|
||||
/// \arg virt The virtual address at which to allocate
|
||||
/// \arg count The number of pages to allocate
|
||||
@@ -104,11 +95,13 @@ public:
|
||||
/// \returns The number of pages actually allocated
|
||||
size_t allocate(uintptr_t virt, size_t count, uintptr_t *phys);
|
||||
|
||||
enum class fault_type { present, write, user, reserved, fetch };
|
||||
|
||||
/// Handle a page fault.
|
||||
/// \arg addr Address which caused the fault
|
||||
/// \arg ft Flags from the interrupt about the kind of fault
|
||||
/// \returns True if the fault was successfully handled
|
||||
bool handle_fault(uintptr_t addr, fault_type fault);
|
||||
bool handle_fault(uintptr_t addr, util::bitset8 fault);
|
||||
|
||||
/// Set up a TCB to operate in this address space.
|
||||
void initialize_tcb(TCB &tcb);
|
||||
@@ -155,6 +148,4 @@ private:
|
||||
util::vector<area> m_areas;
|
||||
|
||||
util::spinlock m_lock;
|
||||
};
|
||||
|
||||
is_bitfield(vm_space::fault_type);
|
||||
};
|
||||
@@ -3,15 +3,9 @@
|
||||
/// Data structures for reading jsix_boot.dat
|
||||
|
||||
#include <stdint.h>
|
||||
#include <util/enum_bitfields.h>
|
||||
|
||||
namespace bootproto {
|
||||
|
||||
enum class desc_flags : uint16_t {
|
||||
graphical = 0x0001,
|
||||
panic = 0x0002,
|
||||
symbols = 0x0004,
|
||||
};
|
||||
is_bitfield(desc_flags);
|
||||
enum class desc_flags { graphical, panic, symbols };
|
||||
|
||||
} // namespace bootproto
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <util/bitset.h>
|
||||
#include <util/counted.h>
|
||||
#include <util/enum_bitfields.h>
|
||||
|
||||
namespace bootproto {
|
||||
|
||||
@@ -18,19 +18,13 @@ constexpr uint64_t header_magic = 0x4c454e52454b366aull; // 'j6KERNEL'
|
||||
constexpr uint16_t header_version = 2;
|
||||
constexpr uint16_t min_header_version = 2;
|
||||
|
||||
enum class section_flags : uint32_t {
|
||||
none = 0,
|
||||
execute = 1,
|
||||
write = 2,
|
||||
read = 4,
|
||||
};
|
||||
is_bitfield(section_flags);
|
||||
enum class section_flags { none, execute, write, read };
|
||||
|
||||
struct program_section {
|
||||
uintptr_t phys_addr;
|
||||
uintptr_t virt_addr;
|
||||
uint32_t size;
|
||||
section_flags type;
|
||||
util::bitset32 type;
|
||||
};
|
||||
|
||||
struct program {
|
||||
@@ -112,18 +106,13 @@ struct frame_block
|
||||
uint64_t *bitmap;
|
||||
};
|
||||
|
||||
enum class boot_flags : uint16_t {
|
||||
none = 0x0000,
|
||||
debug = 0x0001,
|
||||
test = 0x0002,
|
||||
};
|
||||
is_bitfield(boot_flags);
|
||||
enum class boot_flags { none, debug, test };
|
||||
|
||||
struct args
|
||||
{
|
||||
uint32_t magic;
|
||||
uint16_t version;
|
||||
boot_flags flags;
|
||||
util::bitset16 flags;
|
||||
|
||||
void *pml4;
|
||||
util::counted<void> page_tables;
|
||||
|
||||
@@ -18,7 +18,7 @@ enum class feature {
|
||||
max
|
||||
};
|
||||
|
||||
using features = util::bitset<(unsigned)feature::max>;
|
||||
using features = util::sized_bitset<(unsigned)feature::max>;
|
||||
|
||||
class cpu_id
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <util/enum_bitfields.h>
|
||||
#include <util/bitset.h>
|
||||
|
||||
namespace elf {
|
||||
|
||||
@@ -54,19 +54,12 @@ struct file_header
|
||||
|
||||
|
||||
enum class segment_type : uint32_t { null, load, dynamic, interpreter, note };
|
||||
enum class segment_flags : uint32_t
|
||||
{
|
||||
none = 0x00,
|
||||
exec = 0x01,
|
||||
write = 0x02,
|
||||
read = 0x04,
|
||||
};
|
||||
is_bitfield(segment_flags);
|
||||
enum class segment_flags { exec, write, read };
|
||||
|
||||
struct segment_header
|
||||
{
|
||||
segment_type type;
|
||||
segment_flags flags;
|
||||
util::bitset32 flags;
|
||||
uint64_t offset;
|
||||
|
||||
uint64_t vaddr;
|
||||
@@ -80,18 +73,13 @@ struct segment_header
|
||||
|
||||
|
||||
enum class section_type : uint32_t { null, progbits };
|
||||
enum class section_flags : uint64_t
|
||||
{
|
||||
write = 0x01,
|
||||
alloc = 0x02,
|
||||
exec = 0x04,
|
||||
};
|
||||
enum class section_flags { write, alloc, exec };
|
||||
|
||||
struct section_header
|
||||
{
|
||||
uint32_t name_offset;
|
||||
section_type type;
|
||||
section_flags flags;
|
||||
util::bitset64 flags;
|
||||
uint64_t addr;
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
@@ -102,5 +90,3 @@ struct section_header
|
||||
} __attribute__ ((packed));
|
||||
|
||||
} // namespace elf
|
||||
|
||||
is_bitfield(elf::section_flags);
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
/// Enums used as flags for syscalls
|
||||
|
||||
enum j6_vm_flags {
|
||||
#define VM_FLAG(name, v) j6_vm_flag_ ## name = v,
|
||||
j6_vm_flag_none = 0,
|
||||
#define VM_FLAG(name, v) j6_vm_flag_ ## name = (1ul << v),
|
||||
#include <j6/tables/vm_flags.inc>
|
||||
#undef VM_FLAG
|
||||
j6_vm_flag_MAX
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
VM_FLAG( none, 0x00000000 )
|
||||
VM_FLAG( write, 0 )
|
||||
VM_FLAG( exec, 1 )
|
||||
|
||||
VM_FLAG( write, 0x00000001 )
|
||||
VM_FLAG( exec, 0x00000002 )
|
||||
VM_FLAG( contiguous, 4 )
|
||||
VM_FLAG( large_pages, 5 )
|
||||
VM_FLAG( huge_pages, 6 )
|
||||
|
||||
VM_FLAG( contiguous, 0x00000010 )
|
||||
VM_FLAG( large_pages, 0x00000020 )
|
||||
VM_FLAG( huge_pages, 0x00000040 )
|
||||
VM_FLAG( write_combine, 8 )
|
||||
|
||||
VM_FLAG( write_combine, 0x00000100 )
|
||||
VM_FLAG( mmio, 12 )
|
||||
|
||||
VM_FLAG( mmio, 0x00001000 )
|
||||
|
||||
VM_FLAG( exact, 0x00010000 )
|
||||
VM_FLAG( ring, 0x00020000 )
|
||||
VM_FLAG( exact, 16 )
|
||||
VM_FLAG( ring, 17 )
|
||||
@@ -7,34 +7,148 @@
|
||||
namespace util {
|
||||
|
||||
/// A statically-sized templated bitset
|
||||
template <unsigned N>
|
||||
template <typename I>
|
||||
class bitset
|
||||
{
|
||||
public:
|
||||
using storage_type = I;
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
static constexpr storage_type bit_or(T b) { return 1ull << uint64_t(b); }
|
||||
|
||||
template <typename T, typename ...Args>
|
||||
static constexpr storage_type bit_or(T b, Args... bs) { return (1ull << storage_type(b)) | bit_or(bs...); }
|
||||
|
||||
public:
|
||||
constexpr bitset(storage_type v = 0) : m_bits {v} {}
|
||||
|
||||
constexpr bitset(const bitset<I> &o) : m_bits {o.m_bits} {}
|
||||
|
||||
template <typename ...Args>
|
||||
__attribute__ ((always_inline))
|
||||
static constexpr bitset of(Args... args) { return {bit_or(args...)}; }
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((always_inline))
|
||||
static constexpr bitset from(T i) { return {storage_type(i)}; }
|
||||
|
||||
__attribute__ ((always_inline))
|
||||
inline constexpr bitset & operator=(bitset b) { m_bits = b.m_bits; return *this; }
|
||||
|
||||
inline constexpr operator storage_type () const { return m_bits; }
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((always_inline))
|
||||
inline constexpr bool get(T i) const {
|
||||
return m_bits & bit(i);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((always_inline))
|
||||
inline bitset & set(T i) {
|
||||
m_bits |= bit(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((always_inline))
|
||||
inline bitset & clear(T i) {
|
||||
m_bits &= ~bit(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
__attribute__ ((always_inline))
|
||||
inline storage_type range(unsigned start, unsigned count) {
|
||||
return (m_bits >> start) & ~((1 << count) - 1);
|
||||
}
|
||||
|
||||
__attribute__ ((always_inline))
|
||||
inline bitset & set_range(unsigned start, unsigned count, storage_type val) {
|
||||
const storage_type mask = ~((1 << count) - 1) << start;
|
||||
m_bits = (m_bits & ~mask) | ((val << start) & mask);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((always_inline))
|
||||
inline constexpr bool operator[](T i) const { return get(i); }
|
||||
|
||||
__attribute__ ((always_inline))
|
||||
inline constexpr bitset operator|(bitset b) const { return {storage_type(m_bits | b.m_bits)}; }
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((always_inline))
|
||||
inline constexpr bitset operator+(T i) const { return {storage_type(m_bits | bit(i))}; }
|
||||
|
||||
__attribute__ ((always_inline))
|
||||
inline constexpr bitset operator|=(bitset b) { *this = *this|b; return *this; }
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((always_inline))
|
||||
inline constexpr bitset operator+=(T i) { set(i); return *this; }
|
||||
|
||||
__attribute__ ((always_inline))
|
||||
inline constexpr bitset operator&(const bitset &b) const { return {storage_type(m_bits & b.m_bits)}; }
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((always_inline))
|
||||
inline constexpr bitset operator&(T i) const { return {m_bits & bit(i)}; }
|
||||
|
||||
__attribute__ ((always_inline))
|
||||
inline constexpr bitset & operator&=(const bitset &b) { m_bits &= b.m_bits; return *this; }
|
||||
|
||||
__attribute__ ((always_inline))
|
||||
inline constexpr bool operator==(const bitset &b) const { return m_bits == b.m_bits; }
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((always_inline))
|
||||
inline constexpr bool operator==(T i) const { return m_bits == storage_type(i); }
|
||||
|
||||
inline constexpr bool empty() const { return m_bits == 0; }
|
||||
|
||||
inline constexpr uint64_t value() const { return m_bits; }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
inline constexpr storage_type bit(T i) const { return (storage_type(1) << int(i)); }
|
||||
|
||||
storage_type m_bits;
|
||||
};
|
||||
|
||||
using bitset64 = bitset<uint64_t>;
|
||||
using bitset32 = bitset<uint32_t>;
|
||||
using bitset16 = bitset<uint16_t>;
|
||||
using bitset8 = bitset<uint8_t>;
|
||||
|
||||
template <unsigned N>
|
||||
class sized_bitset
|
||||
{
|
||||
static constexpr unsigned num_elems = (N + 63) / 64;
|
||||
|
||||
public:
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
__attribute__ ((always_inline))
|
||||
inline bool get(T i) const {
|
||||
return bits(i) & bit(i);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline bitset & set(T i) {
|
||||
__attribute__ ((always_inline))
|
||||
inline sized_bitset & set(T i) {
|
||||
bits(i) |= bit(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline bitset & clear(T i) {
|
||||
__attribute__ ((always_inline))
|
||||
inline sized_bitset & clear(T i) {
|
||||
bits(i) &= ~bit(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
__attribute__ ((always_inline))
|
||||
inline bool operator[](T i) const { return get(i); }
|
||||
|
||||
inline bool empty() const {
|
||||
@@ -45,260 +159,18 @@ public:
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
__attribute__ ((always_inline))
|
||||
inline uint64_t bit(T i) const { return (1ull << (static_cast<uint64_t>(i) & 63)); }
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
__attribute__ ((always_inline))
|
||||
inline uint64_t &bits(T i) { return m_bits[static_cast<uint64_t>(i) >> 6]; }
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
__attribute__ ((always_inline))
|
||||
inline uint64_t bits(T i) const { return m_bits[static_cast<uint64_t>(i) >> 6]; }
|
||||
|
||||
uint64_t m_bits[num_elems] = {0};
|
||||
};
|
||||
|
||||
namespace {
|
||||
}
|
||||
|
||||
/// A statically-sized templated bitset
|
||||
template <>
|
||||
class bitset<64>
|
||||
{
|
||||
template <typename T>
|
||||
static constexpr uint64_t bit_or(T b) { return 1ull << uint64_t(b); }
|
||||
|
||||
template <typename T, typename ...Args>
|
||||
static constexpr uint64_t bit_or(T b, Args... bs) { return (1ull << uint64_t(b)) | bit_or(bs...); }
|
||||
|
||||
public:
|
||||
bitset(uint64_t v = 0) : m_bits {v} {}
|
||||
|
||||
bitset(const bitset<64> &o) : m_bits {o.m_bits} {}
|
||||
|
||||
template <typename ...Args>
|
||||
constexpr explicit bitset(Args... args) : m_bits(bit_or(args...)) {}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline bitset & operator=(T v) { m_bits = static_cast<uint64_t>(v); return *this; }
|
||||
|
||||
inline constexpr operator const uint64_t () const { return m_bits; }
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline constexpr bool get(T i) const {
|
||||
return m_bits & bit(i);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline bitset & set(T i) {
|
||||
m_bits |= bit(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline bitset & clear(T i) {
|
||||
m_bits &= ~bit(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline constexpr bool operator[](T i) const { return get(i); }
|
||||
|
||||
inline constexpr bool empty() const { return m_bits == 0; }
|
||||
|
||||
inline constexpr uint64_t value() const { return m_bits; }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
inline constexpr uint64_t bit(T i) const { return (1ull << static_cast<uint64_t>(i)); }
|
||||
|
||||
uint64_t m_bits;
|
||||
};
|
||||
|
||||
/// A statically-sized templated bitset
|
||||
template <>
|
||||
class bitset<32>
|
||||
{
|
||||
template <typename T>
|
||||
static constexpr uint32_t bit_or(T b) { return 1u << uint32_t(b); }
|
||||
|
||||
template <typename T, typename ...Args>
|
||||
static constexpr uint32_t bit_or(T b, Args... bs) { return (1u << uint32_t(b)) | bit_or(bs...); }
|
||||
|
||||
public:
|
||||
bitset(uint32_t v = 0) : m_bits {v} {}
|
||||
|
||||
bitset(const bitset<32> &o) : m_bits {o.m_bits} {}
|
||||
|
||||
template <typename ...Args>
|
||||
constexpr bitset(Args... args) : m_bits(bit_or(args...)) {}
|
||||
|
||||
template <typename T>
|
||||
inline bitset & operator=(T v) { m_bits = static_cast<uint32_t>(v); return *this; }
|
||||
|
||||
inline constexpr operator uint32_t () const { return m_bits; }
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline constexpr bool get(T i) const {
|
||||
return m_bits & bit(i);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline bitset & set(T i) {
|
||||
m_bits |= bit(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline bitset & clear(T i) {
|
||||
m_bits &= ~bit(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline bool operator[](T i) const { return get(i); }
|
||||
|
||||
inline bool empty() const { return m_bits == 0; }
|
||||
|
||||
inline constexpr uint32_t value() const { return m_bits; }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
inline uint32_t bit(T i) const { return (1u << static_cast<uint32_t>(i)); }
|
||||
|
||||
uint32_t m_bits;
|
||||
};
|
||||
|
||||
/// A statically-sized templated bitset
|
||||
template <>
|
||||
class bitset<16>
|
||||
{
|
||||
template <typename T>
|
||||
static constexpr uint16_t bit_or(T b) { return 1u << uint16_t(b); }
|
||||
|
||||
template <typename T, typename ...Args>
|
||||
static constexpr uint16_t bit_or(T b, Args... bs) { return (1u << uint16_t(b)) | bit_or(bs...); }
|
||||
|
||||
public:
|
||||
bitset(uint16_t v = 0) : m_bits {v} {}
|
||||
|
||||
bitset(const bitset<16> &o) : m_bits {o.m_bits} {}
|
||||
|
||||
template <typename ...Args>
|
||||
constexpr bitset(Args... args) : m_bits(bit_or(args...)) {}
|
||||
|
||||
template <typename T>
|
||||
inline bitset & operator=(T v) { m_bits = static_cast<uint16_t>(v); return *this; }
|
||||
|
||||
inline constexpr operator uint16_t () const { return m_bits; }
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline constexpr bool get(T i) const {
|
||||
return m_bits & bit(i);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline bitset & set(T i) {
|
||||
m_bits |= bit(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline bitset & clear(T i) {
|
||||
m_bits &= ~bit(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline bool operator[](T i) const { return get(i); }
|
||||
|
||||
inline bool empty() const { return m_bits == 0; }
|
||||
|
||||
inline constexpr uint16_t value() const { return m_bits; }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
inline uint16_t bit(T i) const { return (1u << static_cast<uint16_t>(i)); }
|
||||
|
||||
uint16_t m_bits;
|
||||
};
|
||||
|
||||
|
||||
/// A statically-sized templated bitset
|
||||
template <>
|
||||
class bitset<8>
|
||||
{
|
||||
template <typename T>
|
||||
static constexpr uint8_t bit_or(T b) { return 1u << uint8_t(b); }
|
||||
|
||||
template <typename T, typename ...Args>
|
||||
static constexpr uint8_t bit_or(T b, Args... bs) { return (1u << uint8_t(b)) | bit_or(bs...); }
|
||||
|
||||
public:
|
||||
bitset(uint8_t v = 0) : m_bits {v} {}
|
||||
|
||||
bitset(const bitset<8> &o) : m_bits {o.m_bits} {}
|
||||
|
||||
template <typename ...Args>
|
||||
constexpr bitset(Args... args) : m_bits(bit_or(args...)) {}
|
||||
|
||||
template <typename T>
|
||||
inline bitset & operator=(T v) { m_bits = static_cast<uint8_t>(v); return *this; }
|
||||
|
||||
inline constexpr operator uint8_t () const { return m_bits; }
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline constexpr bool get(T i) const {
|
||||
return m_bits & bit(i);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline bitset & set(T i) {
|
||||
m_bits |= bit(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline bitset & clear(T i) {
|
||||
m_bits &= ~bit(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__attribute__ ((force_inline))
|
||||
inline bool operator[](T i) const { return get(i); }
|
||||
|
||||
inline bool empty() const { return m_bits == 0; }
|
||||
|
||||
inline constexpr uint8_t value() const { return m_bits; }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
inline uint8_t bit(T i) const { return (1u << static_cast<uint8_t>(i)); }
|
||||
|
||||
uint8_t m_bits;
|
||||
};
|
||||
|
||||
using bitset64 = bitset<64>;
|
||||
using bitset32 = bitset<32>;
|
||||
using bitset16 = bitset<16>;
|
||||
using bitset8 = bitset<8>;
|
||||
|
||||
} // namespace util
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <util/basic_types.h>
|
||||
|
||||
namespace util {
|
||||
namespace bits {
|
||||
|
||||
template <typename E>
|
||||
constexpr bool is_enum_bitfield(E) { return false; }
|
||||
|
||||
template <typename E>
|
||||
struct enum_or_int {
|
||||
static constexpr bool value =
|
||||
is_enum_bitfield(typename types::non_const<E>::type{})
|
||||
|| types::is_integral<E>::value;
|
||||
};
|
||||
|
||||
template <typename E, typename F>
|
||||
struct both_enum_or_int {
|
||||
static constexpr bool value =
|
||||
types::conjunction< enum_or_int<E>, enum_or_int<F> >::value;
|
||||
};
|
||||
|
||||
template <typename E, typename R>
|
||||
struct enable_if_bitfield {
|
||||
using enum_t = typename types::non_const<E>::type;
|
||||
using type = typename
|
||||
types::enable_if< is_enum_bitfield(enum_t{}), R >::type;
|
||||
};
|
||||
|
||||
template <typename E, typename F>
|
||||
constexpr typename types::enable_if<both_enum_or_int<E, F>::value,E>::type&
|
||||
operator |= (E &lhs, F rhs)
|
||||
{
|
||||
return lhs = static_cast<E>(
|
||||
static_cast<typename types::integral<E>::type>(lhs) |
|
||||
static_cast<typename types::integral<F>::type>(rhs));
|
||||
}
|
||||
|
||||
template <typename E, typename F>
|
||||
constexpr typename types::enable_if<both_enum_or_int<E, F>::value,E>::type&
|
||||
operator &= (E &lhs, F rhs)
|
||||
{
|
||||
return lhs = static_cast<E>(
|
||||
static_cast<typename types::integral<E>::type>(lhs) &
|
||||
static_cast<typename types::integral<F>::type>(rhs));
|
||||
}
|
||||
|
||||
template <typename E, typename F>
|
||||
constexpr typename types::enable_if<both_enum_or_int<E, F>::value,E>::type&
|
||||
operator ^= (E &lhs, F rhs)
|
||||
{
|
||||
return lhs = static_cast<E>(
|
||||
static_cast<typename types::integral<E>::type>(lhs) ^
|
||||
static_cast<typename types::integral<F>::type>(rhs));
|
||||
}
|
||||
|
||||
template <typename E, typename F>
|
||||
constexpr typename types::enable_if<both_enum_or_int<E, F>::value,E>::type
|
||||
operator & (E lhs, F rhs) { return lhs &= rhs; }
|
||||
|
||||
template <typename E, typename F>
|
||||
constexpr typename types::enable_if<both_enum_or_int<E, F>::value,E>::type
|
||||
operator | (E lhs, F rhs) { return lhs |= rhs; }
|
||||
|
||||
template <typename E, typename F>
|
||||
constexpr typename types::enable_if<both_enum_or_int<E, F>::value,E>::type
|
||||
operator ^ (E lhs, F rhs) { return lhs ^= rhs; }
|
||||
|
||||
template <typename E>
|
||||
constexpr typename enable_if_bitfield<E,E>::type
|
||||
operator ~ (E rhs) { return static_cast<E>(~static_cast<typename types::integral<E>::type>(rhs)); }
|
||||
|
||||
template <typename E>
|
||||
constexpr typename enable_if_bitfield<E,bool>::type
|
||||
operator ! (E rhs) { return static_cast<typename types::integral<E>::type>(rhs) == 0; }
|
||||
|
||||
/// Override logical-and to mean 'rhs contains all bits in lhs'
|
||||
template <typename E>
|
||||
constexpr typename enable_if_bitfield<E,bool>::type
|
||||
operator && (E rhs, E lhs) { return (rhs & lhs) == lhs; }
|
||||
|
||||
/// Generic 'has' for non-marked bitfields
|
||||
template <typename E, typename F>
|
||||
constexpr bool has(E set, F flags)
|
||||
{
|
||||
return
|
||||
(static_cast<typename types::integral<E>::type>(set) &
|
||||
static_cast<typename types::integral<F>::type>(flags)) ==
|
||||
static_cast<typename types::integral<F>::type>(flags);
|
||||
}
|
||||
|
||||
} // namespace bits
|
||||
} // namespace util
|
||||
|
||||
#define is_bitfield(name) \
|
||||
constexpr bool is_enum_bitfield(name) { return true; } \
|
||||
using namespace ::util::bits;
|
||||
|
||||
@@ -20,7 +20,6 @@ module("util",
|
||||
"util/cdb.h",
|
||||
"util/counted.h",
|
||||
"util/deque.h",
|
||||
"util/enum_bitfields.h",
|
||||
"util/format.h",
|
||||
"util/hash.h",
|
||||
"util/linked_list.h",
|
||||
|
||||
@@ -94,7 +94,7 @@ load_image(image_list::item_type &img, j6::proto::vfs::client &vfs)
|
||||
// TODO: way to remap VMA as read-only if there's no write flag on
|
||||
// the segment
|
||||
unsigned long flags = j6_vm_flag_exact | j6_vm_flag_write;
|
||||
if (seg.flags && elf::segment_flags::exec)
|
||||
if (seg.flags.get(elf::segment_flags::exec))
|
||||
flags |= j6_vm_flag_exec;
|
||||
|
||||
uintptr_t start = file.base() + seg.offset;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
/// Data structure for dealing with j6romfs images
|
||||
|
||||
#include <util/counted.h>
|
||||
#include <util/enum_bitfields.h>
|
||||
|
||||
namespace j6romfs
|
||||
{
|
||||
|
||||
@@ -95,7 +95,7 @@ load_program_into(j6_handle_t proc, elf::file &file, uintptr_t image_base, const
|
||||
// TODO: way to remap VMA as read-only if there's no write flag on
|
||||
// the segment
|
||||
unsigned long flags = j6_vm_flag_write;
|
||||
if (seg.flags && elf::segment_flags::exec)
|
||||
if (seg.flags.get(elf::segment_flags::exec))
|
||||
flags |= j6_vm_flag_exec;
|
||||
|
||||
uintptr_t start = file.base() + seg.offset;
|
||||
|
||||
Reference in New Issue
Block a user