[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:
Justin C. Miller
2022-01-13 22:08:35 -08:00
parent 939022bb5e
commit b3aaddadc8
11 changed files with 250 additions and 0 deletions

View File

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

View File

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

View File

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

View File

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