mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 08:24:32 -08:00
Compare commits
23 Commits
v0.8.0
...
feature/mu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7da34dbffb | ||
|
|
90a0eb3c53 | ||
|
|
d1ddbd2cf1 | ||
|
|
81b331e5da | ||
|
|
1ebee17880 | ||
|
|
4649d5f77b | ||
|
|
d3c1d6cc34 | ||
|
|
ee24ec8d5c | ||
|
|
372325fab7 | ||
|
|
8f036d9293 | ||
|
|
e345cdd1a7 | ||
|
|
fca570a163 | ||
|
|
ff64d1989f | ||
|
|
d3f5db2479 | ||
|
|
fa587060f1 | ||
|
|
b137c75eb2 | ||
|
|
05c1361283 | ||
|
|
c6835dad70 | ||
|
|
e7fa1dde97 | ||
|
|
eb62588b79 | ||
|
|
29332cbd45 | ||
|
|
172eb70551 | ||
|
|
7322df98f5 |
40
assets/build/amd64/target.init.yaml
Normal file
40
assets/build/amd64/target.init.yaml
Normal file
@@ -0,0 +1,40 @@
|
||||
---
|
||||
ccflags: [
|
||||
"--target=x86_64-jsix-elf",
|
||||
"-fno-omit-frame-pointer",
|
||||
"-fno-stack-protector",
|
||||
|
||||
"-fvisibility=hidden",
|
||||
"-fvisibility-inlines-hidden",
|
||||
|
||||
"-D__ELF__",
|
||||
"-D__jsix__",
|
||||
"-U__linux",
|
||||
"-U__linux__",
|
||||
|
||||
"-DMSPACES",
|
||||
|
||||
"--sysroot='${source_root}/sysroot'"
|
||||
]
|
||||
|
||||
|
||||
cxxflags: [
|
||||
"-fno-exceptions",
|
||||
"-fno-rtti",
|
||||
"-isystem", "${source_root}/sysroot/include/c++/v1",
|
||||
]
|
||||
|
||||
ldflags: [
|
||||
"-Bstatic",
|
||||
"-m", "elf_x86_64",
|
||||
"--sysroot='${source_root}/sysroot'",
|
||||
"--no-eh-frame-hdr",
|
||||
"-L", "${source_root}/sysroot/lib",
|
||||
"-z", "separate-code",
|
||||
"-lc++", "-lc++abi", "-lunwind",
|
||||
"--no-dependent-libraries",
|
||||
]
|
||||
|
||||
libs: [
|
||||
"${target_dir}/crt0.o",
|
||||
]
|
||||
34
assets/build/amd64/target.user.yaml
Normal file
34
assets/build/amd64/target.user.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
asflags: []
|
||||
|
||||
ccflags: [
|
||||
"--target=x86_64-jsix-elf",
|
||||
"-fno-omit-frame-pointer",
|
||||
"-fno-stack-protector",
|
||||
|
||||
"-fvisibility=hidden",
|
||||
"-fvisibility-inlines-hidden",
|
||||
|
||||
"-D__ELF__",
|
||||
"-D__jsix__",
|
||||
"-U__linux",
|
||||
"-U__linux__",
|
||||
|
||||
"--sysroot='${source_root}/sysroot'",
|
||||
"-fpic",
|
||||
]
|
||||
|
||||
cxxflags: [
|
||||
"-fno-exceptions",
|
||||
"-fno-rtti",
|
||||
"-isystem", "${source_root}/sysroot/include/c++/v1",
|
||||
]
|
||||
|
||||
ldflags: [
|
||||
"-m", "elf_x86_64",
|
||||
"--sysroot='${source_root}/sysroot'",
|
||||
"--no-eh-frame-hdr",
|
||||
"-L", "${source_root}/sysroot/lib",
|
||||
"-z", "separate-code",
|
||||
"--no-dependent-libraries",
|
||||
]
|
||||
9
assets/build/linux/config.debug.yaml
Normal file
9
assets/build/linux/config.debug.yaml
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
ccflags: [
|
||||
"-g3",
|
||||
"-ggdb",
|
||||
]
|
||||
|
||||
ldflags: [
|
||||
"-g",
|
||||
]
|
||||
3
assets/build/linux/config.release.yaml
Normal file
3
assets/build/linux/config.release.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
ccflags: [
|
||||
"-O3",
|
||||
]
|
||||
39
assets/build/linux/global.yaml
Normal file
39
assets/build/linux/global.yaml
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
cc: "clang-16"
|
||||
cxx: "clang++-16"
|
||||
ld: "ld.lld-16"
|
||||
ar: ar
|
||||
nasm: nasm
|
||||
objcopy: objcopy
|
||||
|
||||
ccflags: [
|
||||
"-I${source_root}/src/include",
|
||||
"-I${source_root}/sysroot/include/c++/v1",
|
||||
"-fcolor-diagnostics",
|
||||
"-U__STDCPP_THREADS__",
|
||||
"-D__jsix_config=${build_config}",
|
||||
"-D__jsix_config_${build_config}",
|
||||
"-DVERSION_MAJOR=${version_major}",
|
||||
"-DVERSION_MINOR=${version_minor}",
|
||||
"-DVERSION_PATCH=${version_patch}",
|
||||
"-DVERSION_GITSHA=0x${version_sha}",
|
||||
'-DGIT_VERSION=\"${version_major}.${version_minor}.${version_patch}+${version_sha}\"',
|
||||
'-DGIT_VERSION_WIDE=L\"${version_major}.${version_minor}.${version_patch}+${version_sha}\"',
|
||||
|
||||
"-Wformat=2", "-Winit-self", "-Winline", "-Wmissing-format-attribute",
|
||||
"-Wmissing-include-dirs", "-Wswitch", "-Wundef", "-Wdisabled-optimization",
|
||||
"-Wpointer-arith", "-Wno-attributes", "-Wno-sign-compare", "-Wno-multichar",
|
||||
"-Wno-div-by-zero", "-Wno-endif-labels", "-Wno-pragmas", "-Wno-format-extra-args",
|
||||
"-Wno-unused-result", "-Wno-deprecated-declarations", "-Wno-unused-function",
|
||||
"-Wno-address-of-packed-member", "-Wno-invalid-offsetof", "-Wno-format-nonliteral",
|
||||
"-Werror" ]
|
||||
|
||||
asflags: [
|
||||
"-DVERSION_MAJOR=${version_major}",
|
||||
"-DVERSION_MINOR=${version_minor}",
|
||||
"-DVERSION_PATCH=${version_patch}",
|
||||
"-DVERSION_GITSHA=0x${version_sha}",
|
||||
"-I${source_root}/src/include" ]
|
||||
|
||||
cflags: [ "-std=c11" ]
|
||||
cxxflags: [ "-std=c++17" ]
|
||||
91
assets/build/linux/rules.ninja
Normal file
91
assets/build/linux/rules.ninja
Normal file
@@ -0,0 +1,91 @@
|
||||
rule compile.c
|
||||
command = $cc -MMD -MF $out.d $cflags $ccflags -o $out -c $in
|
||||
description = Compiling [$target]:$name
|
||||
depfile = $out.d
|
||||
deps = gcc
|
||||
|
||||
rule dump_c_defs
|
||||
command = echo | $cc $ccflags $cflags -dM -E - > $out
|
||||
description = Dumping C defines for $target
|
||||
|
||||
rule dump_c_run
|
||||
command = echo '#!/bin/bash' > $out; echo '$cc $ccflags $cflags $$*' >> $
|
||||
$out; chmod a+x $out
|
||||
description = Dumping C arguments for $target
|
||||
|
||||
rule compile.cpp
|
||||
command = $cxx -MMD -MF $out.d $cxxflags $ccflags -o $out -c $in
|
||||
description = Compiling [$target]:$name
|
||||
depfile = $out.d
|
||||
deps = gcc
|
||||
|
||||
rule dump_cpp_defs
|
||||
command = echo | $cxx -x c++ $ccflags $cxxflags -dM -E - > $out
|
||||
description = Dumping C++ defines for $target
|
||||
|
||||
rule dump_cpp_run
|
||||
command = echo '#!/bin/bash' > $out; echo '$cxx $ccflags $cxxflags $$*' $
|
||||
>> $out; chmod a+x $out
|
||||
description = Dumping C++ arguments for $target
|
||||
|
||||
rule compile.s
|
||||
command = $nasm -o $out -felf64 -MD $out.d $asflags $in
|
||||
description = Assembling [$target]:$name
|
||||
depfile = $out.d
|
||||
deps = gcc
|
||||
|
||||
rule parse.cog
|
||||
command = cog -o $out -d -D target=$target $cogflags $in
|
||||
description = Parsing [$target]:$name
|
||||
|
||||
rule exe
|
||||
command = $ld $ldflags -o $out $in $libs
|
||||
description = Linking exe [$target]:$name
|
||||
|
||||
rule driver
|
||||
command = $ld $ldflags -o $out $in $libs
|
||||
description = Linking driver [$target]:$name
|
||||
|
||||
rule lib
|
||||
command = $ld -shared -soname $soname $ldflags -o $out $in $libs
|
||||
description = Linking [$target]:$name
|
||||
|
||||
rule lib_static
|
||||
command = $ar qcs $out $in
|
||||
description = Archiving [$target]:$name
|
||||
|
||||
rule cp
|
||||
command = cp $in $out
|
||||
description = Copying [$target]:$name
|
||||
|
||||
rule dump
|
||||
command = objdump -DSC -M intel $in > $out
|
||||
description = Dumping decompiled $name
|
||||
|
||||
rule makest
|
||||
description = Making symbol table
|
||||
command = nm -n -S --demangle $in | ${source_root}/scripts/build_symbol_table.py $out
|
||||
|
||||
rule makeinitrd
|
||||
description = Creating $name
|
||||
command = ${source_root}/scripts/mkj6romfs.py -c $format $in $out
|
||||
|
||||
rule makefat
|
||||
description = Creating $name
|
||||
command = $
|
||||
cp $in $out; $
|
||||
mcopy -s -D o -i $out@@1M ${build_root}/fatroot/* ::/
|
||||
|
||||
rule strip
|
||||
description = Stripping $name
|
||||
command = $
|
||||
cp $in $out; $
|
||||
objcopy --only-keep-debug $out $debug; $
|
||||
strip --discard-all -g $out; $
|
||||
objcopy --add-gnu-debuglink=$debug $out
|
||||
|
||||
rule touch
|
||||
command = touch $out
|
||||
|
||||
rule compdb
|
||||
command = ninja -t compdb > $out
|
||||
16
assets/build/linux/target.user.exe.yaml
Normal file
16
assets/build/linux/target.user.exe.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
|
||||
ccflags: [
|
||||
"-fpie"
|
||||
]
|
||||
|
||||
ldflags: [
|
||||
"-pie",
|
||||
"-rpath", "${target_dir}",
|
||||
"--dynamic-linker", "/lib64/ld-linux-x86-64.so.2",
|
||||
"--push-state", "--as-needed", "-Bstatic", "-lc++", "-lc++abi", "-lunwind", "--pop-state",
|
||||
]
|
||||
|
||||
libs: [
|
||||
"${target_dir}/crt0.o",
|
||||
]
|
||||
7
assets/build/linux/target.user.shared.yaml
Normal file
7
assets/build/linux/target.user.shared.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
ccflags: [
|
||||
]
|
||||
|
||||
ldflags: [
|
||||
"-shared",
|
||||
]
|
||||
32
configure
vendored
32
configure
vendored
@@ -1,10 +1,10 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
def generate(output, config, manifest):
|
||||
def generate(output, config, arch, manifest):
|
||||
from os import makedirs
|
||||
from glob import iglob
|
||||
from pathlib import Path
|
||||
from bonnibel.module import Module
|
||||
from bonnibel.module import Module, ModuleList
|
||||
from bonnibel.project import Project
|
||||
|
||||
root = Path(__file__).parent.resolve()
|
||||
@@ -18,16 +18,17 @@ def generate(output, config, manifest):
|
||||
str(root / "external/*.module"),
|
||||
]
|
||||
|
||||
modules = {}
|
||||
modules = ModuleList(arch)
|
||||
for source in sources:
|
||||
for modfile in iglob(source, recursive=True):
|
||||
path = Path(modfile).parent
|
||||
modfile = Path(modfile)
|
||||
path = modfile.parent
|
||||
|
||||
def module_init(name, **kwargs):
|
||||
if not "root" in kwargs:
|
||||
kwargs["root"] = path
|
||||
m = Module(name, modfile, **kwargs)
|
||||
modules[m.name] = m
|
||||
modules.add(m)
|
||||
return m
|
||||
|
||||
glo = {
|
||||
@@ -36,18 +37,16 @@ def generate(output, config, manifest):
|
||||
"build_root": output,
|
||||
"module_root": path,
|
||||
"config": config,
|
||||
"arch": arch,
|
||||
}
|
||||
code = compile(open(modfile, 'r').read(), modfile, "exec")
|
||||
|
||||
loc = {}
|
||||
exec(code, glo, loc)
|
||||
|
||||
Module.update(modules)
|
||||
|
||||
makedirs(output.resolve(), exist_ok=True)
|
||||
project.generate(root, output, modules, config, manifest)
|
||||
for mod in modules.values():
|
||||
mod.generate(output)
|
||||
project.generate(root, output, modules, config, arch, manifest)
|
||||
modules.generate(output)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
@@ -57,18 +56,25 @@ if __name__ == "__main__":
|
||||
from argparse import ArgumentParser
|
||||
from bonnibel import BonnibelError
|
||||
|
||||
default_arch = "amd64"
|
||||
|
||||
p = ArgumentParser(description="Generate jsix build files")
|
||||
p.add_argument("--manifest", "-m", metavar="FILE", default="assets/manifests/default.yaml",
|
||||
help="File to use as the system manifest")
|
||||
p.add_argument("--config", "-c", metavar="NAME", default="debug",
|
||||
p.add_argument("--conf", "-c", metavar="NAME", default="debug",
|
||||
help="Configuration to build (eg, 'debug' or 'release')")
|
||||
p.add_argument("output", metavar="DIR", default="build", nargs='?',
|
||||
p.add_argument("--arch", "-a", metavar="NAME", default=default_arch,
|
||||
help="Architecture to build (eg, 'amd64' or 'linux')")
|
||||
p.add_argument("--verbose", "-v", action='count', default=0,
|
||||
help="More verbose log output")
|
||||
p.add_argument("output", metavar="DIR", default=None, nargs='?',
|
||||
help="Where to create the build root")
|
||||
|
||||
args = p.parse_args()
|
||||
|
||||
output = args.output or f"build.{args.arch}"
|
||||
try:
|
||||
generate(args.output, args.config, args.manifest)
|
||||
generate(output, args.conf, args.arch, args.manifest)
|
||||
|
||||
except BonnibelError as be:
|
||||
import sys
|
||||
|
||||
@@ -1,29 +1,38 @@
|
||||
---
|
||||
- name: linear
|
||||
desc: Linearly-mapped physical memory
|
||||
size: 64T
|
||||
shared: true
|
||||
|
||||
- name: bitmap
|
||||
desc: Used/free page tracking bitmap
|
||||
size: 1T
|
||||
shared: true
|
||||
|
||||
- name: heapmap
|
||||
desc: Kernel heap accounting structures
|
||||
size: 32G
|
||||
|
||||
- name: heap
|
||||
desc: Kernel heap
|
||||
size: 32G
|
||||
|
||||
- name: capsmap
|
||||
desc: Capabilities accounting structures
|
||||
size: 32G
|
||||
|
||||
- name: caps
|
||||
desc: Capabilities
|
||||
size: 32G
|
||||
|
||||
- name: stacks
|
||||
desc: Kernel thread stacks
|
||||
size: 64G
|
||||
|
||||
- name: buffers
|
||||
desc: Kernel buffers
|
||||
size: 64G
|
||||
|
||||
- name: logs
|
||||
desc: Kernel logs circular buffer
|
||||
size: 2G
|
||||
|
||||
@@ -12,7 +12,9 @@ object process : object {
|
||||
]
|
||||
|
||||
# Create a new empty process
|
||||
method create [constructor]
|
||||
method create [constructor] {
|
||||
param name string
|
||||
}
|
||||
|
||||
# Stop all threads and exit the given process
|
||||
method kill [destructor cap:kill]
|
||||
|
||||
@@ -19,4 +19,5 @@ help:
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
PYTHONPATH=$(ROOTDIR)/scripts cog -r -D definitions_path=$(ROOTDIR)/definitions -c syscall_interface.rst
|
||||
PYTHONPATH=$(ROOTDIR)/scripts cog -r -D definitions_path=$(ROOTDIR)/definitions -c kernel_memory.rst
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
@@ -71,6 +71,8 @@ The jsix kernel is quite far along now, but the userland systems are still lacki
|
||||
:caption: Site Contents:
|
||||
|
||||
syscall_interface
|
||||
kernel_memory
|
||||
process_initialization
|
||||
|
||||
|
||||
* :ref:`genindex`
|
||||
|
||||
178
docs/kernel_memory.rst
Normal file
178
docs/kernel_memory.rst
Normal file
@@ -0,0 +1,178 @@
|
||||
.. jsix syscall interface.
|
||||
.. Automatically updated from the definition files using cog!
|
||||
|
||||
.. [[[cog code generation
|
||||
.. from os.path import join
|
||||
.. from memory import Layout, unit
|
||||
..
|
||||
.. layout = Layout(join(definitions_path, "memory_layout.yaml"))
|
||||
.. l = max([len(r.name) for r in layout.regions])
|
||||
.. ]]]
|
||||
.. [[[end]]] (checksum: d41d8cd98f00b204e9800998ecf8427e)
|
||||
|
||||
Kernel memory
|
||||
=============
|
||||
|
||||
While jsix probably should eventually use KASLR to randomize its memory layout,
|
||||
currently the layout is mostly fixed. (Kernel code locations are not consistent
|
||||
but aren't explicitly randomized.)
|
||||
|
||||
.. [[[cog code generation
|
||||
.. line_size = 128 * 1024**3 # Each line represents up to 32 GiB
|
||||
.. max_lines = 32
|
||||
.. totals = sum([r.size for r in layout.regions])
|
||||
.. remain = unit((128 * 1024**4) - totals)
|
||||
..
|
||||
.. def split(val):
|
||||
.. return f"0x {val >> 48:04x} {(val >> 32) & 0xffff:04x} {(val >> 16) & 0xffff:04x} {val & 0xffff:04x}"
|
||||
..
|
||||
.. cog.outl()
|
||||
.. cog.outl(f"+-+-----------------------------+----------+---------------------------------------+")
|
||||
.. cog.outl(f"| | Address | Size | Use |")
|
||||
.. cog.outl(f"+=+=============================+==========+=======================================+")
|
||||
..
|
||||
.. for region in layout.regions:
|
||||
.. cog.outl(f"| | ``{split(region.start)}`` | {unit(region.size):>8} | {region.desc:37} |")
|
||||
.. lines = min(max_lines, region.size // line_size)
|
||||
.. for i in range(1, lines):
|
||||
.. cog.outl(f"+-+ | | |")
|
||||
.. cog.outl(f"| | | | |")
|
||||
.. cog.outl(f"+-+-----------------------------+----------+---------------------------------------+")
|
||||
..
|
||||
.. cog.outl(f"| | ... | | |")
|
||||
.. cog.outl(f"+-+-----------------------------+----------+---------------------------------------+")
|
||||
.. cog.outl(f"| | ``0x ffff 0000 0000 0000`` | | Kernel code / headers |")
|
||||
.. cog.outl(f"+-+-----------------------------+----------+---------------------------------------+")
|
||||
.. cog.outl("")
|
||||
.. cog.outl("")
|
||||
.. cog.outl(f"Un-reserved virtual memory address space in the higher half: {remain}")
|
||||
.. cog.outl("")
|
||||
..
|
||||
.. ]]]
|
||||
|
||||
+-+-----------------------------+----------+---------------------------------------+
|
||||
| | Address | Size | Use |
|
||||
+=+=============================+==========+=======================================+
|
||||
| | ``0x ffff c000 0000 0000`` | 64 TiB | Linearly-mapped physical memory |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+-----------------------------+----------+---------------------------------------+
|
||||
| | ``0x ffff bf00 0000 0000`` | 1 TiB | Used/free page tracking bitmap |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+-----------------------------+----------+---------------------------------------+
|
||||
| | ``0x ffff be00 0000 0000`` | 1 TiB | Per-page state tracking structures |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+ | | |
|
||||
| | | | |
|
||||
+-+-----------------------------+----------+---------------------------------------+
|
||||
| | ``0x ffff bdf8 0000 0000`` | 32 GiB | Kernel heap accounting structures |
|
||||
+-+-----------------------------+----------+---------------------------------------+
|
||||
| | ``0x ffff bdf0 0000 0000`` | 32 GiB | Kernel heap |
|
||||
+-+-----------------------------+----------+---------------------------------------+
|
||||
| | ``0x ffff bde8 0000 0000`` | 32 GiB | Capabilities accounting structures |
|
||||
+-+-----------------------------+----------+---------------------------------------+
|
||||
| | ``0x ffff bde0 0000 0000`` | 32 GiB | Capabilities |
|
||||
+-+-----------------------------+----------+---------------------------------------+
|
||||
| | ``0x ffff bdd0 0000 0000`` | 64 GiB | Kernel thread stacks |
|
||||
+-+-----------------------------+----------+---------------------------------------+
|
||||
| | ``0x ffff bdc0 0000 0000`` | 64 GiB | Kernel buffers |
|
||||
+-+-----------------------------+----------+---------------------------------------+
|
||||
| | ``0x ffff bdbf 8000 0000`` | 2 GiB | Kernel logs circular buffer |
|
||||
+-+-----------------------------+----------+---------------------------------------+
|
||||
| | ... | | |
|
||||
+-+-----------------------------+----------+---------------------------------------+
|
||||
| | ``0x ffff 0000 0000 0000`` | | Kernel code / headers |
|
||||
+-+-----------------------------+----------+---------------------------------------+
|
||||
|
||||
|
||||
Un-reserved virtual memory address space in the higher half: 61 TiB
|
||||
|
||||
.. [[[end]]] (checksum: 8c336cc8151beba1a79c8d3b653f1109)
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`search`
|
||||
|
||||
42
docs/process_initialization.rst
Normal file
42
docs/process_initialization.rst
Normal file
@@ -0,0 +1,42 @@
|
||||
.. jsix process initialization in userspace
|
||||
|
||||
Process Initialization
|
||||
======================
|
||||
|
||||
jsix follows the `System V ABI`_ on the ``amd64`` architecture. All arguments
|
||||
needed for program initialization are passed to the program's initial thread on
|
||||
the stack.
|
||||
|
||||
Note that jsix adds a number of additional auxiliary vector entry types for
|
||||
passing jsix-specific data to a program. The jsix-specific auxiliary vector type
|
||||
codes (what the ABI document refers to as ``a_type``) start from ``0xf000``. See
|
||||
the header file ``<j6/init.h>`` for more detail.
|
||||
|
||||
.. _System V ABI: https://gitlab.com/x86-psABIs/x86-64-ABI
|
||||
|
||||
The initial stack frame
|
||||
-----------------------
|
||||
|
||||
============== ==================== ============ =======
|
||||
Address Value Bytes Notes
|
||||
============== ==================== ============ =======
|
||||
``top`` Stack top (out of stack bounds)
|
||||
``top`` - 16 0 16 Stack sentinel
|
||||
\ ``envp`` string data ?
|
||||
\ ``argv`` string data ?
|
||||
\ ... ? Possible padding
|
||||
\ 0, 0 (``AT_NULL``) 16 Aux vector sentinel
|
||||
\ Aux vectors 16 * `m` ``AT_NULL``-terminated array of Aux vectors
|
||||
\ 0 8 Environment sentinel
|
||||
\ ``envp`` 8 * `n` 0-terminated array of environment
|
||||
string pointers
|
||||
\ 0 8 Args sentinel
|
||||
\ ``argv`` 8 * ``argc`` Pointers to argument strings
|
||||
``rsp`` ``argc`` 8 Number of elements in argv
|
||||
============== ==================== ============ =======
|
||||
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`search`
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.. jsix syscall interface.
|
||||
.. Automatically update from the definition files using cog!
|
||||
.. Automatically updated from the definition files using cog!
|
||||
|
||||
.. [[[cog code generation
|
||||
.. from textwrap import indent
|
||||
@@ -14,11 +14,11 @@
|
||||
.. ]]]
|
||||
.. [[[end]]] (checksum: d41d8cd98f00b204e9800998ecf8427e)
|
||||
|
||||
The jsix syscall interface
|
||||
==========================
|
||||
Syscall interface
|
||||
=================
|
||||
|
||||
The jsix kernel's syscall design is based around object handles. Object handles
|
||||
are also a collections capabilities, encoding certain rights over the object
|
||||
are also a collection of capabilities, encoding certain rights over the object
|
||||
they reference.
|
||||
|
||||
Very few syscalls in jsix can be made without some handle, and most of them are
|
||||
@@ -133,7 +133,7 @@ as shared memory channels, but more flexible.
|
||||
|
||||
:param self: Handle to the mailbox object
|
||||
|
||||
.. cpp:function:: j6_result_t j6_mailbox_call (j6_handle_t self, uint64_t * tag, void * data, size_t * data_len, size_t data_in_len, j6_handle_t * handles, size_t * handles_count)
|
||||
.. cpp:function:: j6_result_t j6_mailbox_call (j6_handle_t self, uint64_t * tag, void * data, size_t * data_len, size_t data_size, j6_handle_t * handles, size_t * handles_count, size_t handles_size)
|
||||
|
||||
Send a message to the reciever, and block until a response is
|
||||
sent. Note that getting this response does not require the
|
||||
@@ -144,10 +144,11 @@ as shared memory channels, but more flexible.
|
||||
:param self: Handle to the mailbox object
|
||||
:param tag: *[inout]* Undocumented
|
||||
:param data: *[optional, inout]* Undocumented
|
||||
:param data_in_len: number of bytes in data used for input
|
||||
:param data_size: number of total bytes in data buffer
|
||||
:param handles: *[optional, inout, handle, list]* Undocumented
|
||||
:param handles_size: total size of handles buffer
|
||||
|
||||
.. cpp:function:: j6_result_t j6_mailbox_respond (j6_handle_t self, uint64_t * tag, void * data, size_t * data_len, size_t data_in_len, j6_handle_t * handles, size_t * handles_count, uint64_t * reply_tag, uint64_t flags)
|
||||
.. cpp:function:: j6_result_t j6_mailbox_respond (j6_handle_t self, uint64_t * tag, void * data, size_t * data_len, size_t data_size, j6_handle_t * handles, size_t * handles_count, size_t handles_size, uint64_t * reply_tag, uint64_t flags)
|
||||
|
||||
Respond to a message sent using call, and wait for another
|
||||
message to arrive. Note that this does not require the send
|
||||
@@ -159,8 +160,9 @@ as shared memory channels, but more flexible.
|
||||
:param self: Handle to the mailbox object
|
||||
:param tag: *[inout]* Undocumented
|
||||
:param data: *[optional, inout]* Undocumented
|
||||
:param data_in_len: number of bytes in data used for input
|
||||
:param data_size: number of total bytes in data buffer
|
||||
:param handles: *[optional, inout, handle, list]* Undocumented
|
||||
:param handles_size: total size of handles buffer
|
||||
:param reply_tag: *[inout]* Undocumented
|
||||
:param flags: Undocumented
|
||||
|
||||
@@ -185,7 +187,7 @@ control over the threads, handles, and virtual memory space of that process.
|
||||
|
||||
:param self: Handle to the process object
|
||||
|
||||
.. cpp:function:: j6_result_t j6_process_exit (int32_t result)
|
||||
.. cpp:function:: j6_result_t j6_process_exit (int64_t result)
|
||||
|
||||
Stop all threads and exit the current process
|
||||
|
||||
@@ -353,7 +355,7 @@ necessarily mean that it is mapped into that process' virtual memory space.
|
||||
:param self: Handle to the vma object
|
||||
:param size: *[inout]* New size for the VMA, or 0 to query the current size without changing
|
||||
|
||||
.. [[[end]]] (checksum: fe448e541c009a1bcf8bdc44f4760e32)
|
||||
.. [[[end]]] (checksum: cb17f54e443d1d3b85995870f3e8dbf2)
|
||||
|
||||
Non-object syscalls
|
||||
-------------------
|
||||
@@ -411,6 +413,12 @@ either do not require an object handle, or operate generically on handles.
|
||||
:param clone: *[out]* The new handle
|
||||
:param mask: The capability bitmask
|
||||
|
||||
.. cpp:function:: j6_result_t j6_handle_close (j6_handle_t hnd)
|
||||
|
||||
Close the handle to an object
|
||||
|
||||
:param hnd: *[handle]* The handle to close
|
||||
|
||||
.. cpp:function:: j6_result_t j6_futex_wait (const uint32_t * address, uint32_t current, uint64_t timeout)
|
||||
|
||||
Block waiting on a futex
|
||||
@@ -432,5 +440,5 @@ either do not require an object handle, or operate generically on handles.
|
||||
|
||||
:param exit_code: Undocumented
|
||||
|
||||
.. [[[end]]] (checksum: b8b12e99a4a00c99b3859f05000a7bfd)
|
||||
.. [[[end]]] (checksum: 0b9d051972abcbb6de408f411331785f)
|
||||
|
||||
|
||||
8
qemu.sh
8
qemu.sh
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
root=$(dirname $0)
|
||||
build="${root}/build"
|
||||
build="${root}/build.amd64"
|
||||
assets="${root}/assets"
|
||||
|
||||
no_build=""
|
||||
@@ -41,7 +41,7 @@ while true; do
|
||||
-r | --remote)
|
||||
shift
|
||||
vnchost="${1:-${VNCHOST:-"localhost:5500"}}"
|
||||
gfx="-vnc ${vnchost},reverse"
|
||||
gfx="-vnc ${vnchost},reverse=on"
|
||||
vga=""
|
||||
shift
|
||||
;;
|
||||
@@ -117,13 +117,13 @@ if [[ -n $TMUX ]]; then
|
||||
tmux split-window -h -l $log_width "$debugcon_cmd"
|
||||
tmux last-pane
|
||||
fi
|
||||
tmux split-window -l 10 "sleep 1; telnet localhost 45454"
|
||||
tmux split-window -l 10 "sleep 1; nc localhost 45454"
|
||||
fi
|
||||
elif [[ $DESKTOP_SESSION = "i3" ]]; then
|
||||
if [[ -n $debug ]]; then
|
||||
i3-msg exec i3-sensible-terminal -- -e "gdb ${debugtarget}" &
|
||||
else
|
||||
i3-msg exec i3-sensible-terminal -- -e 'telnet localhost 45454' &
|
||||
i3-msg exec i3-sensible-terminal -- -e 'nc localhost 45454' &
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -43,10 +43,10 @@ def _make_ninja_config(outfile, config, files):
|
||||
build.variable(k, v)
|
||||
|
||||
|
||||
def generate_configs(root, output, config, targets, kinds):
|
||||
def generate_configs(root, output, buildconfig, arch, targets, kinds):
|
||||
|
||||
assets = root / "assets" / "build"
|
||||
base = ["global.yaml", f"config.{config}.yaml"]
|
||||
assets = root / "assets" / "build" / arch
|
||||
base = ["global.yaml", f"config.{buildconfig}.yaml"]
|
||||
|
||||
depfiles = set()
|
||||
|
||||
@@ -65,4 +65,4 @@ def generate_configs(root, output, config, targets, kinds):
|
||||
outfile = output / target / f"config.{kind}.ninja"
|
||||
_make_ninja_config(outfile, config, files)
|
||||
|
||||
return depfiles
|
||||
return depfiles
|
||||
|
||||
@@ -37,9 +37,15 @@ class Manifest:
|
||||
self.drivers = [self.__build_entry(modules, i)
|
||||
for i in config.get("drivers", tuple())]
|
||||
|
||||
libs = set(config.get("libs", tuple()))
|
||||
libs.update(self.__libdeps([modules[e.module] for e in self.services]))
|
||||
libs.update(self.__libdeps([modules[e.module] for e in self.drivers]))
|
||||
def get_libdeps(names):
|
||||
libmods = modules.get_mods(names)
|
||||
deps = modules.all_deps(libmods, stop_at_static=True)
|
||||
deps = [m.name for m in deps if m.kind == "lib"]
|
||||
return deps
|
||||
|
||||
libs = set(get_libdeps(config.get("libs", tuple())))
|
||||
libs.update(get_libdeps([e.module for e in self.services]))
|
||||
libs.update(get_libdeps([e.module for e in self.drivers]))
|
||||
|
||||
self.libs = [self.__build_entry(modules, i)
|
||||
for i in libs]
|
||||
@@ -80,13 +86,6 @@ class Manifest:
|
||||
|
||||
return Manifest.Entry(name, target, mod.get_output(), flags)
|
||||
|
||||
def __libdeps(self, modules):
|
||||
deps = set([m.name for m in modules if m.kind == "lib"])
|
||||
for m in modules:
|
||||
if m.static: continue
|
||||
deps.update(self.__libdeps(m.depmods))
|
||||
return deps
|
||||
|
||||
def add_data(self, output, desc, flags=tuple()):
|
||||
e = Manifest.Entry(None, None, output, flags)
|
||||
self.data.append(e)
|
||||
|
||||
@@ -39,7 +39,7 @@ class Module:
|
||||
"kind": (str, "exe"),
|
||||
"outfile": (str, None),
|
||||
"basename": (str, None),
|
||||
"targets": (set, ()),
|
||||
"target": (str, None),
|
||||
"deps": (set, ()),
|
||||
"public_headers": (set, ()),
|
||||
"copy_headers": (bool, False),
|
||||
@@ -53,6 +53,8 @@ class Module:
|
||||
"no_libc": (bool, False),
|
||||
"ld_script": (str, None),
|
||||
"static": (bool, False),
|
||||
"arch_source": (dict, ()),
|
||||
"skip_arches": (tuple, ()),
|
||||
}
|
||||
|
||||
def __init__(self, name, modfile, root, **kwargs):
|
||||
@@ -81,15 +83,14 @@ class Module:
|
||||
|
||||
# Turn strings into real Source objects
|
||||
self.sources = [make_source(root, f) for f in self.sources]
|
||||
for arch in self.arch_source:
|
||||
self.arch_source[arch] = [make_source(root, f) for f in self.arch_source[arch]]
|
||||
|
||||
header_source = lambda f: make_source(root, Path("include") / f)
|
||||
if self.copy_headers:
|
||||
header_source = lambda f: make_copy_source(root, f, "include")
|
||||
self.public_headers = [header_source(f) for f in self.public_headers]
|
||||
|
||||
# Filled by Module.update
|
||||
self.depmods = set()
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Module {self.kind} {self.name}>"
|
||||
|
||||
@@ -115,227 +116,6 @@ class Module:
|
||||
ext = dict(exe=".elf", driver=".drv", lib=(static and ".a" or ".so"))
|
||||
return self.basename + ext.get(self.kind, "")
|
||||
|
||||
@classmethod
|
||||
def update(cls, mods):
|
||||
from . import BonnibelError
|
||||
|
||||
def resolve(source, modlist):
|
||||
resolved = set()
|
||||
for dep in modlist:
|
||||
if not dep in mods:
|
||||
raise BonnibelError(f"module '{source.name}' references unknown module '{dep}'")
|
||||
mod = mods[dep]
|
||||
resolved.add(mod)
|
||||
return resolved
|
||||
|
||||
for mod in mods.values():
|
||||
mod.depmods = resolve(mod, mod.deps)
|
||||
|
||||
target_mods = [mod for mod in mods.values() if mod.targets]
|
||||
for mod in target_mods:
|
||||
closed = set()
|
||||
children = set(mod.depmods)
|
||||
while children:
|
||||
child = children.pop()
|
||||
closed.add(child)
|
||||
child.targets |= mod.targets
|
||||
children |= {m for m in child.depmods if not m in closed}
|
||||
|
||||
def generate(self, output):
|
||||
from pathlib import Path
|
||||
from collections import defaultdict
|
||||
from ninja.ninja_syntax import Writer
|
||||
|
||||
def walk_deps(deps, static, results):
|
||||
for mod in deps:
|
||||
if static or mod.name not in results:
|
||||
results[mod.name] = (mod, static)
|
||||
walk_deps(mod.depmods, static or mod.static, results)
|
||||
|
||||
all_deps = {}
|
||||
walk_deps(self.depmods, self.static, all_deps)
|
||||
all_deps = all_deps.values()
|
||||
|
||||
def gather_phony(build, deps, child_rel):
|
||||
phony = ".headers.phony"
|
||||
child_phony = [child_rel(phony, module=c.name)
|
||||
for c, _ in all_deps]
|
||||
|
||||
build.build(
|
||||
rule = "touch",
|
||||
outputs = [mod_rel(phony)],
|
||||
implicit = child_phony,
|
||||
order_only = list(map(mod_rel, deps)),
|
||||
)
|
||||
|
||||
filename = str(output / f"module.{self.name}.ninja")
|
||||
with open(filename, "w") as buildfile:
|
||||
build = Writer(buildfile)
|
||||
|
||||
build.comment("This file is automatically generated by bonnibel")
|
||||
build.newline()
|
||||
|
||||
build.variable("module_dir", target_rel(self.name + ".dir"))
|
||||
build.variable("module_kind", self.kind)
|
||||
build.newline()
|
||||
|
||||
build.include(f"${{target_dir}}/config.{self.kind}.ninja")
|
||||
build.newline()
|
||||
|
||||
modopts = BuildOptions(
|
||||
local = [self.root, "${module_dir}"],
|
||||
ld_script = self.ld_script and self.root / self.ld_script,
|
||||
)
|
||||
if self.public_headers:
|
||||
modopts.includes += [
|
||||
self.root / "include",
|
||||
f"${{target_dir}}/{self.name}.dir/include",
|
||||
]
|
||||
|
||||
for key, value in self.variables.items():
|
||||
build.variable(key, value)
|
||||
build.newline()
|
||||
|
||||
for include in self.includes:
|
||||
p = Path(include)
|
||||
if p.is_absolute():
|
||||
if not p in modopts.includes:
|
||||
modopts.includes.append(str(p.resolve()))
|
||||
elif include != ".":
|
||||
incpath = self.root / p
|
||||
destpath = mod_rel(p)
|
||||
for header in incpath.rglob("*.h"):
|
||||
dest_header = f"{destpath}/" + str(header.relative_to(incpath))
|
||||
modopts.includes.append(str(incpath))
|
||||
modopts.includes.append(destpath)
|
||||
|
||||
for dep, static in all_deps:
|
||||
if dep.public_headers:
|
||||
if dep.include_phase == "normal":
|
||||
modopts.includes += [dep.root / "include", f"${{target_dir}}/{dep.name}.dir/include"]
|
||||
elif dep.include_phase == "late":
|
||||
modopts.late += [dep.root / "include", f"${{target_dir}}/{dep.name}.dir/include"]
|
||||
else:
|
||||
from . import BonnibelError
|
||||
raise BonnibelError(f"Module {dep.name} has invalid include_phase={dep.include_phase}")
|
||||
|
||||
if dep.kind == "headers":
|
||||
continue
|
||||
elif dep.kind == "lib":
|
||||
modopts.libs.append((target_rel(dep.get_output(static)), static))
|
||||
else:
|
||||
modopts.order_only.append(target_rel(dep.get_output(static)))
|
||||
|
||||
cc_includes = []
|
||||
if modopts.local:
|
||||
cc_includes += [f"-iquote{i}" for i in modopts.local]
|
||||
|
||||
if modopts.includes:
|
||||
cc_includes += [f"-I{i}" for i in modopts.includes]
|
||||
|
||||
if modopts.late:
|
||||
cc_includes += [f"-idirafter{i}" for i in modopts.late]
|
||||
|
||||
if cc_includes:
|
||||
build.variable("ccflags", ["${ccflags}"] + cc_includes)
|
||||
|
||||
as_includes = [f"-I{d}" for d in modopts.local + modopts.includes + modopts.late]
|
||||
if as_includes:
|
||||
build.variable("asflags", ["${asflags}"] + as_includes)
|
||||
|
||||
if modopts.libs:
|
||||
build.variable("libs", ["-L${target_dir}", "${libs}"] + modopts.linker_args)
|
||||
|
||||
if modopts.ld_script:
|
||||
build.variable("ldflags", ["${ldflags}"] + ["-T", modopts.ld_script])
|
||||
|
||||
header_deps = []
|
||||
inputs = []
|
||||
headers = set(self.public_headers)
|
||||
while headers:
|
||||
source = headers.pop()
|
||||
headers.update(source.next)
|
||||
|
||||
if source.action:
|
||||
build.newline()
|
||||
build.build(rule=source.action, **source.args)
|
||||
|
||||
if source.gather:
|
||||
header_deps += list(source.outputs)
|
||||
|
||||
if source.input:
|
||||
inputs.extend(map(mod_rel, source.outputs))
|
||||
|
||||
build.newline()
|
||||
|
||||
inputs = []
|
||||
sources = set(self.sources)
|
||||
while sources:
|
||||
source = sources.pop()
|
||||
sources.update(source.next)
|
||||
|
||||
if source.action:
|
||||
build.newline()
|
||||
build.build(rule=source.action, **source.args)
|
||||
|
||||
if source.gather:
|
||||
header_deps += list(source.outputs)
|
||||
|
||||
if source.input:
|
||||
inputs.extend(map(mod_rel, source.outputs))
|
||||
|
||||
gather_phony(build, header_deps, target_rel)
|
||||
|
||||
if self.kind == "headers":
|
||||
# Header-only, don't output a build rule
|
||||
return
|
||||
|
||||
output = target_rel(self.get_output())
|
||||
build.newline()
|
||||
build.build(
|
||||
rule = self.kind,
|
||||
outputs = output,
|
||||
inputs = inputs,
|
||||
implicit = modopts.implicit,
|
||||
order_only = modopts.order_only,
|
||||
variables = {"name": self.name,
|
||||
"soname": self.get_output()},
|
||||
)
|
||||
|
||||
dump = output + ".dump"
|
||||
build.newline()
|
||||
build.build(
|
||||
rule = "dump",
|
||||
outputs = dump,
|
||||
inputs = output,
|
||||
variables = {"name": self.name},
|
||||
)
|
||||
|
||||
s_output = target_rel(self.get_output(static=True))
|
||||
if s_output != output:
|
||||
build.newline()
|
||||
build.build(
|
||||
rule = self.kind + "_static",
|
||||
outputs = s_output,
|
||||
inputs = inputs,
|
||||
order_only = modopts.order_only,
|
||||
variables = {"name": self.name},
|
||||
)
|
||||
|
||||
dump = s_output + ".dump"
|
||||
build.newline()
|
||||
build.build(
|
||||
rule = "dump",
|
||||
outputs = dump,
|
||||
inputs = s_output,
|
||||
variables = {"name": self.name},
|
||||
)
|
||||
|
||||
if self.default:
|
||||
build.newline()
|
||||
build.default(output)
|
||||
build.default(dump)
|
||||
|
||||
def add_input(self, path, **kwargs):
|
||||
from .source import make_source
|
||||
s = make_source(self.root, path, **kwargs)
|
||||
@@ -350,3 +130,285 @@ class Module:
|
||||
for source in self.public_headers:
|
||||
if source.path in paths:
|
||||
source.add_deps(deps)
|
||||
|
||||
|
||||
class ModuleList:
|
||||
def __init__(self, arch):
|
||||
self.__arch = arch
|
||||
self.__mods = {}
|
||||
self.__used = {}
|
||||
self.__targets = frozenset()
|
||||
self.__kinds = frozenset()
|
||||
|
||||
def __getitem__(self, name):
|
||||
return self.__mods.get(name)
|
||||
|
||||
def __contains__(self, name):
|
||||
"""Return if the module name is known."""
|
||||
return name in self.__mods
|
||||
|
||||
def __iter__(self):
|
||||
"""Iterate over _non-skipped_ modules."""
|
||||
return self.used.__iter__()
|
||||
|
||||
def __skip(self, mod):
|
||||
if self.__arch in mod.skip_arches: return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def used(self):
|
||||
if self.__used is None:
|
||||
self.__used = {n:m for n,m in self.__mods.items() if not self.__skip(m)}
|
||||
return self.__used
|
||||
|
||||
@property
|
||||
def targets(self):
|
||||
if self.__targets is None:
|
||||
self.__targets = frozenset([m.target for m in self.used.values() if m.target])
|
||||
return self.__targets
|
||||
|
||||
@property
|
||||
def kinds(self):
|
||||
if self.__kinds is None:
|
||||
self.__kinds = frozenset([m.kind for m in self.used.values()])
|
||||
return self.__kinds
|
||||
|
||||
def get(self, name):
|
||||
return self.__mods.get(name)
|
||||
|
||||
def add(self, mod):
|
||||
if mod.name in self.__mods:
|
||||
raise BonnibelError(f"re-adding module '{mod.name}' to this ModuleList")
|
||||
self.__mods[mod.name] = mod
|
||||
self.__used = None
|
||||
self.__targets = None
|
||||
self.__kinds = None
|
||||
|
||||
def get_mods(self, names, filt=None):
|
||||
return {self[n] for n in names
|
||||
if n in self.used
|
||||
and ((not filt) or filt(self[n]))}
|
||||
|
||||
def all_deps(self, mods, stop_at_static=False):
|
||||
search = set(mods)
|
||||
closed = list()
|
||||
|
||||
while search:
|
||||
mod = search.pop()
|
||||
if mod in closed: continue
|
||||
closed.append(mod)
|
||||
|
||||
if stop_at_static and mod.static:
|
||||
continue
|
||||
|
||||
for dep in mod.deps:
|
||||
if not dep in self.__mods:
|
||||
raise BonnibelError(f"module '{mod.name}' references unknown module '{dep}'")
|
||||
if dep in self.used:
|
||||
search.add(self.used[dep])
|
||||
|
||||
return closed
|
||||
|
||||
def target_mods(self, target):
|
||||
return self.all_deps([m for m in self.used.values() if m.target == target])
|
||||
|
||||
def generate(self, output):
|
||||
from pathlib import Path
|
||||
from collections import defaultdict
|
||||
from ninja.ninja_syntax import Writer
|
||||
|
||||
def walk_deps(deps, static, results):
|
||||
for modname in deps:
|
||||
mod = self.used.get(modname)
|
||||
if not mod: continue # skipped
|
||||
if static or modname not in results:
|
||||
results[modname] = (mod, static)
|
||||
walk_deps(mod.deps, static or mod.static, results)
|
||||
|
||||
for mod in self.used.values():
|
||||
all_deps = {}
|
||||
walk_deps(mod.deps, mod.static, all_deps)
|
||||
all_deps = all_deps.values()
|
||||
|
||||
def gather_phony(build, deps, child_rel):
|
||||
phony = ".headers.phony"
|
||||
child_phony = [child_rel(phony, module=c.name)
|
||||
for c, _ in all_deps]
|
||||
|
||||
build.build(
|
||||
rule = "touch",
|
||||
outputs = [mod_rel(phony)],
|
||||
implicit = child_phony,
|
||||
order_only = list(map(mod_rel, deps)),
|
||||
)
|
||||
|
||||
filename = str(output / f"module.{mod.name}.ninja")
|
||||
with open(filename, "w") as buildfile:
|
||||
build = Writer(buildfile)
|
||||
|
||||
build.comment("This file is automatically generated by bonnibel")
|
||||
build.newline()
|
||||
|
||||
build.variable("module_dir", target_rel(mod.name + ".dir"))
|
||||
build.variable("module_kind", mod.kind)
|
||||
build.newline()
|
||||
|
||||
build.include(f"${{target_dir}}/config.{mod.kind}.ninja")
|
||||
build.newline()
|
||||
|
||||
modopts = BuildOptions(
|
||||
local = [mod.root, "${module_dir}"],
|
||||
ld_script = mod.ld_script and mod.root / mod.ld_script,
|
||||
)
|
||||
if mod.public_headers:
|
||||
modopts.includes += [
|
||||
mod.root / "include",
|
||||
f"${{target_dir}}/{mod.name}.dir/include",
|
||||
]
|
||||
|
||||
for key, value in mod.variables.items():
|
||||
build.variable(key, value)
|
||||
build.newline()
|
||||
|
||||
for include in mod.includes:
|
||||
p = Path(include)
|
||||
if p.is_absolute():
|
||||
if not p in modopts.includes:
|
||||
modopts.includes.append(str(p.resolve()))
|
||||
elif include != ".":
|
||||
incpath = mod.root / p
|
||||
destpath = mod_rel(p)
|
||||
for header in incpath.rglob("*.h"):
|
||||
dest_header = f"{destpath}/" + str(header.relative_to(incpath))
|
||||
modopts.includes.append(str(incpath))
|
||||
modopts.includes.append(destpath)
|
||||
|
||||
for dep, static in all_deps:
|
||||
if dep.public_headers:
|
||||
if dep.include_phase == "normal":
|
||||
modopts.includes += [dep.root / "include", f"${{target_dir}}/{dep.name}.dir/include"]
|
||||
elif dep.include_phase == "late":
|
||||
modopts.late += [dep.root / "include", f"${{target_dir}}/{dep.name}.dir/include"]
|
||||
else:
|
||||
from . import BonnibelError
|
||||
raise BonnibelError(f"Module {dep.name} has invalid include_phase={dep.include_phase}")
|
||||
|
||||
if dep.kind == "headers":
|
||||
continue
|
||||
elif dep.kind == "lib":
|
||||
modopts.libs.append((target_rel(dep.get_output(static)), static))
|
||||
else:
|
||||
modopts.order_only.append(target_rel(dep.get_output(static)))
|
||||
|
||||
cc_includes = []
|
||||
if modopts.local:
|
||||
cc_includes += [f"-iquote{i}" for i in modopts.local]
|
||||
|
||||
if modopts.includes:
|
||||
cc_includes += [f"-I{i}" for i in modopts.includes]
|
||||
|
||||
if modopts.late:
|
||||
cc_includes += [f"-idirafter{i}" for i in modopts.late]
|
||||
|
||||
if cc_includes:
|
||||
build.variable("ccflags", ["${ccflags}"] + cc_includes)
|
||||
|
||||
as_includes = [f"-I{d}" for d in modopts.local + modopts.includes + modopts.late]
|
||||
if as_includes:
|
||||
build.variable("asflags", ["${asflags}"] + as_includes)
|
||||
|
||||
if modopts.libs:
|
||||
build.variable("libs", ["-L${target_dir}", "${libs}"] + modopts.linker_args)
|
||||
|
||||
if modopts.ld_script:
|
||||
build.variable("ldflags", ["${ldflags}"] + ["-T", modopts.ld_script])
|
||||
|
||||
header_deps = []
|
||||
inputs = []
|
||||
headers = set(mod.public_headers)
|
||||
while headers:
|
||||
source = headers.pop()
|
||||
headers.update(source.next)
|
||||
|
||||
if source.action:
|
||||
build.newline()
|
||||
build.build(rule=source.action, **source.args)
|
||||
|
||||
if source.gather:
|
||||
header_deps += list(source.outputs)
|
||||
|
||||
if source.input:
|
||||
inputs.extend(map(mod_rel, source.outputs))
|
||||
|
||||
build.newline()
|
||||
|
||||
inputs = []
|
||||
sources = set(mod.sources)
|
||||
sources.update(set(mod.arch_source.get(self.__arch, tuple())))
|
||||
while sources:
|
||||
source = sources.pop()
|
||||
sources.update(source.next)
|
||||
|
||||
if source.action:
|
||||
build.newline()
|
||||
build.build(rule=source.action, **source.args)
|
||||
|
||||
if source.gather:
|
||||
header_deps += list(source.outputs)
|
||||
|
||||
if source.input:
|
||||
inputs.extend(map(mod_rel, source.outputs))
|
||||
|
||||
gather_phony(build, header_deps, target_rel)
|
||||
|
||||
if mod.kind == "headers":
|
||||
# Header-only, don't output a build rule
|
||||
continue
|
||||
|
||||
mod_output = target_rel(mod.get_output())
|
||||
build.newline()
|
||||
build.build(
|
||||
rule = mod.kind,
|
||||
outputs = mod_output,
|
||||
inputs = inputs,
|
||||
implicit = modopts.implicit,
|
||||
order_only = modopts.order_only,
|
||||
variables = {"name": mod.name,
|
||||
"soname": mod.get_output()},
|
||||
)
|
||||
|
||||
dump = mod_output + ".dump"
|
||||
build.newline()
|
||||
build.build(
|
||||
rule = "dump",
|
||||
outputs = dump,
|
||||
inputs = mod_output,
|
||||
variables = {"name": mod.name},
|
||||
)
|
||||
|
||||
s_output = target_rel(mod.get_output(static=True))
|
||||
if s_output != mod_output:
|
||||
build.newline()
|
||||
build.build(
|
||||
rule = mod.kind + "_static",
|
||||
outputs = s_output,
|
||||
inputs = inputs,
|
||||
order_only = modopts.order_only,
|
||||
variables = {"name": mod.name},
|
||||
)
|
||||
|
||||
dump = s_output + ".dump"
|
||||
build.newline()
|
||||
build.build(
|
||||
rule = "dump",
|
||||
outputs = dump,
|
||||
inputs = s_output,
|
||||
variables = {"name": mod.name},
|
||||
)
|
||||
|
||||
if mod.default:
|
||||
build.newline()
|
||||
build.default(mod_output)
|
||||
build.default(dump)
|
||||
|
||||
|
||||
|
||||
@@ -10,22 +10,17 @@ class Project:
|
||||
def __str__(self):
|
||||
return f"{self.name} {self.version.major}.{self.version.minor}.{self.version.patch}-{self.version.sha}"
|
||||
|
||||
def generate(self, root, output, modules, config, manifest_file):
|
||||
def generate(self, root, output, modules, config, arch, manifest_file):
|
||||
import sys
|
||||
from os.path import join
|
||||
from ninja.ninja_syntax import Writer
|
||||
|
||||
targets = set()
|
||||
kinds = set()
|
||||
for mod in modules.values():
|
||||
targets.update(mod.targets)
|
||||
kinds.add(mod.kind)
|
||||
|
||||
from .config import generate_configs
|
||||
config_deps = generate_configs(root, output, config, targets, kinds)
|
||||
config_deps = generate_configs(root, output, config, arch, modules.targets, modules.kinds)
|
||||
|
||||
with open(output / "build.ninja", "w") as buildfile:
|
||||
build = Writer(buildfile)
|
||||
default_builds = []
|
||||
|
||||
build.comment("This file is automatically generated by bonnibel")
|
||||
build.variable("ninja_required_version", "1.3")
|
||||
@@ -34,7 +29,7 @@ class Project:
|
||||
build.variable("build_config", config)
|
||||
build.newline()
|
||||
|
||||
build.include(root / "assets/build/rules.ninja")
|
||||
build.include(root / "assets" / "build" / arch / "rules.ninja")
|
||||
build.newline()
|
||||
|
||||
build.variable("version_major", self.version.major)
|
||||
@@ -49,7 +44,7 @@ class Project:
|
||||
])
|
||||
build.newline()
|
||||
|
||||
for target in targets:
|
||||
for target in modules.targets:
|
||||
build.subninja(output / target / "target.ninja")
|
||||
build.newline()
|
||||
|
||||
@@ -57,7 +52,7 @@ class Project:
|
||||
rule = "touch",
|
||||
outputs = "${build_root}/.all_headers",
|
||||
implicit = [f"${{build_root}}/include/{m.name}/.headers.phony"
|
||||
for m in modules.values() if m.public_headers],
|
||||
for m in modules.used.values() if m.public_headers],
|
||||
)
|
||||
build.build(
|
||||
rule = "phony",
|
||||
@@ -78,56 +73,24 @@ class Project:
|
||||
initrdroot = output / "initrd_root"
|
||||
initrdroot.mkdir(exist_ok=True)
|
||||
|
||||
fatroot_content = []
|
||||
initrd_content = []
|
||||
image_content = {'initrd_root': [], 'fatroot': []}
|
||||
|
||||
def add_fatroot(source, name):
|
||||
output = join(manifest.location, name)
|
||||
fatroot_output = f"${{build_root}}/fatroot/{output}"
|
||||
def add_image_content(image, path, name):
|
||||
output = join(path, name)
|
||||
image_output = f"${{build_root}}/{image}/{output}"
|
||||
|
||||
build.build(
|
||||
rule = "cp",
|
||||
outputs = [fatroot_output],
|
||||
inputs = [source],
|
||||
variables = {
|
||||
"description": f"Installing {output}",
|
||||
})
|
||||
|
||||
fatroot_content.append(fatroot_output)
|
||||
build.newline()
|
||||
|
||||
def add_fatroot_exe(entry):
|
||||
input_path = f"${{build_root}}/{entry.target}/{entry.output}"
|
||||
intermediary = f"${{build_root}}/{entry.output}"
|
||||
|
||||
build.build(
|
||||
rule = "strip",
|
||||
outputs = [intermediary],
|
||||
inputs = [input_path],
|
||||
implicit = [f"{input_path}.dump"],
|
||||
variables = {
|
||||
"name": f"Stripping {entry.module}",
|
||||
"debug": f"${{build_root}}/.debug/{entry.output}.debug",
|
||||
})
|
||||
|
||||
add_fatroot(intermediary, entry.output)
|
||||
|
||||
def add_initrd_content(root, name):
|
||||
output = join(root, name)
|
||||
initrd_output = f"${{build_root}}/initrd_root/{output}"
|
||||
|
||||
build.build(
|
||||
rule = "cp",
|
||||
outputs = [initrd_output],
|
||||
outputs = [image_output],
|
||||
inputs = [f"${{build_root}}/{name}"],
|
||||
variables = {
|
||||
"description": f"Installing {name}",
|
||||
})
|
||||
|
||||
initrd_content.append(initrd_output)
|
||||
image_content[image].append(image_output)
|
||||
build.newline()
|
||||
|
||||
def add_initrd_stripped(root, entry):
|
||||
def add_image_content_exe(image, path, entry):
|
||||
input_path = f"${{build_root}}/{entry.target}/{entry.output}"
|
||||
intermediary = f"${{build_root}}/{entry.output}"
|
||||
|
||||
@@ -141,87 +104,108 @@ class Project:
|
||||
"debug": f"${{build_root}}/.debug/{entry.output}.debug",
|
||||
})
|
||||
|
||||
add_initrd_content(root, entry.output)
|
||||
build.build(
|
||||
rule = "phony",
|
||||
outputs = [entry.output],
|
||||
inputs = [intermediary])
|
||||
|
||||
add_image_content(image, path, entry.output)
|
||||
|
||||
if 'kernel' in modules.used:
|
||||
add_image_content_exe("fatroot", manifest.location, manifest.kernel)
|
||||
|
||||
syms = manifest.add_data("symbol_table.dat",
|
||||
"Symbol table", ("symbols",))
|
||||
|
||||
syms_file = "jsix.symbols"
|
||||
syms_path = join(manifest.location, syms_file );
|
||||
syms_out = join(fatroot, syms_path)
|
||||
build.build(
|
||||
rule = "makest",
|
||||
outputs = [syms_out],
|
||||
inputs = [f"${{build_root}}/kernel/{modules['kernel'].get_output(static=True)}"],
|
||||
)
|
||||
image_content['fatroot'].append(syms_out)
|
||||
manifest.symbols = syms_file
|
||||
|
||||
build.newline()
|
||||
default_builds.append("${build_root}/jsix.img")
|
||||
|
||||
def try_add_manifest_module(entry, section, image, path="jsix"):
|
||||
if entry.module in modules.used:
|
||||
add_image_content_exe(image, path, entry)
|
||||
elif entry.module not in modules:
|
||||
raise BonnibelError(f'unknown {section} module in manifest: {entry.module}')
|
||||
|
||||
try_add_manifest_module(manifest.init, "init", "fatroot")
|
||||
|
||||
add_fatroot_exe(manifest.kernel)
|
||||
add_fatroot_exe(manifest.init)
|
||||
for program in manifest.panics:
|
||||
add_fatroot_exe(program)
|
||||
try_add_manifest_module(program, "panic", "fatroot")
|
||||
|
||||
for program in manifest.services:
|
||||
add_initrd_stripped("jsix/services", program)
|
||||
try_add_manifest_module(program, "services", "initrd_root", "jsix/services")
|
||||
|
||||
for program in manifest.drivers:
|
||||
add_initrd_stripped("jsix/drivers", program)
|
||||
try_add_manifest_module(program, "drivers", "initrd_root", "jsix/drivers")
|
||||
|
||||
for program in manifest.libs:
|
||||
add_initrd_stripped("jsix/lib", program)
|
||||
try_add_manifest_module(program, "libs", "initrd_root", "jsix/lib")
|
||||
|
||||
syms = manifest.add_data("symbol_table.dat",
|
||||
"Symbol table", ("symbols",))
|
||||
extra_regen_outputs = []
|
||||
|
||||
syms_file = "jsix.symbols"
|
||||
syms_path = join(manifest.location, syms_file );
|
||||
syms_out = join(fatroot, syms_path)
|
||||
build.build(
|
||||
rule = "makest",
|
||||
outputs = [syms_out],
|
||||
inputs = [f"${{build_root}}/kernel/{modules['kernel'].get_output(static=True)}"],
|
||||
)
|
||||
fatroot_content.append(syms_out)
|
||||
manifest.symbols = syms_file
|
||||
|
||||
bootloader = "${build_root}/fatroot/efi/boot/bootx64.efi"
|
||||
build.build(
|
||||
rule = "cp",
|
||||
outputs = [bootloader],
|
||||
inputs = ["${build_root}/boot/boot.efi"],
|
||||
variables = {
|
||||
"description": "Installing bootloader",
|
||||
})
|
||||
build.newline()
|
||||
|
||||
boot_config = join(fatroot, "jsix", "boot.conf")
|
||||
manifest.write_boot_config(boot_config)
|
||||
|
||||
initrd = str(fatroot / manifest.location / manifest.initrd["name"])
|
||||
build.build(
|
||||
rule = "makeinitrd",
|
||||
outputs = [initrd],
|
||||
inputs = [str(initrdroot)],
|
||||
implicit = initrd_content + ["${source_root}/scripts/mkj6romfs.py"],
|
||||
variables = {"format": manifest.initrd["format"]},
|
||||
)
|
||||
build.newline()
|
||||
|
||||
fatroot_content.append(initrd)
|
||||
|
||||
build.build(
|
||||
rule = "makefat",
|
||||
outputs = ["${build_root}/jsix.img"],
|
||||
inputs = ["${source_root}/assets/diskbase.img"],
|
||||
implicit = fatroot_content + [bootloader],
|
||||
variables = {"name": "jsix.img"},
|
||||
)
|
||||
build.newline()
|
||||
|
||||
default_assets = {
|
||||
"UEFI Variables": ("ovmf/x64/ovmf_vars.fd", "ovmf_vars.fd"),
|
||||
"GDB Debug Helpers": ("debugging/jsix.elf-gdb.py", "jsix.elf-gdb.py"),
|
||||
}
|
||||
|
||||
for name, assets in default_assets.items():
|
||||
p = root / "assets" / assets[0]
|
||||
out = f"${{build_root}}/{assets[1]}"
|
||||
if 'boot' in modules.used:
|
||||
bootloader = "${build_root}/fatroot/efi/boot/bootx64.efi"
|
||||
build.build(
|
||||
rule = "cp",
|
||||
outputs = [out],
|
||||
inputs = [str(p)],
|
||||
variables = {"name": name},
|
||||
)
|
||||
build.default([out])
|
||||
outputs = [bootloader],
|
||||
inputs = ["${build_root}/boot/boot.efi"],
|
||||
variables = {
|
||||
"description": "Installing bootloader",
|
||||
})
|
||||
build.newline()
|
||||
|
||||
boot_config = join(fatroot, "jsix", "boot.conf")
|
||||
manifest.write_boot_config(boot_config)
|
||||
extra_regen_outputs.append(boot_config)
|
||||
|
||||
initrd = str(fatroot / manifest.location / manifest.initrd["name"])
|
||||
build.build(
|
||||
rule = "makeinitrd",
|
||||
outputs = [initrd],
|
||||
inputs = [str(initrdroot)],
|
||||
implicit = image_content['initrd_root'] + ["${source_root}/scripts/mkj6romfs.py"],
|
||||
variables = {"format": manifest.initrd["format"]},
|
||||
)
|
||||
build.newline()
|
||||
|
||||
image_content['fatroot'].append(initrd)
|
||||
|
||||
build.build(
|
||||
rule = "makefat",
|
||||
outputs = ["${build_root}/jsix.img"],
|
||||
inputs = ["${source_root}/assets/diskbase.img"],
|
||||
implicit = image_content['fatroot'] + [bootloader],
|
||||
variables = {"name": "jsix.img"},
|
||||
)
|
||||
build.newline()
|
||||
|
||||
default_assets = {
|
||||
"UEFI Variables": ("ovmf/x64/ovmf_vars.fd", "ovmf_vars.fd"),
|
||||
"GDB Debug Helpers": ("debugging/jsix.elf-gdb.py", "jsix.elf-gdb.py"),
|
||||
}
|
||||
|
||||
for name, assets in default_assets.items():
|
||||
p = root / "assets" / assets[0]
|
||||
out = f"${{build_root}}/{assets[1]}"
|
||||
build.build(
|
||||
rule = "cp",
|
||||
outputs = [out],
|
||||
inputs = [str(p)],
|
||||
variables = {"name": name},
|
||||
)
|
||||
build.newline()
|
||||
default_builds.append(out)
|
||||
|
||||
compdb = "${source_root}/compile_commands.json"
|
||||
|
||||
build.rule("regen",
|
||||
@@ -233,7 +217,7 @@ class Project:
|
||||
|
||||
regen_implicits = \
|
||||
[f"{self.root}/configure", str(manifest_file)] + \
|
||||
[str(mod.modfile) for mod in modules.values()]
|
||||
[str(mod.modfile) for mod in modules.used.values()]
|
||||
|
||||
regen_implicits += list(map(str, config_deps))
|
||||
|
||||
@@ -242,24 +226,24 @@ class Project:
|
||||
outputs = [compdb],
|
||||
implicit = regen_implicits,
|
||||
)
|
||||
build.default([compdb])
|
||||
build.newline()
|
||||
default_builds.append(compdb)
|
||||
|
||||
build.build(
|
||||
rule = "regen",
|
||||
outputs = ['build.ninja'],
|
||||
implicit = regen_implicits,
|
||||
implicit_outputs =
|
||||
[f"module.{mod.name}.ninja" for mod in modules.values()] +
|
||||
[f"{target}/target.ninja" for target in targets] +
|
||||
[boot_config],
|
||||
[f"module.{mod.name}.ninja" for mod in modules.used.values()] +
|
||||
[f"{target}/target.ninja" for target in modules.targets] +
|
||||
extra_regen_outputs,
|
||||
)
|
||||
|
||||
build.newline()
|
||||
build.default(["${build_root}/jsix.img"])
|
||||
build.default(default_builds)
|
||||
|
||||
for target in targets:
|
||||
mods = [m.name for m in modules.values() if target in m.targets]
|
||||
for target in modules.targets:
|
||||
mods = modules.target_mods(target)
|
||||
|
||||
targetdir = output / target
|
||||
targetdir.mkdir(exist_ok=True)
|
||||
@@ -290,4 +274,4 @@ class Project:
|
||||
build.newline()
|
||||
|
||||
for mod in mods:
|
||||
build.subninja(f"module.{mod}.ninja")
|
||||
build.subninja(f"module.{mod.name}.ninja")
|
||||
|
||||
21
scripts/codegen/__init__.py
Normal file
21
scripts/codegen/__init__.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import cog
|
||||
|
||||
supported_architectures = {
|
||||
"amd64": "__amd64__",
|
||||
}
|
||||
|
||||
def arch_includes(header, root=""):
|
||||
from pathlib import Path
|
||||
root = Path(root)
|
||||
header = Path(header)
|
||||
|
||||
prefix = "if"
|
||||
for arch, define in supported_architectures.items():
|
||||
path = root / "arch" / arch / header
|
||||
cog.outl(f"#{prefix} defined({define})")
|
||||
cog.outl(f"#include <{path}>")
|
||||
prefix = "elif"
|
||||
cog.outl("#else")
|
||||
cog.outl('#error "Unsupported platform"')
|
||||
cog.outl("#endif")
|
||||
|
||||
@@ -1,18 +1,5 @@
|
||||
import cog
|
||||
|
||||
supported_architectures = {
|
||||
"amd64": "__amd64__",
|
||||
}
|
||||
|
||||
def arch_includes(header):
|
||||
prefix = "if"
|
||||
for arch, define in supported_architectures.items():
|
||||
cog.outl(f"#{prefix} defined({define})")
|
||||
cog.outl(f"#include <__j6libc/arch/{arch}/{header}>")
|
||||
prefix = "elif"
|
||||
cog.outl("#endif")
|
||||
|
||||
|
||||
int_widths = (8, 16, 32, 64)
|
||||
int_mods = ("fast", "least")
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
|
||||
def unit(size):
|
||||
units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB']
|
||||
|
||||
o = 0
|
||||
while size >= 1024 and o < len(units):
|
||||
o += 1
|
||||
size = size >> 10
|
||||
|
||||
return f"{size} {units[o]}"
|
||||
|
||||
|
||||
class Layout:
|
||||
from collections import namedtuple
|
||||
Region = namedtuple("Region", ("name", "start", "size", "shared"))
|
||||
Region = namedtuple("Region", ("name", "desc", "start", "size", "shared"))
|
||||
|
||||
sizes = {'G': 1024 ** 3, 'T': 1024 ** 4}
|
||||
|
||||
@@ -26,7 +38,7 @@ class Layout:
|
||||
for r in data:
|
||||
size = Layout.get_size(r["size"])
|
||||
addr -= size
|
||||
regions.append(Layout.Region(r["name"], addr, size,
|
||||
regions.append(Layout.Region(r["name"], r["desc"], addr, size,
|
||||
r.get("shared", False)))
|
||||
|
||||
self.regions = tuple(regions)
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
boot = module("boot",
|
||||
kind = "exe",
|
||||
outfile = "boot.efi",
|
||||
targets = [ "boot" ],
|
||||
target = "boot",
|
||||
deps = [ "cpu", "elf", "util", "bootproto" ],
|
||||
static = True,
|
||||
skip_arches = [ "linux" ],
|
||||
sources = [
|
||||
"allocator.cpp",
|
||||
"bootconfig.cpp",
|
||||
|
||||
@@ -44,7 +44,7 @@ void
|
||||
output(j6_log_entry *entry)
|
||||
{
|
||||
char buffer [256];
|
||||
size_t dlen = util::format({buffer, sizeof(buffer)}, "\e[38;5;%dm%7s %7s\e[38;5;14m|\e[38;5;%dm ",
|
||||
size_t dlen = util::format({buffer, sizeof(buffer)}, "\e[38;5;%dm%7s %7s\e[38;5;14m\u2502\e[38;5;%dm ",
|
||||
level_colors[entry->severity],
|
||||
area_names[entry->area],
|
||||
level_names[entry->severity],
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <stdint.h>
|
||||
#include <util/misc.h> // for checksum
|
||||
#include <util/pointers.h>
|
||||
#include <arch/acpi/tables.h>
|
||||
#include <acpi/tables.h>
|
||||
|
||||
#include "kassert.h"
|
||||
#include "apic.h"
|
||||
|
||||
@@ -117,4 +117,5 @@ ISR (0xe1, 0, isrLINT0)
|
||||
ISR (0xe2, 0, isrLINT1)
|
||||
ISR (0xe3, 0, isrAPICError)
|
||||
ISR (0xe4, 0, ipiSchedule)
|
||||
ISR (0xe5, 0, ipiShootdown)
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ constexpr uintptr_t apic_eoi_addr = 0xfee000b0 + mem::linear_offset;
|
||||
extern "C" {
|
||||
void isr_handler(cpu_state*);
|
||||
void irq_handler(cpu_state*);
|
||||
void _reload_cr3();
|
||||
}
|
||||
|
||||
uint8_t
|
||||
@@ -187,6 +188,11 @@ isr_handler(cpu_state *regs)
|
||||
scheduler::get().schedule();
|
||||
break;
|
||||
|
||||
case isr::ipiShootdown:
|
||||
// TODO: Real shootdown algorithm
|
||||
_reload_cr3();
|
||||
break;
|
||||
|
||||
default:
|
||||
util::format({message, sizeof(message)}, "Unknown interrupt 0x%lx", regs->interrupt);
|
||||
kassert(false, message, regs);
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
kernel = module("kernel",
|
||||
default = True,
|
||||
basename = "jsix",
|
||||
targets = [ "kernel" ],
|
||||
target = "kernel",
|
||||
description = "jsix kernel",
|
||||
deps = [ "util", "cpu", "bootproto", "j6" ],
|
||||
deps = [ "util", "cpu", "bootproto", "j6", "acpi" ],
|
||||
static = True,
|
||||
ld_script = "kernel.ld",
|
||||
skip_arches = [ "linux" ],
|
||||
sources = [
|
||||
"apic.cpp",
|
||||
"kassert.cpp",
|
||||
|
||||
@@ -86,7 +86,7 @@ load_init_server(bootproto::program &program, uintptr_t modules_address)
|
||||
using bootproto::section_flags;
|
||||
using obj::vm_flags;
|
||||
|
||||
obj::process *p = new obj::process;
|
||||
obj::process *p = new obj::process {"srv.init"};
|
||||
|
||||
j6_handle_t sys_handle =
|
||||
g_cap_table.create(&obj::system::get(), obj::system::init_caps);
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
#include "kassert.h"
|
||||
#include "logger.h"
|
||||
#include "objects/system.h"
|
||||
#include "objects/thread.h"
|
||||
|
||||
// The logger is initialized _before_ global constructors are called,
|
||||
// so that we can start log output immediately. Keep its constructor
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <j6/types.h>
|
||||
#include <util/counted.h>
|
||||
#include <util/spinlock.h>
|
||||
|
||||
#include "objects/event.h"
|
||||
#include "wait_queue.h"
|
||||
|
||||
enum class logs : uint8_t {
|
||||
#define LOG(name, lvl) name,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <j6/memutils.h>
|
||||
#include <util/no_construct.h>
|
||||
|
||||
#include "kassert.h"
|
||||
@@ -18,10 +19,18 @@ obj::process &g_kernel_process = __g_kernel_process_storage.value;
|
||||
|
||||
namespace obj {
|
||||
|
||||
process::process() :
|
||||
process::process(const char *name) :
|
||||
kobject {kobject::type::process},
|
||||
m_state {state::running}
|
||||
{
|
||||
if constexpr(__use_process_names) {
|
||||
memset(m_name, 0, sizeof(m_name));
|
||||
if (name) {
|
||||
static constexpr size_t charlen = sizeof(m_name) - 1;
|
||||
for (size_t i = 0; i < charlen && name[i]; ++i)
|
||||
m_name[i] = name[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The "kernel process"-only constructor
|
||||
@@ -30,6 +39,11 @@ process::process(page_table *kpml4) :
|
||||
m_space {kpml4},
|
||||
m_state {state::running}
|
||||
{
|
||||
if constexpr(__use_process_names) {
|
||||
static constexpr char kernel[] = "KERNEL";
|
||||
memcpy(m_name, kernel, sizeof(kernel));
|
||||
memset(m_name + sizeof(kernel), 0, sizeof(m_name) - sizeof(kernel));
|
||||
}
|
||||
}
|
||||
|
||||
process::~process()
|
||||
|
||||
@@ -13,6 +13,14 @@
|
||||
|
||||
namespace obj {
|
||||
|
||||
static constexpr bool __use_process_names =
|
||||
#ifdef __jsix_config_debug
|
||||
true;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
|
||||
|
||||
class process :
|
||||
public kobject
|
||||
{
|
||||
@@ -32,7 +40,7 @@ public:
|
||||
static constexpr kobject::type type = kobject::type::process;
|
||||
|
||||
/// Constructor.
|
||||
process();
|
||||
process(const char *name);
|
||||
|
||||
/// Destructor.
|
||||
virtual ~process();
|
||||
@@ -47,6 +55,9 @@ public:
|
||||
/// Get the process' virtual memory space
|
||||
vm_space & space() { return m_space; }
|
||||
|
||||
/// Get the debugging name of the process
|
||||
const char *name() { if constexpr(__use_process_names) return m_name; else return nullptr; }
|
||||
|
||||
/// Create a new thread in this process
|
||||
/// \args rsp3 If non-zero, sets the ring3 stack pointer to this value
|
||||
/// \args priority The new thread's scheduling priority
|
||||
@@ -107,6 +118,15 @@ private:
|
||||
|
||||
enum class state : uint8_t { running, exited };
|
||||
state m_state;
|
||||
|
||||
static constexpr size_t max_name_len =
|
||||
#ifdef __jsix_config_debug
|
||||
32;
|
||||
#else
|
||||
0;
|
||||
#endif
|
||||
|
||||
char m_name[max_name_len];
|
||||
};
|
||||
|
||||
} // namespace obj
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace obj {
|
||||
using mem::frame_size;
|
||||
|
||||
vm_area::vm_area(size_t size, util::bitset32 flags) :
|
||||
m_size {size},
|
||||
m_size {mem::page_count(size) * mem::frame_size},
|
||||
m_flags {flags},
|
||||
m_spaces {m_vector_static, 0, static_size},
|
||||
kobject {kobject::type::vma}
|
||||
@@ -34,6 +34,10 @@ void
|
||||
vm_area::remove_from(vm_space *space)
|
||||
{
|
||||
m_spaces.remove_swap(space);
|
||||
|
||||
// If we were keeping this space around after its refcount
|
||||
// dropped to zero because it was mapped, check if we should
|
||||
// clean it up now.
|
||||
if (!m_spaces.count() && !handle_count())
|
||||
delete this;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "cpu.h"
|
||||
#include "display.h"
|
||||
#include "kernel.dir/memory.h"
|
||||
#include "objects/process.h"
|
||||
#include "objects/thread.h"
|
||||
#include "serial.h"
|
||||
@@ -9,6 +10,44 @@
|
||||
|
||||
namespace panicking {
|
||||
|
||||
template <typename T> inline bool
|
||||
check_pointer(T p)
|
||||
{
|
||||
static constexpr uint64_t large_flag = (1<<7);
|
||||
static constexpr uint64_t pointer_mask = 0x0000fffffffff000;
|
||||
static constexpr uintptr_t canon_mask = 0xffff800000000000;
|
||||
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
|
||||
|
||||
uintptr_t canon_bits = addr & canon_mask;
|
||||
if (canon_bits && canon_bits != canon_mask)
|
||||
return false;
|
||||
|
||||
uintptr_t pml4 = 0;
|
||||
asm volatile ( "mov %%cr3, %0" : "=r" (pml4) );
|
||||
pml4 += mem::linear_offset;
|
||||
|
||||
uint64_t *table = reinterpret_cast<uint64_t*>(pml4);
|
||||
unsigned shift = 39;
|
||||
|
||||
while (table) {
|
||||
unsigned index = (addr >> shift) & 0x1ffull;
|
||||
uint64_t entry = table[index];
|
||||
|
||||
if ((entry & 0x1) == 0)
|
||||
return false;
|
||||
|
||||
if ((entry & large_flag) || shift <= 12)
|
||||
return true;
|
||||
|
||||
uint64_t next = (entry & pointer_mask) + mem::linear_offset;
|
||||
table = reinterpret_cast<uint64_t*>(next);
|
||||
shift -= 9;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *clear = "\e[0m\n";
|
||||
|
||||
void
|
||||
@@ -40,23 +79,17 @@ print_cpu(serial_port &out, cpu_data &cpu)
|
||||
{
|
||||
uint32_t process = cpu.process ? cpu.process->obj_id() : 0;
|
||||
uint32_t thread = cpu.thread ? cpu.thread->obj_id() : 0;
|
||||
const char *name = cpu.process ? cpu.process->name() : "<Unknown>";
|
||||
|
||||
out.write("\n \e[0;31m==[ CPU: ");
|
||||
|
||||
char buffer[64];
|
||||
util::format({buffer, sizeof(buffer)}, "%4d <%02lx:%02lx>",
|
||||
cpu.id + 1, process, thread);
|
||||
size_t len = util::format({buffer, sizeof(buffer)}, "%4d <%02lx:%02lx> ]: %s ",
|
||||
cpu.id + 1, process, thread, name);
|
||||
out.write(buffer);
|
||||
|
||||
out.write(" ]=============================================================\n");
|
||||
}
|
||||
|
||||
template <typename T> inline bool
|
||||
canonical(T p)
|
||||
{
|
||||
static constexpr uintptr_t mask = 0xffff800000000000;
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
|
||||
return (addr & mask) == mask || (addr & mask) == 0;
|
||||
for (size_t i = 0; i < (74-len); ++i) out.write("=");
|
||||
out.write("\n");
|
||||
}
|
||||
|
||||
void
|
||||
@@ -65,18 +98,26 @@ print_callstack(serial_port &out, symbol_table &syms, frame const *fp)
|
||||
char message[512];
|
||||
unsigned count = 0;
|
||||
|
||||
while (canonical(fp) && fp && fp->return_addr) {
|
||||
char const *name = syms.find_symbol(fp->return_addr);
|
||||
while (fp && check_pointer(fp)) {
|
||||
const uintptr_t ret = fp->return_addr;
|
||||
char const *name = ret ? syms.find_symbol(ret) : "<END>";
|
||||
if (!name)
|
||||
name = canonical(fp->return_addr) ? "<unknown>" : "<corrupt>";
|
||||
name = check_pointer(fp->return_addr) ? "<unknown>" : "<unmapped>";
|
||||
|
||||
util::format({message, sizeof(message)},
|
||||
" \e[0;33mframe %2d: <0x%016lx> \e[1;33m%s\n",
|
||||
count++, fp->return_addr, name);
|
||||
" \e[0;33mframe %2d: <0x%016lx> <0x%016lx> \e[1;33m%s\n",
|
||||
count++, fp, fp->return_addr, name);
|
||||
|
||||
out.write(message);
|
||||
|
||||
if (!ret) return;
|
||||
fp = fp->prev;
|
||||
}
|
||||
|
||||
const char *result = fp ? " <inaccessible>" : "";
|
||||
util::format({message, sizeof(message)}, " \e[0mfinal <0x%016lx>%s\n",
|
||||
fp, result);
|
||||
out.write(message);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
# vim: ft=python
|
||||
|
||||
panic = module("panic.serial",
|
||||
targets = [ "kernel" ],
|
||||
target = "kernel",
|
||||
deps = [ "util", "elf", "kernel" ],
|
||||
static = True,
|
||||
includes = [ ".." ],
|
||||
description = "Serial panic handler",
|
||||
ld_script = "panic.serial.ld",
|
||||
skip_arches = [ "linux" ],
|
||||
sources = [
|
||||
"display.cpp",
|
||||
"entry.s",
|
||||
|
||||
@@ -10,9 +10,9 @@ using namespace obj;
|
||||
namespace syscalls {
|
||||
|
||||
j6_status_t
|
||||
process_create(j6_handle_t *self)
|
||||
process_create(j6_handle_t *self, const char *path)
|
||||
{
|
||||
process *p = construct_handle<process>(self);
|
||||
process *p = construct_handle<process>(self, path);
|
||||
log::info(logs::task, "Process <%02lx> created", p->obj_id());
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
@@ -23,9 +23,10 @@ using system = class ::system;
|
||||
j6_status_t
|
||||
log(uint8_t area, uint8_t severity, const char *message)
|
||||
{
|
||||
const char *name = process::current().name();
|
||||
thread &th = thread::current();
|
||||
log::log(static_cast<logs>(area), static_cast<log::level>(severity),
|
||||
"<%02lx:%02lx>: %s", th.parent().obj_id(), th.obj_id(), message);
|
||||
"<%02lx:%02lx> %s: %s", th.parent().obj_id(), th.obj_id(), name, message);
|
||||
return j6_status_ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,3 +91,10 @@ _current_gsbase:
|
||||
mov rax, [gs:CPU_DATA.self]
|
||||
ret
|
||||
.end:
|
||||
|
||||
global _reload_cr3: function hidden (_reload_cr3.end - _reload_cr3)
|
||||
_reload_cr3:
|
||||
mov rax, cr3
|
||||
mov cr3, rax
|
||||
ret
|
||||
.end:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <j6/memutils.h>
|
||||
#include <arch/memory.h>
|
||||
|
||||
#include "apic.h"
|
||||
#include "kassert.h"
|
||||
#include "frame_allocator.h"
|
||||
#include "logger.h"
|
||||
@@ -81,7 +82,7 @@ vm_space::kernel_space()
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
vm_space::add(uintptr_t base, obj::vm_area *area, util::bitset32 flags)
|
||||
vm_space::add(uintptr_t base, obj::vm_area *new_area, util::bitset32 flags)
|
||||
{
|
||||
if (!base)
|
||||
base = min_auto_address;
|
||||
@@ -89,23 +90,23 @@ vm_space::add(uintptr_t base, obj::vm_area *area, util::bitset32 flags)
|
||||
//TODO: optimize find/insert
|
||||
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();
|
||||
if (base >= aend)
|
||||
const vm_space::area &cur = m_areas[i];
|
||||
uintptr_t cur_end = cur.base + cur.area->size();
|
||||
if (base >= cur_end)
|
||||
continue;
|
||||
|
||||
uintptr_t end = base + area->size();
|
||||
if (end <= a.base)
|
||||
uintptr_t end = base + new_area->size();
|
||||
if (end <= cur.base)
|
||||
break;
|
||||
else if (exact)
|
||||
return 0;
|
||||
else
|
||||
base = aend;
|
||||
base = cur_end;
|
||||
}
|
||||
|
||||
m_areas.sorted_insert({base, area});
|
||||
area->add_to(this);
|
||||
area->handle_retain();
|
||||
m_areas.sorted_insert({base, new_area});
|
||||
new_area->add_to(this);
|
||||
new_area->handle_retain();
|
||||
return base;
|
||||
}
|
||||
|
||||
@@ -250,10 +251,10 @@ vm_space::clear(const obj::vm_area &vma, uintptr_t offset, size_t count, bool fr
|
||||
|
||||
if (flags & page_flags::present) {
|
||||
e = 0;
|
||||
if (flags & page_flags::accessed) {
|
||||
auto *addr = reinterpret_cast<const uint8_t *>(it.vaddress());
|
||||
asm ( "invlpg %0" :: "m"(*addr) : "memory" );
|
||||
}
|
||||
|
||||
auto *addr = reinterpret_cast<const uint8_t *>(it.vaddress());
|
||||
asm ( "invlpg %0" :: "m"(*addr) : "memory" );
|
||||
|
||||
if (free_count && phys == free_start + (free_count * frame_size)) {
|
||||
++free_count;
|
||||
} else {
|
||||
@@ -267,6 +268,9 @@ vm_space::clear(const obj::vm_area &vma, uintptr_t offset, size_t count, bool fr
|
||||
++it;
|
||||
}
|
||||
|
||||
current_cpu().apic->send_ipi_broadcast(
|
||||
lapic::ipi_fixed, false, isr::ipiShootdown);
|
||||
|
||||
if (free && free_count)
|
||||
fa.free(free_start, free_count);
|
||||
}
|
||||
|
||||
79
src/libraries/acpi/acpi.cpp
Normal file
79
src/libraries/acpi/acpi.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include <acpi/acpi.h>
|
||||
#include <acpi/tables.h>
|
||||
#include <j6/syslog.hh>
|
||||
|
||||
namespace acpi {
|
||||
|
||||
system::system(const void* phys, const void *virt) :
|
||||
m_offset { util::get_offset(phys, virt) },
|
||||
m_root { reinterpret_cast<const rsdp2*>(virt) }
|
||||
{}
|
||||
|
||||
system::iterator
|
||||
system::begin() const
|
||||
{
|
||||
const xsdt *sdt =
|
||||
acpi::check_get_table<xsdt>(m_root->xsdt_address);
|
||||
|
||||
if (!sdt)
|
||||
return {nullptr, 0};
|
||||
|
||||
return {&sdt->headers[0], m_offset};
|
||||
}
|
||||
|
||||
|
||||
system::iterator
|
||||
system::end() const
|
||||
{
|
||||
const xsdt *sdt =
|
||||
acpi::check_get_table<xsdt>(m_root->xsdt_address);
|
||||
|
||||
if (!sdt)
|
||||
return {nullptr, 0};
|
||||
|
||||
size_t nheaders = table_entries<xsdt>(sdt, sizeof(table_header*));
|
||||
return {&sdt->headers[nheaders], m_offset};
|
||||
}
|
||||
|
||||
#if 0
|
||||
void
|
||||
load_acpi(j6_handle_t sys, const bootproto::module *mod)
|
||||
{
|
||||
const bootproto::acpi *info = mod->data<bootproto::acpi>();
|
||||
const util::const_buffer ®ion = info->region;
|
||||
|
||||
map_phys(sys, region.pointer, region.count);
|
||||
|
||||
const void *root_table = info->root;
|
||||
if (!root_table) {
|
||||
j6::syslog(j6::logs::srv, j6::log_level::error, "null ACPI root table pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
const acpi::rsdp2 *acpi2 =
|
||||
reinterpret_cast<const acpi::rsdp2 *>(root_table);
|
||||
|
||||
const auto *xsdt =
|
||||
acpi::check_get_table<acpi::xsdt>(acpi2->xsdt_address);
|
||||
|
||||
size_t num_tables = acpi::table_entries(xsdt, sizeof(void*));
|
||||
for (size_t i = 0; i < num_tables; ++i) {
|
||||
const acpi::table_header *header = xsdt->headers[i];
|
||||
if (!header->validate()) {
|
||||
j6::syslog(j6::logs::srv, j6::log_level::error, "ACPI table at %lx failed validation", header);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (header->type) {
|
||||
case acpi::mcfg::type_id:
|
||||
load_mcfg(sys, header);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace acpi
|
||||
12
src/libraries/acpi/acpi.module
Normal file
12
src/libraries/acpi/acpi.module
Normal file
@@ -0,0 +1,12 @@
|
||||
# vim: ft=python
|
||||
|
||||
module("acpi",
|
||||
kind = "lib",
|
||||
deps = [ "util", "j6" ],
|
||||
sources = [
|
||||
"acpi.cpp",
|
||||
],
|
||||
public_headers = [
|
||||
"acpi/acpi.h",
|
||||
"acpi/tables.h",
|
||||
])
|
||||
53
src/libraries/acpi/include/acpi/acpi.h
Normal file
53
src/libraries/acpi/include/acpi/acpi.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
/// \file acpi.h
|
||||
/// Routines for loading and parsing ACPI tables
|
||||
|
||||
#include <stddef.h>
|
||||
#include <acpi/tables.h>
|
||||
#include <util/pointers.h>
|
||||
|
||||
namespace acpi {
|
||||
|
||||
struct system
|
||||
{
|
||||
system(const void* phys, const void *virt);
|
||||
|
||||
/// Iterator for all tables in the system
|
||||
struct iterator
|
||||
{
|
||||
iterator(const table_header *const *addr, ptrdiff_t off) : m_addr {addr}, m_off {off} {};
|
||||
|
||||
operator const table_header *() const { return m_addr ? offset(*m_addr) : nullptr; }
|
||||
const table_header * operator*() const { return m_addr ? offset(*m_addr) : nullptr; }
|
||||
const table_header * operator->() const { return m_addr ? offset(*m_addr) : nullptr; }
|
||||
|
||||
iterator & operator++() { increment(); return *this; }
|
||||
iterator operator++(int) { iterator old = *this; increment(); return old; }
|
||||
|
||||
friend bool operator==(const iterator &a, const iterator &b) { return a.m_addr == b.m_addr; }
|
||||
friend bool operator!=(const iterator &a, const iterator &b) { return a.m_addr != b.m_addr; }
|
||||
|
||||
private:
|
||||
inline void increment() { if (m_addr) ++m_addr; }
|
||||
|
||||
table_header const * const * m_addr;
|
||||
ptrdiff_t m_off;
|
||||
|
||||
inline const table_header * offset(const table_header * addr) const {
|
||||
return util::offset_pointer(addr, m_off);
|
||||
}
|
||||
};
|
||||
|
||||
iterator begin() const;
|
||||
iterator end() const;
|
||||
|
||||
private:
|
||||
const xsdt * get_xsdt() {
|
||||
return check_get_table<xsdt>(util::offset_pointer(m_root->xsdt_address, m_offset));
|
||||
}
|
||||
|
||||
ptrdiff_t m_offset;
|
||||
const rsdp2* m_root;
|
||||
};
|
||||
|
||||
} // namespace acpi
|
||||
@@ -21,6 +21,7 @@ struct table_header
|
||||
uint32_t creator_revision;
|
||||
|
||||
bool validate() const { return util::checksum(this, length) == 0; }
|
||||
bool validate(uint32_t sig) const { return type == sig && validate(); }
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
@@ -12,39 +12,42 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define add_header(name) \
|
||||
static constexpr j6_arg_type type_id = j6_arg_type_ ## name; \
|
||||
j6_arg_header header;
|
||||
#else
|
||||
#define add_header(name) \
|
||||
j6_arg_header header;
|
||||
#endif
|
||||
enum j6_aux_type {
|
||||
// The SysV ABI-specified aux vector types
|
||||
j6_aux_null, // AT_NULL
|
||||
j6_aux_ignore, // AT_IGNORE
|
||||
j6_aux_execfd, // AD_EXECFD - File descriptor of the exe to load
|
||||
j6_aux_phdr, // AD_PHDR - Program headers pointer for the exe to load
|
||||
j6_aux_phent, // AD_PHENT - Size of a program header entry
|
||||
j6_aux_phnum, // AD_PHNUM - Number of program header entries
|
||||
j6_aux_pagesz, // AD_PAGESZ - System page size
|
||||
j6_aux_base, // AD_BASE - Base address of dynamic loader
|
||||
j6_aux_flags, // AD_FLAGS - Flags
|
||||
j6_aux_entry, // AD_ENTRY - Entrypoint for the exe to load
|
||||
j6_aux_notelf, // AD_NOTELF - If non-zero, this program is not ELF
|
||||
j6_aux_uid, // AD_UID - User ID
|
||||
j6_aux_euid, // AD_EUID - Effective User ID
|
||||
j6_aux_gid, // AD_GID - Group ID
|
||||
j6_aux_egid, // AD_EGID - Effective Group ID
|
||||
|
||||
enum j6_arg_type {
|
||||
j6_arg_type_none,
|
||||
j6_arg_type_sysv_init,
|
||||
j6_arg_type_loader,
|
||||
j6_arg_type_driver,
|
||||
j6_arg_type_handles,
|
||||
j6_aux_start = 0xf000,
|
||||
j6_aux_handles, // Pointer to a j6_arg_handles structure
|
||||
j6_aux_device, // Pointer to a j6_arg_driver structure
|
||||
j6_aux_loader, // Pointer to a j6_arg_loader structure
|
||||
};
|
||||
|
||||
struct j6_arg_header
|
||||
struct j6_aux
|
||||
{
|
||||
uint32_t size;
|
||||
uint16_t type;
|
||||
uint16_t reserved;
|
||||
j6_arg_header *next;
|
||||
};
|
||||
|
||||
struct j6_arg_none
|
||||
{
|
||||
add_header(none);
|
||||
uint64_t type;
|
||||
union {
|
||||
uint64_t value;
|
||||
void *pointer;
|
||||
void (*func)();
|
||||
};
|
||||
};
|
||||
|
||||
struct j6_arg_loader
|
||||
{
|
||||
add_header(loader);
|
||||
uintptr_t loader_base;
|
||||
uintptr_t image_base;
|
||||
uintptr_t *got;
|
||||
@@ -54,8 +57,8 @@ struct j6_arg_loader
|
||||
|
||||
struct j6_arg_driver
|
||||
{
|
||||
add_header(driver);
|
||||
uint64_t device;
|
||||
uint32_t size;
|
||||
uint8_t data [0];
|
||||
};
|
||||
|
||||
@@ -67,32 +70,13 @@ struct j6_arg_handle_entry
|
||||
|
||||
struct j6_arg_handles
|
||||
{
|
||||
add_header(handles);
|
||||
size_t nhandles;
|
||||
j6_arg_handle_entry handles[0];
|
||||
};
|
||||
|
||||
struct j6_init_args
|
||||
{
|
||||
uint64_t argv[2];
|
||||
j6_arg_header *args;
|
||||
};
|
||||
|
||||
|
||||
/// Find the first handle of the given type held by this process
|
||||
j6_handle_t API j6_find_first_handle(j6_object_type obj_type);
|
||||
|
||||
/// Find the first handle tagged with the given proto in the process init args
|
||||
j6_handle_t API j6_find_init_handle(uint64_t proto);
|
||||
|
||||
/// Get the init args
|
||||
const j6_init_args * j6_get_init_args();
|
||||
|
||||
/// Drivers may use driver_main instead of main
|
||||
int driver_main(unsigned, const char **, const char **, const j6_init_args *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#undef add_header
|
||||
|
||||
@@ -8,4 +8,6 @@ enum j6_proto_vfs_tag
|
||||
{
|
||||
j6_proto_vfs_load = j6_proto_base_first_proto_id,
|
||||
j6_proto_vfs_file,
|
||||
};
|
||||
j6_proto_vfs_get_tag,
|
||||
j6_proto_vfs_tag,
|
||||
};
|
||||
|
||||
@@ -13,7 +13,13 @@ class API client
|
||||
public:
|
||||
/// Constructor.
|
||||
/// \arg vfs_mb Handle to the VFS service's mailbox
|
||||
client(j6_handle_t vfs_mb);
|
||||
client(j6_handle_t vfs_mb = 0);
|
||||
|
||||
/// Copy constructor
|
||||
client(const client& c);
|
||||
|
||||
/// Check if this client's handle is valid
|
||||
inline bool valid() const { return m_service != j6_handle_invalid; }
|
||||
|
||||
/// Load a file into a VMA
|
||||
/// \arg path Path of the file to load
|
||||
@@ -21,8 +27,13 @@ public:
|
||||
/// \arg size [out] Size of the file
|
||||
j6_status_t load_file(char *path, j6_handle_t &vma, size_t &size);
|
||||
|
||||
/// Get fs tag
|
||||
/// \arg tag [out] The filesystem's tag
|
||||
/// \arg size [inout] Size of the input buffer, length of the returned string
|
||||
j6_status_t get_tag(char *tag, size_t &len);
|
||||
|
||||
private:
|
||||
j6_handle_t m_service;
|
||||
};
|
||||
|
||||
} // namespace j6::proto::vfs
|
||||
} // namespace j6::proto::vfs
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// The kernel depends on libj6 for some shared code,
|
||||
// but should not include the user-specific code.
|
||||
#include "j6/init.h"
|
||||
#include "j6/types.h"
|
||||
#ifndef __j6kernel
|
||||
|
||||
#include <stddef.h>
|
||||
@@ -10,65 +12,45 @@
|
||||
#include <j6/types.h>
|
||||
|
||||
namespace {
|
||||
constexpr size_t static_arr_count = 32;
|
||||
j6_handle_descriptor handle_array[static_arr_count];
|
||||
j6_init_args init_args = { 0, 0, 0 };
|
||||
} // namespace
|
||||
char const * const *envp = nullptr;
|
||||
const j6_aux *aux = nullptr;
|
||||
|
||||
j6_handle_t
|
||||
j6_find_first_handle(j6_object_type obj_type)
|
||||
{
|
||||
size_t count = static_arr_count;
|
||||
j6_handle_descriptor *handles = handle_array;
|
||||
j6_status_t s = j6_handle_list(handles, &count);
|
||||
|
||||
if (s != j6_err_insufficient && s != j6_status_ok)
|
||||
return j6_handle_invalid;
|
||||
|
||||
if (count > static_arr_count)
|
||||
count = static_arr_count;
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
j6_handle_descriptor &desc = handle_array[i];
|
||||
if (desc.type == obj_type) return desc.handle;
|
||||
const j6_aux * find_aux(uint64_t type) {
|
||||
if (!aux) return nullptr;
|
||||
for (j6_aux const *p = aux; p->type; ++p)
|
||||
if (p->type == type) return p;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return j6_handle_invalid;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
j6_handle_t
|
||||
j6_find_init_handle(uint64_t proto)
|
||||
{
|
||||
j6_arg_header *arg = init_args.args;
|
||||
while (arg) {
|
||||
if (arg->type == j6_arg_type_handles) {
|
||||
j6_arg_handles *harg = reinterpret_cast<j6_arg_handles*>(arg);
|
||||
for (unsigned i = 0; i < harg->nhandles; ++i) {
|
||||
j6_arg_handle_entry &ent = harg->handles[i];
|
||||
if (ent.proto == proto)
|
||||
return ent.handle;
|
||||
}
|
||||
}
|
||||
arg = arg->next;
|
||||
const j6_aux *aux_handles = find_aux(j6_aux_handles);
|
||||
if (!aux_handles)
|
||||
return j6_handle_invalid;
|
||||
|
||||
const j6_arg_handles *arg = reinterpret_cast<const j6_arg_handles*>(aux_handles->pointer);
|
||||
for (unsigned i = 0; i < arg->nhandles; ++i) {
|
||||
const j6_arg_handle_entry &ent = arg->handles[i];
|
||||
if (ent.proto == proto)
|
||||
return ent.handle;
|
||||
}
|
||||
|
||||
return j6_handle_invalid;
|
||||
}
|
||||
|
||||
|
||||
const j6_init_args * API
|
||||
j6_get_init_args()
|
||||
{
|
||||
return &init_args;
|
||||
}
|
||||
|
||||
extern "C" void API
|
||||
__init_libj6(uint64_t argv0, uint64_t argv1, j6_arg_header *args)
|
||||
__init_libj6(const uint64_t *stack)
|
||||
{
|
||||
init_args.argv[0] = argv0;
|
||||
init_args.argv[1] = argv1;
|
||||
init_args.args = args;
|
||||
}
|
||||
// Walk the stack to get the aux vector
|
||||
uint64_t argc = *stack++;
|
||||
stack += argc + 1; // Skip argv's and sentinel
|
||||
|
||||
envp = reinterpret_cast<char const * const *>(stack);
|
||||
while (*stack++); // Skip envp's and sentinel
|
||||
|
||||
aux = reinterpret_cast<const j6_aux*>(stack);
|
||||
}
|
||||
|
||||
#endif // __j6kernel
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
extern driver_main
|
||||
global main:function weak (main.end - main)
|
||||
main:
|
||||
jmp driver_main
|
||||
main.end:
|
||||
|
||||
@@ -14,10 +14,17 @@ j6 = module("j6",
|
||||
"protocols/service_locator.cpp",
|
||||
"protocols/vfs.cpp",
|
||||
"ring_buffer.cpp",
|
||||
"syscalls.s.cog",
|
||||
"sysconf.cpp.cog",
|
||||
"syslog.cpp",
|
||||
],
|
||||
arch_source = {
|
||||
"amd64": [
|
||||
"syscalls.s.cog",
|
||||
],
|
||||
"linux": [
|
||||
"linux/syscalls.s.cog",
|
||||
],
|
||||
},
|
||||
public_headers = [
|
||||
"j6/cap_flags.h.cog",
|
||||
"j6/channel.hh",
|
||||
|
||||
49
src/libraries/j6/linux/syscalls.s.cog
Normal file
49
src/libraries/j6/linux/syscalls.s.cog
Normal file
@@ -0,0 +1,49 @@
|
||||
; vim: ft=asm
|
||||
|
||||
%macro define_syscall 2
|
||||
global j6_%1: function (j6_%1.end - j6_%1)
|
||||
j6_%1:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
|
||||
; if the syscall has more than 6 arguments, the rest
|
||||
; will be pushed on the stack. in that case, we'd need
|
||||
; to pass this stack pointer to the kernel, so stash
|
||||
; off rbx (callee-saved) and pass the pointer to the
|
||||
; arguments there.
|
||||
push rbx
|
||||
mov rbx, rbp
|
||||
add rbx, 16 ; account for stack frame
|
||||
|
||||
; args should already be in rdi, etc, but rcx will
|
||||
; get stomped, so stash it in r10, which isn't a
|
||||
; callee-saved register, but also isn't used in the
|
||||
; function call ABI.
|
||||
mov r10, rcx
|
||||
|
||||
mov rax, %2
|
||||
syscall
|
||||
; result is now already in rax, so just return
|
||||
|
||||
pop rbx
|
||||
pop rbp
|
||||
ret
|
||||
.end:
|
||||
%endmacro
|
||||
|
||||
; [[[cog code generation
|
||||
; from definitions.context import Context
|
||||
;
|
||||
; ctx = Context(definitions_path)
|
||||
; ctx.parse("syscalls.def")
|
||||
; syscalls = ctx.interfaces['syscalls']
|
||||
;
|
||||
; if target != "kernel":
|
||||
; for id, scope, method in syscalls.methods:
|
||||
; if scope:
|
||||
; name = f"{scope.name}_{method.name}"
|
||||
; else:
|
||||
; name = method.name
|
||||
; cog.outl(f"define_syscall {name:20}, {id}")
|
||||
; ]]]
|
||||
; [[[end]]]
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "j6/types.h"
|
||||
#include <j6/errors.h>
|
||||
#include <j6/protocols/vfs.hh>
|
||||
#include <j6/syscalls.h>
|
||||
@@ -12,6 +13,11 @@ client::client(j6_handle_t vfs_mb) :
|
||||
{
|
||||
}
|
||||
|
||||
client::client(const client& c) :
|
||||
m_service {c.m_service}
|
||||
{
|
||||
}
|
||||
|
||||
inline size_t simple_strlen(const char *s) { size_t n = 0; while (s && *s) s++, n++; return n; }
|
||||
|
||||
j6_status_t
|
||||
@@ -61,5 +67,31 @@ client::load_file(char *path, j6_handle_t &vma, size_t &size)
|
||||
}
|
||||
|
||||
|
||||
j6_status_t
|
||||
client::get_tag(char *tag, size_t &len)
|
||||
{
|
||||
if (len < sizeof(j6_status_t))
|
||||
return j6_err_insufficient;
|
||||
|
||||
uint64_t message_tag = j6_proto_vfs_get_tag;
|
||||
size_t handle_count = 0;
|
||||
|
||||
size_t in_len = 0;
|
||||
j6_status_t s = j6_mailbox_call(m_service, &message_tag,
|
||||
tag, &in_len, len, nullptr, &handle_count, 0);
|
||||
|
||||
if (s != j6_status_ok)
|
||||
return s;
|
||||
|
||||
if (message_tag == j6_proto_base_status)
|
||||
return *reinterpret_cast<j6_status_t*>(tag); // contains a status
|
||||
|
||||
if (message_tag != j6_proto_vfs_tag)
|
||||
return j6_err_unexpected;
|
||||
|
||||
len = in_len;
|
||||
return j6_status_ok; // data is now in `tag` and `len`
|
||||
}
|
||||
|
||||
} // namespace j6::proto::vfs
|
||||
#endif // __j6kernel
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
; This file is part of the C standard library for the jsix operating
|
||||
; system.
|
||||
;
|
||||
; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
; file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
extern _GLOBAL_OFFSET_TABLE_
|
||||
|
||||
extern main
|
||||
@@ -5,6 +12,52 @@ extern exit
|
||||
extern __init_libj6
|
||||
extern __init_libc
|
||||
|
||||
extern __preinit_array_start
|
||||
extern __preinit_array_end
|
||||
extern __init_array_start
|
||||
extern __init_array_end
|
||||
|
||||
global __run_ctor_list:function hidden (__run_ctor_list.end - __run_ctor_list)
|
||||
__run_ctor_list:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
|
||||
push rbx
|
||||
push r12
|
||||
mov rbx, rdi
|
||||
mov r12, rsi
|
||||
.start:
|
||||
cmp rbx, r12
|
||||
je .fin
|
||||
mov rax, [rbx]
|
||||
call rax
|
||||
add rbx, 8
|
||||
jmp .start
|
||||
.fin:
|
||||
|
||||
pop r12
|
||||
pop rbx
|
||||
pop rbp
|
||||
ret
|
||||
.end:
|
||||
|
||||
global __run_global_ctors:function hidden (__run_global_ctors.end - __run_global_ctors)
|
||||
__run_global_ctors:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
|
||||
lea rdi, [rel __preinit_array_start]
|
||||
lea rsi, [rel __preinit_array_end]
|
||||
call __run_ctor_list
|
||||
lea rdi, [rel __init_array_start]
|
||||
lea rsi, [rel __init_array_end]
|
||||
call __run_ctor_list
|
||||
|
||||
pop rbp
|
||||
ret
|
||||
.end:
|
||||
|
||||
|
||||
; Put the address of the given symbol in rax
|
||||
; This macro is the same as in util/got.inc,
|
||||
; but crt0 can't have a dep on libutil
|
||||
@@ -18,12 +71,13 @@ global _libc_crt0_start:function (_libc_crt0_start.end - _libc_crt0_start)
|
||||
|
||||
_start:
|
||||
_libc_crt0_start:
|
||||
mov rdx, [rsp] ; grab args pointer
|
||||
mov r15, rsp ; grab initial stack pointer
|
||||
|
||||
push 0 ; Add null frame
|
||||
push 0
|
||||
mov rbp, rsp
|
||||
|
||||
mov rdi, r15
|
||||
lookup_GOT __init_libj6
|
||||
call rax
|
||||
mov rbx, rax
|
||||
@@ -31,10 +85,18 @@ _libc_crt0_start:
|
||||
lookup_GOT __init_libc
|
||||
call rax
|
||||
|
||||
mov rdi, 0
|
||||
mov rsi, rsp
|
||||
mov rdx, 0 ; TODO: actually parse stack for argc, argv, envp
|
||||
mov rcx, rbx
|
||||
call __run_global_ctors
|
||||
|
||||
; argc
|
||||
mov rdi, [r15]
|
||||
|
||||
; argv
|
||||
mov rsi, r15
|
||||
add rsi, 8
|
||||
|
||||
; envp
|
||||
lea rdx, [rsi + rdi*8 + 8]
|
||||
|
||||
lookup_GOT main
|
||||
call rax
|
||||
|
||||
|
||||
10
src/libraries/libc/arch/amd64/errno.cpp
Normal file
10
src/libraries/libc/arch/amd64/errno.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#include <arch/amd64/errno.h>
|
||||
|
||||
static int errno_value = 0;
|
||||
|
||||
int *
|
||||
__errno_location()
|
||||
{
|
||||
// TODO: thread-local errno
|
||||
return &errno_value;
|
||||
}
|
||||
@@ -1,33 +1,6 @@
|
||||
#include <stddef.h>
|
||||
|
||||
using cb = void (*)(void);
|
||||
extern cb __preinit_array_start;
|
||||
extern cb __preinit_array_end;
|
||||
extern cb __init_array_start;
|
||||
extern cb __init_array_end;
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
run_ctor_list(cb *p, cb *end)
|
||||
{
|
||||
while (p && end && p < end) {
|
||||
if (p) (*p)();
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run_global_ctors()
|
||||
{
|
||||
run_ctor_list(&__preinit_array_start, &__preinit_array_end);
|
||||
run_ctor_list(&__init_array_start, &__init_array_end);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" void
|
||||
__init_libc()
|
||||
{
|
||||
run_global_ctors();
|
||||
}
|
||||
|
||||
@@ -2,4 +2,13 @@
|
||||
/// \file arch/amd64/errno.h
|
||||
/// errno implementation for amd64
|
||||
|
||||
extern int errno;
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int * __errno_location();
|
||||
#define errno (*__errno_location())
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern C
|
||||
#endif
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
|
||||
|
||||
/**[[[cog code generation
|
||||
from j6libc import arch_includes
|
||||
from codegen import arch_includes
|
||||
|
||||
arch_includes("errno.h")
|
||||
arch_includes("errno.h", root="__j6libc")
|
||||
|
||||
]]]*/
|
||||
/*[[[end]]]*/
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
/**[[[cog code generation
|
||||
import cog
|
||||
from j6libc import definition, int_widths, int_mods
|
||||
from codegen.int_types import definition, int_widths, int_mods
|
||||
|
||||
for width in int_widths:
|
||||
definition("#define", f"PRId{width}", f"__INT{width}_FMTd__")
|
||||
|
||||
@@ -10,4 +10,10 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#error setjmp.h is not yet implemented.
|
||||
#include <stdint.h>
|
||||
#include <stdnoreturn.h>
|
||||
|
||||
typedef uint64_t jmp_buf[9];
|
||||
|
||||
int setjmp(jmp_buf env);
|
||||
_Noreturn void longjmp(jmp_buf env, int val);
|
||||
|
||||
@@ -18,7 +18,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/**[[[cog code generation
|
||||
from j6libc import atomic_types
|
||||
from codegen.int_types import atomic_types
|
||||
|
||||
deftypes = ["BOOL", "CHAR16", "CHAR32", "CHAR", "INT",
|
||||
"LLONG", "SHORT", "WCHAR_T", "POINTER"]
|
||||
|
||||
76
src/libraries/libc/setjmp/setjmp.s
Normal file
76
src/libraries/libc/setjmp/setjmp.s
Normal file
@@ -0,0 +1,76 @@
|
||||
; This file is part of the C standard library for the jsix operating
|
||||
; system.
|
||||
;
|
||||
; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
; file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
struc JMPBUF
|
||||
.rbx: resq 1
|
||||
.rsp: resq 1
|
||||
.rbp: resq 1
|
||||
.r12: resq 1
|
||||
.r13: resq 1
|
||||
.r14: resq 1
|
||||
.r15: resq 1
|
||||
|
||||
.retaddr: resq 1
|
||||
|
||||
.mxcsr: resd 1
|
||||
.fcw: resw 1
|
||||
|
||||
endstruc
|
||||
|
||||
global setjmp: function (setjmp.end - setjmp)
|
||||
setjmp:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
|
||||
mov rax, [rsp + 8]
|
||||
mov [rdi + JMPBUF.retaddr], rax
|
||||
|
||||
mov [rdi + JMPBUF.rbx], rbx
|
||||
mov [rdi + JMPBUF.rsp], rsp
|
||||
mov [rdi + JMPBUF.rbp], rbp
|
||||
mov [rdi + JMPBUF.r12], r12
|
||||
mov [rdi + JMPBUF.r13], r13
|
||||
mov [rdi + JMPBUF.r14], r14
|
||||
mov [rdi + JMPBUF.r15], r15
|
||||
|
||||
stmxcsr [rdi + JMPBUF.mxcsr]
|
||||
fnstcw [rdi + JMPBUF.fcw]
|
||||
|
||||
mov rax, 0 ; actual setjmp returns 0
|
||||
|
||||
pop rbp
|
||||
ret
|
||||
.end:
|
||||
|
||||
|
||||
global longjmp: function (longjmp.end - longjmp)
|
||||
longjmp:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
|
||||
mov rbx, [rdi + JMPBUF.rbx]
|
||||
mov rbp, [rdi + JMPBUF.rbp]
|
||||
mov r12, [rdi + JMPBUF.r12]
|
||||
mov r13, [rdi + JMPBUF.r13]
|
||||
mov r14, [rdi + JMPBUF.r14]
|
||||
mov r15, [rdi + JMPBUF.r15]
|
||||
|
||||
ldmxcsr [rdi + JMPBUF.mxcsr]
|
||||
fnclex
|
||||
fldcw [rdi + JMPBUF.fcw]
|
||||
|
||||
mov rsp, [rdi + JMPBUF.rsp]
|
||||
|
||||
mov rax, rsi
|
||||
cmp rax, 0
|
||||
jne .done
|
||||
mov rax, 1
|
||||
|
||||
.done:
|
||||
pop rbp
|
||||
ret
|
||||
.end:
|
||||
18
src/libraries/libc/stdlib/strtod.cpp
Normal file
18
src/libraries/libc/stdlib/strtod.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file strtod.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
double strtod( const char * restrict nptr, char ** restrict endptr )
|
||||
{
|
||||
assert(!"strtod() NYI");
|
||||
return 0;
|
||||
}
|
||||
18
src/libraries/libc/stdlib/strtof.cpp
Normal file
18
src/libraries/libc/stdlib/strtof.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file strtof.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
float strtof( const char * restrict nptr, char ** restrict endptr )
|
||||
{
|
||||
assert(!"strtof() NYI");
|
||||
return 0;
|
||||
}
|
||||
18
src/libraries/libc/stdlib/strtol.cpp
Normal file
18
src/libraries/libc/stdlib/strtol.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file strtol.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
long strtol( const char * restrict nptr, char ** restrict endptr, int base )
|
||||
{
|
||||
assert(!"strtol() NYI");
|
||||
return 0;
|
||||
}
|
||||
18
src/libraries/libc/stdlib/strtold.cpp
Normal file
18
src/libraries/libc/stdlib/strtold.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file strtold.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
long double strtold( const char * restrict nptr, char ** restrict endptr )
|
||||
{
|
||||
assert(!"strtold() NYI");
|
||||
return 0;
|
||||
}
|
||||
18
src/libraries/libc/stdlib/strtoll.cpp
Normal file
18
src/libraries/libc/stdlib/strtoll.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file strtoll.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
long long strtoll( const char * restrict nptr, char ** restrict endptr, int base )
|
||||
{
|
||||
assert(!"strtoll() NYI");
|
||||
return 0;
|
||||
}
|
||||
18
src/libraries/libc/stdlib/strtoul.cpp
Normal file
18
src/libraries/libc/stdlib/strtoul.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file strtoul.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
unsigned long strtoul( const char * restrict nptr, char ** restrict endptr, int base )
|
||||
{
|
||||
assert(!"strtoul() NYI");
|
||||
return 0;
|
||||
}
|
||||
18
src/libraries/libc/stdlib/strtoull.cpp
Normal file
18
src/libraries/libc/stdlib/strtoull.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file strtoull.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
unsigned long long strtoull( const char * restrict nptr, char ** restrict endptr, int base )
|
||||
{
|
||||
assert(!"strtoull() NYI");
|
||||
return 0;
|
||||
}
|
||||
@@ -23,3 +23,5 @@ int memcmp(const void *s1, const void *s2, size_t n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int bcmp(const void *s1, const void *s2, size_t n)
|
||||
__attribute__ ((weak, alias ("memcmp")));
|
||||
|
||||
18
src/libraries/libc/wchar/swprintf.cpp
Normal file
18
src/libraries/libc/wchar/swprintf.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file swprintf.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <wchar.h>
|
||||
|
||||
int swprintf(wchar_t * restrict s, size_t n, const wchar_t * restrict format, ...)
|
||||
{
|
||||
assert(!"swprintf() NYI");
|
||||
return 0;
|
||||
}
|
||||
18
src/libraries/libc/wchar/wcslen.cpp
Normal file
18
src/libraries/libc/wchar/wcslen.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file wcslen.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <wchar.h>
|
||||
|
||||
size_t wcslen(const wchar_t * s)
|
||||
{
|
||||
assert(!"wcslen() NYI");
|
||||
return 0;
|
||||
}
|
||||
18
src/libraries/libc/wchar/wcstod.cpp
Normal file
18
src/libraries/libc/wchar/wcstod.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file wcstod.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <wchar.h>
|
||||
|
||||
double wcstod(const wchar_t * restrict nptr, wchar_t ** restrict endptr)
|
||||
{
|
||||
assert(!"wcstod() NYI");
|
||||
return 0;
|
||||
}
|
||||
18
src/libraries/libc/wchar/wcstof.cpp
Normal file
18
src/libraries/libc/wchar/wcstof.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file wcstof.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <wchar.h>
|
||||
|
||||
float wcstof(const wchar_t * restrict nptr, wchar_t ** restrict endptr)
|
||||
{
|
||||
assert(!"wcstof() NYI");
|
||||
return 0;
|
||||
}
|
||||
18
src/libraries/libc/wchar/wcstol.cpp
Normal file
18
src/libraries/libc/wchar/wcstol.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file wcstol.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <wchar.h>
|
||||
|
||||
long wcstol(const wchar_t * restrict nptr, wchar_t ** restrict endptr, int base)
|
||||
{
|
||||
assert(!"wcstol() NYI");
|
||||
return 0;
|
||||
}
|
||||
18
src/libraries/libc/wchar/wcstold.cpp
Normal file
18
src/libraries/libc/wchar/wcstold.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file wcstold.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <wchar.h>
|
||||
|
||||
long double wcstold(const wchar_t * restrict nptr, wchar_t ** restrict endptr)
|
||||
{
|
||||
assert(!"wcstold() NYI");
|
||||
return 0;
|
||||
}
|
||||
18
src/libraries/libc/wchar/wcstoll.cpp
Normal file
18
src/libraries/libc/wchar/wcstoll.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file wcstoll.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <wchar.h>
|
||||
|
||||
long long wcstoll(const wchar_t * restrict nptr, wchar_t ** restrict endptr, int base)
|
||||
{
|
||||
assert(!"wcstoll() NYI");
|
||||
return 0;
|
||||
}
|
||||
18
src/libraries/libc/wchar/wcstoul.cpp
Normal file
18
src/libraries/libc/wchar/wcstoul.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file wcstoul.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <wchar.h>
|
||||
|
||||
unsigned long wcstoul(const wchar_t * restrict nptr, wchar_t ** restrict endptr, int base)
|
||||
{
|
||||
assert(!"wcstoul() NYI");
|
||||
return 0;
|
||||
}
|
||||
18
src/libraries/libc/wchar/wcstoull.cpp
Normal file
18
src/libraries/libc/wchar/wcstoull.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file wcstoull.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <wchar.h>
|
||||
|
||||
unsigned long long wcstoull(const wchar_t * restrict nptr, wchar_t ** restrict endptr, int base)
|
||||
{
|
||||
assert(!"wcstoull() NYI");
|
||||
return 0;
|
||||
}
|
||||
18
src/libraries/libc/wchar/wmemchr.cpp
Normal file
18
src/libraries/libc/wchar/wmemchr.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file wmemchr.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <wchar.h>
|
||||
|
||||
wchar_t * wmemchr(const wchar_t * s, wchar_t c, size_t n)
|
||||
{
|
||||
assert(!"wmemchr() NYI");
|
||||
return 0;
|
||||
}
|
||||
18
src/libraries/libc/wchar/wmememp.cpp
Normal file
18
src/libraries/libc/wchar/wmememp.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/** \file wmemcmp.cpp
|
||||
*
|
||||
* This file is part of the C standard library for the jsix operating
|
||||
* system.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <wchar.h>
|
||||
|
||||
int wmemcmp(const wchar_t * s1, const wchar_t * s2, size_t n)
|
||||
{
|
||||
assert(!"wmemcmp() NYI");
|
||||
return 0;
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
/**[[[cog code generation
|
||||
import cog
|
||||
from j6libc import definition, int_widths, int_mods
|
||||
from codegen.int_types import definition, int_widths, int_mods
|
||||
|
||||
for width in int_widths:
|
||||
definition("typedef", f"__INT{width}_TYPE__", f"int{width}_t;")
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
#include <assert.h>
|
||||
|
||||
#include <j6/syslog.hh>
|
||||
#include <pci/device.h>
|
||||
|
||||
#include "pci.h"
|
||||
namespace pci {
|
||||
|
||||
struct pci_cap_msi
|
||||
struct cap_msi
|
||||
{
|
||||
pci_cap::type id;
|
||||
cap::type id;
|
||||
uint8_t next;
|
||||
uint16_t control;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct pci_cap_msi32
|
||||
struct cap_msi32
|
||||
{
|
||||
pci_cap::type id;
|
||||
cap::type id;
|
||||
uint8_t next;
|
||||
uint16_t control;
|
||||
uint32_t address;
|
||||
@@ -23,9 +24,9 @@ struct pci_cap_msi32
|
||||
uint32_t pending;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct pci_cap_msi64
|
||||
struct cap_msi64
|
||||
{
|
||||
pci_cap::type id;
|
||||
cap::type id;
|
||||
uint8_t next;
|
||||
uint16_t control;
|
||||
uint64_t address;
|
||||
@@ -35,53 +36,23 @@ struct pci_cap_msi64
|
||||
uint32_t pending;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/*
|
||||
void dump_msi(pci_cap_msi *cap)
|
||||
{
|
||||
auto cons = console::get();
|
||||
cons->printf("MSI Cap:\n");
|
||||
cons->printf(" id: %02x\n", cap->id);
|
||||
cons->printf(" next: %02x\n", cap->next);
|
||||
cons->printf("control: %04x\n", cap->control);
|
||||
if (cap->control & 0x0080) {
|
||||
pci_cap_msi64 *cap64 = reinterpret_cast<pci_cap_msi64 *>(cap);
|
||||
cons->printf("address: %016x\n", cap64->address);
|
||||
cons->printf(" data: %04x\n", cap64->data);
|
||||
if (cap->control & 0x100) {
|
||||
cons->printf(" mask: %08x\n", cap64->mask);
|
||||
cons->printf("pending: %08x\n", cap64->pending);
|
||||
}
|
||||
} else {
|
||||
pci_cap_msi32 *cap32 = reinterpret_cast<pci_cap_msi32 *>(cap);
|
||||
cons->printf("address: %08x\n", cap32->address);
|
||||
cons->printf(" data: %04x\n", cap32->data);
|
||||
if (cap->control & 0x100) {
|
||||
cons->printf(" mask: %08x\n", cap32->mask);
|
||||
cons->printf("pending: %08x\n", cap32->pending);
|
||||
}
|
||||
}
|
||||
cons->putc('\n');
|
||||
};
|
||||
*/
|
||||
|
||||
pci_device::pci_device() :
|
||||
m_base(nullptr),
|
||||
m_bus_addr(0),
|
||||
m_vendor(0),
|
||||
m_device(0),
|
||||
m_class(0),
|
||||
m_subclass(0),
|
||||
m_progif(0),
|
||||
m_revision(0),
|
||||
m_header_type(0)
|
||||
device::device() :
|
||||
m_base {nullptr},
|
||||
m_bus_addr {0, 0, 0},
|
||||
m_vendor {0},
|
||||
m_device {0},
|
||||
m_class {0},
|
||||
m_subclass {0},
|
||||
m_progif {0},
|
||||
m_revision {0},
|
||||
m_header_type {0}
|
||||
{
|
||||
}
|
||||
|
||||
pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t func) :
|
||||
m_base(group.base_for(bus, device, func)),
|
||||
m_msi(nullptr),
|
||||
m_bus_addr(bus_addr(bus, device, func))
|
||||
device::device(bus_addr addr, uint32_t *base) :
|
||||
m_base {base},
|
||||
m_msi {nullptr},
|
||||
m_bus_addr {addr}
|
||||
{
|
||||
m_vendor = m_base[0] & 0xffff;
|
||||
m_device = (m_base[0] >> 16) & 0xffff;
|
||||
@@ -99,8 +70,10 @@ pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t fu
|
||||
|
||||
uint16_t *status = command + 1;
|
||||
|
||||
j6::syslog(j6::logs::srv, j6::log_level::info, "Found PCIe device at %02d:%02d:%d of type %x.%x.%x id %04x:%04x",
|
||||
bus, device, func, m_class, m_subclass, m_progif, m_vendor, m_device);
|
||||
j6::syslog(j6::logs::srv, j6::log_level::info,
|
||||
"Found PCIe device at %02d:%02d:%d of type %x.%x.%x id %04x:%04x",
|
||||
addr.bus, addr.device, addr.function,
|
||||
m_class, m_subclass, m_progif, m_vendor, m_device);
|
||||
|
||||
j6::syslog(j6::logs::srv, j6::log_level::verbose, " = BAR0 %016lld", get_bar(0));
|
||||
j6::syslog(j6::logs::srv, j6::log_level::verbose, " = BAR1 %016lld", get_bar(1));
|
||||
@@ -109,13 +82,13 @@ pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t fu
|
||||
// Walk the extended capabilities list
|
||||
uint8_t next = m_base[13] & 0xff;
|
||||
while (next) {
|
||||
pci_cap *cap = reinterpret_cast<pci_cap *>(util::offset_pointer(m_base, next));
|
||||
next = cap->next;
|
||||
//log::verbose(logs::device, " - found PCI cap type %02x", cap->id);
|
||||
cap *c = reinterpret_cast<cap *>(util::offset_pointer(m_base, next));
|
||||
next = c->next;
|
||||
//log::verbose(logs::device, " - found PCI cap type %02x", c->id);
|
||||
|
||||
if (cap->id == pci_cap::type::msi) {
|
||||
m_msi = cap;
|
||||
pci_cap_msi *mcap = reinterpret_cast<pci_cap_msi *>(cap);
|
||||
if (c->id == cap::type::msi) {
|
||||
m_msi = c;
|
||||
cap_msi *mcap = reinterpret_cast<cap_msi *>(c);
|
||||
mcap->control &= ~0x70; // at most 1 vector allocated
|
||||
mcap->control |= 0x01; // Enable interrupts, at most 1 vector allocated
|
||||
}
|
||||
@@ -124,20 +97,17 @@ pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t fu
|
||||
}
|
||||
|
||||
uint32_t
|
||||
pci_device::get_bar(unsigned i)
|
||||
device::get_bar(unsigned i)
|
||||
{
|
||||
if (m_header_type == 0) {
|
||||
assert(i < 6); // Device max BAR is 5
|
||||
} else {
|
||||
assert(m_header_type == 1); // Only device or bridge
|
||||
assert(i < 2); // Bridge max BAR is 1
|
||||
}
|
||||
if ((m_header_type == 0 && i > 5) || // Device max BAR is 5
|
||||
(m_header_type == 1 && i > 2)) // Bridge max BAR is 1
|
||||
return 0;
|
||||
|
||||
return m_base[4+i];
|
||||
}
|
||||
|
||||
void
|
||||
pci_device::set_bar(unsigned i, uint32_t val)
|
||||
device::set_bar(unsigned i, uint32_t val)
|
||||
{
|
||||
if (m_header_type == 0) {
|
||||
assert(i < 6); // Device max BAR is 5
|
||||
@@ -150,19 +120,19 @@ pci_device::set_bar(unsigned i, uint32_t val)
|
||||
}
|
||||
|
||||
void
|
||||
pci_device::write_msi_regs(uintptr_t address, uint16_t data)
|
||||
device::write_msi_regs(uintptr_t address, uint16_t data)
|
||||
{
|
||||
if (!m_msi)
|
||||
return;
|
||||
|
||||
if (m_msi->id == pci_cap::type::msi) {
|
||||
pci_cap_msi *mcap = reinterpret_cast<pci_cap_msi *>(m_msi);
|
||||
if (m_msi->id == cap::type::msi) {
|
||||
cap_msi *mcap = reinterpret_cast<cap_msi *>(m_msi);
|
||||
if (mcap->control & 0x0080) {
|
||||
pci_cap_msi64 *mcap64 = reinterpret_cast<pci_cap_msi64 *>(m_msi);
|
||||
cap_msi64 *mcap64 = reinterpret_cast<cap_msi64 *>(m_msi);
|
||||
mcap64->address = address;
|
||||
mcap64->data = data;
|
||||
} else {
|
||||
pci_cap_msi32 *mcap32 = reinterpret_cast<pci_cap_msi32 *>(m_msi);
|
||||
cap_msi32 *mcap32 = reinterpret_cast<cap_msi32 *>(m_msi);
|
||||
mcap32->address = address;
|
||||
mcap32->data = data;
|
||||
}
|
||||
@@ -175,8 +145,33 @@ pci_device::write_msi_regs(uintptr_t address, uint16_t data)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
pci_group::has_device(uint8_t bus, uint8_t device, uint8_t func)
|
||||
/*
|
||||
void dump_msi(cap_msi *cap)
|
||||
{
|
||||
return (*base_for(bus, device, func) & 0xffff) != 0xffff;
|
||||
}
|
||||
auto cons = console::get();
|
||||
cons->printf("MSI Cap:\n");
|
||||
cons->printf(" id: %02x\n", cap->id);
|
||||
cons->printf(" next: %02x\n", cap->next);
|
||||
cons->printf("control: %04x\n", cap->control);
|
||||
if (cap->control & 0x0080) {
|
||||
cap_msi64 *cap64 = reinterpret_cast<cap_msi64 *>(cap);
|
||||
cons->printf("address: %016x\n", cap64->address);
|
||||
cons->printf(" data: %04x\n", cap64->data);
|
||||
if (cap->control & 0x100) {
|
||||
cons->printf(" mask: %08x\n", cap64->mask);
|
||||
cons->printf("pending: %08x\n", cap64->pending);
|
||||
}
|
||||
} else {
|
||||
cap_msi32 *cap32 = reinterpret_cast<cap_msi32 *>(cap);
|
||||
cons->printf("address: %08x\n", cap32->address);
|
||||
cons->printf(" data: %04x\n", cap32->data);
|
||||
if (cap->control & 0x100) {
|
||||
cons->printf(" mask: %08x\n", cap32->mask);
|
||||
cons->printf("pending: %08x\n", cap32->pending);
|
||||
}
|
||||
}
|
||||
cons->putc('\n');
|
||||
};
|
||||
*/
|
||||
|
||||
} // namespace pci
|
||||
55
src/libraries/pci/group.cpp
Normal file
55
src/libraries/pci/group.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "pci/config.h"
|
||||
#include <j6/syslog.hh>
|
||||
#include <pci/config.h>
|
||||
#include <pci/device.h>
|
||||
#include <pci/group.h>
|
||||
|
||||
namespace pci {
|
||||
|
||||
//map config space into memory:
|
||||
//inline constexpr j6_vm_flags mmio_flags = (j6_vm_flags)(j6_vm_flag_write | j6_vm_flag_mmio);
|
||||
//map_phys(sys, group.base, pci::group::config_size, mmio_flags);
|
||||
group::iterator::iterator(const group &g, bus_addr a) :
|
||||
m_group {g}, m_addr {a}
|
||||
{
|
||||
increment_until_valid(false);
|
||||
}
|
||||
|
||||
void
|
||||
group::iterator::increment()
|
||||
{
|
||||
// If we're iterating functions, the device must be valid.
|
||||
// Finish iterating all functions.
|
||||
if (m_addr.function && m_addr.function < bus_addr::max_functions) {
|
||||
++m_addr.function;
|
||||
return;
|
||||
}
|
||||
|
||||
m_addr.function = 0;
|
||||
if (m_addr.device < bus_addr::max_devices) {
|
||||
++m_addr.device;
|
||||
return;
|
||||
}
|
||||
|
||||
m_addr.device = 0;
|
||||
++m_addr.bus;
|
||||
}
|
||||
|
||||
void
|
||||
group::iterator::increment_until_valid(bool pre_increment)
|
||||
{
|
||||
if (pre_increment)
|
||||
increment();
|
||||
|
||||
bus_addr end_addr = {0, 0, uint16_t(m_group.bus_end+1)};
|
||||
if (!m_group.has_device(m_addr) && m_addr < end_addr)
|
||||
increment();
|
||||
}
|
||||
|
||||
bool
|
||||
group::has_device(bus_addr addr) const
|
||||
{
|
||||
return device_base(addr)->vendor != 0xffff;
|
||||
}
|
||||
|
||||
} // namespace pci
|
||||
28
src/libraries/pci/include/pci/bus_addr.h
Normal file
28
src/libraries/pci/include/pci/bus_addr.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
/// \file bus_addr.h
|
||||
/// PCIe Bus Address structure
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace pci {
|
||||
|
||||
/// Bus address: 15:8 bus, 7:3 device, 2:0 device
|
||||
struct bus_addr
|
||||
{
|
||||
static constexpr uint16_t max_functions = 8;
|
||||
static constexpr uint16_t max_devices = 32;
|
||||
|
||||
uint16_t function : 3;
|
||||
uint16_t device : 5;
|
||||
uint16_t bus : 8;
|
||||
|
||||
uint16_t as_int() const { return *reinterpret_cast<const uint16_t*>(this); }
|
||||
operator uint16_t() const { return as_int(); }
|
||||
};
|
||||
|
||||
inline bool operator==(const bus_addr &a, const bus_addr &b) { return a.as_int() == b.as_int(); }
|
||||
inline bool operator!=(const bus_addr &a, const bus_addr &b) { return a.as_int() != b.as_int(); }
|
||||
inline bool operator< (const bus_addr &a, const bus_addr &b) { return a.as_int() < b.as_int(); }
|
||||
inline bool operator> (const bus_addr &a, const bus_addr &b) { return a.as_int() > b.as_int(); }
|
||||
|
||||
} // namespace pci
|
||||
131
src/libraries/pci/include/pci/config.h
Normal file
131
src/libraries/pci/include/pci/config.h
Normal file
@@ -0,0 +1,131 @@
|
||||
#pragma once
|
||||
/// \file config.h
|
||||
/// PCIe device configuration headers
|
||||
|
||||
#include <stdint.h>
|
||||
#include <util/bitset.h>
|
||||
|
||||
namespace pci {
|
||||
|
||||
/// Command register bits
|
||||
enum class control
|
||||
{
|
||||
io_space, // Respond to IO space access
|
||||
mem_space, // Respond to memory space access
|
||||
bus_master, // Allow acting as a bus master
|
||||
special, // (Not in PCIe) Enable Special Cycle
|
||||
mwi_enable, // (Not in PCIe) Enable Memory Write and Invalidate
|
||||
vga_snoop, // (Not in PCIe) Enable VGA Palette Snoop
|
||||
parity_err, // Enable PERR# assertion for parity errors
|
||||
reserved7,
|
||||
serr_enable, // Enable SERR# pin
|
||||
fb2b_enable, // (Not in PCIe) Allow fast back-to-back
|
||||
int_disable, // Disable INTx# assertions
|
||||
};
|
||||
|
||||
/// Status register bits
|
||||
enum class status
|
||||
{
|
||||
intr = 3, // Interrupt status
|
||||
caps = 4, // Has capability list
|
||||
mhz66 = 5, // (Not in PCIe) Can run at 66MHz
|
||||
fb2b = 7, // (Not in PCIe) Supports fast back-to-back
|
||||
md_parity = 8, // Master data parity error
|
||||
tgt_abort_s = 11, // Target-Abort sent
|
||||
tgt_abort_r = 12, // Target-Abort received
|
||||
mst_abort_r = 13, // Master-Abort received
|
||||
sys_err_s = 14, // SERR# asserted
|
||||
parity = 15, // Parity error dedected
|
||||
};
|
||||
|
||||
struct header_base
|
||||
{
|
||||
uint16_t vendor; // Vendor ID
|
||||
uint16_t device; // Vendor's device ID
|
||||
|
||||
util::bitset16 command;
|
||||
util::bitset16 status;
|
||||
|
||||
uint8_t revision; // Device revision
|
||||
uint8_t device_class[3];
|
||||
|
||||
uint8_t cache_line; // Not used in PCIe
|
||||
uint8_t master_latency; // Not used in PCIe
|
||||
uint8_t header_type : 7;
|
||||
uint8_t multi_device : 1;
|
||||
uint8_t bist; // Built-in Self Test
|
||||
};
|
||||
|
||||
struct header_unknown :
|
||||
public header_base
|
||||
{
|
||||
uint8_t unknown1[36];
|
||||
|
||||
uint8_t caps;
|
||||
uint8_t unknown2[7];
|
||||
|
||||
uint8_t int_line;
|
||||
uint8_t int_pin;
|
||||
|
||||
uint8_t unknown3[2];
|
||||
};
|
||||
|
||||
/// Device configuration header
|
||||
struct header0 :
|
||||
public header_base
|
||||
{
|
||||
uint32_t bar[6]; // Base address registers
|
||||
|
||||
uint32_t cis;
|
||||
|
||||
uint16_t subsystem_vendor;
|
||||
uint16_t subsystem;
|
||||
|
||||
uint32_t exrom;
|
||||
|
||||
uint8_t caps;
|
||||
uint8_t reserved1[3];
|
||||
uint32_t reserved2;
|
||||
|
||||
uint8_t int_line;
|
||||
uint8_t int_pin;
|
||||
uint8_t min_gnt; // Not used in PCIe
|
||||
uint8_t max_lat; // Not used in PCIe
|
||||
};
|
||||
|
||||
/// Bridge configuration header
|
||||
struct header1 :
|
||||
public header_base
|
||||
{
|
||||
uint32_t bar[2]; // Base address registers
|
||||
|
||||
uint8_t pri_bus; // Not used in PCIe
|
||||
uint8_t sec_bus;
|
||||
uint8_t sub_bus;
|
||||
uint8_t sec_lat; // Not used in PCIe
|
||||
|
||||
uint8_t io_base;
|
||||
uint8_t io_limit;
|
||||
uint16_t sec_status;
|
||||
|
||||
uint16_t mem_base;
|
||||
uint16_t mem_limit;
|
||||
uint16_t prefetch_mem_base;
|
||||
uint16_t prefetch_mem_limit;
|
||||
|
||||
uint32_t prefetch_mem_base_high;
|
||||
uint32_t prefetch_mem_limit_high;
|
||||
uint16_t io_base_high;
|
||||
uint16_t io_limit_high;
|
||||
|
||||
uint8_t caps;
|
||||
uint8_t reserved1[3];
|
||||
|
||||
uint32_t exrom;
|
||||
|
||||
uint8_t int_line;
|
||||
uint8_t int_pin;
|
||||
uint16_t bridge_control;
|
||||
};
|
||||
|
||||
} // namespace pci
|
||||
88
src/libraries/pci/include/pci/device.h
Normal file
88
src/libraries/pci/include/pci/device.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
/// \file device.h
|
||||
/// PCIe device
|
||||
|
||||
#include <stdint.h>
|
||||
#include <pci/bus_addr.h>
|
||||
#include <util/pointers.h>
|
||||
|
||||
namespace pci {
|
||||
|
||||
struct cap
|
||||
{
|
||||
enum class type : uint8_t
|
||||
{
|
||||
msi = 0x05,
|
||||
msix = 0x11
|
||||
};
|
||||
|
||||
type id;
|
||||
uint8_t next;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/// Information about a discovered PCIe device
|
||||
class device
|
||||
{
|
||||
public:
|
||||
/// Default constructor creates an empty object.
|
||||
device();
|
||||
|
||||
/// Constructor
|
||||
/// \arg addr The bus address of this device
|
||||
/// \arg base Base address of this device's config space
|
||||
device(bus_addr addr, uint32_t *base);
|
||||
|
||||
/// Check if this device is multi-function.
|
||||
/// \returns True if this device is multi-function
|
||||
inline bool multi() const { return m_multi; }
|
||||
|
||||
/// Get the bus address of this device/function
|
||||
inline bus_addr addr() const { return m_bus_addr; }
|
||||
|
||||
/// Get the device class
|
||||
/// \returns The PCI device class
|
||||
inline uint8_t devclass() const { return m_class; }
|
||||
|
||||
/// Get the device subclass
|
||||
/// \returns The PCI device subclass
|
||||
inline uint8_t subclass() const { return m_subclass; }
|
||||
|
||||
/// Get the device program interface
|
||||
/// \returns The PCI device program interface
|
||||
inline uint8_t progif() const { return m_progif; }
|
||||
|
||||
/// Read one of the device's Base Address Registers
|
||||
/// \arg i Which BAR to read (up to 5 for non-bridges)
|
||||
/// \returns The contents of the BAR
|
||||
uint32_t get_bar(unsigned i);
|
||||
|
||||
/// Write one of the device's Base Address Registers
|
||||
/// \arg i Which BAR to read (up to 5 for non-bridges)
|
||||
/// \arg val The value to write
|
||||
void set_bar(unsigned i, uint32_t val);
|
||||
|
||||
/// Write to the MSI registers
|
||||
/// \arg addr The address to write to the MSI address registers
|
||||
/// \arg data The value to write to the MSI data register
|
||||
void write_msi_regs(uintptr_t addr, uint16_t data);
|
||||
|
||||
private:
|
||||
uint32_t *m_base;
|
||||
cap *m_msi;
|
||||
|
||||
bus_addr m_bus_addr;
|
||||
|
||||
uint16_t m_vendor;
|
||||
uint16_t m_device;
|
||||
|
||||
uint8_t m_class;
|
||||
uint8_t m_subclass;
|
||||
uint8_t m_progif;
|
||||
uint8_t m_revision;
|
||||
bool m_multi;
|
||||
|
||||
uint8_t m_header_type;
|
||||
};
|
||||
|
||||
} // namespace pci
|
||||
64
src/libraries/pci/include/pci/group.h
Normal file
64
src/libraries/pci/include/pci/group.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
/// \file pci.h
|
||||
/// PCIe devices and groups
|
||||
|
||||
#include <stdint.h>
|
||||
#include <pci/bus_addr.h>
|
||||
#include <util/pointers.h>
|
||||
|
||||
namespace pci {
|
||||
|
||||
struct header_unknown;
|
||||
|
||||
/// Represents data about a PCI bus group from the ACPI MCFG
|
||||
struct group
|
||||
{
|
||||
static constexpr size_t config_size = 0x1000'0000;
|
||||
|
||||
uint16_t group_id;
|
||||
uint16_t bus_start;
|
||||
uint16_t bus_end;
|
||||
|
||||
header_unknown *base;
|
||||
|
||||
/// Iterator that returns successive valid bus addresses for a group
|
||||
struct iterator {
|
||||
iterator(const group &g, bus_addr a = {0,0,0});
|
||||
iterator(const iterator &i) : m_group {i.m_group}, m_addr {i.m_addr} {}
|
||||
|
||||
inline const bus_addr & operator*() const { return m_addr; }
|
||||
inline const bus_addr * operator->() const { return &m_addr; }
|
||||
inline bus_addr & operator*() { return m_addr; }
|
||||
inline bus_addr * operator->() { return &m_addr; }
|
||||
|
||||
iterator & operator++() { increment_until_valid(); return *this; }
|
||||
iterator operator++(int) { iterator old = *this; increment_until_valid(); return old; }
|
||||
|
||||
friend bool operator==(const iterator &a, const iterator &b) { return a.m_addr == b.m_addr; }
|
||||
friend bool operator!=(const iterator &a, const iterator &b) { return a.m_addr != b.m_addr; }
|
||||
|
||||
private:
|
||||
void increment();
|
||||
void increment_until_valid(bool pre_increment=true);
|
||||
|
||||
const group &m_group;
|
||||
bus_addr m_addr;
|
||||
};
|
||||
|
||||
iterator begin() const { return iterator {*this, {0, 0, bus_start}}; }
|
||||
iterator end() const { return iterator {*this, {0, 0, uint16_t(bus_end + 1)}}; }
|
||||
|
||||
/// Get the base address of the MMIO configuration registers for a device
|
||||
/// \arg addr The bus address of the device
|
||||
/// \returns A pointer to the MMIO configuration registers
|
||||
inline header_unknown* device_base(bus_addr addr) const {
|
||||
return util::offset_pointer(base, addr.as_int() << 12);
|
||||
}
|
||||
|
||||
/// Check if the given device function is present.
|
||||
/// \arg addr The bus address of the device (relative to this group)
|
||||
/// \returns True if the device function is present
|
||||
bool has_device(bus_addr addr) const;
|
||||
};
|
||||
|
||||
} // namespace pci
|
||||
14
src/libraries/pci/pci.module
Normal file
14
src/libraries/pci/pci.module
Normal file
@@ -0,0 +1,14 @@
|
||||
# vim: ft=python
|
||||
|
||||
module("pci",
|
||||
kind = "lib",
|
||||
deps = [ "libc", "util" ],
|
||||
sources = [
|
||||
"device.cpp",
|
||||
"group.cpp",
|
||||
],
|
||||
public_headers = [
|
||||
"pci/bus_addr.h",
|
||||
"pci/device.h",
|
||||
"pci/group.h",
|
||||
])
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user