mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 08:24:32 -08:00
[kernel] Expose a sysconf page to userspace
A structure, system_config, which is dynamically defined by the definitions/sysconf.yaml config, is now mapped into every user address space. The kernel fills this with information about itself and the running machine. User programs access this through the new j6_sysconf fake syscall in libj6. See: Github bug #242 See: [frobozz blog post](https://jsix.dev/posts/frobozz/) Tags:
This commit is contained in:
@@ -60,6 +60,8 @@ kernel = module("kernel",
|
||||
"syscalls/system.cpp",
|
||||
"syscalls/thread.cpp",
|
||||
"syscalls/vm_area.cpp",
|
||||
"sysconf.cpp",
|
||||
"sysconf.h.cog",
|
||||
"task.s",
|
||||
"tss.cpp",
|
||||
"vm_space.cpp",
|
||||
@@ -69,9 +71,11 @@ from glob import glob
|
||||
from os.path import join
|
||||
|
||||
layout = join(source_root, "definitions/memory_layout.yaml")
|
||||
sysconf = join(source_root, "definitions/sysconf.yaml")
|
||||
definitions = glob('definitions/**/*.def', recursive=True)
|
||||
|
||||
kernel.add_depends(["memory.h.cog"], [layout])
|
||||
kernel.add_depends(["sysconf.h.cog"], [sysconf])
|
||||
kernel.add_depends(["syscall.cpp.cog", "syscall.h.cog", "syscalls.inc.cog"], definitions)
|
||||
|
||||
kernel.variables['ldflags'] = ["${ldflags}", "-T", "${source_root}/src/kernel/kernel.ld"]
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "scheduler.h"
|
||||
#include "serial.h"
|
||||
#include "syscall.h"
|
||||
#include "sysconf.h"
|
||||
#include "tss.h"
|
||||
#include "vm_space.h"
|
||||
|
||||
@@ -151,6 +152,7 @@ kernel_main(bootproto::args *args)
|
||||
const auto &apic_ids = devices.get_apic_ids();
|
||||
g_num_cpus = start_aps(*apic, apic_ids, args->pml4);
|
||||
|
||||
sysconf_create();
|
||||
interrupts_enable();
|
||||
g_com1.handle_interrupt();
|
||||
|
||||
|
||||
@@ -55,6 +55,11 @@ for region in layout.regions:
|
||||
/// through the linear_offset area.
|
||||
constexpr bool linear_mappable(uintptr_t a) { return (a & linear_offset) == 0; }
|
||||
|
||||
/// Get the number of pages needed to hold `bytes` bytes
|
||||
inline constexpr size_t bytes_to_pages(size_t bytes) {
|
||||
return ((bytes - 1) / frame_size) + 1;
|
||||
}
|
||||
|
||||
/// Convert a physical address to a virtual one (in the linear-mapped area)
|
||||
template <typename T> T * to_virtual(uintptr_t a) {
|
||||
return reinterpret_cast<T*>(a|linear_offset);
|
||||
|
||||
53
src/kernel/sysconf.cpp
Normal file
53
src/kernel/sysconf.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "assert.h"
|
||||
#include "cpu.h"
|
||||
#include "frame_allocator.h"
|
||||
#include "memory.h"
|
||||
#include "sysconf.h"
|
||||
|
||||
struct kheader
|
||||
{
|
||||
uint64_t magic;
|
||||
uint16_t header_len;
|
||||
uint16_t header_version;
|
||||
|
||||
uint16_t version_major;
|
||||
uint16_t version_minor;
|
||||
uint16_t version_patch;
|
||||
uint16_t _reserved;
|
||||
uint32_t version_gitsha;
|
||||
|
||||
uint64_t flags;
|
||||
};
|
||||
|
||||
extern kheader _kernel_header;
|
||||
|
||||
system_config *g_sysconf = nullptr;
|
||||
uintptr_t g_sysconf_phys = 0;
|
||||
|
||||
constexpr size_t sysconf_pages = mem::bytes_to_pages(sizeof(system_config));
|
||||
|
||||
void
|
||||
sysconf_create()
|
||||
{
|
||||
auto &fa = frame_allocator::get();
|
||||
|
||||
size_t count = fa.allocate(sysconf_pages, &g_sysconf_phys);
|
||||
|
||||
kassert(count == sysconf_pages,
|
||||
"Could not get enough contiguous pages for sysconf");
|
||||
|
||||
g_sysconf = mem::to_virtual<system_config>(g_sysconf_phys);
|
||||
memset(g_sysconf, 0, sysconf_pages * mem::frame_size);
|
||||
|
||||
g_sysconf->kernel_version_major = _kernel_header.version_major;
|
||||
g_sysconf->kernel_version_minor = _kernel_header.version_minor;
|
||||
g_sysconf->kernel_version_patch = _kernel_header.version_patch;
|
||||
g_sysconf->kernel_version_gitsha = _kernel_header.version_gitsha;
|
||||
|
||||
g_sysconf->sys_page_size = mem::frame_size;
|
||||
g_sysconf->sys_large_page_size = 0;
|
||||
g_sysconf->sys_huge_page_size = 0;
|
||||
g_sysconf->sys_num_cpus = g_num_cpus;
|
||||
}
|
||||
28
src/kernel/sysconf.h.cog
Normal file
28
src/kernel/sysconf.h.cog
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
// vim: ft=cpp
|
||||
|
||||
/// \file sysconf.h
|
||||
/// Kernel-side implementation of sysconf struct
|
||||
|
||||
/*[[[cog code generation
|
||||
from os.path import join
|
||||
from sysconf import Sysconf
|
||||
sc = Sysconf(join(definitions_path, "sysconf.yaml"))
|
||||
|
||||
cog.outl(f"constexpr uintptr_t sysconf_user_address = {sc.address:#x};")
|
||||
]]]*/
|
||||
///[[[end]]]
|
||||
|
||||
struct system_config
|
||||
{
|
||||
/*[[[cog code generation
|
||||
for var in sc.vars:
|
||||
cog.outl(f"{var.type:10} {var.section}_{var.name};")
|
||||
]]]*/
|
||||
///[[[end]]]
|
||||
};
|
||||
|
||||
extern system_config *g_sysconf;
|
||||
extern uintptr_t g_sysconf_phys;
|
||||
|
||||
void sysconf_create();
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "objects/process.h"
|
||||
#include "objects/thread.h"
|
||||
#include "objects/vm_area.h"
|
||||
#include "sysconf.h"
|
||||
#include "vm_space.h"
|
||||
|
||||
// The initial memory for the array of areas for the kernel space
|
||||
@@ -46,6 +47,14 @@ vm_space::vm_space() :
|
||||
memset(m_pml4, 0, mem::frame_size/2);
|
||||
for (unsigned i = arch::kernel_root_index; i < arch::table_entries; ++i)
|
||||
m_pml4->entries[i] = kpml4->entries[i];
|
||||
|
||||
// Every vm space has sysconf in it
|
||||
vm_area *sysc = new vm_area_fixed(
|
||||
g_sysconf_phys,
|
||||
sizeof(system_config),
|
||||
vm_flags::none);
|
||||
|
||||
add(sysconf_user_address, sysc);
|
||||
}
|
||||
|
||||
vm_space::~vm_space()
|
||||
|
||||
44
src/libraries/j6/include/j6/sysconf.h.cog
Normal file
44
src/libraries/j6/include/j6/sysconf.h.cog
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
// vim: ft=cpp
|
||||
|
||||
/// \file sysconf.h
|
||||
/// Get kernel configuration
|
||||
|
||||
// The kernel depends on libj6 for some shared code,
|
||||
// but should not include the user-specific code.
|
||||
#ifndef __j6kernel
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*[[[cog code generation
|
||||
from os.path import join
|
||||
from sysconf import Sysconf
|
||||
sc = Sysconf(join(definitions_path, "sysconf.yaml"))
|
||||
]]]*/
|
||||
///[[[end]]]
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum j6_sysconf_arg
|
||||
{
|
||||
/*[[[cog code generation
|
||||
for var in sc.vars:
|
||||
cog.outl(f"j6sc_{var.name},")
|
||||
]]]*/
|
||||
///[[[end]]]
|
||||
|
||||
j6sc_MAX
|
||||
};
|
||||
|
||||
/// Get the kernel configuration value specified by
|
||||
/// the argument.
|
||||
unsigned long j6_sysconf(j6_sysconf_arg arg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern C
|
||||
#endif
|
||||
|
||||
#endif // __j6kernel
|
||||
@@ -6,10 +6,15 @@ j6 = module("j6",
|
||||
sources = [
|
||||
"init.cpp",
|
||||
"include/j6/syscalls.h.cog",
|
||||
"include/j6/sysconf.h.cog",
|
||||
"syscalls.s.cog",
|
||||
"sysconf.cpp.cog",
|
||||
])
|
||||
|
||||
from glob import glob
|
||||
from os.path import join
|
||||
|
||||
sysconf = join(source_root, "definitions/sysconf.yaml")
|
||||
definitions = glob('definitions/**/*.def', recursive=True)
|
||||
|
||||
j6.add_depends([
|
||||
@@ -17,3 +22,8 @@ j6.add_depends([
|
||||
"syscalls.s.cog",
|
||||
], definitions)
|
||||
|
||||
j6.add_depends([
|
||||
"include/j6/sysconf.h.cog",
|
||||
"sysconf.cpp.cog",
|
||||
], [sysconf])
|
||||
|
||||
|
||||
44
src/libraries/j6/sysconf.cpp.cog
Normal file
44
src/libraries/j6/sysconf.cpp.cog
Normal file
@@ -0,0 +1,44 @@
|
||||
// vim: ft=cpp
|
||||
|
||||
// The kernel depends on libj6 for some shared code,
|
||||
// but should not include the user-specific code.
|
||||
#ifndef __j6kernel
|
||||
|
||||
#include <j6/sysconf.h>
|
||||
|
||||
/*[[[cog code generation
|
||||
from os.path import join
|
||||
from sysconf import Sysconf
|
||||
sc = Sysconf(join(definitions_path, "sysconf.yaml"))
|
||||
|
||||
cog.outl(f"constexpr uintptr_t __sysconf_address = {sc.address:#x};")
|
||||
]]]*/
|
||||
///[[[end]]]
|
||||
|
||||
struct __system_config
|
||||
{
|
||||
/*[[[cog code generation
|
||||
for var in sc.vars:
|
||||
cog.outl(f"{var.type:10} {var.section}_{var.name};")
|
||||
]]]*/
|
||||
///[[[end]]]
|
||||
};
|
||||
|
||||
unsigned long
|
||||
j6_sysconf(j6_sysconf_arg arg)
|
||||
{
|
||||
__system_config &sc =
|
||||
* reinterpret_cast<__system_config*>(__sysconf_address);
|
||||
|
||||
switch (arg) {
|
||||
/*[[[cog code generation
|
||||
for var in sc.vars:
|
||||
cog.outl(f"case j6sc_{var.name}: return sc.{var.section}_{var.name};")
|
||||
]]]*/
|
||||
///[[[end]]]
|
||||
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __j6kernel
|
||||
Reference in New Issue
Block a user