[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:
Justin C. Miller
2024-02-25 23:40:14 -08:00
parent f7ea46e49e
commit 9f54927a82
36 changed files with 352 additions and 622 deletions

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();

View File

@@ -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);

View File

@@ -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

View File

@@ -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));
}

View File

@@ -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);

View File

@@ -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()

View File

@@ -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 &sect : 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);

View File

@@ -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),

View File

@@ -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>

View File

@@ -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}
{

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);
};

View File

@@ -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

View File

@@ -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;

View File

@@ -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
{

View File

@@ -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);

View File

@@ -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

View File

@@ -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 )

View File

@@ -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

View File

@@ -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;

View File

@@ -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",

View File

@@ -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;

View File

@@ -3,7 +3,6 @@
/// Data structure for dealing with j6romfs images
#include <util/counted.h>
#include <util/enum_bitfields.h>
namespace j6romfs
{

View File

@@ -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;