mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14: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:
34
definitions/sysconf.yaml
Normal file
34
definitions/sysconf.yaml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
address: 0x6a360000
|
||||||
|
vars:
|
||||||
|
- name: version_major
|
||||||
|
section: kernel
|
||||||
|
type: uint8_t
|
||||||
|
|
||||||
|
- name: version_minor
|
||||||
|
section: kernel
|
||||||
|
type: uint8_t
|
||||||
|
|
||||||
|
- name: version_patch
|
||||||
|
section: kernel
|
||||||
|
type: uint16_t
|
||||||
|
|
||||||
|
- name: version_gitsha
|
||||||
|
section: kernel
|
||||||
|
type: uint32_t
|
||||||
|
|
||||||
|
- name: page_size
|
||||||
|
section: sys
|
||||||
|
type: size_t
|
||||||
|
|
||||||
|
- name: large_page_size
|
||||||
|
section: sys
|
||||||
|
type: size_t
|
||||||
|
|
||||||
|
- name: huge_page_size
|
||||||
|
section: sys
|
||||||
|
type: size_t
|
||||||
|
|
||||||
|
- name: num_cpus
|
||||||
|
section: sys
|
||||||
|
type: uint32_t
|
||||||
17
scripts/sysconf.py
Normal file
17
scripts/sysconf.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
class Sysconf:
|
||||||
|
from collections import namedtuple
|
||||||
|
Var = namedtuple("Var", ("name", "section", "type"))
|
||||||
|
|
||||||
|
def __init__(self, path):
|
||||||
|
from yaml import safe_load
|
||||||
|
|
||||||
|
sys_vars = []
|
||||||
|
|
||||||
|
with open(path, 'r') as infile:
|
||||||
|
data = safe_load(infile.read())
|
||||||
|
self.address = data["address"]
|
||||||
|
|
||||||
|
for v in data["vars"]:
|
||||||
|
sys_vars.append(Sysconf.Var(v["name"], v["section"], v["type"]))
|
||||||
|
|
||||||
|
self.vars = tuple(sys_vars)
|
||||||
@@ -60,6 +60,8 @@ kernel = module("kernel",
|
|||||||
"syscalls/system.cpp",
|
"syscalls/system.cpp",
|
||||||
"syscalls/thread.cpp",
|
"syscalls/thread.cpp",
|
||||||
"syscalls/vm_area.cpp",
|
"syscalls/vm_area.cpp",
|
||||||
|
"sysconf.cpp",
|
||||||
|
"sysconf.h.cog",
|
||||||
"task.s",
|
"task.s",
|
||||||
"tss.cpp",
|
"tss.cpp",
|
||||||
"vm_space.cpp",
|
"vm_space.cpp",
|
||||||
@@ -69,9 +71,11 @@ from glob import glob
|
|||||||
from os.path import join
|
from os.path import join
|
||||||
|
|
||||||
layout = join(source_root, "definitions/memory_layout.yaml")
|
layout = join(source_root, "definitions/memory_layout.yaml")
|
||||||
|
sysconf = join(source_root, "definitions/sysconf.yaml")
|
||||||
definitions = glob('definitions/**/*.def', recursive=True)
|
definitions = glob('definitions/**/*.def', recursive=True)
|
||||||
|
|
||||||
kernel.add_depends(["memory.h.cog"], [layout])
|
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.add_depends(["syscall.cpp.cog", "syscall.h.cog", "syscalls.inc.cog"], definitions)
|
||||||
|
|
||||||
kernel.variables['ldflags'] = ["${ldflags}", "-T", "${source_root}/src/kernel/kernel.ld"]
|
kernel.variables['ldflags'] = ["${ldflags}", "-T", "${source_root}/src/kernel/kernel.ld"]
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
|
#include "sysconf.h"
|
||||||
#include "tss.h"
|
#include "tss.h"
|
||||||
#include "vm_space.h"
|
#include "vm_space.h"
|
||||||
|
|
||||||
@@ -151,6 +152,7 @@ kernel_main(bootproto::args *args)
|
|||||||
const auto &apic_ids = devices.get_apic_ids();
|
const auto &apic_ids = devices.get_apic_ids();
|
||||||
g_num_cpus = start_aps(*apic, apic_ids, args->pml4);
|
g_num_cpus = start_aps(*apic, apic_ids, args->pml4);
|
||||||
|
|
||||||
|
sysconf_create();
|
||||||
interrupts_enable();
|
interrupts_enable();
|
||||||
g_com1.handle_interrupt();
|
g_com1.handle_interrupt();
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,11 @@ for region in layout.regions:
|
|||||||
/// through the linear_offset area.
|
/// through the linear_offset area.
|
||||||
constexpr bool linear_mappable(uintptr_t a) { return (a & linear_offset) == 0; }
|
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)
|
/// Convert a physical address to a virtual one (in the linear-mapped area)
|
||||||
template <typename T> T * to_virtual(uintptr_t a) {
|
template <typename T> T * to_virtual(uintptr_t a) {
|
||||||
return reinterpret_cast<T*>(a|linear_offset);
|
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/process.h"
|
||||||
#include "objects/thread.h"
|
#include "objects/thread.h"
|
||||||
#include "objects/vm_area.h"
|
#include "objects/vm_area.h"
|
||||||
|
#include "sysconf.h"
|
||||||
#include "vm_space.h"
|
#include "vm_space.h"
|
||||||
|
|
||||||
// The initial memory for the array of areas for the kernel space
|
// 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);
|
memset(m_pml4, 0, mem::frame_size/2);
|
||||||
for (unsigned i = arch::kernel_root_index; i < arch::table_entries; ++i)
|
for (unsigned i = arch::kernel_root_index; i < arch::table_entries; ++i)
|
||||||
m_pml4->entries[i] = kpml4->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()
|
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 = [
|
sources = [
|
||||||
"init.cpp",
|
"init.cpp",
|
||||||
"include/j6/syscalls.h.cog",
|
"include/j6/syscalls.h.cog",
|
||||||
|
"include/j6/sysconf.h.cog",
|
||||||
"syscalls.s.cog",
|
"syscalls.s.cog",
|
||||||
|
"sysconf.cpp.cog",
|
||||||
])
|
])
|
||||||
|
|
||||||
from glob import glob
|
from glob import glob
|
||||||
|
from os.path import join
|
||||||
|
|
||||||
|
sysconf = join(source_root, "definitions/sysconf.yaml")
|
||||||
definitions = glob('definitions/**/*.def', recursive=True)
|
definitions = glob('definitions/**/*.def', recursive=True)
|
||||||
|
|
||||||
j6.add_depends([
|
j6.add_depends([
|
||||||
@@ -17,3 +22,8 @@ j6.add_depends([
|
|||||||
"syscalls.s.cog",
|
"syscalls.s.cog",
|
||||||
], definitions)
|
], 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