Compare commits
149 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1ddbd2cf1 | ||
|
|
81b331e5da | ||
|
|
1ebee17880 | ||
|
|
4649d5f77b | ||
|
|
d3c1d6cc34 | ||
|
|
ee24ec8d5c | ||
|
|
372325fab7 | ||
|
|
8f036d9293 | ||
|
|
e345cdd1a7 | ||
|
|
fca570a163 | ||
|
|
ff64d1989f | ||
|
|
d3f5db2479 | ||
|
|
fa587060f1 | ||
|
|
b137c75eb2 | ||
|
|
05c1361283 | ||
|
|
c6835dad70 | ||
|
|
e7fa1dde97 | ||
|
|
eb62588b79 | ||
|
|
29332cbd45 | ||
|
|
172eb70551 | ||
|
|
7322df98f5 | ||
| 70af5a31cd | |||
| 0ab2f59fe8 | |||
| ab84cdb790 | |||
| da9041823b | |||
| 2d7cfc6c59 | |||
| cee4fe67fc | |||
| 53f90f5a1d | |||
| bab2dd5c69 | |||
| 3b9efc11d0 | |||
| 182d3b0a6a | |||
|
|
ed38e989b1 | ||
|
|
1bc6f422c5 | ||
|
|
4909d15c20 | ||
|
|
e725795a17 | ||
|
|
d8a21608c3 | ||
|
|
396fc131e0 | ||
|
|
40130076b2 | ||
|
|
9f54927a82 | ||
|
|
f7ea46e49e | ||
|
|
bc46c9a7d5 | ||
|
|
a1e2c58afc | ||
|
|
4e73e933db | ||
|
|
9f8e75f680 | ||
|
|
e17119254b | ||
|
|
17261622c6 | ||
|
|
dff9e53658 | ||
|
|
0bf709a339 | ||
|
|
c245949ea4 | ||
|
|
c27f8baa31 | ||
|
|
f51f519c31 | ||
|
|
55a485ee67 | ||
|
|
ba6e8e1349 | ||
|
|
75d30fb56d | ||
|
|
4abcf238a0 | ||
|
|
c05b4211fa | ||
|
|
337b8bb36b | ||
|
|
97433fc7d1 | ||
|
|
fc16ed54b3 | ||
|
|
8cbde13139 | ||
|
|
646a534dfd | ||
|
|
eda816ad90 | ||
|
|
c4bb60299e | ||
|
|
3cfd0cf86b | ||
|
|
8b3fa3ed01 | ||
|
|
a0f91ed0fd | ||
|
|
77590b31a6 | ||
|
|
ce27749705 | ||
|
|
b239bb6df2 | ||
|
|
28379dc0f6 | ||
|
|
c86c0f2ae6 | ||
|
|
bbe27c6b53 | ||
|
|
21916ab869 | ||
|
|
778e766f6b | ||
|
|
5d1fdd0e81 | ||
|
|
f5208d1641 | ||
|
|
a7beb0df18 | ||
|
|
1ec46ee641 | ||
|
|
3ba0600694 | ||
|
|
a449a88395 | ||
|
|
4bf03266a9 | ||
|
|
4bceac3d56 | ||
|
|
350396d70f | ||
|
|
ad3afae315 | ||
|
|
0dc86f2a0d | ||
|
|
2b3c276f33 | ||
|
|
8bf2425c4a | ||
|
|
72530ccb15 | ||
|
|
da14fd123e | ||
|
|
f215b98f74 | ||
|
|
b5662bfd25 | ||
|
|
3b3857548c | ||
|
|
1e2e154747 | ||
|
|
2d8d4fd200 | ||
|
|
459b40ad57 | ||
|
|
90cf1e2220 | ||
|
|
692e0d8656 | ||
|
|
3ab1a6b170 | ||
|
|
069bc63d1f | ||
|
|
373121c455 | ||
|
|
936b12a977 | ||
|
|
2a4c286f2b | ||
|
|
bfab4f085e | ||
|
|
201e7191ef | ||
|
|
9fa588566f | ||
|
|
ed95574c24 | ||
|
|
0c777bc62f | ||
|
|
1d7d5e8015 | ||
|
|
95627ba43c | ||
|
|
841ac41e36 | ||
|
|
a46d8bce37 | ||
|
|
4052911ac4 | ||
|
|
3a7a18011c | ||
|
|
15e2f8abf3 | ||
|
|
6b43ddc8d7 | ||
|
|
508058c3d7 | ||
|
|
4c9ff44b1c | ||
|
|
c092e07832 | ||
|
|
abe7fe37d0 | ||
|
|
cca8e8b3ad | ||
|
|
7c194950bb | ||
|
|
723f7d0330 | ||
|
|
274891854f | ||
|
|
94b2a79f79 | ||
|
|
d2a6113fb7 | ||
|
|
55c88dd943 | ||
|
|
42db1e8899 | ||
|
|
38ca7004a6 | ||
|
|
8817766469 | ||
|
|
e250aaef30 | ||
|
|
7b29ba7d23 | ||
|
|
dc30437ce7 | ||
|
|
2c2398b549 | ||
|
|
bce01591f3 | ||
|
|
847ef1ccfe | ||
|
|
6fa9b33ac0 | ||
|
|
df6d5b3b16 | ||
|
|
4884a624d9 | ||
|
|
ea587076ed | ||
|
|
0eddb002f0 | ||
|
|
8f968f4954 | ||
|
|
094b54d728 | ||
|
|
4125175870 | ||
|
|
1cb8f1258d | ||
|
|
f05a1d3310 | ||
|
|
71069cb38b | ||
|
|
393db1e792 | ||
|
|
0a097ec7d3 | ||
|
|
ada660deeb |
56
.github/workflows/sphinx_deploy.yml
vendored
Normal file
56
.github/workflows/sphinx_deploy.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
name: Deploy docs site with Sphinx
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
|
||||||
|
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
|
||||||
|
concurrency:
|
||||||
|
group: "pages"
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
# Default to bash
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
- name: Setup Pages
|
||||||
|
id: pages
|
||||||
|
uses: actions/configure-pages@v4
|
||||||
|
- name: Sphinx build
|
||||||
|
uses: jsix-os/sphinx-action@master
|
||||||
|
with:
|
||||||
|
docs-folder: "docs/"
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
with:
|
||||||
|
path: ./docs/_build/html
|
||||||
|
|
||||||
|
# Deployment job
|
||||||
|
deploy:
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
steps:
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v4
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -3,7 +3,7 @@
|
|||||||
/build*
|
/build*
|
||||||
*.bak
|
*.bak
|
||||||
tags
|
tags
|
||||||
jsix.log
|
*.log
|
||||||
*.out
|
*.out
|
||||||
*.o
|
*.o
|
||||||
*.a
|
*.a
|
||||||
@@ -13,3 +13,7 @@ sysroot
|
|||||||
__pycache__
|
__pycache__
|
||||||
/venv
|
/venv
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
buddy_allocs.txt
|
||||||
|
frame_allocs.txt
|
||||||
|
heap_allocs.txt
|
||||||
|
/docs/_build
|
||||||
|
|||||||
19
.vscode/c_cpp_properties.json
vendored
Normal file
19
.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Linux",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/src/libraries/**",
|
||||||
|
"${workspaceFolder}/build/**",
|
||||||
|
"${workspaceFolder}/sysroot/include"
|
||||||
|
],
|
||||||
|
"defines": [],
|
||||||
|
"compilerPath": "/usr/bin/clang",
|
||||||
|
"cStandard": "c17",
|
||||||
|
"cppStandard": "c++17",
|
||||||
|
"intelliSenseMode": "linux-clang-x64",
|
||||||
|
"compileCommands": "${workspaceFolder}/compile_commands.json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
||||||
32
.vscode/launch.json
vendored
Normal file
32
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "QEMU Debug Server",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/build/jsix.elf",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"logging": {
|
||||||
|
//"engineLogging": true,
|
||||||
|
"programOutput": true
|
||||||
|
},
|
||||||
|
"stopAtConnect": true,
|
||||||
|
"stopAtEntry": false,
|
||||||
|
|
||||||
|
"setupCommands": [
|
||||||
|
{"text": "dashboard -enabled off", "ignoreFailures": true}
|
||||||
|
],
|
||||||
|
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"miDebuggerServerAddress": "localhost:1234",
|
||||||
|
"debugServerPath": "${workspaceFolder}/qemu.sh",
|
||||||
|
"debugServerArgs": "--debug --no-build",
|
||||||
|
"serverLaunchTimeout": 5000,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
45
.vscode/tasks.json
vendored
45
.vscode/tasks.json
vendored
@@ -1,28 +1,41 @@
|
|||||||
{
|
{
|
||||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
// for the documentation about the tasks.json format
|
// for the documentation about the tasks.json format
|
||||||
"version": "0.1.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"taskName": "make",
|
"label": "Ninja",
|
||||||
"command": "make.bat",
|
"type": "shell",
|
||||||
"isBuildCommand": true
|
"command": "source ${workspaceFolder}/venv/bin/activate.fish; ninja",
|
||||||
|
"detail": "Build the project",
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}/build"
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskName": "clean",
|
"label": "Run QEMU",
|
||||||
"command": "make.bat",
|
"command": "./qemu.sh",
|
||||||
"args": [ "clean" ],
|
"args": [ "--no-build", "--kvm" ],
|
||||||
"isShellCommand": true
|
"dependsOn": ["Ninja"],
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskName": "qemu (windowed)",
|
"label": "clean",
|
||||||
"command": "qemu-win.bat",
|
"command": "${workspaceFolder}/venv/bin/ninja",
|
||||||
"showOutput": "never",
|
"options": {
|
||||||
"isTestCommand": true
|
"cwd": "${workspaceFolder}/build"
|
||||||
},
|
},
|
||||||
{
|
"args": [
|
||||||
"taskName": "qemu",
|
"-t",
|
||||||
"command": "qemu.bat"
|
"clean"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
---
|
|
||||||
variables:
|
|
||||||
cc: "${source_root}/sysroot/bin/clang"
|
|
||||||
cxx: "${source_root}/sysroot/bin/clang++"
|
|
||||||
ld: "${source_root}/sysroot/bin/ld.lld"
|
|
||||||
ar: ar
|
|
||||||
nasm: nasm
|
|
||||||
objcopy: objcopy
|
|
||||||
|
|
||||||
ccflags: [
|
|
||||||
"-I${source_root}/src/include",
|
|
||||||
"-I${source_root}/src/include/x86_64",
|
|
||||||
"-fcolor-diagnostics",
|
|
||||||
"-U__STDCPP_THREADS__",
|
|
||||||
"-D_LIBCPP_HAS_NO_THREADS",
|
|
||||||
"-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", "-Wfloat-equal", "-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" ]
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
---
|
|
||||||
extends: base
|
|
||||||
|
|
||||||
variables:
|
|
||||||
ld: clang++
|
|
||||||
|
|
||||||
ccflags: [
|
|
||||||
"-nostdlib",
|
|
||||||
"-nodefaultlibs",
|
|
||||||
"-fno-builtin",
|
|
||||||
|
|
||||||
"-I${source_root}/external",
|
|
||||||
"--target=x86_64-unknown-windows",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-mno-red-zone",
|
|
||||||
"-fshort-wchar",
|
|
||||||
"-fno-omit-frame-pointer",
|
|
||||||
"-ggdb",
|
|
||||||
"-g3" ]
|
|
||||||
|
|
||||||
cxxflags: [ "-fno-exceptions", "-fno-rtti" ]
|
|
||||||
|
|
||||||
ldflags: [
|
|
||||||
"--target=x86_64-unknown-windows",
|
|
||||||
"-nostdlib",
|
|
||||||
"-Wl,-entry:efi_main",
|
|
||||||
"-Wl,-subsystem:efi_application",
|
|
||||||
"-fuse-ld=lld-link",
|
|
||||||
"-g" ]
|
|
||||||
|
|
||||||
9
assets/build/config.debug.yaml
Normal file
9
assets/build/config.debug.yaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
ccflags: [
|
||||||
|
"-g3",
|
||||||
|
"-ggdb",
|
||||||
|
]
|
||||||
|
|
||||||
|
ldflags: [
|
||||||
|
"-g",
|
||||||
|
]
|
||||||
3
assets/build/config.release.yaml
Normal file
3
assets/build/config.release.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ccflags: [
|
||||||
|
"-O3",
|
||||||
|
]
|
||||||
39
assets/build/global.yaml
Normal file
39
assets/build/global.yaml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
cc: "${source_root}/sysroot/bin/clang"
|
||||||
|
cxx: "${source_root}/sysroot/bin/clang++"
|
||||||
|
ld: "${source_root}/sysroot/bin/ld.lld"
|
||||||
|
ar: ar
|
||||||
|
nasm: nasm
|
||||||
|
objcopy: objcopy
|
||||||
|
|
||||||
|
ccflags: [
|
||||||
|
"-I${source_root}/src/include",
|
||||||
|
"-fcolor-diagnostics",
|
||||||
|
"-U__STDCPP_THREADS__",
|
||||||
|
"-D_LIBCPP_HAS_NO_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" ]
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
---
|
|
||||||
extends: base
|
|
||||||
|
|
||||||
variables:
|
|
||||||
asflags: [ "-I${source_root}/src/kernel/" ]
|
|
||||||
|
|
||||||
ccflags: [
|
|
||||||
"--target=x86_64-jsix-elf",
|
|
||||||
"-fno-stack-protector",
|
|
||||||
|
|
||||||
"-I${source_root}/external",
|
|
||||||
|
|
||||||
"-nostdinc",
|
|
||||||
"-nostdlib",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-nodefaultlibs",
|
|
||||||
"-fno-builtin",
|
|
||||||
"-fno-plt",
|
|
||||||
|
|
||||||
"-mno-sse",
|
|
||||||
"-fno-omit-frame-pointer",
|
|
||||||
"-mno-red-zone",
|
|
||||||
"-mcmodel=kernel",
|
|
||||||
"-fvisibility=hidden",
|
|
||||||
"-fvisibility-inlines-hidden",
|
|
||||||
|
|
||||||
"-g3",
|
|
||||||
"-ggdb",
|
|
||||||
|
|
||||||
"-D__ELF__",
|
|
||||||
"-D__jsix__",
|
|
||||||
"-D__j6kernel",
|
|
||||||
"-U__linux",
|
|
||||||
"-U__linux__",
|
|
||||||
"-DPRINTF_ALIAS_STANDARD_FUNCTION_NAMES=1",
|
|
||||||
"-DPRINTF_INCLUDE_CONFIG_H=1",
|
|
||||||
|
|
||||||
"-isystem${build_root}/include/libc",
|
|
||||||
"-isystem${source_root}/sysroot/include",
|
|
||||||
"--sysroot='${source_root}/sysroot'" ]
|
|
||||||
|
|
||||||
|
|
||||||
cflags: [ '-nostdinc' ]
|
|
||||||
|
|
||||||
cxxflags: [
|
|
||||||
"-fno-exceptions",
|
|
||||||
"-fno-rtti",
|
|
||||||
"-nostdinc",
|
|
||||||
"-isystem${source_root}/sysroot/include/c++/v1" ]
|
|
||||||
|
|
||||||
ldflags: [
|
|
||||||
"-g",
|
|
||||||
"-m", "elf_x86_64",
|
|
||||||
"-nostdlib",
|
|
||||||
"-Bstatic",
|
|
||||||
"--no-eh-frame-hdr",
|
|
||||||
"-z", "norelro",
|
|
||||||
"-z", "separate-code" ]
|
|
||||||
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
# This file is automatically generated by bonnibel
|
|
||||||
|
|
||||||
rule compile.c
|
rule compile.c
|
||||||
command = $cc -MMD -MF $out.d $cflags $ccflags -o $out -c $in
|
command = $cc -MMD -MF $out.d $cflags $ccflags -o $out -c $in
|
||||||
description = Compiling $name
|
description = Compiling [$target]:$name
|
||||||
depfile = $out.d
|
depfile = $out.d
|
||||||
deps = gcc
|
deps = gcc
|
||||||
|
|
||||||
@@ -17,7 +15,7 @@ rule dump_c_run
|
|||||||
|
|
||||||
rule compile.cpp
|
rule compile.cpp
|
||||||
command = $cxx -MMD -MF $out.d $cxxflags $ccflags -o $out -c $in
|
command = $cxx -MMD -MF $out.d $cxxflags $ccflags -o $out -c $in
|
||||||
description = Compiling $name
|
description = Compiling [$target]:$name
|
||||||
depfile = $out.d
|
depfile = $out.d
|
||||||
deps = gcc
|
deps = gcc
|
||||||
|
|
||||||
@@ -32,25 +30,33 @@ rule dump_cpp_run
|
|||||||
|
|
||||||
rule compile.s
|
rule compile.s
|
||||||
command = $nasm -o $out -felf64 -MD $out.d $asflags $in
|
command = $nasm -o $out -felf64 -MD $out.d $asflags $in
|
||||||
description = Assembling $name
|
description = Assembling [$target]:$name
|
||||||
depfile = $out.d
|
depfile = $out.d
|
||||||
deps = gcc
|
deps = gcc
|
||||||
|
|
||||||
rule parse.cog
|
rule parse.cog
|
||||||
command = cog -o $out -d -D target=$target $cogflags $in
|
command = cog -o $out -d -D target=$target $cogflags $in
|
||||||
description = Parsing $name
|
description = Parsing [$target]:$name
|
||||||
|
|
||||||
rule exe
|
rule exe
|
||||||
command = $ld $ldflags -o $out $in $libs
|
command = $ld $ldflags -o $out $in $libs
|
||||||
description = Linking $name
|
description = Linking exe [$target]:$name
|
||||||
|
|
||||||
|
rule driver
|
||||||
|
command = $ld $ldflags -o $out $in $libs
|
||||||
|
description = Linking driver [$target]:$name
|
||||||
|
|
||||||
rule lib
|
rule lib
|
||||||
|
command = $ld -shared -soname $soname $ldflags -o $out $in $libs
|
||||||
|
description = Linking [$target]:$name
|
||||||
|
|
||||||
|
rule lib_static
|
||||||
command = $ar qcs $out $in
|
command = $ar qcs $out $in
|
||||||
description = Archiving $name
|
description = Archiving [$target]:$name
|
||||||
|
|
||||||
rule cp
|
rule cp
|
||||||
command = cp $in $out
|
command = cp $in $out
|
||||||
description = Copying $name
|
description = Copying [$target]:$name
|
||||||
|
|
||||||
rule dump
|
rule dump
|
||||||
command = objdump -DSC -M intel $in > $out
|
command = objdump -DSC -M intel $in > $out
|
||||||
|
|||||||
26
assets/build/target.boot.yaml
Normal file
26
assets/build/target.boot.yaml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
ld: clang++
|
||||||
|
|
||||||
|
ccflags: [
|
||||||
|
"-nostdlib",
|
||||||
|
"-nodefaultlibs",
|
||||||
|
"-fno-builtin",
|
||||||
|
|
||||||
|
"-I${source_root}/external",
|
||||||
|
"--target=x86_64-unknown-windows",
|
||||||
|
"-ffreestanding",
|
||||||
|
"-mno-red-zone",
|
||||||
|
"-fshort-wchar",
|
||||||
|
"-fno-omit-frame-pointer",
|
||||||
|
]
|
||||||
|
|
||||||
|
cxxflags: [ "-fno-exceptions", "-fno-rtti" ]
|
||||||
|
|
||||||
|
ldflags: [
|
||||||
|
"--target=x86_64-unknown-windows",
|
||||||
|
"-nostdlib",
|
||||||
|
"-Wl,-entry:efi_main",
|
||||||
|
"-Wl,-subsystem:efi_application",
|
||||||
|
"-fuse-ld=lld-link",
|
||||||
|
]
|
||||||
|
|
||||||
40
assets/build/target.init.yaml
Normal file
40
assets/build/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",
|
||||||
|
]
|
||||||
52
assets/build/target.kernel.yaml
Normal file
52
assets/build/target.kernel.yaml
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
asflags: [ "-I${source_root}/src/kernel/" ]
|
||||||
|
|
||||||
|
ccflags: [
|
||||||
|
"--target=x86_64-jsix-elf",
|
||||||
|
"-fno-stack-protector",
|
||||||
|
|
||||||
|
"-I${source_root}/external",
|
||||||
|
|
||||||
|
"-nostdinc",
|
||||||
|
"-nostdlib",
|
||||||
|
"-ffreestanding",
|
||||||
|
"-nodefaultlibs",
|
||||||
|
"-fno-builtin",
|
||||||
|
"-fno-plt",
|
||||||
|
|
||||||
|
"-mno-sse",
|
||||||
|
"-fno-omit-frame-pointer",
|
||||||
|
"-mno-red-zone",
|
||||||
|
"-mcmodel=kernel",
|
||||||
|
"-fvisibility=hidden",
|
||||||
|
"-fvisibility-inlines-hidden",
|
||||||
|
|
||||||
|
"-D__ELF__",
|
||||||
|
"-D__jsix__",
|
||||||
|
"-D__j6kernel",
|
||||||
|
"-U__linux",
|
||||||
|
"-U__linux__",
|
||||||
|
"-DPRINTF_ALIAS_STANDARD_FUNCTION_NAMES=1",
|
||||||
|
"-DPRINTF_INCLUDE_CONFIG_H=1",
|
||||||
|
|
||||||
|
"--sysroot='${source_root}/sysroot'"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
cflags: [ '-nostdinc' ]
|
||||||
|
|
||||||
|
cxxflags: [
|
||||||
|
"-fno-exceptions",
|
||||||
|
"-fno-rtti",
|
||||||
|
"-nostdinc",
|
||||||
|
]
|
||||||
|
|
||||||
|
ldflags: [
|
||||||
|
"-m", "elf_x86_64",
|
||||||
|
"-nostdlib",
|
||||||
|
"-Bstatic",
|
||||||
|
"--no-eh-frame-hdr",
|
||||||
|
"-z", "norelro",
|
||||||
|
"-z", "separate-code"
|
||||||
|
]
|
||||||
|
|
||||||
15
assets/build/target.user.exe.yaml
Normal file
15
assets/build/target.user.exe.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
ccflags: [
|
||||||
|
"-fpie"
|
||||||
|
]
|
||||||
|
|
||||||
|
ldflags: [
|
||||||
|
"-pie",
|
||||||
|
"--dynamic-linker", "/jsix/lib/ld.so",
|
||||||
|
"--push-state", "--as-needed", "-Bstatic", "-lc++", "-lc++abi", "-lunwind", "--pop-state",
|
||||||
|
]
|
||||||
|
|
||||||
|
libs: [
|
||||||
|
"${target_dir}/crt0.o",
|
||||||
|
]
|
||||||
7
assets/build/target.user.shared.yaml
Normal file
7
assets/build/target.user.shared.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
ccflags: [
|
||||||
|
]
|
||||||
|
|
||||||
|
ldflags: [
|
||||||
|
"-shared",
|
||||||
|
]
|
||||||
34
assets/build/target.user.yaml
Normal file
34
assets/build/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",
|
||||||
|
]
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
---
|
|
||||||
extends: base
|
|
||||||
|
|
||||||
variables:
|
|
||||||
asflags: [ "-I${source_root}/src/kernel/" ]
|
|
||||||
|
|
||||||
ccflags: [
|
|
||||||
"--target=x86_64-jsix-elf",
|
|
||||||
"-fno-omit-frame-pointer",
|
|
||||||
"-fno-stack-protector",
|
|
||||||
|
|
||||||
"-g",
|
|
||||||
|
|
||||||
"-D__ELF__",
|
|
||||||
"-D__jsix__",
|
|
||||||
"-U__linux",
|
|
||||||
"-U__linux__",
|
|
||||||
|
|
||||||
"-isystem${source_root}/sysroot/include",
|
|
||||||
"-isystem${build_root}/include/libc",
|
|
||||||
"--sysroot='${source_root}/sysroot'" ]
|
|
||||||
|
|
||||||
|
|
||||||
cxxflags: [
|
|
||||||
"-fno-exceptions",
|
|
||||||
"-fno-rtti",
|
|
||||||
"-isystem${source_root}/sysroot/include/c++/v1" ]
|
|
||||||
|
|
||||||
ldflags: [
|
|
||||||
"-g",
|
|
||||||
"-Bstatic",
|
|
||||||
"--sysroot='${source_root}/sysroot'",
|
|
||||||
"-L", "${source_root}/sysroot/lib",
|
|
||||||
"-z", "separate-code",
|
|
||||||
"-lc++", "-lc++abi", "-lunwind",
|
|
||||||
"--no-dependent-libraries",
|
|
||||||
]
|
|
||||||
|
|
||||||
@@ -1,8 +1,14 @@
|
|||||||
import gdb
|
import gdb
|
||||||
import gdb.printing
|
import gdb.printing
|
||||||
|
|
||||||
|
import sys
|
||||||
|
sys.path.append('./scripts')
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
Capability = namedtuple("Capability", ["id", "parent", "refcount", "caps", "type", "koid"])
|
Capability = namedtuple("Capability", ["id", "parent", "refcount", "caps", "type", "koid"])
|
||||||
|
LogEntry = namedtuple("LogHeader", ["id", "bytes", "severity", "area", "message"])
|
||||||
|
|
||||||
class PrintStackCommand(gdb.Command):
|
class PrintStackCommand(gdb.Command):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -168,12 +174,12 @@ class GetThreadsCommand(gdb.Command):
|
|||||||
rsp = int(gdb.parse_and_eval(f"{tcb}->rsp"))
|
rsp = int(gdb.parse_and_eval(f"{tcb}->rsp"))
|
||||||
pri = int(gdb.parse_and_eval(f"{tcb}->priority"))
|
pri = int(gdb.parse_and_eval(f"{tcb}->priority"))
|
||||||
flags = int(gdb.parse_and_eval(f"{thread}->m_state"))
|
flags = int(gdb.parse_and_eval(f"{thread}->m_state"))
|
||||||
koid = int(gdb.parse_and_eval(f"{thread}->m_koid"))
|
koid = int(gdb.parse_and_eval(f"{thread}->m_obj_id"))
|
||||||
proc = int(gdb.parse_and_eval(f"{thread}->m_parent.m_koid"))
|
proc = int(gdb.parse_and_eval(f"{thread}->m_parent.m_obj_id"))
|
||||||
|
|
||||||
creator = int(gdb.parse_and_eval(f"{thread}->m_creator"))
|
creator = int(gdb.parse_and_eval(f"{thread}->m_creator"))
|
||||||
if creator != 0:
|
if creator != 0:
|
||||||
creator_koid = int(gdb.parse_and_eval(f"{thread}->m_creator->m_koid"))
|
creator_koid = int(gdb.parse_and_eval(f"{thread}->m_creator->m_obj_id"))
|
||||||
creator = f"{creator_koid:x}"
|
creator = f"{creator_koid:x}"
|
||||||
else:
|
else:
|
||||||
creator = "<no thread>"
|
creator = "<no thread>"
|
||||||
@@ -233,11 +239,7 @@ class GetThreadsCommand(gdb.Command):
|
|||||||
self.print_cpudata(cpu)
|
self.print_cpudata(cpu)
|
||||||
|
|
||||||
previous = int(gdb.parse_and_eval(f"{runlist}.prev"))
|
previous = int(gdb.parse_and_eval(f"{runlist}.prev"))
|
||||||
if previous != 0:
|
print(f" prev: {previous:x}")
|
||||||
tcb = f"((TCB*){previous:#x})"
|
|
||||||
thread = f"({tcb}->thread)"
|
|
||||||
koid = int(gdb.parse_and_eval(f"{thread}->m_koid"))
|
|
||||||
print(f" prev: {koid:x}")
|
|
||||||
print()
|
print()
|
||||||
|
|
||||||
for pri in range(8):
|
for pri in range(8):
|
||||||
@@ -283,6 +285,79 @@ class PrintProfilesCommand(gdb.Command):
|
|||||||
print(f"{name:>{max_len}}: {avg:15.3f}")
|
print(f"{name:>{max_len}}: {avg:15.3f}")
|
||||||
|
|
||||||
|
|
||||||
|
class DumpLogCommand(gdb.Command):
|
||||||
|
level_names = ["", "fatal", "error", "warn", "info", "verbose", "spam"]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__("j6log", gdb.COMMAND_DATA)
|
||||||
|
|
||||||
|
from memory import Layout
|
||||||
|
layout = Layout("definitions/memory_layout.yaml")
|
||||||
|
for region in layout.regions:
|
||||||
|
if region.name == "logs":
|
||||||
|
self.base_addr = region.start
|
||||||
|
break
|
||||||
|
|
||||||
|
self.areas = []
|
||||||
|
area_re = re.compile(r"LOG\(\s*(\w+).*")
|
||||||
|
with open("src/libraries/j6/include/j6/tables/log_areas.inc", 'r') as areas_inc:
|
||||||
|
for line in areas_inc:
|
||||||
|
m = area_re.match(line)
|
||||||
|
if m:
|
||||||
|
self.areas.append(m.group(1))
|
||||||
|
|
||||||
|
def get_entry(self, addr):
|
||||||
|
addr = int(addr)
|
||||||
|
size = int(gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->bytes"))
|
||||||
|
mlen = size - 8
|
||||||
|
|
||||||
|
return LogEntry(
|
||||||
|
int(gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->id")),
|
||||||
|
size,
|
||||||
|
int(gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->severity")),
|
||||||
|
int(gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->area")),
|
||||||
|
gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->message").string(length=mlen))
|
||||||
|
|
||||||
|
def invoke(self, arg, from_tty):
|
||||||
|
start = gdb.parse_and_eval("g_logger.m_start & (g_logger.m_buffer.count - 1)")
|
||||||
|
end = gdb.parse_and_eval("g_logger.m_end & (g_logger.m_buffer.count - 1)")
|
||||||
|
if end < start:
|
||||||
|
end += gdb.parse_and_eval("g_logger.m_buffer.count")
|
||||||
|
|
||||||
|
print(f"Logs are {start} -> {end}")
|
||||||
|
|
||||||
|
addr = self.base_addr + start
|
||||||
|
end += self.base_addr
|
||||||
|
while addr < end:
|
||||||
|
entry = self.get_entry(addr)
|
||||||
|
if entry.bytes < 8:
|
||||||
|
print(f"Bad log header size: {entry.bytes}")
|
||||||
|
break
|
||||||
|
addr += entry.bytes
|
||||||
|
area = "??"
|
||||||
|
if entry.area < len(self.areas):
|
||||||
|
area = self.areas[entry.area]
|
||||||
|
level = self.level_names[entry.severity]
|
||||||
|
print(f"{area:>7}:{level:7} {entry.message}")
|
||||||
|
|
||||||
|
|
||||||
|
class ShowCurrentProcessCommand(gdb.Command):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__("j6current", gdb.COMMAND_DATA)
|
||||||
|
|
||||||
|
def invoke(self, arg, from_tty):
|
||||||
|
def get_obj_and_id(name):
|
||||||
|
obj = int(gdb.parse_and_eval(f"((cpu_data*)$gs_base)->{name}"))
|
||||||
|
oid = -1
|
||||||
|
if obj != 0:
|
||||||
|
oid = int(gdb.parse_and_eval(f"((obj::kobject*){obj:#x})->m_obj_id"))
|
||||||
|
return obj, oid
|
||||||
|
|
||||||
|
process, pid = get_obj_and_id("process")
|
||||||
|
thread, tid = get_obj_and_id("thread")
|
||||||
|
print(f"{pid:02x}/{tid:02x} [ {process:x} / {thread:x} ]")
|
||||||
|
|
||||||
|
|
||||||
class CapTablePrinter:
|
class CapTablePrinter:
|
||||||
def __init__(self, val):
|
def __init__(self, val):
|
||||||
node_map = val["m_caps"]
|
node_map = val["m_caps"]
|
||||||
@@ -307,7 +382,7 @@ class CapTablePrinter:
|
|||||||
refcount = int(node["holders"]),
|
refcount = int(node["holders"]),
|
||||||
caps = int(node["caps"]),
|
caps = int(node["caps"]),
|
||||||
type = str(node["type"])[14:],
|
type = str(node["type"])[14:],
|
||||||
koid = node['object']['m_koid']))
|
koid = node['object']['m_obj_id']))
|
||||||
|
|
||||||
self.nodes.sort(key=lambda n: n.id, reverse=True)
|
self.nodes.sort(key=lambda n: n.id, reverse=True)
|
||||||
|
|
||||||
@@ -399,11 +474,51 @@ class HandleSetPrinter:
|
|||||||
return self._iterator(self.node_map['m_nodes'], self.capacity)
|
return self._iterator(self.node_map['m_nodes'], self.capacity)
|
||||||
|
|
||||||
|
|
||||||
|
class LinkedListPrinter:
|
||||||
|
def __init__(self, llist):
|
||||||
|
self.name = llist.type.tag
|
||||||
|
self.head = llist['m_head']
|
||||||
|
self.tail = llist['m_tail']
|
||||||
|
|
||||||
|
self.items = []
|
||||||
|
current = self.head
|
||||||
|
while current:
|
||||||
|
item = current.dereference()
|
||||||
|
self.items.append((str(len(self.items)), item))
|
||||||
|
current = item['m_next']
|
||||||
|
|
||||||
|
class _iterator:
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return f"{self.name}[{len(self.items)}]"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.items
|
||||||
|
|
||||||
|
|
||||||
|
class IsRunning(gdb.Function):
|
||||||
|
def __init__(self):
|
||||||
|
super(IsRunning, self).__init__("is_running")
|
||||||
|
|
||||||
|
def invoke(self):
|
||||||
|
inferior = gdb.selected_inferior()
|
||||||
|
return \
|
||||||
|
inferior is not None and \
|
||||||
|
inferior.is_valid() and \
|
||||||
|
len(inferior.threads()) > 0
|
||||||
|
|
||||||
|
|
||||||
def build_pretty_printers():
|
def build_pretty_printers():
|
||||||
pp = gdb.printing.RegexpCollectionPrettyPrinter("jsix")
|
pp = gdb.printing.RegexpCollectionPrettyPrinter("jsix")
|
||||||
pp.add_printer("cap table", '^cap_table$', CapTablePrinter)
|
pp.add_printer("cap table", '^cap_table$', CapTablePrinter)
|
||||||
pp.add_printer("handle set", '^util::node_set<unsigned long, 0, heap_allocated>$', HandleSetPrinter)
|
pp.add_printer("handle set", '^util::node_set<unsigned long, 0, heap_allocated>$', HandleSetPrinter)
|
||||||
pp.add_printer("vector", '^util::vector<.*>$', VectorPrinter)
|
pp.add_printer("vector", '^util::vector<.*>$', VectorPrinter)
|
||||||
|
pp.add_printer("linked list", '^util::linked_list<.*>$', LinkedListPrinter)
|
||||||
return pp
|
return pp
|
||||||
|
|
||||||
gdb.printing.register_pretty_printer(
|
gdb.printing.register_pretty_printer(
|
||||||
@@ -415,8 +530,12 @@ PrintBacktraceCommand()
|
|||||||
TableWalkCommand()
|
TableWalkCommand()
|
||||||
GetThreadsCommand()
|
GetThreadsCommand()
|
||||||
PrintProfilesCommand()
|
PrintProfilesCommand()
|
||||||
|
DumpLogCommand()
|
||||||
|
ShowCurrentProcessCommand()
|
||||||
|
IsRunning()
|
||||||
|
|
||||||
gdb.execute("display/i $rip")
|
gdb.execute("display/i $rip")
|
||||||
|
gdb.execute("define hook-quit\nif $is_running()\n kill\nend\nend")
|
||||||
if not gdb.selected_inferior().was_attached:
|
if not gdb.selected_inferior().was_attached:
|
||||||
gdb.execute("add-symbol-file build/panic.serial.elf")
|
gdb.execute("add-symbol-file build/panic.serial.elf")
|
||||||
gdb.execute("target remote :1234")
|
gdb.execute("target remote :1234")
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ name: IDENTIFIER
|
|||||||
options: "[" ( OPTION | IDENTIFIER )+ "]"
|
options: "[" ( OPTION | IDENTIFIER )+ "]"
|
||||||
description: COMMENT+
|
description: COMMENT+
|
||||||
|
|
||||||
PRIMITIVE: INT_TYPE | "size" | "string" | "buffer" | "address"
|
PRIMITIVE: INT_TYPE "*"? | "size" | "string" | "buffer" | "address"
|
||||||
INT_TYPE: /u?int(8|16|32|64)?/
|
INT_TYPE: /u?int(8|16|32|64)?/
|
||||||
NUMBER: /(0x)?[0-9a-fA-F]+/
|
NUMBER: /(0x)?[0-9a-fA-F]+/
|
||||||
UID: /[0-9a-fA-F]{16}/
|
UID: /[0-9a-fA-F]{16}/
|
||||||
|
|||||||
@@ -8,5 +8,9 @@ panic:
|
|||||||
- panic.serial
|
- panic.serial
|
||||||
services:
|
services:
|
||||||
- srv.logger
|
- srv.logger
|
||||||
|
- testapp
|
||||||
drivers:
|
drivers:
|
||||||
- drv.uart
|
- drv.uart
|
||||||
|
- drv.uefi_fb
|
||||||
|
libs:
|
||||||
|
- ld.so
|
||||||
14
assets/manifests/minimal.yaml
Normal file
14
assets/manifests/minimal.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
location: jsix
|
||||||
|
init: srv.init
|
||||||
|
initrd:
|
||||||
|
name: initrd.dat
|
||||||
|
format: zstd
|
||||||
|
panic:
|
||||||
|
- panic.serial
|
||||||
|
services:
|
||||||
|
- srv.logger
|
||||||
|
drivers:
|
||||||
|
- drv.uart
|
||||||
|
libs:
|
||||||
|
- ld.so
|
||||||
14
assets/manifests/shell.yaml
Normal file
14
assets/manifests/shell.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
location: jsix
|
||||||
|
init: srv.init
|
||||||
|
initrd:
|
||||||
|
name: initrd.dat
|
||||||
|
format: zstd
|
||||||
|
panic:
|
||||||
|
- panic.serial
|
||||||
|
services:
|
||||||
|
- 6s
|
||||||
|
drivers:
|
||||||
|
- drv.uart
|
||||||
|
libs:
|
||||||
|
- ld.so
|
||||||
@@ -9,5 +9,3 @@ panic:
|
|||||||
- panic.serial
|
- panic.serial
|
||||||
services:
|
services:
|
||||||
- test_runner
|
- test_runner
|
||||||
drivers:
|
|
||||||
- drv.uart
|
|
||||||
|
|||||||
1
configure
vendored
1
configure
vendored
@@ -35,6 +35,7 @@ def generate(output, config, manifest):
|
|||||||
"source_root": root,
|
"source_root": root,
|
||||||
"build_root": output,
|
"build_root": output,
|
||||||
"module_root": path,
|
"module_root": path,
|
||||||
|
"config": config,
|
||||||
}
|
}
|
||||||
code = compile(open(modfile, 'r').read(), modfile, "exec")
|
code = compile(open(modfile, 'r').read(), modfile, "exec")
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,38 @@
|
|||||||
---
|
---
|
||||||
- name: linear
|
- name: linear
|
||||||
|
desc: Linearly-mapped physical memory
|
||||||
size: 64T
|
size: 64T
|
||||||
shared: true
|
shared: true
|
||||||
|
|
||||||
- name: bitmap
|
- name: bitmap
|
||||||
|
desc: Used/free page tracking bitmap
|
||||||
size: 1T
|
size: 1T
|
||||||
shared: true
|
shared: true
|
||||||
|
|
||||||
- name: heapmap
|
- name: heapmap
|
||||||
|
desc: Kernel heap accounting structures
|
||||||
size: 32G
|
size: 32G
|
||||||
|
|
||||||
- name: heap
|
- name: heap
|
||||||
|
desc: Kernel heap
|
||||||
size: 32G
|
size: 32G
|
||||||
|
|
||||||
- name: capsmap
|
- name: capsmap
|
||||||
|
desc: Capabilities accounting structures
|
||||||
size: 32G
|
size: 32G
|
||||||
|
|
||||||
- name: caps
|
- name: caps
|
||||||
|
desc: Capabilities
|
||||||
size: 32G
|
size: 32G
|
||||||
|
|
||||||
- name: stacks
|
- name: stacks
|
||||||
|
desc: Kernel thread stacks
|
||||||
size: 64G
|
size: 64G
|
||||||
|
|
||||||
- name: buffers
|
- name: buffers
|
||||||
|
desc: Kernel buffers
|
||||||
size: 64G
|
size: 64G
|
||||||
|
|
||||||
|
- name: logs
|
||||||
|
desc: Kernel logs circular buffer
|
||||||
|
size: 2G
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
object channel : object {
|
|
||||||
uid 3ea38b96aa0e54c8
|
|
||||||
|
|
||||||
capabilities [
|
|
||||||
send
|
|
||||||
receive
|
|
||||||
close
|
|
||||||
]
|
|
||||||
|
|
||||||
method create [constructor]
|
|
||||||
method close [destructor cap:close]
|
|
||||||
|
|
||||||
method send [cap:send] {
|
|
||||||
param data buffer [inout]
|
|
||||||
}
|
|
||||||
|
|
||||||
method receive [cap:receive] {
|
|
||||||
param data buffer [out]
|
|
||||||
param flags uint64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
# An ``event`` is a simple synchronization object. It contains up to 64 signals
|
||||||
|
# that threads can wait for and signal in parallel.
|
||||||
|
|
||||||
object event : object {
|
object event : object {
|
||||||
uid f441e03da5516b1a
|
uid f441e03da5516b1a
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# Mailboxes are objects that enable synchronous IPC via short message-passing
|
# Mailboxes are objects that enable synchronous IPC via arbitrary
|
||||||
# of tagged handles.
|
# message-passing of tagged data and/or handles. Not as efficient
|
||||||
|
# as shared memory channels, but more flexible.
|
||||||
|
|
||||||
object mailbox : object {
|
object mailbox : object {
|
||||||
uid 99934ad04ece1e07
|
uid 99934ad04ece1e07
|
||||||
@@ -13,13 +14,15 @@ object mailbox : object {
|
|||||||
method create [constructor]
|
method create [constructor]
|
||||||
method close [destructor cap:close]
|
method close [destructor cap:close]
|
||||||
|
|
||||||
# Send a message to the reciever, and block until a
|
# Send a message to the reciever, and block until a response is
|
||||||
# response is sent. Note that getting this response
|
# sent. Note that getting this response does not require the
|
||||||
# does not require the receive capability.
|
# receive capability.
|
||||||
method call [cap:send] {
|
method call [cap:send] {
|
||||||
param tag uint64 [inout]
|
param tag uint64 [inout]
|
||||||
param subtag uint64 [inout]
|
param data buffer [optional inout]
|
||||||
param give_handle ref object [optional inout handle]
|
param data_size size # number of total bytes in data buffer
|
||||||
|
param handles ref object [optional inout handle list]
|
||||||
|
param handles_size size # total size of handles buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
# Respond to a message sent using call, and wait for another
|
# Respond to a message sent using call, and wait for another
|
||||||
@@ -28,8 +31,10 @@ object mailbox : object {
|
|||||||
# to waiting for a new message.
|
# to waiting for a new message.
|
||||||
method respond [cap:receive] {
|
method respond [cap:receive] {
|
||||||
param tag uint64 [inout]
|
param tag uint64 [inout]
|
||||||
param subtag uint64 [inout]
|
param data buffer [optional inout]
|
||||||
param give_handle ref object [optional inout handle]
|
param data_size size # number of total bytes in data buffer
|
||||||
|
param handles ref object [optional inout handle list]
|
||||||
|
param handles_size size # total size of handles buffer
|
||||||
param reply_tag uint64 [inout]
|
param reply_tag uint64 [inout]
|
||||||
param flags uint64
|
param flags uint64
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
# The base type of all kernel-exposed objects
|
# All kernel-exposed objects inherit from the base ``object`` type, so the
|
||||||
|
# ``object`` syscalls can be used with any object's handle.
|
||||||
|
|
||||||
object object [virtual] {
|
object object [virtual] {
|
||||||
uid 667f61fb2cd57bb4
|
uid 667f61fb2cd57bb4
|
||||||
cname kobject
|
cname kobject
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import "objects/object.def"
|
import "objects/object.def"
|
||||||
|
|
||||||
# Processes are a collection of handles and a virtual memory
|
# A ``process`` object represents a process running on the system, and allows
|
||||||
# space inside which threads are run.
|
# control over the threads, handles, and virtual memory space of that process.
|
||||||
|
|
||||||
object process : object {
|
object process : object {
|
||||||
uid 0c69ee0b7502ba31
|
uid 0c69ee0b7502ba31
|
||||||
@@ -12,14 +12,16 @@ object process : object {
|
|||||||
]
|
]
|
||||||
|
|
||||||
# Create a new empty process
|
# Create a new empty process
|
||||||
method create [constructor]
|
method create [constructor] {
|
||||||
|
param name string
|
||||||
|
}
|
||||||
|
|
||||||
# Stop all threads and exit the given process
|
# Stop all threads and exit the given process
|
||||||
method kill [destructor cap:kill]
|
method kill [destructor cap:kill]
|
||||||
|
|
||||||
# Stop all threads and exit the current process
|
# Stop all threads and exit the current process
|
||||||
method exit [static noreturn] {
|
method exit [static noreturn] {
|
||||||
param result int32 # The result to retrun to the parent process
|
param result int64 # The result to retrun to the parent process
|
||||||
}
|
}
|
||||||
|
|
||||||
# Give the given process a handle that points to the same
|
# Give the given process a handle that points to the same
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# The system object represents a handle to kernel functionality
|
# The singular ``system`` object represents a handle to kernel functionality
|
||||||
# needed by drivers and other priviledged services
|
# needed by drivers and other priviledged services.
|
||||||
|
|
||||||
object system : object {
|
object system : object {
|
||||||
uid fa72506a2cf71a30
|
uid fa72506a2cf71a30
|
||||||
|
|
||||||
@@ -10,9 +11,10 @@ object system : object {
|
|||||||
change_iopl
|
change_iopl
|
||||||
]
|
]
|
||||||
|
|
||||||
# Get a log line from the kernel log
|
# Get the next log line from the kernel log
|
||||||
method get_log [cap:get_log] {
|
method get_log [cap:get_log] {
|
||||||
param buffer buffer [out zero_ok] # Buffer for the log message data structure
|
param seen uint64 # Last seen log id
|
||||||
|
param buffer buffer [out zero_ok] # Buffer for the log message data structure
|
||||||
}
|
}
|
||||||
|
|
||||||
# Ask the kernel to send this process messages whenever
|
# Ask the kernel to send this process messages whenever
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
# A ``thread`` object represents a thread of execution within a process running
|
||||||
|
# on the system. The actual thread does not need to be currently running to
|
||||||
|
# hold a handle to it.
|
||||||
|
|
||||||
object thread : object {
|
object thread : object {
|
||||||
uid 11f23e593d5761bd
|
uid 11f23e593d5761bd
|
||||||
|
|
||||||
@@ -7,9 +11,11 @@ object thread : object {
|
|||||||
]
|
]
|
||||||
|
|
||||||
method create [constructor] {
|
method create [constructor] {
|
||||||
param process ref process [cap:create_thread]
|
param process ref process [optional cap:create_thread]
|
||||||
param stack_top address
|
param stack_top address
|
||||||
param entrypoint address
|
param entrypoint address
|
||||||
|
param arg0 uint64
|
||||||
|
param arg1 uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
method kill [destructor cap:kill]
|
method kill [destructor cap:kill]
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import "objects/process.def"
|
import "objects/process.def"
|
||||||
|
|
||||||
|
# A ``vma`` object represents a single virtual memory area, which may be shared
|
||||||
|
# between several processes. A process having a handle to a ``vma`` does not
|
||||||
|
# necessarily mean that it is mapped into that process' virtual memory space.
|
||||||
|
|
||||||
object vma : object {
|
object vma : object {
|
||||||
uid d6a12b63b3ed3937
|
uid d6a12b63b3ed3937
|
||||||
cname vm_area
|
cname vm_area
|
||||||
@@ -17,20 +21,21 @@ object vma : object {
|
|||||||
|
|
||||||
method create_map [constructor cap:map] {
|
method create_map [constructor cap:map] {
|
||||||
param size size
|
param size size
|
||||||
param address address
|
param address address [inout]
|
||||||
param flags uint32
|
param flags uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
method map [cap:map] {
|
method map [cap:map] {
|
||||||
param process ref process
|
param process ref process [optional]
|
||||||
param address address
|
param address address [inout]
|
||||||
|
param flags uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
method unmap [cap:unmap] {
|
method unmap [cap:unmap] {
|
||||||
param process ref process
|
param process ref process [optional]
|
||||||
}
|
}
|
||||||
|
|
||||||
method resize [cap:resize] {
|
method resize [cap:resize] {
|
||||||
param size size [inout]
|
param size size [inout] # New size for the VMA, or 0 to query the current size without changing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import "objects/object.def"
|
import "objects/object.def"
|
||||||
|
|
||||||
import "objects/channel.def"
|
|
||||||
import "objects/event.def"
|
import "objects/event.def"
|
||||||
import "objects/mailbox.def"
|
import "objects/mailbox.def"
|
||||||
import "objects/process.def"
|
import "objects/process.def"
|
||||||
@@ -12,12 +11,12 @@ interface syscalls [syscall] {
|
|||||||
uid 01d9b6a948961097
|
uid 01d9b6a948961097
|
||||||
|
|
||||||
expose ref object
|
expose ref object
|
||||||
expose ref system
|
|
||||||
expose ref event
|
expose ref event
|
||||||
expose ref process
|
|
||||||
expose ref thread
|
|
||||||
expose ref mailbox
|
expose ref mailbox
|
||||||
expose ref channel
|
expose ref process
|
||||||
|
expose ref system
|
||||||
|
expose ref thread
|
||||||
expose ref vma
|
expose ref vma
|
||||||
|
|
||||||
# Simple no-op syscall for testing
|
# Simple no-op syscall for testing
|
||||||
@@ -25,6 +24,8 @@ interface syscalls [syscall] {
|
|||||||
|
|
||||||
# Write a message to the kernel log
|
# Write a message to the kernel log
|
||||||
function log {
|
function log {
|
||||||
|
param area uint8
|
||||||
|
param severity uint8
|
||||||
param message string
|
param message string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,6 +44,24 @@ interface syscalls [syscall] {
|
|||||||
param mask uint32 # The capability bitmask
|
param mask uint32 # The capability bitmask
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Close the handle to an object
|
||||||
|
function handle_close {
|
||||||
|
param hnd ref object [handle] # The handle to close
|
||||||
|
}
|
||||||
|
|
||||||
|
# Block waiting on a futex
|
||||||
|
function futex_wait [static] {
|
||||||
|
param address uint32* # Address of the futex value
|
||||||
|
param current uint32 # Current value of the futex
|
||||||
|
param timeout uint64 # Wait timeout in nanoseconds
|
||||||
|
}
|
||||||
|
|
||||||
|
# Wake threads waiting on a futex
|
||||||
|
function futex_wake [static] {
|
||||||
|
param address uint32* # Address of the futex value
|
||||||
|
param count uint64 # Number of threads to wake, or 0 for all
|
||||||
|
}
|
||||||
|
|
||||||
# Testing mode only: Have the kernel finish and exit QEMU with the given exit code
|
# Testing mode only: Have the kernel finish and exit QEMU with the given exit code
|
||||||
function test_finish [test] {
|
function test_finish [test] {
|
||||||
param exit_code uint32
|
param exit_code uint32
|
||||||
|
|||||||
23
docs/Makefile
Normal file
23
docs/Makefile
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Minimal makefile for Sphinx documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
# You can set these variables from the command line, and also
|
||||||
|
# from the environment for the first two.
|
||||||
|
SPHINXOPTS ?=
|
||||||
|
SPHINXBUILD ?= sphinx-build
|
||||||
|
SOURCEDIR = .
|
||||||
|
BUILDDIR = _build
|
||||||
|
ROOTDIR = $(SOURCEDIR)/..
|
||||||
|
|
||||||
|
# Put it first so that "make" without argument is like "make help".
|
||||||
|
help:
|
||||||
|
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
|
|
||||||
|
.PHONY: help Makefile
|
||||||
|
|
||||||
|
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||||
|
# "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)
|
||||||
254
docs/_static/custom.css
vendored
Normal file
254
docs/_static/custom.css
vendored
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
/* custom.css - jsix version */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--background-color: #181820;
|
||||||
|
--link-color: #7070e0;
|
||||||
|
--link-hover-color: #9090ff;
|
||||||
|
--text-color: #3d3d3d;
|
||||||
|
--text-literal-color: #d26a98;
|
||||||
|
}
|
||||||
|
.wy-nav-side {
|
||||||
|
background: var(--background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 1100px) {
|
||||||
|
.wy-nav-content-wrap {
|
||||||
|
background: var(--background-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--link-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: var(--link-hover-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:visited {
|
||||||
|
color: var(--link-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content code.literal {
|
||||||
|
color: var(--text-literal-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content tt.literal {
|
||||||
|
color: var(--text-literal-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content .note {
|
||||||
|
color: #003274;
|
||||||
|
background: #ccddf3;
|
||||||
|
padding: 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content .note .admonition-title {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content .warning {
|
||||||
|
color: #605000;
|
||||||
|
background: #fcf4cc;
|
||||||
|
padding: 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content .warning .admonition-title {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content .highlight {
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-side-scroll {
|
||||||
|
background-color: var(--background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-side-nav-search {
|
||||||
|
background-color: var(--background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-side-nav-search input[type="text"] {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 0px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-color: var(--background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical a {
|
||||||
|
font-size: 100%;
|
||||||
|
color: #d9d9d9;
|
||||||
|
padding-top: 0.6rem;
|
||||||
|
padding-bottom: 0.6rem;
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical a:hover {
|
||||||
|
background-color: unset;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.current > a {
|
||||||
|
background-color: var(--background-color);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.current > a span.toctree-expand {
|
||||||
|
display: block;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.current > a span.toctree-expand:before {
|
||||||
|
display: block;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.current > a span.toctree-expand:hover {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.current > a:hover {
|
||||||
|
background-color: var(--background-color);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.current > a:hover span.toctree-expand {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical .toctree-l1 {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical .toctree-l1:hover {
|
||||||
|
opacity: 1;
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l1.current {
|
||||||
|
opacity: 1;
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l1.current > a {
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical .toctree-l2:hover {
|
||||||
|
background-color: #566673;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2.current > a {
|
||||||
|
background-color: #566673;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a {
|
||||||
|
background-color: #e4e7ea;
|
||||||
|
color: #838383;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:hover {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:hover span.toctree-expand {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current > a {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2 a {
|
||||||
|
border: 0px;
|
||||||
|
background-color: #566673;
|
||||||
|
color: #d9d9d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2 a span.toctree-expand {
|
||||||
|
display: block;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2 a span.toctree-expand:before {
|
||||||
|
display: block;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2 a span.toctree-expand:hover {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2 a:hover {
|
||||||
|
color: white;
|
||||||
|
background-color: #566673;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l3.current > a {
|
||||||
|
background-color: #e4e7ea;
|
||||||
|
color: #838383;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a {
|
||||||
|
background-color: #e4e7ea;
|
||||||
|
color: #838383;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l3.current li.toctree-l4.current > a {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-nav-top {
|
||||||
|
background-color: var(--background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: var(--text-color);
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
vertical-align: middle;
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
padding: 0.375rem 0.75rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
border-radius: 0;
|
||||||
|
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||||
|
box-shadow: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-neutral {
|
||||||
|
background: unset !important;
|
||||||
|
color: #838383 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-neutral:active {
|
||||||
|
padding: 0.375rem 0.75rem;
|
||||||
|
box-shadow: unset;
|
||||||
|
}
|
||||||
50
docs/conf.py
Normal file
50
docs/conf.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# Configuration file for the Sphinx documentation builder.
|
||||||
|
#
|
||||||
|
# For the full list of built-in configuration values, see the documentation:
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||||
|
|
||||||
|
# -- Project information -----------------------------------------------------
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||||
|
|
||||||
|
project = 'jsix'
|
||||||
|
copyright = '2024, Justin C. Miller'
|
||||||
|
author = 'Justin C. Miller'
|
||||||
|
release = '0.8'
|
||||||
|
|
||||||
|
# -- General configuration ---------------------------------------------------
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||||
|
|
||||||
|
extensions = ['sphinx.ext.todo']
|
||||||
|
primary_domain = 'cpp'
|
||||||
|
todo_include_todos = True
|
||||||
|
|
||||||
|
templates_path = ['_templates']
|
||||||
|
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output -------------------------------------------------
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||||
|
|
||||||
|
html_theme = 'renku'
|
||||||
|
html_title = 'jsix'
|
||||||
|
html_logo = 'jsix_transparent.svg'
|
||||||
|
html_static_path = ['_static']
|
||||||
|
html_css_files = ['custom.css']
|
||||||
|
html_theme_options = {
|
||||||
|
"description": "The jsix description",
|
||||||
|
"github_repo": "https://github.com/justinian/jsix",
|
||||||
|
"logo_only": True,
|
||||||
|
"footer_icons": [
|
||||||
|
{
|
||||||
|
"name": "GitHub",
|
||||||
|
"url": "https://github.com/justinian/jsix",
|
||||||
|
"html": """
|
||||||
|
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 16 16">
|
||||||
|
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
|
||||||
|
</svg>
|
||||||
|
""",
|
||||||
|
"class": "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
81
docs/index.rst
Normal file
81
docs/index.rst
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
.. jsix documentation master file
|
||||||
|
.. |amd64| replace:: :abbr:`amd64 (aka x86_64)`
|
||||||
|
|
||||||
|
The jsix Operating System
|
||||||
|
=========================
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
|
**jsix** is a custom multi-core x64 operating system being built from scratch,
|
||||||
|
supporting modern [#]_ Intel or AMD CPUs, and UEFI firmware. It was initially
|
||||||
|
created out of a desire to explore UEFI and to explore what's possible with a
|
||||||
|
microkernel architecture on modern 64-bit architectures.
|
||||||
|
|
||||||
|
Most of jsix is written in C++ (C++17, using `LLVM <https://llvm.org>`_), but
|
||||||
|
you'll also find some assembly (in `NASM <https://nasm.us>`_ syntax) and Python
|
||||||
|
for development tooling.
|
||||||
|
|
||||||
|
jsix can be found `on GitHub <https://github.com/justinian/jsix>`_, and is
|
||||||
|
released under the terms of the `MPL 2.0 <https://mozilla.org/MPL/2.0/>`_.
|
||||||
|
|
||||||
|
.. admonition:: A note on the name
|
||||||
|
|
||||||
|
This kernel was originally named Popcorn, but I have since discovered that
|
||||||
|
the Popcorn Linux project is also developing a kernel with that name,
|
||||||
|
started around the same time as this project. So I've renamed this kernel
|
||||||
|
jsix as an homage to L4, xv6, and my wonderful wife.
|
||||||
|
|
||||||
|
The name jsix is always styled *jsix* or ``j6``, never capitalized.
|
||||||
|
|
||||||
|
.. [#] jsix aims to support amd64 (x86_64) CPUs released in the last 10 years.
|
||||||
|
|
||||||
|
Current Features
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The jsix kernel is quite far along now, but the userland systems are still lacking.
|
||||||
|
|
||||||
|
- Platform: |amd64|
|
||||||
|
- UEFI bootloader
|
||||||
|
- Multi-core & multi-tasking microkernel
|
||||||
|
|
||||||
|
- Work-stealing SMP scheduler
|
||||||
|
- Pluggable panic handler modules
|
||||||
|
|
||||||
|
- Capability-style object-oriented syscall API
|
||||||
|
|
||||||
|
- Custom IDL for specifying and documenting syscalls
|
||||||
|
|
||||||
|
- Virtual memory based on sharable Virtual Memory Area objects (VMAs)
|
||||||
|
- Kernel API library (libj6), also provides features built on kernel primitives:
|
||||||
|
|
||||||
|
- Channels (async stream IPC) built on shared memory and futexes
|
||||||
|
- Ring buffers via doubly-mapped pages
|
||||||
|
|
||||||
|
- Custom libc
|
||||||
|
- Runtime dynamic linker
|
||||||
|
- Init service
|
||||||
|
|
||||||
|
- Built-in VFS service for the initrd
|
||||||
|
- ELF loader
|
||||||
|
- Service-lookup protocol service
|
||||||
|
|
||||||
|
- Userland UART driver
|
||||||
|
- Userland UEFI framebuffer driver
|
||||||
|
- Userland kernel log output service
|
||||||
|
- Userland unit test runner
|
||||||
|
- Build configuration system (bonnibel)
|
||||||
|
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
:caption: Site Contents:
|
||||||
|
|
||||||
|
syscall_interface
|
||||||
|
kernel_memory
|
||||||
|
process_initialization
|
||||||
|
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`search`
|
||||||
|
|
||||||
|
|
||||||
12
docs/jsix_transparent.svg
Normal file
12
docs/jsix_transparent.svg
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Gravit.io -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="isolation:isolate" viewBox="176.562 356.069 211.11 113" width="211.11pt" height="113pt">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path d=" M 212.981 372.36 L 219.564 376.16 L 226.147 379.961 L 226.147 387.563 L 226.147 395.164 L 219.564 398.965 L 212.981 402.766 L 206.398 398.965 L 199.815 395.164 L 199.815 387.563 L 199.815 379.961 L 206.398 376.16 L 212.981 372.36 L 212.981 372.36 L 212.981 372.36 Z M 256.292 397.366 L 262.875 401.166 L 269.458 404.967 L 269.458 412.569 L 269.458 420.17 L 262.875 423.971 L 256.292 427.772 L 249.709 423.971 L 243.126 420.17 L 243.126 412.569 L 243.126 404.967 L 249.709 401.166 L 256.292 397.366 L 256.292 397.366 Z M 183.622 387.283 L 205.52 374.64 L 227.418 361.997 L 249.316 374.64 L 271.214 387.283 L 271.214 412.569 L 271.214 437.854 L 249.316 450.497 L 227.418 463.14 L 205.52 450.497 L 183.622 437.854 L 183.622 412.569 L 183.622 387.283 L 183.622 387.283 L 183.622 387.283 Z M 241.855 372.36 L 248.438 376.16 L 255.021 379.961 L 255.021 387.563 L 255.021 395.164 L 248.438 398.965 L 241.855 402.766 L 235.272 398.965 L 228.689 395.164 L 228.689 387.563 L 228.689 379.961 L 235.272 376.16 L 241.855 372.36 Z " fill-rule="evenodd" fill="rgb(49,79,128)"/>
|
||||||
|
<path d=" M 298.642 379.579 L 291.621 379.579 L 291.621 372.558 L 298.642 372.558 L 298.642 379.579 Z M 285.214 446.718 L 285.214 441.452 L 287.32 441.452 L 287.32 441.452 Q 289.339 441.452 290.524 440.092 L 290.524 440.092 L 290.524 440.092 Q 291.708 438.731 291.708 436.625 L 291.708 436.625 L 291.708 387.039 L 298.729 387.039 L 298.729 436.011 L 298.729 436.011 Q 298.729 440.925 295.921 443.822 L 295.921 443.822 L 295.921 443.822 Q 293.113 446.718 288.286 446.718 L 288.286 446.718 L 285.214 446.718 Z M 306.628 432.676 L 306.628 427.41 L 314.088 427.41 L 314.088 427.41 Q 317.862 427.41 319.573 425.347 L 319.573 425.347 L 319.573 425.347 Q 321.285 423.285 321.285 419.95 L 321.285 419.95 L 321.285 419.95 Q 321.285 417.317 319.705 415.474 L 319.705 415.474 L 319.705 415.474 Q 318.125 413.631 314.966 411.174 L 314.966 411.174 L 314.966 411.174 Q 312.245 408.98 310.621 407.356 L 310.621 407.356 L 310.621 407.356 Q 308.998 405.732 307.813 403.319 L 307.813 403.319 L 307.813 403.319 Q 306.628 400.905 306.628 397.746 L 306.628 397.746 L 306.628 397.746 Q 306.628 393.095 309.744 390.067 L 309.744 390.067 L 309.744 390.067 Q 312.859 387.039 318.125 387.039 L 318.125 387.039 L 325.76 387.039 L 325.76 392.305 L 319.441 392.305 L 319.441 392.305 Q 313.21 392.305 313.21 398.185 L 313.21 398.185 L 313.21 398.185 Q 313.21 400.467 314.615 402.134 L 314.615 402.134 L 314.615 402.134 Q 316.019 403.802 319.003 406.083 L 319.003 406.083 L 319.003 406.083 Q 321.723 408.19 323.479 409.901 L 323.479 409.901 L 323.479 409.901 Q 325.234 411.613 326.463 414.202 L 326.463 414.202 L 326.463 414.202 Q 327.691 416.791 327.691 420.301 L 327.691 420.301 L 327.691 420.301 Q 327.691 426.532 324.4 429.604 L 324.4 429.604 L 324.4 429.604 Q 321.109 432.676 315.141 432.676 L 315.141 432.676 L 306.628 432.676 Z M 342.611 379.579 L 335.59 379.579 L 335.59 372.558 L 342.611 372.558 L 342.611 379.579 Z M 342.611 432.676 L 335.59 432.676 L 335.59 387.039 L 342.611 387.039 L 342.611 432.676 Z M 356.126 432.676 L 348.754 432.676 L 361.392 409.77 L 349.632 387.039 L 356.39 387.039 L 364.639 403.187 L 372.977 387.039 L 379.735 387.039 L 367.974 409.77 L 380.612 432.676 L 373.24 432.676 L 364.639 416.001 L 356.126 432.676 Z " fill="rgb(49,79,128)"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.6 KiB |
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`
|
||||||
|
|
||||||
7
docs/modd.conf
Normal file
7
docs/modd.conf
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
** !_build/** ../definitions/**.def {
|
||||||
|
prep: rm -rf _build; make html
|
||||||
|
}
|
||||||
|
|
||||||
|
_build/html/** {
|
||||||
|
daemon: devd -m _build/html
|
||||||
|
}
|
||||||
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`
|
||||||
|
|
||||||
|
|
||||||
5
docs/requirements.txt
Normal file
5
docs/requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
cogapp >= 3
|
||||||
|
pyyaml >= 5.4
|
||||||
|
lark == 0.12.0
|
||||||
|
sphinx
|
||||||
|
renku-sphinx-theme
|
||||||
444
docs/syscall_interface.rst
Normal file
444
docs/syscall_interface.rst
Normal file
@@ -0,0 +1,444 @@
|
|||||||
|
.. jsix syscall interface.
|
||||||
|
.. Automatically updated from the definition files using cog!
|
||||||
|
|
||||||
|
.. [[[cog code generation
|
||||||
|
.. from textwrap import indent
|
||||||
|
.. from definitions.context import Context
|
||||||
|
..
|
||||||
|
.. ctx = Context(definitions_path)
|
||||||
|
.. ctx.parse("syscalls.def")
|
||||||
|
.. syscalls = ctx.interfaces["syscalls"]
|
||||||
|
..
|
||||||
|
.. def caplist(caps):
|
||||||
|
.. return ', '.join([f"``{c}``" for c in caps])
|
||||||
|
.. ]]]
|
||||||
|
.. [[[end]]] (checksum: d41d8cd98f00b204e9800998ecf8427e)
|
||||||
|
|
||||||
|
Syscall interface
|
||||||
|
=================
|
||||||
|
|
||||||
|
The jsix kernel's syscall design is based around object handles. Object handles
|
||||||
|
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
|
||||||
|
requests to the kernel to create a given kind of object. This is analogous to
|
||||||
|
methods on an object in an object-oriented programming language.
|
||||||
|
|
||||||
|
.. [[[cog code generation
|
||||||
|
.. cog.outl()
|
||||||
|
.. for obj in syscalls.exposes:
|
||||||
|
.. cog.outl(f"``{obj.name}`` syscalls")
|
||||||
|
.. cog.outl(f"-------------------------")
|
||||||
|
.. desc = obj.desc or "Undocumented"
|
||||||
|
.. cog.outl(desc)
|
||||||
|
.. cog.outl()
|
||||||
|
.. cog.outl(f":capabilites: {caplist(obj.caps)}")
|
||||||
|
.. cog.outl()
|
||||||
|
.. for method in obj.methods:
|
||||||
|
.. args = []
|
||||||
|
.. if method.constructor:
|
||||||
|
.. args.append("j6_handle_t *self")
|
||||||
|
.. elif not method.static:
|
||||||
|
.. args.append("j6_handle_t self")
|
||||||
|
..
|
||||||
|
.. for param in method.params:
|
||||||
|
.. for type, suffix in param.type.c_names(param.options):
|
||||||
|
.. args.append(f"{type} {param.name}{suffix}")
|
||||||
|
..
|
||||||
|
.. cog.outl(f".. cpp:function:: j6_result_t j6_{obj.name}_{method.name} ({', '.join(args)})")
|
||||||
|
.. cog.outl()
|
||||||
|
.. desc = method.desc or "Undocumented"
|
||||||
|
.. cog.outl(indent(desc, " "))
|
||||||
|
.. cog.outl()
|
||||||
|
.. if "cap" in method.options:
|
||||||
|
.. cog.outl(f" :capabilities: {caplist(method.options['cap'])}")
|
||||||
|
.. cog.outl()
|
||||||
|
.. if method.constructor:
|
||||||
|
.. cog.outl(f" :param self: *[out]* Handle to the new {obj.name} object")
|
||||||
|
.. elif not method.static:
|
||||||
|
.. cog.outl(f" :param self: Handle to the {obj.name} object")
|
||||||
|
.. for param in method.params:
|
||||||
|
.. opts = param.options and f"*[{', '.join(param.options)}]*" or ""
|
||||||
|
.. desc = param.desc or 'Undocumented'
|
||||||
|
.. cog.outl(f" :param {param.name}: {opts} {desc}")
|
||||||
|
.. cog.outl()
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
``object`` syscalls
|
||||||
|
-------------------------
|
||||||
|
All kernel-exposed objects inherit from the base ``object`` type, so the
|
||||||
|
``object`` syscalls can be used with any object's handle.
|
||||||
|
|
||||||
|
:capabilites: ``clone``
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_object_koid (j6_handle_t self, uint64_t * koid)
|
||||||
|
|
||||||
|
Get the internal kernel object id of an object
|
||||||
|
|
||||||
|
:param self: Handle to the object object
|
||||||
|
:param koid: *[out]* Undocumented
|
||||||
|
|
||||||
|
``event`` syscalls
|
||||||
|
-------------------------
|
||||||
|
An ``event`` is a simple synchronization object. It contains up to 64 signals
|
||||||
|
that threads can wait for and signal in parallel.
|
||||||
|
|
||||||
|
:capabilites: ``signal``, ``wait``
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_event_create (j6_handle_t *self)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:param self: *[out]* Handle to the new event object
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_event_signal (j6_handle_t self, uint64_t signals)
|
||||||
|
|
||||||
|
Signal events on this object
|
||||||
|
|
||||||
|
:capabilities: ``signal``
|
||||||
|
|
||||||
|
:param self: Handle to the event object
|
||||||
|
:param signals: A bitset of which events to signal
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_event_wait (j6_handle_t self, uint64_t * signals, uint64_t timeout)
|
||||||
|
|
||||||
|
Wait for signaled events on this object
|
||||||
|
|
||||||
|
:capabilities: ``wait``
|
||||||
|
|
||||||
|
:param self: Handle to the event object
|
||||||
|
:param signals: *[out]* A bitset of which events were signaled
|
||||||
|
:param timeout: Wait timeout in nanoseconds
|
||||||
|
|
||||||
|
``mailbox`` syscalls
|
||||||
|
-------------------------
|
||||||
|
Mailboxes are objects that enable synchronous IPC via arbitrary
|
||||||
|
message-passing of tagged data and/or handles. Not as efficient
|
||||||
|
as shared memory channels, but more flexible.
|
||||||
|
|
||||||
|
:capabilites: ``send``, ``receive``, ``close``
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_mailbox_create (j6_handle_t *self)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:param self: *[out]* Handle to the new mailbox object
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_mailbox_close (j6_handle_t self)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:capabilities: ``close``
|
||||||
|
|
||||||
|
: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_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
|
||||||
|
receive capability.
|
||||||
|
|
||||||
|
:capabilities: ``send``
|
||||||
|
|
||||||
|
:param self: Handle to the mailbox object
|
||||||
|
:param tag: *[inout]* Undocumented
|
||||||
|
:param data: *[optional, inout]* Undocumented
|
||||||
|
: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_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
|
||||||
|
capability. A reply tag of 0 skips the reply and goes directly
|
||||||
|
to waiting for a new message.
|
||||||
|
|
||||||
|
:capabilities: ``receive``
|
||||||
|
|
||||||
|
:param self: Handle to the mailbox object
|
||||||
|
:param tag: *[inout]* Undocumented
|
||||||
|
:param data: *[optional, inout]* Undocumented
|
||||||
|
: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
|
||||||
|
|
||||||
|
``process`` syscalls
|
||||||
|
-------------------------
|
||||||
|
A ``process`` object represents a process running on the system, and allows
|
||||||
|
control over the threads, handles, and virtual memory space of that process.
|
||||||
|
|
||||||
|
:capabilites: ``kill``, ``create_thread``
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_process_create (j6_handle_t *self)
|
||||||
|
|
||||||
|
Create a new empty process
|
||||||
|
|
||||||
|
:param self: *[out]* Handle to the new process object
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_process_kill (j6_handle_t self)
|
||||||
|
|
||||||
|
Stop all threads and exit the given process
|
||||||
|
|
||||||
|
:capabilities: ``kill``
|
||||||
|
|
||||||
|
:param self: Handle to the process object
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_process_exit (int64_t result)
|
||||||
|
|
||||||
|
Stop all threads and exit the current process
|
||||||
|
|
||||||
|
:param result: The result to retrun to the parent process
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_process_give_handle (j6_handle_t self, j6_handle_t target)
|
||||||
|
|
||||||
|
Give the given process a handle that points to the same
|
||||||
|
object as the specified handle.
|
||||||
|
|
||||||
|
:param self: Handle to the process object
|
||||||
|
:param target: *[handle]* A handle in the caller process to send
|
||||||
|
|
||||||
|
``system`` syscalls
|
||||||
|
-------------------------
|
||||||
|
The singular ``system`` object represents a handle to kernel functionality
|
||||||
|
needed by drivers and other priviledged services.
|
||||||
|
|
||||||
|
:capabilites: ``get_log``, ``bind_irq``, ``map_phys``, ``change_iopl``
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_system_get_log (j6_handle_t self, uint64_t seen, void * buffer, size_t * buffer_len)
|
||||||
|
|
||||||
|
Get the next log line from the kernel log
|
||||||
|
|
||||||
|
:capabilities: ``get_log``
|
||||||
|
|
||||||
|
:param self: Handle to the system object
|
||||||
|
:param seen: Last seen log id
|
||||||
|
:param buffer: *[out, zero_ok]* Buffer for the log message data structure
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_system_bind_irq (j6_handle_t self, j6_handle_t dest, unsigned irq, unsigned signal)
|
||||||
|
|
||||||
|
Ask the kernel to send this process messages whenever
|
||||||
|
the given IRQ fires
|
||||||
|
|
||||||
|
:capabilities: ``bind_irq``
|
||||||
|
|
||||||
|
:param self: Handle to the system object
|
||||||
|
:param dest: Event object that will receive messages
|
||||||
|
:param irq: IRQ number to bind
|
||||||
|
:param signal: Signal number on the event to bind to
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_system_map_phys (j6_handle_t self, j6_handle_t * area, uintptr_t phys, size_t size, uint32_t flags)
|
||||||
|
|
||||||
|
Create a VMA and map an area of physical memory into it,
|
||||||
|
also mapping that VMA into the current process
|
||||||
|
|
||||||
|
:capabilities: ``map_phys``
|
||||||
|
|
||||||
|
:param self: Handle to the system object
|
||||||
|
:param area: *[out]* Receives a handle to the VMA created
|
||||||
|
:param phys: The physical address of the area
|
||||||
|
:param size: Size of the area, in bytes
|
||||||
|
:param flags: Flags to apply to the created VMA
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_system_request_iopl (j6_handle_t self, unsigned iopl)
|
||||||
|
|
||||||
|
Request the kernel change the IOPL for this process. The only values
|
||||||
|
that make sense are 0 and 3.
|
||||||
|
|
||||||
|
:capabilities: ``change_iopl``
|
||||||
|
|
||||||
|
:param self: Handle to the system object
|
||||||
|
:param iopl: The IOPL to set for this process
|
||||||
|
|
||||||
|
``thread`` syscalls
|
||||||
|
-------------------------
|
||||||
|
A ``thread`` object represents a thread of execution within a process running
|
||||||
|
on the system. The actual thread does not need to be currently running to
|
||||||
|
hold a handle to it.
|
||||||
|
|
||||||
|
:capabilites: ``kill``, ``join``
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_thread_create (j6_handle_t *self, j6_handle_t process, uintptr_t stack_top, uintptr_t entrypoint, uint64_t arg0, uint64_t arg1)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:param self: *[out]* Handle to the new thread object
|
||||||
|
:param process: *[optional, cap]* Undocumented
|
||||||
|
:param stack_top: Undocumented
|
||||||
|
:param entrypoint: Undocumented
|
||||||
|
:param arg0: Undocumented
|
||||||
|
:param arg1: Undocumented
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_thread_kill (j6_handle_t self)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:capabilities: ``kill``
|
||||||
|
|
||||||
|
:param self: Handle to the thread object
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_thread_join (j6_handle_t self)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:capabilities: ``join``
|
||||||
|
|
||||||
|
:param self: Handle to the thread object
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_thread_exit ()
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_thread_sleep (uint64_t duration)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:param duration: Undocumented
|
||||||
|
|
||||||
|
``vma`` syscalls
|
||||||
|
-------------------------
|
||||||
|
A ``vma`` object represents a single virtual memory area, which may be shared
|
||||||
|
between several processes. A process having a handle to a ``vma`` does not
|
||||||
|
necessarily mean that it is mapped into that process' virtual memory space.
|
||||||
|
|
||||||
|
:capabilites: ``map``, ``unmap``, ``resize``
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_vma_create (j6_handle_t *self, size_t size, uint32_t flags)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:param self: *[out]* Handle to the new vma object
|
||||||
|
:param size: Undocumented
|
||||||
|
:param flags: Undocumented
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_vma_create_map (j6_handle_t *self, size_t size, uintptr_t * address, uint32_t flags)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:capabilities: ``map``
|
||||||
|
|
||||||
|
:param self: *[out]* Handle to the new vma object
|
||||||
|
:param size: Undocumented
|
||||||
|
:param address: *[inout]* Undocumented
|
||||||
|
:param flags: Undocumented
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_vma_map (j6_handle_t self, j6_handle_t process, uintptr_t * address, uint32_t flags)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:capabilities: ``map``
|
||||||
|
|
||||||
|
:param self: Handle to the vma object
|
||||||
|
:param process: *[optional]* Undocumented
|
||||||
|
:param address: *[inout]* Undocumented
|
||||||
|
:param flags: Undocumented
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_vma_unmap (j6_handle_t self, j6_handle_t process)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:capabilities: ``unmap``
|
||||||
|
|
||||||
|
:param self: Handle to the vma object
|
||||||
|
:param process: *[optional]* Undocumented
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_vma_resize (j6_handle_t self, size_t * size)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:capabilities: ``resize``
|
||||||
|
|
||||||
|
: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: cb17f54e443d1d3b85995870f3e8dbf2)
|
||||||
|
|
||||||
|
Non-object syscalls
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
The following are the system calls that aren't constructors for objects, and
|
||||||
|
either do not require an object handle, or operate generically on handles.
|
||||||
|
|
||||||
|
.. [[[cog code generation
|
||||||
|
.. cog.outl()
|
||||||
|
.. for func in syscalls.functions:
|
||||||
|
.. args = []
|
||||||
|
.. for param in func.params:
|
||||||
|
.. for type, suffix in param.type.c_names(param.options):
|
||||||
|
.. args.append(f"{type} {param.name}{suffix}")
|
||||||
|
..
|
||||||
|
.. cog.outl(f".. cpp:function:: j6_result_t j6_{func.name} ({', '.join(args)})")
|
||||||
|
.. cog.outl()
|
||||||
|
.. desc = func.desc or "Undocumented"
|
||||||
|
.. cog.outl(indent(desc, " "))
|
||||||
|
.. cog.outl()
|
||||||
|
.. for param in func.params:
|
||||||
|
.. opts = param.options and f"*[{', '.join(param.options)}]*" or ""
|
||||||
|
.. desc = param.desc or 'Undocumented'
|
||||||
|
.. cog.outl(f" :param {param.name}: {opts} {desc}")
|
||||||
|
.. cog.outl()
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_noop ()
|
||||||
|
|
||||||
|
Simple no-op syscall for testing
|
||||||
|
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_log (uint8_t area, uint8_t severity, const char * message)
|
||||||
|
|
||||||
|
Write a message to the kernel log
|
||||||
|
|
||||||
|
:param area: Undocumented
|
||||||
|
:param severity: Undocumented
|
||||||
|
:param message: Undocumented
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_handle_list (struct j6_handle_descriptor * handles, size_t * handles_size)
|
||||||
|
|
||||||
|
Get a list of handles owned by this process. If the
|
||||||
|
supplied list is not big enough, will set the size
|
||||||
|
needed in `size` and return j6_err_insufficient
|
||||||
|
|
||||||
|
:param handles: *[list, inout, zero_ok]* A list of handles to be filled
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_handle_clone (j6_handle_t orig, j6_handle_t * clone, uint32_t mask)
|
||||||
|
|
||||||
|
Create a clone of an existing handle, possibly with
|
||||||
|
some capabilities masked out.
|
||||||
|
|
||||||
|
:param orig: *[handle, cap]* The handle to clone
|
||||||
|
: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
|
||||||
|
|
||||||
|
:param address: Address of the futex value
|
||||||
|
:param current: Current value of the futex
|
||||||
|
:param timeout: Wait timeout in nanoseconds
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_futex_wake (const uint32_t * address, uint64_t count)
|
||||||
|
|
||||||
|
Wake threads waiting on a futex
|
||||||
|
|
||||||
|
:param address: Address of the futex value
|
||||||
|
:param count: Number of threads to wake, or 0 for all
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_test_finish (uint32_t exit_code)
|
||||||
|
|
||||||
|
Testing mode only: Have the kernel finish and exit QEMU with the given exit code
|
||||||
|
|
||||||
|
:param exit_code: Undocumented
|
||||||
|
|
||||||
|
.. [[[end]]] (checksum: 0b9d051972abcbb6de408f411331785f)
|
||||||
|
|
||||||
4
external/zstd.module
vendored
4
external/zstd.module
vendored
@@ -3,8 +3,8 @@
|
|||||||
zstd = module("zstd",
|
zstd = module("zstd",
|
||||||
root = "${source_root}/external/zstd",
|
root = "${source_root}/external/zstd",
|
||||||
kind = "lib",
|
kind = "lib",
|
||||||
deps = [ ],
|
copy_headers = True,
|
||||||
output = "libzstd.a",
|
deps = [ "libc" ],
|
||||||
sources = [
|
sources = [
|
||||||
"decompress/zstd_decompress.c",
|
"decompress/zstd_decompress.c",
|
||||||
"decompress/zstd_ddict.c",
|
"decompress/zstd_ddict.c",
|
||||||
|
|||||||
79
qemu.sh
79
qemu.sh
@@ -1,7 +1,10 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
build="$(dirname $0)/build"
|
root=$(dirname $0)
|
||||||
assets="$(dirname $0)/assets"
|
build="${root}/build"
|
||||||
|
assets="${root}/assets"
|
||||||
|
|
||||||
|
no_build=""
|
||||||
debug=""
|
debug=""
|
||||||
isaexit='-device isa-debug-exit,iobase=0xf4,iosize=0x04'
|
isaexit='-device isa-debug-exit,iobase=0xf4,iosize=0x04'
|
||||||
debugtarget="${build}/jsix.elf"
|
debugtarget="${build}/jsix.elf"
|
||||||
@@ -9,7 +12,9 @@ gfx="-nographic"
|
|||||||
vga="-vga none"
|
vga="-vga none"
|
||||||
log=""
|
log=""
|
||||||
kvm=""
|
kvm=""
|
||||||
cpu="Broadwell,+pdpe1gb"
|
debugcon_cmd=""
|
||||||
|
cpu_features=",+pdpe1gb,+invtsc,+hypervisor,+x2apic,+xsavec,+xsaves,+xsaveopt"
|
||||||
|
cpu="Broadwell"
|
||||||
smp=4
|
smp=4
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
@@ -35,14 +40,14 @@ while true; do
|
|||||||
;;
|
;;
|
||||||
-r | --remote)
|
-r | --remote)
|
||||||
shift
|
shift
|
||||||
vnchost="${1:-${VNCHOST:-localhost}}"
|
vnchost="${1:-${VNCHOST:-"localhost:5500"}}"
|
||||||
gfx="-vnc ${vnchost}:7000,reverse"
|
gfx="-vnc ${vnchost},reverse=on"
|
||||||
vga=""
|
vga=""
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
-k | --kvm)
|
-k | --kvm)
|
||||||
kvm="-enable-kvm"
|
kvm="-enable-kvm"
|
||||||
cpu="host"
|
cpu="max"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
-c | --cpus)
|
-c | --cpus)
|
||||||
@@ -50,7 +55,15 @@ while true; do
|
|||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
-l | --log)
|
-l | --log)
|
||||||
log="-d mmu,int,guest_errors -D jsix.log"
|
log="-d mmu,int,guest_errors -D ${root}/jsix.log"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-x | --debugcon)
|
||||||
|
debugcon_cmd="less --follow-name -R +F debugcon.log"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--no-build)
|
||||||
|
no_build="yes"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -67,39 +80,71 @@ if [[ ! -c /dev/kvm ]]; then
|
|||||||
kvm=""
|
kvm=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! ninja -C "${build}"; then
|
[[ -z "${no_build}" ]] && if ! ninja -C "${build}"; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n $TMUX ]]; then
|
if [[ -n $TMUX ]]; then
|
||||||
|
cols=$(tput cols)
|
||||||
|
log_width=100
|
||||||
|
|
||||||
if [[ -n $debug ]]; then
|
if [[ -n $debug ]]; then
|
||||||
tmux split-window -h "gdb ${debugtarget}" &
|
log_cols=1
|
||||||
|
if [[ $debugcon_cmd ]]; then
|
||||||
|
log_cols=2
|
||||||
|
fi
|
||||||
|
|
||||||
|
gdb_width=$(($cols - $log_cols * $log_width))
|
||||||
|
|
||||||
|
if (($gdb_width < 150)); then
|
||||||
|
stack=1
|
||||||
|
gdb_width=$(($cols - $log_width))
|
||||||
|
tmux split-window -h -l $gdb_width "gdb ${debugtarget}"
|
||||||
|
if [[ $debugcon_cmd ]]; then
|
||||||
|
tmux select-pane -t .left
|
||||||
|
tmux split-window -v "$debugcon_cmd"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [[ $debugcon_cmd ]]; then
|
||||||
|
tmux split-window -h -l $(($log_width + $gdb_width)) "$debugcon_cmd"
|
||||||
|
fi
|
||||||
|
tmux split-window -h -l $gdb_width "gdb ${debugtarget}"
|
||||||
|
tmux select-pane -t .left
|
||||||
|
tmux select-pane -t .right
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
tmux split-window -h -l 100 "sleep 1; telnet localhost 45455" &
|
if [[ $debugcon_cmd ]]; then
|
||||||
tmux last-pane
|
tmux split-window -h -l $log_width "$debugcon_cmd"
|
||||||
tmux split-window -l 10 "sleep 1; telnet localhost 45454" &
|
tmux last-pane
|
||||||
|
fi
|
||||||
|
tmux split-window -l 10 "sleep 1; nc localhost 45454"
|
||||||
fi
|
fi
|
||||||
elif [[ $DESKTOP_SESSION = "i3" ]]; then
|
elif [[ $DESKTOP_SESSION = "i3" ]]; then
|
||||||
if [[ -n $debug ]]; then
|
if [[ -n $debug ]]; then
|
||||||
i3-msg exec i3-sensible-terminal -- -e "gdb ${debugtarget}" &
|
i3-msg exec i3-sensible-terminal -- -e "gdb ${debugtarget}" &
|
||||||
else
|
else
|
||||||
i3-msg exec i3-sensible-terminal -- -e 'telnet localhost 45454' &
|
i3-msg exec i3-sensible-terminal -- -e 'nc localhost 45454' &
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ -n "${debug}" ]]; then
|
||||||
|
(sleep 1; echo "Debugging ready.") &
|
||||||
|
fi
|
||||||
|
|
||||||
qemu-system-x86_64 \
|
qemu-system-x86_64 \
|
||||||
-drive "if=pflash,format=raw,readonly,file=${assets}/ovmf/x64/ovmf_code.fd" \
|
-drive "if=pflash,format=raw,readonly=on,file=${assets}/ovmf/x64/ovmf_code.fd" \
|
||||||
-drive "if=pflash,format=raw,file=${build}/ovmf_vars.fd" \
|
-drive "if=pflash,format=raw,file=${build}/ovmf_vars.fd" \
|
||||||
-drive "format=raw,file=${build}/jsix.img" \
|
-drive "format=raw,file=${build}/jsix.img" \
|
||||||
-chardev socket,host=localhost,port=45455,server,nowait,telnet=on,id=jsix_debug -device isa-debugcon,iobase=0x6600,chardev=jsix_debug \
|
-chardev "file,path=${root}/debugcon.log,id=jsix_debug" \
|
||||||
|
-device "isa-debugcon,iobase=0x6600,chardev=jsix_debug" \
|
||||||
-monitor telnet:localhost:45454,server,nowait \
|
-monitor telnet:localhost:45454,server,nowait \
|
||||||
-serial stdio \
|
-serial stdio \
|
||||||
-smp "${smp}" \
|
-smp "${smp}" \
|
||||||
-m 4096 \
|
-m 4096 \
|
||||||
-cpu "${cpu}" \
|
-cpu "${cpu}${cpu_features}" \
|
||||||
-M q35 \
|
-M q35 \
|
||||||
-no-reboot \
|
-no-reboot \
|
||||||
-name "jsix" \
|
-name jsix \
|
||||||
$isaexit $log $gfx $vga $kvm $debug
|
$isaexit $log $gfx $vga $kvm $debug
|
||||||
|
|
||||||
((result = ($? >> 1) - 1))
|
((result = ($? >> 1) - 1))
|
||||||
|
|||||||
@@ -5,3 +5,7 @@ pyyaml >= 5.4
|
|||||||
lark == 0.12.0
|
lark == 0.12.0
|
||||||
pure-cdb == 4
|
pure-cdb == 4
|
||||||
pyzstd == 0.15
|
pyzstd == 0.15
|
||||||
|
pyelftools
|
||||||
|
iced-x86
|
||||||
|
sphinx
|
||||||
|
renku-sphinx-theme
|
||||||
|
|||||||
68
scripts/bonnibel/config.py
Normal file
68
scripts/bonnibel/config.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
_config_cache = {}
|
||||||
|
|
||||||
|
def _load(filename, depfiles):
|
||||||
|
from . import load_config
|
||||||
|
if not filename in _config_cache:
|
||||||
|
if filename.exists():
|
||||||
|
depfiles.add(filename)
|
||||||
|
data = load_config(filename)
|
||||||
|
_config_cache[filename] = data
|
||||||
|
return _config_cache.get(filename, dict())
|
||||||
|
|
||||||
|
|
||||||
|
def _build_config(chain, depfiles):
|
||||||
|
config = {}
|
||||||
|
for d in [_load(c, depfiles) for c in chain]:
|
||||||
|
for k, v in d.items():
|
||||||
|
if isinstance(v, (list, tuple)):
|
||||||
|
config[k] = config.get(k, list()) + list(v)
|
||||||
|
elif isinstance(v, dict):
|
||||||
|
config[k] = config.get(k, dict())
|
||||||
|
config[k].update(v)
|
||||||
|
else:
|
||||||
|
config[k] = v
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def _make_ninja_config(outfile, config, files):
|
||||||
|
from os import makedirs
|
||||||
|
from ninja.ninja_syntax import Writer
|
||||||
|
|
||||||
|
makedirs(outfile.parent, exist_ok=True)
|
||||||
|
|
||||||
|
with open(outfile, "w") as buildfile:
|
||||||
|
build = Writer(buildfile)
|
||||||
|
build.comment("This file is automatically generated by bonnibel")
|
||||||
|
build.comment("Source config files:")
|
||||||
|
for f in files:
|
||||||
|
build.comment(f" - {f}")
|
||||||
|
|
||||||
|
build.newline()
|
||||||
|
for k, v in config.items():
|
||||||
|
build.variable(k, v)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_configs(root, output, config, targets, kinds):
|
||||||
|
|
||||||
|
assets = root / "assets" / "build"
|
||||||
|
base = ["global.yaml", f"config.{config}.yaml"]
|
||||||
|
|
||||||
|
depfiles = set()
|
||||||
|
|
||||||
|
for target in targets:
|
||||||
|
chain = base + [f"target.{target}.yaml"]
|
||||||
|
|
||||||
|
files = [assets / f for f in chain]
|
||||||
|
config = _build_config(files, depfiles)
|
||||||
|
outfile = output / target / f"config.ninja"
|
||||||
|
_make_ninja_config(outfile, config, files)
|
||||||
|
|
||||||
|
for kind in kinds:
|
||||||
|
custom = [f"kind.{kind}.yaml", f"target.{target}.{kind}.yaml"]
|
||||||
|
files = [assets / f for f in chain + custom]
|
||||||
|
config = _build_config(files, depfiles)
|
||||||
|
outfile = output / target / f"config.{kind}.ninja"
|
||||||
|
_make_ninja_config(outfile, config, files)
|
||||||
|
|
||||||
|
return depfiles
|
||||||
@@ -26,7 +26,7 @@ class Manifest:
|
|||||||
name="kernel", target="kernel")
|
name="kernel", target="kernel")
|
||||||
|
|
||||||
self.init = self.__build_entry(modules,
|
self.init = self.__build_entry(modules,
|
||||||
config.get("init", None))
|
config.get("init", None), target="init")
|
||||||
|
|
||||||
self.panics = [self.__build_entry(modules, i, target="kernel")
|
self.panics = [self.__build_entry(modules, i, target="kernel")
|
||||||
for i in config.get("panic", tuple())]
|
for i in config.get("panic", tuple())]
|
||||||
@@ -37,6 +37,13 @@ class Manifest:
|
|||||||
self.drivers = [self.__build_entry(modules, i)
|
self.drivers = [self.__build_entry(modules, i)
|
||||||
for i in config.get("drivers", tuple())]
|
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]))
|
||||||
|
|
||||||
|
self.libs = [self.__build_entry(modules, i)
|
||||||
|
for i in libs]
|
||||||
|
|
||||||
self.flags = config.get("flags", tuple())
|
self.flags = config.get("flags", tuple())
|
||||||
|
|
||||||
self.symbols = ""
|
self.symbols = ""
|
||||||
@@ -71,7 +78,14 @@ class Manifest:
|
|||||||
if not f in Manifest.flags:
|
if not f in Manifest.flags:
|
||||||
raise BonnibelError(f"Manifest specifies unknown flag '{f}'")
|
raise BonnibelError(f"Manifest specifies unknown flag '{f}'")
|
||||||
|
|
||||||
return Manifest.Entry(name, target, mod.output, flags)
|
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()):
|
def add_data(self, output, desc, flags=tuple()):
|
||||||
e = Manifest.Entry(None, None, output, flags)
|
e = Manifest.Entry(None, None, output, flags)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from . import include_rel, mod_rel, target_rel
|
from . import include_rel, mod_rel, target_rel
|
||||||
|
from . import BonnibelError
|
||||||
|
|
||||||
def resolve(path):
|
def resolve(path):
|
||||||
if path.startswith('/') or path.startswith('$'):
|
if path.startswith('/') or path.startswith('$'):
|
||||||
@@ -7,29 +8,43 @@ def resolve(path):
|
|||||||
return str(Path(path).resolve())
|
return str(Path(path).resolve())
|
||||||
|
|
||||||
class BuildOptions:
|
class BuildOptions:
|
||||||
def __init__(self, includes=tuple(), libs=tuple(), order_only=tuple(), ld_script=None):
|
def __init__(self, includes=tuple(), local=tuple(), late=tuple(), libs=tuple(), order_only=tuple(), ld_script=None):
|
||||||
self.includes = list(includes)
|
self.includes = list(includes)
|
||||||
|
self.local = list(local)
|
||||||
|
self.late = list(late)
|
||||||
self.libs = list(libs)
|
self.libs = list(libs)
|
||||||
self.order_only = list(order_only)
|
self.order_only = list(order_only)
|
||||||
self.ld_script = ld_script and str(ld_script)
|
self.ld_script = ld_script and str(ld_script)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def implicit(self):
|
def implicit(self):
|
||||||
|
libfiles = list(map(lambda x: x[0], self.libs))
|
||||||
if self.ld_script is not None:
|
if self.ld_script is not None:
|
||||||
return self.libs + [self.ld_script]
|
return libfiles + [self.ld_script]
|
||||||
else:
|
else:
|
||||||
return self.libs
|
return libfiles
|
||||||
|
|
||||||
|
@property
|
||||||
|
def linker_args(self):
|
||||||
|
from pathlib import Path
|
||||||
|
def arg(path, static):
|
||||||
|
if static: return path
|
||||||
|
return "-l:" + Path(path).name
|
||||||
|
return [arg(*l) for l in self.libs]
|
||||||
|
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
__fields = {
|
__fields = {
|
||||||
# name: (type, default)
|
# name: (type, default)
|
||||||
"kind": (str, "exe"),
|
"kind": (str, "exe"),
|
||||||
"output": (str, None),
|
"outfile": (str, None),
|
||||||
|
"basename": (str, None),
|
||||||
"targets": (set, ()),
|
"targets": (set, ()),
|
||||||
"deps": (set, ()),
|
"deps": (set, ()),
|
||||||
"public_headers": (set, ()),
|
"public_headers": (set, ()),
|
||||||
|
"copy_headers": (bool, False),
|
||||||
"includes": (tuple, ()),
|
"includes": (tuple, ()),
|
||||||
|
"include_phase": (str, "normal"),
|
||||||
"sources": (tuple, ()),
|
"sources": (tuple, ()),
|
||||||
"drivers": (tuple, ()),
|
"drivers": (tuple, ()),
|
||||||
"variables": (dict, ()),
|
"variables": (dict, ()),
|
||||||
@@ -37,13 +52,15 @@ class Module:
|
|||||||
"description": (str, None),
|
"description": (str, None),
|
||||||
"no_libc": (bool, False),
|
"no_libc": (bool, False),
|
||||||
"ld_script": (str, None),
|
"ld_script": (str, None),
|
||||||
|
"static": (bool, False),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, name, modfile, root, **kwargs):
|
def __init__(self, name, modfile, root, **kwargs):
|
||||||
from .source import make_source
|
from pathlib import Path
|
||||||
|
from .source import make_source, make_copy_source
|
||||||
|
|
||||||
# Required fields
|
# Required fields
|
||||||
self.root = root
|
self.root = Path(root)
|
||||||
self.name = name
|
self.name = name
|
||||||
self.modfile = modfile
|
self.modfile = modfile
|
||||||
|
|
||||||
@@ -57,31 +74,46 @@ class Module:
|
|||||||
|
|
||||||
for name in kwargs:
|
for name in kwargs:
|
||||||
if not name in self.__fields:
|
if not name in self.__fields:
|
||||||
raise AttributeError(f"No attribute named {name} on Module")
|
raise AttributeError(f"No attribute named {name} on Module ({modfile})")
|
||||||
|
|
||||||
|
if not self.no_libc:
|
||||||
|
self.deps.add("libc_free")
|
||||||
|
|
||||||
# Turn strings into real Source objects
|
# Turn strings into real Source objects
|
||||||
self.sources = [make_source(root, f) for f in self.sources]
|
self.sources = [make_source(root, f) for f in self.sources]
|
||||||
self.public_headers = [make_source(root, f) for f in self.public_headers]
|
|
||||||
|
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
|
# Filled by Module.update
|
||||||
self.depmods = set()
|
self.depmods = set()
|
||||||
|
|
||||||
def __str__(self):
|
def __repr__(self):
|
||||||
return "Module {} {}\n\t{}".format(self.kind, self.name, "\n\t".join(map(str, self.sources)))
|
return f"<Module {self.kind} {self.name}>"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def output(self):
|
def basename(self):
|
||||||
if self.__output is not None:
|
if self.__basename is not None:
|
||||||
return self.__output
|
return self.__basename
|
||||||
|
|
||||||
if self.kind == "lib":
|
if self.kind == "lib":
|
||||||
return f"lib{self.name}.a"
|
return f"lib{self.name}"
|
||||||
else:
|
else:
|
||||||
return f"{self.name}.elf"
|
return self.name
|
||||||
|
|
||||||
@output.setter
|
@basename.setter
|
||||||
def output(self, value):
|
def basename(self, value):
|
||||||
self.__output = value
|
self.__basename = value
|
||||||
|
|
||||||
|
def get_output(self, static=False):
|
||||||
|
if self.outfile is not None:
|
||||||
|
return self.outfile
|
||||||
|
elif self.kind == "headers":
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
ext = dict(exe=".elf", driver=".drv", lib=(static and ".a" or ".so"))
|
||||||
|
return self.basename + ext.get(self.kind, "")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def update(cls, mods):
|
def update(cls, mods):
|
||||||
@@ -114,66 +146,28 @@ class Module:
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from ninja.ninja_syntax import Writer
|
from ninja.ninja_syntax import Writer
|
||||||
|
|
||||||
def walk_deps(deps):
|
def walk_deps(deps, static, results):
|
||||||
open_set = set(deps)
|
for mod in deps:
|
||||||
closed_set = set()
|
if static or mod.name not in results:
|
||||||
while open_set:
|
results[mod.name] = (mod, static)
|
||||||
dep = open_set.pop()
|
walk_deps(mod.depmods, static or mod.static, results)
|
||||||
closed_set.add(dep)
|
|
||||||
open_set |= {m for m in dep.depmods if not m in closed_set}
|
|
||||||
return closed_set
|
|
||||||
|
|
||||||
all_deps = walk_deps(self.depmods)
|
all_deps = {}
|
||||||
|
walk_deps(self.depmods, self.static, all_deps)
|
||||||
|
all_deps = all_deps.values()
|
||||||
|
|
||||||
def gather_phony(build, deps, child_rel, add_headers=False):
|
def gather_phony(build, deps, child_rel):
|
||||||
phony = ".headers.phony"
|
phony = ".headers.phony"
|
||||||
child_phony = [child_rel(phony, module=c.name)
|
child_phony = [child_rel(phony, module=c.name)
|
||||||
for c in all_deps]
|
for c, _ in all_deps]
|
||||||
|
|
||||||
header_targets = []
|
|
||||||
if add_headers:
|
|
||||||
if not self.no_libc:
|
|
||||||
header_targets.append(f"${{build_root}}/include/libc/{phony}")
|
|
||||||
if self.public_headers:
|
|
||||||
header_targets.append(f"${{build_root}}/include/{self.name}/{phony}")
|
|
||||||
|
|
||||||
build.build(
|
build.build(
|
||||||
rule = "touch",
|
rule = "touch",
|
||||||
outputs = [mod_rel(phony)],
|
outputs = [mod_rel(phony)],
|
||||||
implicit = child_phony + header_targets,
|
implicit = child_phony,
|
||||||
order_only = list(map(mod_rel, deps)),
|
order_only = list(map(mod_rel, deps)),
|
||||||
)
|
)
|
||||||
|
|
||||||
filename = str(output / f"headers.{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", f"${{build_root}}/include/{self.name}")
|
|
||||||
|
|
||||||
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()
|
|
||||||
gather_phony(build, header_deps, include_rel)
|
|
||||||
|
|
||||||
filename = str(output / f"module.{self.name}.ninja")
|
filename = str(output / f"module.{self.name}.ninja")
|
||||||
with open(filename, "w") as buildfile:
|
with open(filename, "w") as buildfile:
|
||||||
build = Writer(buildfile)
|
build = Writer(buildfile)
|
||||||
@@ -182,13 +176,21 @@ class Module:
|
|||||||
build.newline()
|
build.newline()
|
||||||
|
|
||||||
build.variable("module_dir", target_rel(self.name + ".dir"))
|
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(
|
modopts = BuildOptions(
|
||||||
includes = [self.root, "${module_dir}"],
|
local = [self.root, "${module_dir}"],
|
||||||
ld_script = self.ld_script and self.root / self.ld_script,
|
ld_script = self.ld_script and self.root / self.ld_script,
|
||||||
)
|
)
|
||||||
if self.public_headers:
|
if self.public_headers:
|
||||||
modopts.includes += [f"${{build_root}}/include/{self.name}"]
|
modopts.includes += [
|
||||||
|
self.root / "include",
|
||||||
|
f"${{target_dir}}/{self.name}.dir/include",
|
||||||
|
]
|
||||||
|
|
||||||
for key, value in self.variables.items():
|
for key, value in self.variables.items():
|
||||||
build.variable(key, value)
|
build.variable(key, value)
|
||||||
@@ -207,27 +209,64 @@ class Module:
|
|||||||
modopts.includes.append(str(incpath))
|
modopts.includes.append(str(incpath))
|
||||||
modopts.includes.append(destpath)
|
modopts.includes.append(destpath)
|
||||||
|
|
||||||
all_deps = walk_deps(self.depmods)
|
for dep, static in all_deps:
|
||||||
for dep in all_deps:
|
|
||||||
if dep.public_headers:
|
if dep.public_headers:
|
||||||
modopts.includes += [f"${{build_root}}/include/{dep.name}"]
|
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 == "lib":
|
if dep.kind == "headers":
|
||||||
modopts.libs.append(target_rel(dep.output))
|
continue
|
||||||
|
elif dep.kind == "lib":
|
||||||
|
modopts.libs.append((target_rel(dep.get_output(static)), static))
|
||||||
else:
|
else:
|
||||||
modopts.order_only.append(target_rel(dep.output))
|
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:
|
if modopts.includes:
|
||||||
build.variable("ccflags", ["${ccflags}"] + [f"-I{i}" for i in modopts.includes])
|
cc_includes += [f"-I{i}" for i in modopts.includes]
|
||||||
build.variable("asflags", ["${asflags}"] + [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:
|
if modopts.libs:
|
||||||
build.variable("libs", ["${libs}"] + modopts.libs)
|
build.variable("libs", ["-L${target_dir}", "${libs}"] + modopts.linker_args)
|
||||||
|
|
||||||
if modopts.ld_script:
|
if modopts.ld_script:
|
||||||
build.variable("ldflags", ["${ldflags}"] + ["-T", modopts.ld_script])
|
build.variable("ldflags", ["${ldflags}"] + ["-T", modopts.ld_script])
|
||||||
|
|
||||||
header_deps = []
|
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 = []
|
inputs = []
|
||||||
sources = set(self.sources)
|
sources = set(self.sources)
|
||||||
@@ -245,11 +284,13 @@ class Module:
|
|||||||
if source.input:
|
if source.input:
|
||||||
inputs.extend(map(mod_rel, source.outputs))
|
inputs.extend(map(mod_rel, source.outputs))
|
||||||
|
|
||||||
build.newline()
|
gather_phony(build, header_deps, target_rel)
|
||||||
|
|
||||||
gather_phony(build, header_deps, target_rel, add_headers=True)
|
if self.kind == "headers":
|
||||||
|
# Header-only, don't output a build rule
|
||||||
|
return
|
||||||
|
|
||||||
output = target_rel(self.output)
|
output = target_rel(self.get_output())
|
||||||
build.newline()
|
build.newline()
|
||||||
build.build(
|
build.build(
|
||||||
rule = self.kind,
|
rule = self.kind,
|
||||||
@@ -257,6 +298,8 @@ class Module:
|
|||||||
inputs = inputs,
|
inputs = inputs,
|
||||||
implicit = modopts.implicit,
|
implicit = modopts.implicit,
|
||||||
order_only = modopts.order_only,
|
order_only = modopts.order_only,
|
||||||
|
variables = {"name": self.name,
|
||||||
|
"soname": self.get_output()},
|
||||||
)
|
)
|
||||||
|
|
||||||
dump = output + ".dump"
|
dump = output + ".dump"
|
||||||
@@ -268,14 +311,34 @@ class Module:
|
|||||||
variables = {"name": self.name},
|
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:
|
if self.default:
|
||||||
build.newline()
|
build.newline()
|
||||||
build.default(output)
|
build.default(output)
|
||||||
build.default(dump)
|
build.default(dump)
|
||||||
|
|
||||||
def add_input(self, path, **kwargs):
|
def add_input(self, path, **kwargs):
|
||||||
from .source import Source
|
from .source import make_source
|
||||||
s = Source(self.root, path, **kwargs)
|
s = make_source(self.root, path, **kwargs)
|
||||||
self.sources.append(s)
|
self.sources.append(s)
|
||||||
return s.outputs
|
return s.outputs
|
||||||
|
|
||||||
|
|||||||
@@ -12,14 +12,17 @@ class Project:
|
|||||||
|
|
||||||
def generate(self, root, output, modules, config, manifest_file):
|
def generate(self, root, output, modules, config, manifest_file):
|
||||||
import sys
|
import sys
|
||||||
import bonnibel
|
|
||||||
from os.path import join
|
from os.path import join
|
||||||
from ninja.ninja_syntax import Writer
|
from ninja.ninja_syntax import Writer
|
||||||
from .target import Target
|
|
||||||
|
|
||||||
targets = set()
|
targets = set()
|
||||||
|
kinds = set()
|
||||||
for mod in modules.values():
|
for mod in modules.values():
|
||||||
targets.update({Target.load(root, t, config) for t in mod.targets})
|
targets.update(mod.targets)
|
||||||
|
kinds.add(mod.kind)
|
||||||
|
|
||||||
|
from .config import generate_configs
|
||||||
|
config_deps = generate_configs(root, output, config, targets, kinds)
|
||||||
|
|
||||||
with open(output / "build.ninja", "w") as buildfile:
|
with open(output / "build.ninja", "w") as buildfile:
|
||||||
build = Writer(buildfile)
|
build = Writer(buildfile)
|
||||||
@@ -28,6 +31,7 @@ class Project:
|
|||||||
build.variable("ninja_required_version", "1.3")
|
build.variable("ninja_required_version", "1.3")
|
||||||
build.variable("build_root", output)
|
build.variable("build_root", output)
|
||||||
build.variable("source_root", root)
|
build.variable("source_root", root)
|
||||||
|
build.variable("build_config", config)
|
||||||
build.newline()
|
build.newline()
|
||||||
|
|
||||||
build.include(root / "assets/build/rules.ninja")
|
build.include(root / "assets/build/rules.ninja")
|
||||||
@@ -46,11 +50,7 @@ class Project:
|
|||||||
build.newline()
|
build.newline()
|
||||||
|
|
||||||
for target in targets:
|
for target in targets:
|
||||||
build.subninja(output / target.name / "target.ninja")
|
build.subninja(output / target / "target.ninja")
|
||||||
build.newline()
|
|
||||||
|
|
||||||
for mod in modules.values():
|
|
||||||
build.subninja(output / f"headers.{mod.name}.ninja")
|
|
||||||
build.newline()
|
build.newline()
|
||||||
|
|
||||||
build.build(
|
build.build(
|
||||||
@@ -154,6 +154,9 @@ class Project:
|
|||||||
for program in manifest.drivers:
|
for program in manifest.drivers:
|
||||||
add_initrd_stripped("jsix/drivers", program)
|
add_initrd_stripped("jsix/drivers", program)
|
||||||
|
|
||||||
|
for program in manifest.libs:
|
||||||
|
add_initrd_stripped("jsix/lib", program)
|
||||||
|
|
||||||
syms = manifest.add_data("symbol_table.dat",
|
syms = manifest.add_data("symbol_table.dat",
|
||||||
"Symbol table", ("symbols",))
|
"Symbol table", ("symbols",))
|
||||||
|
|
||||||
@@ -163,7 +166,7 @@ class Project:
|
|||||||
build.build(
|
build.build(
|
||||||
rule = "makest",
|
rule = "makest",
|
||||||
outputs = [syms_out],
|
outputs = [syms_out],
|
||||||
inputs = [f"${{build_root}}/kernel/{modules['kernel'].output}"],
|
inputs = [f"${{build_root}}/kernel/{modules['kernel'].get_output(static=True)}"],
|
||||||
)
|
)
|
||||||
fatroot_content.append(syms_out)
|
fatroot_content.append(syms_out)
|
||||||
manifest.symbols = syms_file
|
manifest.symbols = syms_file
|
||||||
@@ -232,8 +235,7 @@ class Project:
|
|||||||
[f"{self.root}/configure", str(manifest_file)] + \
|
[f"{self.root}/configure", str(manifest_file)] + \
|
||||||
[str(mod.modfile) for mod in modules.values()]
|
[str(mod.modfile) for mod in modules.values()]
|
||||||
|
|
||||||
for target in targets:
|
regen_implicits += list(map(str, config_deps))
|
||||||
regen_implicits += target.depfiles
|
|
||||||
|
|
||||||
build.build(
|
build.build(
|
||||||
rule = "compdb",
|
rule = "compdb",
|
||||||
@@ -249,7 +251,7 @@ class Project:
|
|||||||
implicit = regen_implicits,
|
implicit = regen_implicits,
|
||||||
implicit_outputs =
|
implicit_outputs =
|
||||||
[f"module.{mod.name}.ninja" for mod in modules.values()] +
|
[f"module.{mod.name}.ninja" for mod in modules.values()] +
|
||||||
[f"{target.name}/target.ninja" for target in targets] +
|
[f"{target}/target.ninja" for target in targets] +
|
||||||
[boot_config],
|
[boot_config],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -257,9 +259,9 @@ class Project:
|
|||||||
build.default(["${build_root}/jsix.img"])
|
build.default(["${build_root}/jsix.img"])
|
||||||
|
|
||||||
for target in targets:
|
for target in targets:
|
||||||
mods = [m.name for m in modules.values() if target.name in m.targets]
|
mods = [m.name for m in modules.values() if target in m.targets]
|
||||||
|
|
||||||
targetdir = output / target.name
|
targetdir = output / target
|
||||||
targetdir.mkdir(exist_ok=True)
|
targetdir.mkdir(exist_ok=True)
|
||||||
|
|
||||||
buildfilename = str(targetdir / "target.ninja")
|
buildfilename = str(targetdir / "target.ninja")
|
||||||
@@ -268,17 +270,16 @@ class Project:
|
|||||||
build.comment("This file is automatically generated by bonnibel")
|
build.comment("This file is automatically generated by bonnibel")
|
||||||
build.newline()
|
build.newline()
|
||||||
|
|
||||||
build.variable("target", target.name)
|
build.variable("target", target)
|
||||||
build.variable("target_dir", output / target.name)
|
build.variable("target_dir", output / target)
|
||||||
build.newline()
|
build.newline()
|
||||||
|
|
||||||
for name, value in target.items():
|
build.include(f"{target}/config.ninja")
|
||||||
build.variable(name, value)
|
|
||||||
|
|
||||||
build.newline()
|
build.newline()
|
||||||
for kind in ('defs', 'run'):
|
for kind in ('defs', 'run'):
|
||||||
for lang in ('c', 'cpp'):
|
for lang in ('c', 'cpp'):
|
||||||
deffile = str(output / target.name / f"{lang}.{kind}")
|
deffile = str(output / target / f"{lang}.{kind}")
|
||||||
|
|
||||||
build.build(
|
build.build(
|
||||||
rule = f"dump_{lang}_{kind}",
|
rule = f"dump_{lang}_{kind}",
|
||||||
|
|||||||
@@ -72,22 +72,21 @@ class ParseSource(Source):
|
|||||||
variables = dict(name=self.path),
|
variables = dict(name=self.path),
|
||||||
)
|
)
|
||||||
|
|
||||||
class HeaderSource(Source):
|
class CopySource(ParseSource):
|
||||||
action = "cp"
|
action = "cp"
|
||||||
gather = True
|
|
||||||
|
def __init__(self, path, root = "${module_dir}", deps=tuple(), prefix = ""):
|
||||||
|
self.path = path
|
||||||
|
self.root = root
|
||||||
|
self.deps = deps
|
||||||
|
self.prefix = prefix
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def outputs(self):
|
def output(self):
|
||||||
return (self.path,)
|
from pathlib import Path
|
||||||
|
return Path(self.prefix) / self.path
|
||||||
|
|
||||||
@property
|
class HeaderSource(Source): pass
|
||||||
def args(self):
|
|
||||||
return dict(
|
|
||||||
outputs = [mod_rel(self.path)],
|
|
||||||
inputs = [join(self.root, self.path)],
|
|
||||||
implicit = list(map(_resolve, self.deps)),
|
|
||||||
variables = dict(name=self.path),
|
|
||||||
)
|
|
||||||
|
|
||||||
class CompileSource(Source):
|
class CompileSource(Source):
|
||||||
action = property(_dynamic_action("compile"))
|
action = property(_dynamic_action("compile"))
|
||||||
@@ -117,3 +116,6 @@ def make_source(root, path):
|
|||||||
return HeaderSource(path, root)
|
return HeaderSource(path, root)
|
||||||
else:
|
else:
|
||||||
raise RuntimeError(f"{path} has no Source type")
|
raise RuntimeError(f"{path} has no Source type")
|
||||||
|
|
||||||
|
def make_copy_source(root, path, prefix = ""):
|
||||||
|
return CopySource(path, root, prefix=prefix)
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
class Target(dict):
|
|
||||||
__targets = {}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def load(cls, root, name, config=None):
|
|
||||||
from . import load_config
|
|
||||||
|
|
||||||
if (name, config) in cls.__targets:
|
|
||||||
return cls.__targets[(name, config)]
|
|
||||||
|
|
||||||
configs = root / "assets/build"
|
|
||||||
|
|
||||||
dicts = []
|
|
||||||
depfiles = []
|
|
||||||
basename = name
|
|
||||||
if config:
|
|
||||||
basename += f"-{config}"
|
|
||||||
|
|
||||||
while basename is not None:
|
|
||||||
filename = str(configs / (basename + ".yaml"))
|
|
||||||
depfiles.append(filename)
|
|
||||||
desc = load_config(filename)
|
|
||||||
basename = desc.get("extends")
|
|
||||||
dicts.append(desc.get("variables", dict()))
|
|
||||||
|
|
||||||
t = Target(name, config, depfiles)
|
|
||||||
for d in reversed(dicts):
|
|
||||||
for k, v in d.items():
|
|
||||||
if isinstance(v, (list, tuple)):
|
|
||||||
t[k] = t.get(k, list()) + list(v)
|
|
||||||
elif isinstance(v, dict):
|
|
||||||
t[k] = t.get(k, dict())
|
|
||||||
t[k].update(v)
|
|
||||||
else:
|
|
||||||
t[k] = v
|
|
||||||
|
|
||||||
cls.__targets[(name, config)] = t
|
|
||||||
return t
|
|
||||||
|
|
||||||
def __init__(self, name, config, depfiles):
|
|
||||||
self.__name = name
|
|
||||||
self.__config = config
|
|
||||||
self.__depfiles = tuple(depfiles)
|
|
||||||
|
|
||||||
def __hash__(self):
|
|
||||||
return hash((self.__name, self.__config))
|
|
||||||
|
|
||||||
name = property(lambda self: self.__name)
|
|
||||||
config = property(lambda self: self.__config)
|
|
||||||
depfiles = property(lambda self: self.__depfiles)
|
|
||||||
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
|
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_widths = (8, 16, 32, 64)
|
||||||
int_mods = ("fast", "least")
|
int_mods = ("fast", "least")
|
||||||
|
|
||||||
62
scripts/debug_buddy_alloc.gdb
Normal file
62
scripts/debug_buddy_alloc.gdb
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
das -enabled off
|
||||||
|
|
||||||
|
break heap_allocator.cpp:200
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "n %016lx %d\n", m_end, current
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
break heap_allocator.cpp:206
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "N %016lx %d\n", m_end, order
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
break heap_allocator::register_free_block
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "F %016lx %d\n", block, order
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
break heap_allocator.cpp:118
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "f %016lx %d\n", block, info->order
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
break heap_allocator.cpp:241
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "S %016lx %d\n", block, order
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
break heap_allocator.cpp:158
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "P %016lx %d\n", block, order
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
break heap_allocator.cpp:180
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "p %016lx %d\n", block, order
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
break heap_allocator.cpp:182
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "M %016lx %016lx %d\n", block, buddy, order
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
set logging file buddy_allocs.txt
|
||||||
|
set logging overwrite on
|
||||||
|
set logging enabled on
|
||||||
|
continue
|
||||||
18
scripts/debug_frame_alloc.gdb
Normal file
18
scripts/debug_frame_alloc.gdb
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
das -enabled off
|
||||||
|
break frame_allocator.cpp:62
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "+ %016lx %3d\n", *address, n
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
break frame_allocator.cpp:95
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "- %016lx %3d\n", address, count
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
set logging file frame_allocs.txt
|
||||||
|
set logging overwrite on
|
||||||
|
set logging enabled on
|
||||||
|
continue
|
||||||
29
scripts/debug_heap_alloc.gdb
Normal file
29
scripts/debug_heap_alloc.gdb
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
das -enabled off
|
||||||
|
break heap_allocator.cpp:81
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "+ %016lx %4d\n", block, length
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
break heap_allocator.cpp:86
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "+ %016lx %4d\n", block, length
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
break heap_allocator.cpp:120
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "- %016lx\n", p
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
break heap_allocator.cpp:140
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "> %016lx %4d %4d\n", p, old_length, new_length
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
set logging file heap_allocs.txt
|
||||||
|
set logging overwrite on
|
||||||
|
set logging enabled on
|
||||||
|
continue
|
||||||
File diff suppressed because one or more lines are too long
@@ -42,31 +42,37 @@ class PrimitiveRef(Primitive):
|
|||||||
def cxx_names(self, options):
|
def cxx_names(self, options):
|
||||||
return self.c_names(options)
|
return self.c_names(options)
|
||||||
|
|
||||||
|
_inttypes = {
|
||||||
|
"int": "int",
|
||||||
|
"uint": "unsigned",
|
||||||
|
"size": "size_t",
|
||||||
|
"address": "uintptr_t",
|
||||||
|
|
||||||
|
"int8": "int8_t",
|
||||||
|
"uint8": "uint8_t",
|
||||||
|
"int16": "int16_t",
|
||||||
|
"uint16": "uint16_t",
|
||||||
|
"int32": "int32_t",
|
||||||
|
"uint32": "uint32_t",
|
||||||
|
"int64": "int64_t",
|
||||||
|
"uint64": "uint64_t",
|
||||||
|
}
|
||||||
|
|
||||||
_primitives = {
|
_primitives = {
|
||||||
"string": PrimitiveRef("string", "char"),
|
"string": PrimitiveRef("string", "char"),
|
||||||
"buffer": PrimitiveRef("buffer", "void", counted=True),
|
"buffer": PrimitiveRef("buffer", "void", counted=True),
|
||||||
|
|
||||||
"int": Primitive("int", "int"),
|
|
||||||
"uint": Primitive("uint", "unsigned"),
|
|
||||||
"size": Primitive("size", "size_t"),
|
|
||||||
"address": Primitive("address", "uintptr_t"),
|
|
||||||
|
|
||||||
"int8": Primitive("int8", "int8_t"),
|
|
||||||
"uint8": Primitive("uint8", "uint8_t"),
|
|
||||||
|
|
||||||
"int16": Primitive("int16", "int16_t"),
|
|
||||||
"uint16": Primitive("uint16", "uint16_t"),
|
|
||||||
|
|
||||||
"int32": Primitive("int32", "int32_t"),
|
|
||||||
"uint32": Primitive("uint32", "uint32_t"),
|
|
||||||
|
|
||||||
"int64": Primitive("int64", "int64_t"),
|
|
||||||
"uint64": Primitive("uint64", "uint64_t"),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_primitive(name):
|
def get_primitive(name):
|
||||||
p = _primitives.get(name)
|
p = _primitives.get(name)
|
||||||
if not p:
|
if p: return p
|
||||||
from ..errors import InvalidType
|
|
||||||
raise InvalidType(name)
|
it = _inttypes.get(name.replace('*', ''))
|
||||||
return p
|
if it:
|
||||||
|
if '*' in name:
|
||||||
|
return PrimitiveRef(name, it)
|
||||||
|
else:
|
||||||
|
return Primitive(name, it)
|
||||||
|
|
||||||
|
from ..errors import InvalidType
|
||||||
|
raise InvalidType(name)
|
||||||
|
|||||||
@@ -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:
|
class Layout:
|
||||||
from collections import namedtuple
|
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}
|
sizes = {'G': 1024 ** 3, 'T': 1024 ** 4}
|
||||||
|
|
||||||
@@ -26,7 +38,7 @@ class Layout:
|
|||||||
for r in data:
|
for r in data:
|
||||||
size = Layout.get_size(r["size"])
|
size = Layout.get_size(r["size"])
|
||||||
addr -= 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)))
|
r.get("shared", False)))
|
||||||
|
|
||||||
self.regions = tuple(regions)
|
self.regions = tuple(regions)
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ def add_dir(path, files, dirs, inode_data, dir_inodes, output, compress):
|
|||||||
compressed = uncompressed
|
compressed = uncompressed
|
||||||
comp_size = uncomp_size
|
comp_size = uncomp_size
|
||||||
|
|
||||||
output.write(uncompressed)
|
output.write(compressed)
|
||||||
inode_data.append((inode_type_dir, offset, comp_size, uncomp_size))
|
inode_data.append((inode_type_dir, offset, comp_size, uncomp_size))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
93
scripts/parse_buddy_allocs.py
Executable file
93
scripts/parse_buddy_allocs.py
Executable file
@@ -0,0 +1,93 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
class block:
|
||||||
|
def __init__(self, start, order, free=False):
|
||||||
|
self.start = start
|
||||||
|
self.order = order
|
||||||
|
self.free = free
|
||||||
|
|
||||||
|
@property
|
||||||
|
def end(self):
|
||||||
|
return self.start + (1<<self.order)
|
||||||
|
|
||||||
|
def overlaps(self, other):
|
||||||
|
return other.start < self.end and other.end > self.start
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"[{self.start:016x} {self.order:2} {self.free and 'free' or 'used'}]"
|
||||||
|
|
||||||
|
def get_block(blocks, addr, order, reason):
|
||||||
|
b = blocks.get(addr)
|
||||||
|
if b is None:
|
||||||
|
print(f"ERROR: {reason} unknown block [{addr:016x}, {order}]")
|
||||||
|
elif b.order != order:
|
||||||
|
print(f"ERROR: {reason} block {b} for order {order}")
|
||||||
|
else:
|
||||||
|
return b
|
||||||
|
return None
|
||||||
|
|
||||||
|
def new_block(blocks, addr, order):
|
||||||
|
b = block(addr, order)
|
||||||
|
for existing in blocks.values():
|
||||||
|
if b.overlaps(existing):
|
||||||
|
print(f"ERROR: new block {b} overlaps existing {existing}")
|
||||||
|
blocks[addr] = b
|
||||||
|
|
||||||
|
def free_block(blocks, addr, order, free):
|
||||||
|
s = free and "freeing" or "popping"
|
||||||
|
b = get_block(blocks, addr, order, s)
|
||||||
|
if b and b.free == free:
|
||||||
|
print(f"ERROR: {s} block {b}")
|
||||||
|
elif b:
|
||||||
|
b.free = free
|
||||||
|
|
||||||
|
def split_block(blocks, addr, order):
|
||||||
|
b = get_block(blocks, addr, order+1, "splitting")
|
||||||
|
if b:
|
||||||
|
b.order = order
|
||||||
|
buddy = b.start ^ (1<<order)
|
||||||
|
blocks[buddy] = block(buddy, order)
|
||||||
|
|
||||||
|
def merge_blocks(blocks, addr1, addr2, order):
|
||||||
|
b1 = get_block(blocks, addr1, order, "merging")
|
||||||
|
b2 = get_block(blocks, addr2, order, "merging")
|
||||||
|
if b1.start > b2.start:
|
||||||
|
b1, b2 = b2, b1
|
||||||
|
del blocks[b2.start]
|
||||||
|
b1.order = order + 1
|
||||||
|
|
||||||
|
def parse_line(blocks, line):
|
||||||
|
args = line.strip().split()
|
||||||
|
match args:
|
||||||
|
case ['N', addr, order]:
|
||||||
|
new_block(blocks, int(addr, base=16), int(order))
|
||||||
|
case ['n', addr, order]:
|
||||||
|
new_block(blocks, int(addr, base=16), int(order))
|
||||||
|
case ['P', addr, order]:
|
||||||
|
free_block(blocks, int(addr, base=16), int(order), False)
|
||||||
|
case ['p', addr, order]:
|
||||||
|
free_block(blocks, int(addr, base=16), int(order), False)
|
||||||
|
case ['F', addr, order]:
|
||||||
|
free_block(blocks, int(addr, base=16), int(order), True)
|
||||||
|
case ['S', addr, order]:
|
||||||
|
split_block(blocks, int(addr, base=16), int(order))
|
||||||
|
case ['M', addr1, addr2, order]:
|
||||||
|
merge_blocks(blocks, int(addr1, base=16), int(addr2, base=16), int(order))
|
||||||
|
case _:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def parse_file(f):
|
||||||
|
blocks = {}
|
||||||
|
for line in f.readlines():
|
||||||
|
parse_line(blocks, line)
|
||||||
|
|
||||||
|
#for addr in sorted(blocks.keys()):
|
||||||
|
# print(f"{addr:09x}: {blocks[addr]}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
with open(sys.argv[1]) as f:
|
||||||
|
parse_file(f)
|
||||||
|
else:
|
||||||
|
parse_file(sys.stdin)
|
||||||
40
scripts/parse_frame_allocs.py
Executable file
40
scripts/parse_frame_allocs.py
Executable file
@@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
def add_maps(allocs, addr, count):
|
||||||
|
for i in range(count):
|
||||||
|
if addr+i in allocs:
|
||||||
|
print(f"ERROR: frame {addr+i:012x} map collision.")
|
||||||
|
else:
|
||||||
|
#print(f" frame {addr+i:012x} mapped")
|
||||||
|
allocs.add(addr+i)
|
||||||
|
|
||||||
|
def remove_maps(allocs, addr, count):
|
||||||
|
for i in range(count):
|
||||||
|
if addr+i not in allocs:
|
||||||
|
print(f" WARN: removing unmapped frame {addr+i:012x}")
|
||||||
|
else:
|
||||||
|
#print(f" frame {addr+i:012x} unmapped")
|
||||||
|
allocs.remove(addr+i)
|
||||||
|
|
||||||
|
def parse_line(allocs, line):
|
||||||
|
args = line.strip().split()
|
||||||
|
match args:
|
||||||
|
case ['+', addr, count]:
|
||||||
|
add_maps(allocs, int(addr, base=16), int(count))
|
||||||
|
case ['-', addr, count]:
|
||||||
|
remove_maps(allocs, int(addr, base=16), int(count))
|
||||||
|
case _:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def parse_file(f):
|
||||||
|
allocs = set()
|
||||||
|
for line in f.readlines():
|
||||||
|
parse_line(allocs, line)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
with open(sys.argv[1]) as f:
|
||||||
|
parse_file(f)
|
||||||
|
else:
|
||||||
|
parse_file(sys.stdin)
|
||||||
62
scripts/parse_heap_allocs.py
Executable file
62
scripts/parse_heap_allocs.py
Executable file
@@ -0,0 +1,62 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from bisect import bisect_left, insort
|
||||||
|
from operator import attrgetter
|
||||||
|
|
||||||
|
by_start = attrgetter('start')
|
||||||
|
|
||||||
|
class alloc:
|
||||||
|
def __init__(self, start, size):
|
||||||
|
self.start = start
|
||||||
|
self.size = size
|
||||||
|
|
||||||
|
@property
|
||||||
|
def end(self):
|
||||||
|
return self.start + self.size
|
||||||
|
|
||||||
|
def overlaps(self, other):
|
||||||
|
return other.start < self.end and other.end > self.start
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"[{self.start:012x} - {self.end:012x}]"
|
||||||
|
|
||||||
|
def __gt__(self, other):
|
||||||
|
return self.start > other.start
|
||||||
|
|
||||||
|
def add_alloc(allocs, addr, length):
|
||||||
|
a = alloc(addr, length)
|
||||||
|
for existing in allocs:
|
||||||
|
if a.overlaps(existing):
|
||||||
|
print(f"ERROR: allocation {a} overlaps existing {existing}")
|
||||||
|
insort(allocs, a)
|
||||||
|
|
||||||
|
def remove_alloc(allocs, addr):
|
||||||
|
a = alloc(addr, 0)
|
||||||
|
i = bisect_left(allocs, a)
|
||||||
|
if len(allocs) > i and allocs[i].start == addr:
|
||||||
|
del allocs[i]
|
||||||
|
else:
|
||||||
|
print(f"ERROR: freeing unallocated {a}")
|
||||||
|
|
||||||
|
def parse_line(allocs, line):
|
||||||
|
args = line.strip().split()
|
||||||
|
match args:
|
||||||
|
case ['+', addr, length]:
|
||||||
|
add_alloc(allocs, int(addr, base=16), int(length))
|
||||||
|
case ['-', addr]:
|
||||||
|
remove_alloc(allocs, int(addr, base=16))
|
||||||
|
case _:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def parse_file(f):
|
||||||
|
allocs = []
|
||||||
|
for line in f.readlines():
|
||||||
|
parse_line(allocs, line)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
with open(sys.argv[1]) as f:
|
||||||
|
parse_file(f)
|
||||||
|
else:
|
||||||
|
parse_file(sys.stdin)
|
||||||
124
scripts/print_got.py
Executable file
124
scripts/print_got.py
Executable file
@@ -0,0 +1,124 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
|
||||||
|
def section_header(name):
|
||||||
|
print()
|
||||||
|
print(name)
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
|
||||||
|
def print_dyn(elf):
|
||||||
|
section = elf.get_section_by_name(".dynamic")
|
||||||
|
if section is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
section_header(".dynamic")
|
||||||
|
for tag in section.iter_tags():
|
||||||
|
print(tag)
|
||||||
|
|
||||||
|
|
||||||
|
def print_got(elf, name):
|
||||||
|
import struct
|
||||||
|
|
||||||
|
section = elf.get_section_by_name(name)
|
||||||
|
if section is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
section_header(name)
|
||||||
|
base_ip = section['sh_addr']
|
||||||
|
|
||||||
|
data = section.data()
|
||||||
|
n = section.data_size // 8
|
||||||
|
for i in range(n):
|
||||||
|
addr = struct.unpack_from("Q", data, i*8)[0]
|
||||||
|
print(f"[{i:2x}]: {base_ip+i*8:6x} {addr:16x}")
|
||||||
|
|
||||||
|
|
||||||
|
def print_plt(elf):
|
||||||
|
from iced_x86 import Decoder, Formatter, FormatterSyntax
|
||||||
|
|
||||||
|
section_header(".plt")
|
||||||
|
|
||||||
|
section = elf.get_section_by_name(".plt")
|
||||||
|
n = section.data_size // 16
|
||||||
|
data = section.data()
|
||||||
|
|
||||||
|
frm = Formatter(FormatterSyntax.NASM)
|
||||||
|
frm.digit_separator = "'"
|
||||||
|
frm.first_operand_char_index = 8
|
||||||
|
frm.hex_prefix = "0x"
|
||||||
|
frm.hex_suffix = ""
|
||||||
|
frm.leading_zeros = False
|
||||||
|
frm.rip_relative_addresses = False
|
||||||
|
frm.small_hex_numbers_in_decimal = False
|
||||||
|
frm.uppercase_hex = False
|
||||||
|
|
||||||
|
base_ip = section['sh_addr']
|
||||||
|
|
||||||
|
for i in range(n):
|
||||||
|
entry = data[ i*16 : (i+1)*16 ]
|
||||||
|
d = Decoder(64, entry, ip=base_ip + i*16)
|
||||||
|
|
||||||
|
indent = f"[{i:2x}]:"
|
||||||
|
for instr in d:
|
||||||
|
disasm = frm.format(instr)
|
||||||
|
print(f"{indent:6} {instr.ip:6x} {disasm}")
|
||||||
|
indent = ""
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def print_gnu_hash(elf):
|
||||||
|
hash_section = elf.get_section_by_name(".gnu.hash")
|
||||||
|
data = hash_section.data()
|
||||||
|
|
||||||
|
import struct
|
||||||
|
(nbuckets, symoff, bloom_sz, bloom_sh) = struct.unpack_from("IIII", data, 0)
|
||||||
|
blooms = struct.unpack_from(f"{bloom_sz}Q", data, 16)
|
||||||
|
buckets = struct.unpack_from(f"{nbuckets}I", data, 16+(bloom_sz*8))
|
||||||
|
|
||||||
|
p = 16 + (bloom_sz*8) + (nbuckets*4)
|
||||||
|
n = (len(data) - p) // 4
|
||||||
|
chains = struct.unpack_from(f"{n}I", data, p)
|
||||||
|
|
||||||
|
section_header(".gnu.hash")
|
||||||
|
print(f" Bucket Count: {nbuckets}")
|
||||||
|
print(f"Symbol Offset: {symoff}")
|
||||||
|
print(f" Buckets: {buckets}")
|
||||||
|
|
||||||
|
print("\n Bloom words:")
|
||||||
|
for i in range(len(blooms)):
|
||||||
|
print(f" [{i:2}]: {blooms[i]:016x}")
|
||||||
|
|
||||||
|
print("\n Hashes:")
|
||||||
|
for i in range(len(chains)):
|
||||||
|
h = chains[i]
|
||||||
|
end = ""
|
||||||
|
if (h & 1) == 1:
|
||||||
|
end = "END"
|
||||||
|
bloom_idx = (h>>6) % bloom_sz
|
||||||
|
bloom_msk = ((1<<(h%64)) | (1<<((h>>bloom_sh)%64)))
|
||||||
|
print(f" [{i+symoff:2}]: {h:08x} {end:5} {bloom_idx:2}/{bloom_msk:016x}")
|
||||||
|
|
||||||
|
|
||||||
|
def print_tables(filename):
|
||||||
|
from elftools.elf.elffile import ELFFile
|
||||||
|
|
||||||
|
print(filename)
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
with open(filename, 'rb') as f:
|
||||||
|
elf = ELFFile(f)
|
||||||
|
print_got(elf, ".got")
|
||||||
|
print_got(elf, ".got.plt")
|
||||||
|
print_plt(elf)
|
||||||
|
print_dyn(elf)
|
||||||
|
print_gnu_hash(elf)
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
for filename in sys.argv[1:]:
|
||||||
|
print_tables(filename)
|
||||||
1
scripts/wsl_set_vnchost.fish
Normal file
1
scripts/wsl_set_vnchost.fish
Normal file
@@ -0,0 +1 @@
|
|||||||
|
set -gx VNCHOST (ip -j route list default | jq -r '.[0].gateway'):5500
|
||||||
@@ -71,10 +71,10 @@ allocator::add_modules()
|
|||||||
allocate_pages(1, alloc_type::init_args, true));
|
allocate_pages(1, alloc_type::init_args, true));
|
||||||
|
|
||||||
if (m_modules)
|
if (m_modules)
|
||||||
m_modules->next = reinterpret_cast<uintptr_t>(mods);
|
m_modules->next = mods;
|
||||||
|
|
||||||
m_modules = mods;
|
m_modules = mods;
|
||||||
m_next_mod = mods->modules;
|
m_next_mod = reinterpret_cast<module*>(mods+1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,9 +109,9 @@ allocator::allocate_pages(size_t count, alloc_type type, bool zero)
|
|||||||
}
|
}
|
||||||
|
|
||||||
module *
|
module *
|
||||||
allocator::allocate_module()
|
allocator::allocate_module(size_t extra)
|
||||||
{
|
{
|
||||||
static constexpr size_t size = sizeof(module);
|
size_t size = sizeof(module) + extra;
|
||||||
|
|
||||||
size_t remaining =
|
size_t remaining =
|
||||||
reinterpret_cast<uintptr_t>(m_modules) + page_size
|
reinterpret_cast<uintptr_t>(m_modules) + page_size
|
||||||
@@ -120,8 +120,8 @@ allocator::allocate_module()
|
|||||||
if (size > remaining)
|
if (size > remaining)
|
||||||
add_modules();
|
add_modules();
|
||||||
|
|
||||||
++m_modules->count;
|
|
||||||
module *m = m_next_mod;
|
module *m = m_next_mod;
|
||||||
|
m->bytes = size;
|
||||||
m_next_mod = util::offset_pointer(m_next_mod, size);
|
m_next_mod = util::offset_pointer(m_next_mod, size);
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public:
|
|||||||
|
|
||||||
void * allocate_pages(size_t count, alloc_type type, bool zero = false);
|
void * allocate_pages(size_t count, alloc_type type, bool zero = false);
|
||||||
|
|
||||||
module * allocate_module();
|
module * allocate_module(size_t extra = 0);
|
||||||
|
|
||||||
void memset(void *start, size_t size, uint8_t value);
|
void memset(void *start, size_t size, uint8_t value);
|
||||||
void copy(void *to, const void *from, size_t size);
|
void copy(void *to, const void *from, size_t size);
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
boot = module("boot",
|
boot = module("boot",
|
||||||
kind = "exe",
|
kind = "exe",
|
||||||
output = "boot.efi",
|
outfile = "boot.efi",
|
||||||
targets = [ "boot" ],
|
targets = [ "boot" ],
|
||||||
deps = [ "cpu", "elf", "util", "bootproto" ],
|
deps = [ "cpu", "elf", "util", "bootproto" ],
|
||||||
|
static = True,
|
||||||
sources = [
|
sources = [
|
||||||
"allocator.cpp",
|
"allocator.cpp",
|
||||||
"bootconfig.cpp",
|
"bootconfig.cpp",
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ read_string(util::buffer &data)
|
|||||||
static void
|
static void
|
||||||
read_descriptor(descriptor &e, util::buffer &data)
|
read_descriptor(descriptor &e, util::buffer &data)
|
||||||
{
|
{
|
||||||
e.flags = static_cast<desc_flags>(*util::read<uint16_t>(data));
|
e.flags = util::bitset16 {*util::read<uint16_t>(data)};
|
||||||
e.path = read_string(data);
|
e.path = read_string(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <bootproto/bootconfig.h>
|
#include <bootproto/bootconfig.h>
|
||||||
|
#include <util/bitset.h>
|
||||||
#include <util/counted.h>
|
#include <util/counted.h>
|
||||||
|
|
||||||
namespace uefi {
|
namespace uefi {
|
||||||
@@ -14,7 +15,7 @@ namespace boot {
|
|||||||
using desc_flags = bootproto::desc_flags;
|
using desc_flags = bootproto::desc_flags;
|
||||||
|
|
||||||
struct descriptor {
|
struct descriptor {
|
||||||
desc_flags flags;
|
util::bitset16 flags;
|
||||||
wchar_t const *path;
|
wchar_t const *path;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ public:
|
|||||||
/// Constructor. Loads bootconfig from the given buffer.
|
/// Constructor. Loads bootconfig from the given buffer.
|
||||||
bootconfig(util::buffer data, uefi::boot_services *bs);
|
bootconfig(util::buffer data, uefi::boot_services *bs);
|
||||||
|
|
||||||
inline uint16_t flags() const { return m_flags; }
|
inline util::bitset16 flags() const { return m_flags; }
|
||||||
inline const descriptor & kernel() const { return m_kernel; }
|
inline const descriptor & kernel() const { return m_kernel; }
|
||||||
inline const descriptor & init() const { return m_init; }
|
inline const descriptor & init() const { return m_init; }
|
||||||
inline const wchar_t * initrd() const { return m_initrd; }
|
inline const wchar_t * initrd() const { return m_initrd; }
|
||||||
@@ -35,7 +36,7 @@ public:
|
|||||||
inline const descriptors & panics() { return m_panics; }
|
inline const descriptors & panics() { return m_panics; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t m_flags;
|
util::bitset16 m_flags;
|
||||||
descriptor m_kernel;
|
descriptor m_kernel;
|
||||||
descriptor m_init;
|
descriptor m_init;
|
||||||
descriptors m_panics;
|
descriptors m_panics;
|
||||||
|
|||||||
@@ -79,10 +79,11 @@ check_cpu_supported()
|
|||||||
status_line status {L"Checking CPU features"};
|
status_line status {L"Checking CPU features"};
|
||||||
|
|
||||||
cpu::cpu_id cpu;
|
cpu::cpu_id cpu;
|
||||||
cpu::cpu_id::features features = cpu.validate();
|
cpu::features features = cpu.features();
|
||||||
bool supported = true;
|
bool supported = true;
|
||||||
|
|
||||||
#define CPU_FEATURE_OPT(...)
|
#define CPU_FEATURE_OPT(...)
|
||||||
|
#define CPU_FEATURE_WRN(...)
|
||||||
#define CPU_FEATURE_REQ(name, ...) \
|
#define CPU_FEATURE_REQ(name, ...) \
|
||||||
if (!features[cpu::feature::name]) { \
|
if (!features[cpu::feature::name]) { \
|
||||||
status::fail(L"CPU required feature " L ## #name, uefi::status::unsupported); \
|
status::fail(L"CPU required feature " L ## #name, uefi::status::unsupported); \
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ parse_program(const wchar_t *name, util::const_buffer data, bootproto::program &
|
|||||||
section.phys_addr = elf.base() + seg.offset;
|
section.phys_addr = elf.base() + seg.offset;
|
||||||
section.virt_addr = seg.vaddr;
|
section.virt_addr = seg.vaddr;
|
||||||
section.size = seg.mem_size;
|
section.size = seg.mem_size;
|
||||||
section.type = static_cast<bootproto::section_flags>(seg.flags);
|
section.type = seg.flags;
|
||||||
|
|
||||||
if (seg.mem_size != seg.file_size)
|
if (seg.mem_size != seg.file_size)
|
||||||
section.phys_addr = allocate_bss(seg);
|
section.phys_addr = allocate_bss(seg);
|
||||||
@@ -128,8 +128,6 @@ load_program(
|
|||||||
paging::pager &pager,
|
paging::pager &pager,
|
||||||
bool verify)
|
bool verify)
|
||||||
{
|
{
|
||||||
using util::bits::has;
|
|
||||||
|
|
||||||
status_line status(L"Loading program", name);
|
status_line status(L"Loading program", name);
|
||||||
|
|
||||||
elf::file elf {data};
|
elf::file elf {data};
|
||||||
@@ -155,8 +153,8 @@ load_program(
|
|||||||
|
|
||||||
pager.map_pages(phys_addr, seg.vaddr,
|
pager.map_pages(phys_addr, seg.vaddr,
|
||||||
memory::bytes_to_pages(seg.mem_size),
|
memory::bytes_to_pages(seg.mem_size),
|
||||||
has(seg.flags, elf::segment_flags::write),
|
seg.flags.get(elf::segment_flags::write),
|
||||||
has(seg.flags, elf::segment_flags::exec));
|
seg.flags.get(elf::segment_flags::exec));
|
||||||
}
|
}
|
||||||
|
|
||||||
return elf.entrypoint();
|
return elf.entrypoint();
|
||||||
@@ -167,15 +165,15 @@ load_module(
|
|||||||
fs::file &disk,
|
fs::file &disk,
|
||||||
const wchar_t *name,
|
const wchar_t *name,
|
||||||
const wchar_t *path,
|
const wchar_t *path,
|
||||||
bootproto::module_type type,
|
bootproto::module_type type)
|
||||||
uint16_t subtype)
|
|
||||||
{
|
{
|
||||||
status_line status(L"Loading module", name);
|
status_line status(L"Loading module", name);
|
||||||
|
|
||||||
bootproto::module *mod = g_alloc.allocate_module();
|
bootproto::module *mod = g_alloc.allocate_module(sizeof(util::buffer));
|
||||||
mod->type = type;
|
mod->type = type;
|
||||||
mod->subtype = subtype;
|
|
||||||
mod->data = load_file(disk, path);
|
util::buffer *data = mod->data<util::buffer>();
|
||||||
|
*data = load_file(disk, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace loader
|
} // namespace loader
|
||||||
|
|||||||
@@ -60,14 +60,12 @@ load_program(
|
|||||||
/// \arg name The human-readable name of the module
|
/// \arg name The human-readable name of the module
|
||||||
/// \arg path The path of the file to load the module from
|
/// \arg path The path of the file to load the module from
|
||||||
/// \arg type The major type to set on the module
|
/// \arg type The major type to set on the module
|
||||||
/// \arg subtype The subtype to set on the module
|
|
||||||
void
|
void
|
||||||
load_module(
|
load_module(
|
||||||
fs::file &disk,
|
fs::file &disk,
|
||||||
const wchar_t *name,
|
const wchar_t *name,
|
||||||
const wchar_t *path,
|
const wchar_t *path,
|
||||||
bootproto::module_type type,
|
bootproto::module_type type);
|
||||||
uint16_t subtype);
|
|
||||||
|
|
||||||
} // namespace loader
|
} // namespace loader
|
||||||
} // namespace boot
|
} // namespace boot
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <bootproto/acpi.h>
|
||||||
#include <bootproto/bootconfig.h>
|
#include <bootproto/bootconfig.h>
|
||||||
#include <bootproto/kernel.h>
|
#include <bootproto/kernel.h>
|
||||||
#include <bootproto/memory.h>
|
#include <bootproto/memory.h>
|
||||||
@@ -81,9 +82,8 @@ load_resources(
|
|||||||
util::buffer kernel = loader::load_file(disk, bc.kernel().path);
|
util::buffer kernel = loader::load_file(disk, bc.kernel().path);
|
||||||
uintptr_t kentry = loader::load_program(kernel, L"jsix kernel", pager, true);
|
uintptr_t kentry = loader::load_program(kernel, L"jsix kernel", pager, true);
|
||||||
|
|
||||||
args->flags = static_cast<bootproto::boot_flags>(bc.flags());
|
args->flags = bc.flags();
|
||||||
|
|
||||||
namespace bits = util::bits;
|
|
||||||
using bootproto::desc_flags;
|
using bootproto::desc_flags;
|
||||||
|
|
||||||
bool has_panic = false;
|
bool has_panic = false;
|
||||||
@@ -95,7 +95,7 @@ load_resources(
|
|||||||
// Find the screen-specific panic handler first to
|
// Find the screen-specific panic handler first to
|
||||||
// give it priority
|
// give it priority
|
||||||
for (const descriptor &d : bc.panics()) {
|
for (const descriptor &d : bc.panics()) {
|
||||||
if (bits::has(d.flags, desc_flags::graphical)) {
|
if (d.flags.get(desc_flags::graphical)) {
|
||||||
panic = loader::load_file(disk, d.path);
|
panic = loader::load_file(disk, d.path);
|
||||||
has_panic = true;
|
has_panic = true;
|
||||||
break;
|
break;
|
||||||
@@ -105,7 +105,7 @@ load_resources(
|
|||||||
|
|
||||||
if (!has_panic) {
|
if (!has_panic) {
|
||||||
for (const descriptor &d : bc.panics()) {
|
for (const descriptor &d : bc.panics()) {
|
||||||
if (!bits::has(d.flags, desc_flags::graphical)) {
|
if (!d.flags.get(desc_flags::graphical)) {
|
||||||
panic = loader::load_file(disk, d.path);
|
panic = loader::load_file(disk, d.path);
|
||||||
has_panic = true;
|
has_panic = true;
|
||||||
break;
|
break;
|
||||||
@@ -125,7 +125,7 @@ load_resources(
|
|||||||
loader::parse_program(L"init server", init, args->init);
|
loader::parse_program(L"init server", init, args->init);
|
||||||
|
|
||||||
loader::load_module(disk, L"initrd", bc.initrd(),
|
loader::load_module(disk, L"initrd", bc.initrd(),
|
||||||
bootproto::module_type::initrd, 0);
|
bootproto::module_type::initrd);
|
||||||
|
|
||||||
return reinterpret_cast<bootproto::entrypoint>(kentry);
|
return reinterpret_cast<bootproto::entrypoint>(kentry);
|
||||||
}
|
}
|
||||||
@@ -176,9 +176,23 @@ efi_main(uefi::handle image, uefi::system_table *st)
|
|||||||
bootproto::entrypoint kentry =
|
bootproto::entrypoint kentry =
|
||||||
load_resources(args, screen, image, pager, bs);
|
load_resources(args, screen, image, pager, bs);
|
||||||
|
|
||||||
|
bootproto::module *acpi_mod =
|
||||||
|
g_alloc.allocate_module(sizeof(bootproto::acpi));
|
||||||
|
acpi_mod->type = bootproto::module_type::acpi;
|
||||||
|
bootproto::acpi *acpi = acpi_mod->data<bootproto::acpi>();
|
||||||
|
acpi->root = args->acpi_table;
|
||||||
|
|
||||||
pager.update_kernel_args(args);
|
pager.update_kernel_args(args);
|
||||||
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);
|
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < args->mem_map.count; ++i) {
|
||||||
|
bootproto::mem_entry &e = args->mem_map.pointer[i];
|
||||||
|
if (e.type == bootproto::mem_type::acpi) {
|
||||||
|
acpi->region = util::buffer::from(e.start, e.pages * memory::page_size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
args->allocations = allocs;
|
args->allocations = allocs;
|
||||||
args->init_modules = reinterpret_cast<uintptr_t>(modules);
|
args->init_modules = reinterpret_cast<uintptr_t>(modules);
|
||||||
|
|
||||||
@@ -194,6 +208,7 @@ efi_main(uefi::handle image, uefi::system_table *st)
|
|||||||
|
|
||||||
change_pointer(args);
|
change_pointer(args);
|
||||||
change_pointer(args->pml4);
|
change_pointer(args->pml4);
|
||||||
|
change_pointer(args->symbol_table.pointer);
|
||||||
change_pointer(args->init.sections.pointer);
|
change_pointer(args->init.sections.pointer);
|
||||||
|
|
||||||
//status.next();
|
//status.next();
|
||||||
|
|||||||
@@ -249,13 +249,13 @@ build_frame_blocks(const util::counted<bootproto::mem_entry> &kmap)
|
|||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
|
|
||||||
uint64_t b1 = (page_count + 4095) / 4096;
|
uint64_t b1 = (page_count + 4095) / 4096;
|
||||||
blk->map1 = (1 << b1) - 1;
|
blk->map1 = (1ull << b1) - 1;
|
||||||
|
|
||||||
uint64_t b2 = (page_count + 63) / 64;
|
uint64_t b2 = (page_count + 63) / 64;
|
||||||
uint64_t b2q = b2 / 64;
|
uint64_t b2q = b2 / 64;
|
||||||
uint64_t b2r = b2 % 64;
|
uint64_t b2r = b2 % 64;
|
||||||
g_alloc.memset(blk->map2, b2q, 0xff);
|
g_alloc.memset(blk->map2, b2q, 0xff);
|
||||||
blk->map2[b2q] = (1 << b2r) - 1;
|
blk->map2[b2q] = (1ull << b2r) - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,7 +269,7 @@ build_frame_blocks(const util::counted<bootproto::mem_entry> &kmap)
|
|||||||
size_t b = blk.count / 64;
|
size_t b = blk.count / 64;
|
||||||
size_t r = blk.count % 64;
|
size_t r = blk.count % 64;
|
||||||
g_alloc.memset(blk.bitmap, b*8, 0xff);
|
g_alloc.memset(blk.bitmap, b*8, 0xff);
|
||||||
blk.bitmap[b] = (1 << r) - 1;
|
blk.bitmap[b] = (1ull << r) - 1;
|
||||||
|
|
||||||
bitmap += bitmap_size(blk.count);
|
bitmap += bitmap_size(blk.count);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ pick_mode(uefi::boot_services *bs)
|
|||||||
uint32_t res = info->horizontal_resolution * info->vertical_resolution;
|
uint32_t res = info->horizontal_resolution * info->vertical_resolution;
|
||||||
int pixmode = static_cast<int>(info->pixel_format);
|
int pixmode = static_cast<int>(info->pixel_format);
|
||||||
|
|
||||||
|
/*
|
||||||
const uint32_t modes = gop->mode->max_mode;
|
const uint32_t modes = gop->mode->max_mode;
|
||||||
for (uint32_t i = 0; i < modes; ++i) {
|
for (uint32_t i = 0; i < modes; ++i) {
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
@@ -63,6 +64,7 @@ pick_mode(uefi::boot_services *bs)
|
|||||||
pixmode = new_pixmode;
|
pixmode = new_pixmode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
screen *s = new screen;
|
screen *s = new screen;
|
||||||
s->mode = {
|
s->mode = {
|
||||||
@@ -109,20 +111,15 @@ make_module(screen *s)
|
|||||||
{
|
{
|
||||||
using bootproto::module;
|
using bootproto::module;
|
||||||
using bootproto::module_type;
|
using bootproto::module_type;
|
||||||
using bootproto::device_type;
|
namespace devices = bootproto::devices;
|
||||||
using bootproto::devices::uefi_fb;
|
|
||||||
|
|
||||||
uefi_fb *fb = new uefi_fb;
|
module *mod = g_alloc.allocate_module(sizeof(devices::uefi_fb));
|
||||||
|
mod->type = module_type::device;
|
||||||
|
mod->type_id = devices::type_id_uefi_fb;
|
||||||
|
|
||||||
|
devices::uefi_fb *fb = mod->data<devices::uefi_fb>();
|
||||||
fb->framebuffer = s->framebuffer;
|
fb->framebuffer = s->framebuffer;
|
||||||
fb->mode = s->mode;
|
fb->mode = s->mode;
|
||||||
|
|
||||||
module *mod = g_alloc.allocate_module();
|
|
||||||
mod->type = module_type::device;
|
|
||||||
mod->subtype = static_cast<uint16_t>(device_type::uefi_fb);
|
|
||||||
mod->data = {
|
|
||||||
.pointer = fb,
|
|
||||||
.count = sizeof(uefi_fb),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace video
|
} // namespace video
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "apic.h"
|
#include "apic.h"
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "clock.h"
|
#include "clock.h"
|
||||||
#include "interrupts.h"
|
#include "interrupts.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
@@ -71,21 +71,19 @@ lapic::get_id()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lapic::send_ipi(ipi mode, isr vector, uint8_t dest)
|
lapic::send_ipi(util::bitset32 mode, isr vector, uint8_t dest)
|
||||||
{
|
{
|
||||||
// Wait until the APIC is ready to send
|
// Wait until the APIC is ready to send
|
||||||
ipi_wait();
|
ipi_wait();
|
||||||
|
|
||||||
uint32_t command =
|
uint32_t command = util::bitset32::from(vector) | mode;
|
||||||
static_cast<uint32_t>(vector) |
|
|
||||||
static_cast<uint32_t>(mode);
|
|
||||||
|
|
||||||
apic_write(m_base, lapic_icr_high, static_cast<uint32_t>(dest) << 24);
|
apic_write(m_base, lapic_icr_high, static_cast<uint32_t>(dest) << 24);
|
||||||
apic_write(m_base, lapic_icr_low, command);
|
apic_write(m_base, lapic_icr_low, command);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lapic::send_ipi_broadcast(ipi mode, bool self, isr vector)
|
lapic::send_ipi_broadcast(util::bitset32 mode, bool self, isr vector)
|
||||||
{
|
{
|
||||||
// Wait until the APIC is ready to send
|
// Wait until the APIC is ready to send
|
||||||
ipi_wait();
|
ipi_wait();
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
/// Classes to control both local and I/O APICs.
|
/// Classes to control both local and I/O APICs.
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <util/enum_bitfields.h>
|
#include <util/bitset.h>
|
||||||
|
|
||||||
#include "interrupts.h"
|
#include "interrupts.h"
|
||||||
|
|
||||||
@@ -33,33 +33,30 @@ public:
|
|||||||
/// Get the local APIC's ID
|
/// Get the local APIC's ID
|
||||||
uint8_t get_id();
|
uint8_t get_id();
|
||||||
|
|
||||||
enum class ipi : uint32_t
|
enum class ipi_flags
|
||||||
{
|
{
|
||||||
// Delivery modes
|
logical = 11,
|
||||||
fixed = 0x0000,
|
pending = 12,
|
||||||
smi = 0x0200,
|
assert = 14,
|
||||||
nmi = 0x0400,
|
level = 15,
|
||||||
init = 0x0500,
|
|
||||||
startup = 0x0600,
|
|
||||||
|
|
||||||
// Flags
|
|
||||||
deassert = 0x0000,
|
|
||||||
assert = 0x4000,
|
|
||||||
edge = 0x0000, ///< edge-triggered
|
|
||||||
level = 0x8000, ///< level-triggered
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// IPI flags based on delivery mode (bits 8-10)
|
||||||
|
static constexpr util::bitset32 ipi_fixed = 0;
|
||||||
|
static constexpr util::bitset32 ipi_init = 0x500;
|
||||||
|
static constexpr util::bitset32 ipi_sipi = 0x600;
|
||||||
|
|
||||||
/// Send an inter-processor interrupt.
|
/// Send an inter-processor interrupt.
|
||||||
/// \arg mode The sending mode
|
/// \arg mode The sending mode
|
||||||
/// \arg vector The interrupt vector
|
/// \arg vector The interrupt vector
|
||||||
/// \arg dest The APIC ID of the destination
|
/// \arg dest The APIC ID of the destination
|
||||||
void send_ipi(ipi mode, isr vector, uint8_t dest);
|
void send_ipi(util::bitset32 mode, isr vector, uint8_t dest);
|
||||||
|
|
||||||
/// Send an inter-processor broadcast interrupt to all other CPUs
|
/// Send an inter-processor broadcast interrupt to all other CPUs
|
||||||
/// \arg mode The sending mode
|
/// \arg mode The sending mode
|
||||||
/// \arg self If true, include this CPU in the broadcast
|
/// \arg self If true, include this CPU in the broadcast
|
||||||
/// \arg vector The interrupt vector
|
/// \arg vector The interrupt vector
|
||||||
void send_ipi_broadcast(ipi mode, bool self, isr vector);
|
void send_ipi_broadcast(util::bitset32 mode, bool self, isr vector);
|
||||||
|
|
||||||
/// Wait for an IPI to finish sending. This is done automatically
|
/// Wait for an IPI to finish sending. This is done automatically
|
||||||
/// before sending another IPI with send_ipi().
|
/// before sending another IPI with send_ipi().
|
||||||
@@ -145,6 +142,3 @@ private:
|
|||||||
uint8_t m_id;
|
uint8_t m_id;
|
||||||
uint8_t m_version;
|
uint8_t m_version;
|
||||||
};
|
};
|
||||||
|
|
||||||
is_bitfield(lapic::ipi);
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
#include "assert.h"
|
|
||||||
#include "idt.h"
|
|
||||||
|
|
||||||
namespace panic {
|
|
||||||
|
|
||||||
uint32_t *apic_icr = reinterpret_cast<uint32_t*>(0xffffc000fee00300);
|
|
||||||
void const *symbol_table = nullptr;
|
|
||||||
|
|
||||||
void
|
|
||||||
install(uintptr_t entrypoint, util::const_buffer symbol_data)
|
|
||||||
{
|
|
||||||
IDT::set_nmi_handler(entrypoint);
|
|
||||||
symbol_table = symbol_data.pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace panic
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
void __assert_fail(const char *message, const char *file, unsigned line, const char *function) {
|
|
||||||
panic::panic(message, nullptr, function, file, line);
|
|
||||||
}
|
|
||||||
@@ -68,6 +68,7 @@ cap_table::derive(j6_handle_t base, j6_cap_t caps)
|
|||||||
capability *
|
capability *
|
||||||
cap_table::find_without_retain(j6_handle_t id)
|
cap_table::find_without_retain(j6_handle_t id)
|
||||||
{
|
{
|
||||||
|
util::scoped_lock lock {m_lock};
|
||||||
return m_caps.find(id);
|
return m_caps.find(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
|
|
||||||
using __exit_func = void (*)(void *);
|
using __exit_func = void (*)(void *);
|
||||||
|
|
||||||
|
|||||||
@@ -1,58 +1,72 @@
|
|||||||
#include <new>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <j6/memutils.h>
|
||||||
#include <util/bitset.h>
|
#include <util/bitset.h>
|
||||||
|
#include <util/no_construct.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "cpu/cpu_id.h"
|
|
||||||
#include "device_manager.h"
|
#include "device_manager.h"
|
||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "msr.h"
|
#include "msr.h"
|
||||||
#include "objects/thread.h"
|
#include "objects/thread.h"
|
||||||
#include "scheduler.h"
|
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
#include "tss.h"
|
#include "tss.h"
|
||||||
|
#include "xsave.h"
|
||||||
|
|
||||||
unsigned g_num_cpus = 1;
|
unsigned g_num_cpus = 1;
|
||||||
|
|
||||||
panic_data g_panic_data;
|
panic_data g_panic_data;
|
||||||
panic_data *g_panic_data_p = &g_panic_data;
|
panic_data *g_panic_data_p = &g_panic_data;
|
||||||
|
|
||||||
cpu_data g_bsp_cpu_data;
|
static util::no_construct<cpu_data> __g_bsp_cpu_storage;
|
||||||
|
cpu_data &g_bsp_cpu_data = __g_bsp_cpu_storage.value;
|
||||||
|
|
||||||
cpu_data **g_cpu_data = nullptr;
|
cpu_data **g_cpu_data = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
static cpu::features
|
||||||
|
get_features()
|
||||||
|
{
|
||||||
|
cpu::cpu_id cpuid;
|
||||||
|
return cpuid.features();
|
||||||
|
}
|
||||||
|
|
||||||
// Validate the required CPU features are present. Really, the bootloader already
|
// Validate the required CPU features are present. Really, the bootloader already
|
||||||
// validated the required features, but still iterate the options and log about them.
|
// validated the required features, but still iterate the options and log about them.
|
||||||
void
|
static cpu::features
|
||||||
cpu_validate()
|
cpu_validate(cpu_data *c)
|
||||||
{
|
{
|
||||||
cpu::cpu_id cpu;
|
cpu::cpu_id cpuid;
|
||||||
|
|
||||||
char brand_name[50];
|
char brand_name[50];
|
||||||
cpu.brand_name(brand_name);
|
cpuid.brand_name(brand_name);
|
||||||
|
|
||||||
cpu::cpu_id::features features = cpu.validate();
|
cpu::features &features = c->features;
|
||||||
|
|
||||||
log::info(logs::boot, "CPU: %s", brand_name);
|
log::info(logs::boot, "CPU %2d: %s", c->index, brand_name);
|
||||||
log::info(logs::boot, " Vendor is %s", cpu.vendor_id());
|
log::info(logs::boot, " Vendor is %s", cpuid.vendor_id());
|
||||||
|
|
||||||
log::spam(logs::boot, " Higest basic CPUID: 0x%02x", cpu.highest_basic());
|
log::spam(logs::boot, " Higest basic CPUID: 0x%02x", cpuid.highest_basic());
|
||||||
log::spam(logs::boot, " Higest ext CPUID: 0x%02x", cpu.highest_ext() & ~cpu::cpu_id::cpuid_extended);
|
log::spam(logs::boot, " Higest ext CPUID: 0x%02x", cpuid.highest_ext() & ~cpu::cpu_id::cpuid_extended);
|
||||||
|
|
||||||
#define CPU_FEATURE_OPT(name, ...) \
|
#define CPU_FEATURE_OPT(name, ...) \
|
||||||
log::verbose(logs::boot, " Supports %9s: %s", #name, features[cpu::feature::name] ? "yes" : "no");
|
log::verbose(logs::boot, " Flag %11s: %s", #name, features[cpu::feature::name] ? "yes" : "no");
|
||||||
|
|
||||||
|
#define CPU_FEATURE_WRN(name, feat_leaf, feat_sub, regname, bit) \
|
||||||
|
log::verbose(logs::boot, " Flag %11s: %s", #name, features[cpu::feature::name] ? "yes" : "no"); \
|
||||||
|
if (!features[cpu::feature::name]) log::warn(logs::boot, "Missing cpu feature %s but continuing", #name);
|
||||||
|
|
||||||
#define CPU_FEATURE_REQ(name, feat_leaf, feat_sub, regname, bit) \
|
#define CPU_FEATURE_REQ(name, feat_leaf, feat_sub, regname, bit) \
|
||||||
log::verbose(logs::boot, " Supports %9s: %s", #name, features[cpu::feature::name] ? "yes" : "no"); \
|
log::verbose(logs::boot, " Flag %11s: %s", #name, features[cpu::feature::name] ? "yes" : "no"); \
|
||||||
kassert(features[cpu::feature::name], "Missing required CPU feature " #name );
|
kassert(features[cpu::feature::name], "Missing required CPU feature " #name );
|
||||||
|
|
||||||
#include "cpu/features.inc"
|
#include "cpu/features.inc"
|
||||||
#undef CPU_FEATURE_OPT
|
#undef CPU_FEATURE_OPT
|
||||||
#undef CPU_FEATURE_REQ
|
#undef CPU_FEATURE_REQ
|
||||||
|
|
||||||
|
return features;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -64,13 +78,31 @@ cpu_early_init(cpu_data *cpu)
|
|||||||
cpu->idt->install();
|
cpu->idt->install();
|
||||||
cpu->gdt->install();
|
cpu->gdt->install();
|
||||||
|
|
||||||
|
util::bitset64 cr0_val = 0;
|
||||||
|
asm ("mov %%cr0, %0" : "=r"(cr0_val));
|
||||||
|
cr0_val
|
||||||
|
.set(cr0::WP)
|
||||||
|
.clear(cr0::CD);
|
||||||
|
asm volatile ( "mov %0, %%cr0" :: "r" (cr0_val) );
|
||||||
|
|
||||||
|
cpu->features = get_features();
|
||||||
|
|
||||||
|
uintptr_t cr3_val;
|
||||||
|
asm ("mov %%cr3, %0" : "=r"(cr3_val));
|
||||||
|
|
||||||
util::bitset64 cr4_val = 0;
|
util::bitset64 cr4_val = 0;
|
||||||
asm ("mov %%cr4, %0" : "=r"(cr4_val));
|
asm ("mov %%cr4, %0" : "=r"(cr4_val));
|
||||||
cr4_val
|
cr4_val
|
||||||
.set(cr4::OSXFSR)
|
.set(cr4::OSXFSR)
|
||||||
.set(cr4::OSXMMEXCPT)
|
.set(cr4::OSXMMEXCPT)
|
||||||
.set(cr4::PCIDE)
|
|
||||||
.set(cr4::OSXSAVE);
|
.set(cr4::OSXSAVE);
|
||||||
|
|
||||||
|
// TODO: On KVM setting PCIDE generates a #GP even though
|
||||||
|
// the feature is listed as available in CPUID.
|
||||||
|
/*
|
||||||
|
if (cpu->features[cpu::feature::pcid])
|
||||||
|
cr4_val.set(cr4::PCIDE);
|
||||||
|
*/
|
||||||
asm volatile ( "mov %0, %%cr4" :: "r" (cr4_val) );
|
asm volatile ( "mov %0, %%cr4" :: "r" (cr4_val) );
|
||||||
|
|
||||||
// Enable SYSCALL and NX bit
|
// Enable SYSCALL and NX bit
|
||||||
@@ -80,6 +112,23 @@ cpu_early_init(cpu_data *cpu)
|
|||||||
.set(efer::NXE);
|
.set(efer::NXE);
|
||||||
wrmsr(msr::ia32_efer, efer_val);
|
wrmsr(msr::ia32_efer, efer_val);
|
||||||
|
|
||||||
|
util::bitset64 xcr0_val = get_xcr0();
|
||||||
|
xcr0_val
|
||||||
|
.set(xcr0::SSE);
|
||||||
|
set_xcr0(xcr0_val);
|
||||||
|
|
||||||
|
// Set initial floating point state
|
||||||
|
const util::bitset32 mxcsr_val = util::bitset32::of(
|
||||||
|
mxcsr::DAZ,
|
||||||
|
mxcsr::IM,
|
||||||
|
mxcsr::DM,
|
||||||
|
mxcsr::ZM,
|
||||||
|
mxcsr::OM,
|
||||||
|
mxcsr::UM,
|
||||||
|
mxcsr::PM,
|
||||||
|
mxcsr::FTZ);
|
||||||
|
asm ( "ldmxcsr %0" :: "m"(mxcsr_val) );
|
||||||
|
|
||||||
// Install the GS base pointint to the cpu_data
|
// Install the GS base pointint to the cpu_data
|
||||||
wrmsr(msr::ia32_gs_base, reinterpret_cast<uintptr_t>(cpu));
|
wrmsr(msr::ia32_gs_base, reinterpret_cast<uintptr_t>(cpu));
|
||||||
}
|
}
|
||||||
@@ -87,7 +136,6 @@ cpu_early_init(cpu_data *cpu)
|
|||||||
cpu_data *
|
cpu_data *
|
||||||
bsp_early_init()
|
bsp_early_init()
|
||||||
{
|
{
|
||||||
cpu_validate();
|
|
||||||
memset(&g_panic_data, 0, sizeof(g_panic_data));
|
memset(&g_panic_data, 0, sizeof(g_panic_data));
|
||||||
|
|
||||||
extern IDT &g_bsp_idt;
|
extern IDT &g_bsp_idt;
|
||||||
@@ -104,6 +152,7 @@ bsp_early_init()
|
|||||||
cpu->gdt = new (&g_bsp_gdt) GDT {cpu->tss};
|
cpu->gdt = new (&g_bsp_gdt) GDT {cpu->tss};
|
||||||
cpu->rsp0 = reinterpret_cast<uintptr_t>(&idle_stack_end);
|
cpu->rsp0 = reinterpret_cast<uintptr_t>(&idle_stack_end);
|
||||||
cpu_early_init(cpu);
|
cpu_early_init(cpu);
|
||||||
|
xsave_init();
|
||||||
|
|
||||||
return cpu;
|
return cpu;
|
||||||
}
|
}
|
||||||
@@ -120,8 +169,12 @@ bsp_late_init()
|
|||||||
asm ("mov %%cr0, %0" : "=r"(cr0v));
|
asm ("mov %%cr0, %0" : "=r"(cr0v));
|
||||||
asm ("mov %%cr4, %0" : "=r"(cr4v));
|
asm ("mov %%cr4, %0" : "=r"(cr4v));
|
||||||
|
|
||||||
|
uint32_t mxcsrv = get_mxcsr();
|
||||||
|
uint64_t xcr0v = get_xcr0();
|
||||||
|
|
||||||
uint64_t efer = rdmsr(msr::ia32_efer);
|
uint64_t efer = rdmsr(msr::ia32_efer);
|
||||||
log::spam(logs::boot, "Control regs: cr0:%lx cr4:%lx efer:%lx", cr0v, cr4v, efer);
|
log::spam(logs::boot, "Control regs: cr0:%lx cr4:%lx efer:%lx mxcsr:%x xcr0:%x", cr0v, cr4v, efer, mxcsrv, xcr0v);
|
||||||
|
cpu_validate(&g_bsp_cpu_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_data *
|
cpu_data *
|
||||||
@@ -162,7 +215,6 @@ cpu_init(cpu_data *cpu, bool bsp)
|
|||||||
|
|
||||||
obj::thread *idle = obj::thread::create_idle_thread(
|
obj::thread *idle = obj::thread::create_idle_thread(
|
||||||
g_kernel_process,
|
g_kernel_process,
|
||||||
scheduler::max_priority,
|
|
||||||
cpu->rsp0);
|
cpu->rsp0);
|
||||||
|
|
||||||
cpu->thread = idle;
|
cpu->thread = idle;
|
||||||
@@ -190,4 +242,16 @@ cpu_init(cpu_data *cpu, bool bsp)
|
|||||||
cpu->id = apic->get_id();
|
cpu->id = apic->get_id();
|
||||||
apic->calibrate_timer();
|
apic->calibrate_timer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xsave_enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set up initial per-thread CPU state. Called once from initialize_user_cpu in
|
||||||
|
/// syscall.s, the first code run after a thread comes out of task_switch for the
|
||||||
|
/// very first time.
|
||||||
|
extern "C" void
|
||||||
|
cpu_initialize_thread_state()
|
||||||
|
{
|
||||||
|
const util::bitset32 &mxcsr_val = obj::thread::current().m_mxcsr;
|
||||||
|
asm ( "ldmxcsr %0" :: "m"(mxcsr_val) );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <cpu/cpu_id.h>
|
||||||
|
|
||||||
class GDT;
|
class GDT;
|
||||||
class IDT;
|
class IDT;
|
||||||
@@ -17,9 +18,12 @@ enum class cr0
|
|||||||
{
|
{
|
||||||
PE = 0, // Protected mode enable
|
PE = 0, // Protected mode enable
|
||||||
MP = 1, // Monitor co-processor
|
MP = 1, // Monitor co-processor
|
||||||
|
EM = 2, // (FPU) Emulation
|
||||||
|
TS = 3, // Task switched
|
||||||
ET = 4, // Extension type
|
ET = 4, // Extension type
|
||||||
NE = 5, // Numeric error
|
NE = 5, // Numeric error
|
||||||
WP = 16, // (ring 0) Write protect
|
WP = 16, // (ring 0) Write protect
|
||||||
|
CD = 30, // Cache disable
|
||||||
PG = 31, // Paging
|
PG = 31, // Paging
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -47,6 +51,8 @@ enum class xcr0
|
|||||||
ZMM_Hi256,
|
ZMM_Hi256,
|
||||||
ZMM_Hi16,
|
ZMM_Hi16,
|
||||||
PKRU = 9,
|
PKRU = 9,
|
||||||
|
|
||||||
|
J6_SUPPORTED = X87 | SSE | AVX | BINDREG | BINDCSR | OPMASK | ZMM_Hi16 | ZMM_Hi256,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class efer
|
enum class efer
|
||||||
@@ -58,6 +64,26 @@ enum class efer
|
|||||||
FFXSR = 14, // Fast FXSAVE
|
FFXSR = 14, // Fast FXSAVE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class mxcsr
|
||||||
|
{
|
||||||
|
IE = 0, // Invalid operation flag
|
||||||
|
DE = 1, // Denormal flag
|
||||||
|
ZE = 2, // Divide by zero flag
|
||||||
|
OE = 3, // Overflow flag
|
||||||
|
UE = 4, // Underflow flag
|
||||||
|
PE = 5, // Precision flag
|
||||||
|
DAZ = 6, // Denormals are zero
|
||||||
|
IM = 7, // Invalid operation mask
|
||||||
|
DM = 8, // Denormal mask
|
||||||
|
ZM = 9, // Divide by zero mask
|
||||||
|
OM = 10, // Overflow mask
|
||||||
|
UM = 11, // Underflow mask
|
||||||
|
PM = 12, // Precision mask
|
||||||
|
RC0 = 13, // Rounding control bit 0
|
||||||
|
RC1 = 14, // Rounding control bit 1
|
||||||
|
FTZ = 15, // Flush to zero
|
||||||
|
};
|
||||||
|
|
||||||
struct cpu_state
|
struct cpu_state
|
||||||
{
|
{
|
||||||
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
|
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
|
||||||
@@ -105,9 +131,20 @@ struct cpu_data
|
|||||||
// the assembly version
|
// the assembly version
|
||||||
lapic *apic;
|
lapic *apic;
|
||||||
panic_data *panic;
|
panic_data *panic;
|
||||||
|
cpu::features features;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" cpu_data * _current_gsbase();
|
extern "C" {
|
||||||
|
uint32_t get_mxcsr();
|
||||||
|
uint32_t set_mxcsr(uint32_t val);
|
||||||
|
|
||||||
|
uint64_t get_xcr0();
|
||||||
|
uint64_t set_xcr0(uint64_t val);
|
||||||
|
|
||||||
|
cpu_data * _current_gsbase();
|
||||||
|
|
||||||
|
void cpu_initialize_thread_state();
|
||||||
|
}
|
||||||
|
|
||||||
/// Do early initialization of the BSP CPU.
|
/// Do early initialization of the BSP CPU.
|
||||||
/// \returns A pointer to the BSP cpu_data structure
|
/// \returns A pointer to the BSP cpu_data structure
|
||||||
|
|||||||
@@ -1,3 +1,34 @@
|
|||||||
|
global get_mxcsr: function hidden (get_mxcsr.end - get_mxcsr)
|
||||||
|
get_mxcsr:
|
||||||
|
push 0
|
||||||
|
stmxcsr [rsp]
|
||||||
|
pop rax
|
||||||
|
ret
|
||||||
|
.end:
|
||||||
|
|
||||||
|
global set_mxcsr: function hidden (set_mxcsr.end - set_mxcsr)
|
||||||
|
set_mxcsr:
|
||||||
|
push rdi
|
||||||
|
ldmxcsr [rsp]
|
||||||
|
pop rax
|
||||||
|
ret
|
||||||
|
.end:
|
||||||
|
|
||||||
|
global get_xcr0: function hidden (get_xcr0.end - get_xcr0)
|
||||||
|
get_xcr0:
|
||||||
|
xor rcx, rcx ; there is no dana there is only xcr0
|
||||||
|
xgetbv
|
||||||
|
ret ; technically edx has the high 32 bits, but bits 10+ are reserved
|
||||||
|
.end:
|
||||||
|
|
||||||
|
global set_xcr0: function hidden (set_xcr0.end - set_xcr0)
|
||||||
|
set_xcr0:
|
||||||
|
xor rcx, rcx ; there is no dana there is only xcr0
|
||||||
|
mov rax, rdi ; technically edx should be or'd into the high bits, but xcr0 bits 10+ are resereved
|
||||||
|
xsetbv
|
||||||
|
ret
|
||||||
|
.end:
|
||||||
|
|
||||||
global get_rsp: function hidden (get_rsp.end - get_rsp)
|
global get_rsp: function hidden (get_rsp.end - get_rsp)
|
||||||
get_rsp:
|
get_rsp:
|
||||||
mov rax, rsp
|
mov rax, rsp
|
||||||
87
src/kernel/debugcon.cpp
Normal file
87
src/kernel/debugcon.cpp
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#include <util/format.h>
|
||||||
|
|
||||||
|
#include "debugcon.h"
|
||||||
|
#include "interrupts.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
namespace debugcon {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
static const uint8_t level_colors[] = {0x00, 0x09, 0x01, 0x0b, 0x0f, 0x07, 0x08};
|
||||||
|
const char *level_names[] = {"", "fatal", "error", "warn", "info", "verbose", "spam"};
|
||||||
|
const char *area_names[] = {
|
||||||
|
#define LOG(name, lvl) #name ,
|
||||||
|
#include <j6/tables/log_areas.inc>
|
||||||
|
#undef LOG
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void debug_out(const char *msg, size_t size) {
|
||||||
|
asm ( "rep outsb;" :: "c"(size), "d"(port), "S"(msg) );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void debug_endline() {
|
||||||
|
static const char *newline = "\e[0m\r\n";
|
||||||
|
asm ( "rep outsb;" :: "c"(6), "d"(port), "S"(newline) );
|
||||||
|
}
|
||||||
|
} // anon namespace
|
||||||
|
|
||||||
|
void
|
||||||
|
write(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
char buffer[256];
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, fmt);
|
||||||
|
size_t n = util::vformat({buffer, sizeof(buffer)}, fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
debug_out(buffer, n);
|
||||||
|
debug_out("\r\n", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
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\u2502\e[38;5;%dm ",
|
||||||
|
level_colors[entry->severity],
|
||||||
|
area_names[entry->area],
|
||||||
|
level_names[entry->severity],
|
||||||
|
level_colors[entry->severity]);
|
||||||
|
|
||||||
|
debug_out(buffer, dlen);
|
||||||
|
|
||||||
|
debug_out(entry->message, entry->bytes - sizeof(j6_log_entry));
|
||||||
|
debug_endline();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
logger_task()
|
||||||
|
{
|
||||||
|
using entry = j6_log_entry;
|
||||||
|
|
||||||
|
uint64_t seen = 0;
|
||||||
|
size_t buf_size = 128;
|
||||||
|
uint8_t *buf = new uint8_t [buf_size];
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
size_t size = g_logger.get_entry(seen, buf, buf_size);
|
||||||
|
if (size > buf_size) {
|
||||||
|
delete [] buf;
|
||||||
|
buf_size *= 2;
|
||||||
|
buf = new uint8_t [buf_size];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry *header = reinterpret_cast<entry*>(buf);
|
||||||
|
while (size > sizeof(entry)) {
|
||||||
|
output(header);
|
||||||
|
seen = header->id;
|
||||||
|
size -= header->bytes;
|
||||||
|
header = util::offset_pointer(header, header->bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace debugcon
|
||||||
31
src/kernel/debugcon.h
Normal file
31
src/kernel/debugcon.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file debugcon.h
|
||||||
|
/// Kernel debugcon log output process
|
||||||
|
|
||||||
|
#include "scheduler.h"
|
||||||
|
|
||||||
|
namespace debugcon {
|
||||||
|
|
||||||
|
static constexpr bool enable =
|
||||||
|
#ifdef __jsix_config_debug
|
||||||
|
true;
|
||||||
|
#else
|
||||||
|
false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static constexpr uint16_t port = 0x6600;
|
||||||
|
|
||||||
|
void logger_task();
|
||||||
|
void write(const char *fmt, ...);
|
||||||
|
|
||||||
|
inline void
|
||||||
|
init_logger()
|
||||||
|
{
|
||||||
|
if constexpr (enable) {
|
||||||
|
static constexpr uint8_t pri = scheduler::max_priority - 1;
|
||||||
|
scheduler &s = scheduler::get();
|
||||||
|
s.create_kernel_task(logger_task, pri, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace debugcon
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
#include <new>
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <util/misc.h> // for checksum
|
#include <util/misc.h> // for checksum
|
||||||
#include <util/pointers.h>
|
#include <util/pointers.h>
|
||||||
|
#include <acpi/tables.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "acpi_tables.h"
|
|
||||||
#include "apic.h"
|
#include "apic.h"
|
||||||
#include "clock.h"
|
#include "clock.h"
|
||||||
#include "device_manager.h"
|
#include "device_manager.h"
|
||||||
@@ -21,37 +20,6 @@ static const char expected_signature[] = "RSD PTR ";
|
|||||||
|
|
||||||
device_manager device_manager::s_instance;
|
device_manager device_manager::s_instance;
|
||||||
|
|
||||||
struct acpi1_rsdp
|
|
||||||
{
|
|
||||||
char signature[8];
|
|
||||||
uint8_t checksum;
|
|
||||||
char oem_id[6];
|
|
||||||
uint8_t revision;
|
|
||||||
uint32_t rsdt_address;
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
struct acpi2_rsdp
|
|
||||||
{
|
|
||||||
char signature[8];
|
|
||||||
uint8_t checksum10;
|
|
||||||
char oem_id[6];
|
|
||||||
uint8_t revision;
|
|
||||||
uint32_t rsdt_address;
|
|
||||||
|
|
||||||
uint32_t length;
|
|
||||||
acpi_table_header *xsdt_address;
|
|
||||||
uint8_t checksum20;
|
|
||||||
uint8_t reserved[3];
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
bool
|
|
||||||
acpi_table_header::validate(uint32_t expected_type) const
|
|
||||||
{
|
|
||||||
if (util::checksum(this, length) != 0) return false;
|
|
||||||
return !expected_type || (expected_type == type);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
device_manager::device_manager() :
|
device_manager::device_manager() :
|
||||||
m_lapic_base(0)
|
m_lapic_base(0)
|
||||||
{
|
{
|
||||||
@@ -63,37 +31,32 @@ device_manager::device_manager() :
|
|||||||
m_irqs[2] = {ignore_event, 0};
|
m_irqs[2] = {ignore_event, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> static const T *
|
|
||||||
check_get_table(const acpi_table_header *header)
|
|
||||||
{
|
|
||||||
kassert(header && header->validate(T::type_id), "Invalid ACPI table.");
|
|
||||||
return reinterpret_cast<const T *>(header);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
device_manager::parse_acpi(const void *root_table)
|
device_manager::parse_acpi(const void *root_table)
|
||||||
{
|
{
|
||||||
kassert(root_table != 0, "ACPI root table pointer is null.");
|
kassert(root_table != 0, "ACPI root table pointer is null.");
|
||||||
|
|
||||||
const acpi1_rsdp *acpi1 = mem::to_virtual(
|
const acpi::rsdp1 *acpi1 = mem::to_virtual(
|
||||||
reinterpret_cast<const acpi1_rsdp *>(root_table));
|
reinterpret_cast<const acpi::rsdp1 *>(root_table));
|
||||||
|
|
||||||
for (int i = 0; i < sizeof(acpi1->signature); ++i)
|
for (int i = 0; i < sizeof(acpi1->signature); ++i)
|
||||||
kassert(acpi1->signature[i] == expected_signature[i],
|
kassert(acpi1->signature[i] == expected_signature[i],
|
||||||
"ACPI RSDP table signature mismatch");
|
"ACPI RSDP table signature mismatch");
|
||||||
|
|
||||||
uint8_t sum = util::checksum(acpi1, sizeof(acpi1_rsdp), 0);
|
uint8_t sum = util::checksum(acpi1, sizeof(acpi::rsdp1), 0);
|
||||||
kassert(sum == 0, "ACPI 1.0 RSDP checksum mismatch.");
|
kassert(sum == 0, "ACPI 1.0 RSDP checksum mismatch.");
|
||||||
|
|
||||||
kassert(acpi1->revision > 1, "ACPI 1.0 not supported.");
|
kassert(acpi1->revision > 1, "ACPI 1.0 not supported.");
|
||||||
|
|
||||||
const acpi2_rsdp *acpi2 =
|
const acpi::rsdp2 *acpi2 =
|
||||||
reinterpret_cast<const acpi2_rsdp *>(acpi1);
|
reinterpret_cast<const acpi::rsdp2 *>(acpi1);
|
||||||
|
|
||||||
sum = util::checksum(acpi2, sizeof(acpi2_rsdp), sizeof(acpi1_rsdp));
|
sum = util::checksum(acpi2, sizeof(acpi::rsdp2), sizeof(acpi::rsdp1));
|
||||||
kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch.");
|
kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch.");
|
||||||
|
|
||||||
load_xsdt(mem::to_virtual(acpi2->xsdt_address));
|
const acpi::table_header *xsdt = mem::to_virtual(acpi2->xsdt_address);
|
||||||
|
kassert(xsdt->validate(), "Bad XSDT table");
|
||||||
|
load_xsdt(xsdt);
|
||||||
}
|
}
|
||||||
|
|
||||||
const device_manager::apic_nmi *
|
const device_manager::apic_nmi *
|
||||||
@@ -129,53 +92,50 @@ put_sig(char *into, uint32_t type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
device_manager::load_xsdt(const acpi_table_header *header)
|
device_manager::load_xsdt(const acpi::table_header *header)
|
||||||
{
|
{
|
||||||
const auto *xsdt = check_get_table<acpi_xsdt>(header);
|
const auto *xsdt = acpi::check_get_table<acpi::xsdt>(header);
|
||||||
|
|
||||||
char sig[5] = {0,0,0,0,0};
|
char sig[5] = {0,0,0,0,0};
|
||||||
log::info(logs::device, "ACPI 2.0+ tables loading");
|
log::info(logs::device, "ACPI 2.0+ tables loading");
|
||||||
|
|
||||||
put_sig(sig, xsdt->header.type);
|
put_sig(sig, xsdt->header.type);
|
||||||
log::verbose(logs::device, " Found table %s", sig);
|
log::verbose(logs::device, " Loading table %s", sig);
|
||||||
|
|
||||||
size_t num_tables = acpi_table_entries(xsdt, sizeof(void*));
|
size_t num_tables = acpi::table_entries(xsdt, sizeof(void*));
|
||||||
for (size_t i = 0; i < num_tables; ++i) {
|
for (size_t i = 0; i < num_tables; ++i) {
|
||||||
const acpi_table_header *header =
|
const acpi::table_header *header =
|
||||||
mem::to_virtual(xsdt->headers[i]);
|
mem::to_virtual(xsdt->headers[i]);
|
||||||
|
|
||||||
put_sig(sig, header->type);
|
|
||||||
log::verbose(logs::device, " Found table %s", sig);
|
|
||||||
|
|
||||||
kassert(header->validate(), "Table failed validation.");
|
kassert(header->validate(), "Table failed validation.");
|
||||||
|
put_sig(sig, header->type);
|
||||||
|
|
||||||
switch (header->type) {
|
switch (header->type) {
|
||||||
case acpi_apic::type_id:
|
case acpi::apic::type_id:
|
||||||
|
log::verbose(logs::device, " Loading table %s", sig);
|
||||||
load_apic(header);
|
load_apic(header);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case acpi_mcfg::type_id:
|
case acpi::hpet::type_id:
|
||||||
load_mcfg(header);
|
log::verbose(logs::device, " Loading table %s", sig);
|
||||||
break;
|
|
||||||
|
|
||||||
case acpi_hpet::type_id:
|
|
||||||
load_hpet(header);
|
load_hpet(header);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
log::verbose(logs::device, " Skipping table %s", sig);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
device_manager::load_apic(const acpi_table_header *header)
|
device_manager::load_apic(const acpi::table_header *header)
|
||||||
{
|
{
|
||||||
const auto *apic = check_get_table<acpi_apic>(header);
|
const auto *apic = acpi::check_get_table<acpi::apic>(header);
|
||||||
|
|
||||||
m_lapic_base = apic->local_address;
|
m_lapic_base = apic->local_address;
|
||||||
|
|
||||||
size_t count = acpi_table_entries(apic, 1);
|
size_t count = acpi::table_entries(apic, 1);
|
||||||
uint8_t const *p = apic->controller_data;
|
uint8_t const *p = apic->controller_data;
|
||||||
uint8_t const *end = p + count;
|
uint8_t const *end = p + count;
|
||||||
|
|
||||||
@@ -265,33 +225,9 @@ device_manager::load_apic(const acpi_table_header *header)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
device_manager::load_mcfg(const acpi_table_header *header)
|
device_manager::load_hpet(const acpi::table_header *header)
|
||||||
{
|
{
|
||||||
const auto *mcfg = check_get_table<acpi_mcfg>(header);
|
const auto *hpet = acpi::check_get_table<acpi::hpet>(header);
|
||||||
|
|
||||||
size_t count = acpi_table_entries(mcfg, sizeof(acpi_mcfg_entry));
|
|
||||||
m_pci.set_size(count);
|
|
||||||
m_devices.set_capacity(16);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < count; ++i) {
|
|
||||||
const acpi_mcfg_entry &mcfge = mcfg->entries[i];
|
|
||||||
|
|
||||||
m_pci[i].group = mcfge.group;
|
|
||||||
m_pci[i].bus_start = mcfge.bus_start;
|
|
||||||
m_pci[i].bus_end = mcfge.bus_end;
|
|
||||||
m_pci[i].base = mem::to_virtual<uint32_t>(mcfge.base);
|
|
||||||
|
|
||||||
log::spam(logs::device, " Found MCFG entry: base %lx group %d bus %d-%d",
|
|
||||||
mcfge.base, mcfge.group, mcfge.bus_start, mcfge.bus_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
probe_pci();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
device_manager::load_hpet(const acpi_table_header *header)
|
|
||||||
{
|
|
||||||
const auto *hpet = check_get_table<acpi_hpet>(header);
|
|
||||||
|
|
||||||
log::verbose(logs::device, " Found HPET device #%3d: base %016lx pmin %d attr %02x",
|
log::verbose(logs::device, " Found HPET device #%3d: base %016lx pmin %d attr %02x",
|
||||||
hpet->index, hpet->base_address.address, hpet->periodic_min, hpet->attributes);
|
hpet->index, hpet->base_address.address, hpet->periodic_min, hpet->attributes);
|
||||||
@@ -311,28 +247,6 @@ device_manager::load_hpet(const acpi_table_header *header)
|
|||||||
reinterpret_cast<uint64_t*>(hpet->base_address.address + mem::linear_offset));
|
reinterpret_cast<uint64_t*>(hpet->base_address.address + mem::linear_offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
device_manager::probe_pci()
|
|
||||||
{
|
|
||||||
for (auto &pci : m_pci) {
|
|
||||||
log::verbose(logs::device, "Probing PCI group at base %016lx", pci.base);
|
|
||||||
|
|
||||||
for (int bus = pci.bus_start; bus <= pci.bus_end; ++bus) {
|
|
||||||
for (int dev = 0; dev < 32; ++dev) {
|
|
||||||
if (!pci.has_device(bus, dev, 0)) continue;
|
|
||||||
|
|
||||||
auto &d0 = m_devices.emplace(pci, bus, dev, 0);
|
|
||||||
if (!d0.multi()) continue;
|
|
||||||
|
|
||||||
for (int i = 1; i < 8; ++i) {
|
|
||||||
if (pci.has_device(bus, dev, i))
|
|
||||||
m_devices.emplace(pci, bus, dev, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t
|
static uint64_t
|
||||||
tsc_clock_source(void*)
|
tsc_clock_source(void*)
|
||||||
{
|
{
|
||||||
@@ -366,7 +280,7 @@ device_manager::init_drivers()
|
|||||||
|
|
||||||
// becomes the singleton
|
// becomes the singleton
|
||||||
master_clock = new clock(h.rate(), hpet_clock_source, &h);
|
master_clock = new clock(h.rate(), hpet_clock_source, &h);
|
||||||
log::info(logs::clock, "Created master clock using HPET 0: Rate %d", h.rate());
|
log::info(logs::timer, "Created master clock using HPET 0: Rate %d", h.rate());
|
||||||
} else {
|
} else {
|
||||||
//TODO: Other clocks, APIC clock?
|
//TODO: Other clocks, APIC clock?
|
||||||
master_clock = new clock(5000, tsc_clock_source, nullptr);
|
master_clock = new clock(5000, tsc_clock_source, nullptr);
|
||||||
@@ -385,7 +299,7 @@ device_manager::dispatch_irq(unsigned irq)
|
|||||||
if (!binding.target || binding.target == ignore_event)
|
if (!binding.target || binding.target == ignore_event)
|
||||||
return binding.target == ignore_event;
|
return binding.target == ignore_event;
|
||||||
|
|
||||||
binding.target->signal(1 << binding.signal);
|
binding.target->signal(1ull << binding.signal);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,10 +324,10 @@ device_manager::unbind_irqs(obj::event *target)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
bool
|
bool
|
||||||
device_manager::allocate_msi(const char *name, pci_device &device, irq_callback cb, void *data)
|
device_manager::allocate_msi(const char *name, pci_device &device, irq_callback cb, void *data)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
// TODO: find gaps to fill
|
// TODO: find gaps to fill
|
||||||
uint8_t irq = m_irqs.count();
|
uint8_t irq = m_irqs.count();
|
||||||
isr vector = isr::irq00 + irq;
|
isr vector = isr::irq00 + irq;
|
||||||
@@ -424,12 +338,6 @@ device_manager::allocate_msi(const char *name, pci_device &device, irq_callback
|
|||||||
device.write_msi_regs(
|
device.write_msi_regs(
|
||||||
0xFEE00000,
|
0xFEE00000,
|
||||||
static_cast<uint16_t>(vector));
|
static_cast<uint16_t>(vector));
|
||||||
*/
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
void
|
|
||||||
device_manager::register_block_device(block_device *blockdev)
|
|
||||||
{
|
|
||||||
m_blockdevs.append(blockdev);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,11 +6,13 @@
|
|||||||
|
|
||||||
#include "apic.h"
|
#include "apic.h"
|
||||||
#include "hpet.h"
|
#include "hpet.h"
|
||||||
#include "pci.h"
|
|
||||||
|
|
||||||
struct acpi_table_header;
|
|
||||||
class block_device;
|
class block_device;
|
||||||
|
|
||||||
|
namespace acpi {
|
||||||
|
struct table_header;
|
||||||
|
}
|
||||||
|
|
||||||
namespace obj {
|
namespace obj {
|
||||||
class event;
|
class event;
|
||||||
}
|
}
|
||||||
@@ -53,18 +55,6 @@ public:
|
|||||||
/// \arg target The endpoint to remove
|
/// \arg target The endpoint to remove
|
||||||
void unbind_irqs(obj::event *target);
|
void unbind_irqs(obj::event *target);
|
||||||
|
|
||||||
/// Allocate an MSI IRQ for a device
|
|
||||||
/// \arg name Name of the interrupt, for display to user
|
|
||||||
/// \arg device Device this MSI is being allocated for
|
|
||||||
/// \arg cb Callback to call when the interrupt is received
|
|
||||||
/// \arg data Data to pass to the callback
|
|
||||||
/// \returns True if an interrupt was allocated successfully
|
|
||||||
bool allocate_msi(
|
|
||||||
const char *name,
|
|
||||||
pci_device &device,
|
|
||||||
irq_callback cb,
|
|
||||||
void *data);
|
|
||||||
|
|
||||||
/// Dispatch an IRQ interrupt
|
/// Dispatch an IRQ interrupt
|
||||||
/// \arg irq The irq number of the interrupt
|
/// \arg irq The irq number of the interrupt
|
||||||
/// \returns True if the interrupt was handled
|
/// \returns True if the interrupt was handled
|
||||||
@@ -103,23 +93,6 @@ public:
|
|||||||
/// configuration, or null if no configuration was provided
|
/// configuration, or null if no configuration was provided
|
||||||
const irq_override * get_irq_override(uint8_t irq) const;
|
const irq_override * get_irq_override(uint8_t irq) const;
|
||||||
|
|
||||||
/// Register the existance of a block device.
|
|
||||||
/// \arg blockdev Pointer to the block device
|
|
||||||
void register_block_device(block_device *blockdev);
|
|
||||||
|
|
||||||
/// Get the number of block devices in the system
|
|
||||||
/// \returns A count of devices
|
|
||||||
inline unsigned get_num_block_devices() const { return m_blockdevs.count(); }
|
|
||||||
|
|
||||||
/// Get a block device
|
|
||||||
/// \arg i Index of the device to get
|
|
||||||
/// \returns A pointer to the requested device, or nullptr
|
|
||||||
inline block_device * get_block_device(unsigned i)
|
|
||||||
{
|
|
||||||
return i < m_blockdevs.count() ?
|
|
||||||
m_blockdevs[i] : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get an HPET device
|
/// Get an HPET device
|
||||||
/// \arg i Index of the device to get
|
/// \arg i Index of the device to get
|
||||||
/// \returns A pointer to the requested device, or nullptr
|
/// \returns A pointer to the requested device, or nullptr
|
||||||
@@ -132,23 +105,15 @@ public:
|
|||||||
private:
|
private:
|
||||||
/// Parse the ACPI XSDT and load relevant sub-tables.
|
/// Parse the ACPI XSDT and load relevant sub-tables.
|
||||||
/// \arg xsdt Pointer to the XSDT from the firmware
|
/// \arg xsdt Pointer to the XSDT from the firmware
|
||||||
void load_xsdt(const acpi_table_header *xsdt);
|
void load_xsdt(const acpi::table_header *xsdt);
|
||||||
|
|
||||||
/// Parse the ACPI MADT and initialize APICs from it.
|
/// Parse the ACPI MADT and initialize APICs from it.
|
||||||
/// \arg apic Pointer to the MADT from the XSDT
|
/// \arg apic Pointer to the MADT from the XSDT
|
||||||
void load_apic(const acpi_table_header *apic);
|
void load_apic(const acpi::table_header *apic);
|
||||||
|
|
||||||
/// Parse the ACPI MCFG and initialize PCIe from it.
|
|
||||||
/// \arg mcfg Pointer to the MCFG from the XSDT
|
|
||||||
void load_mcfg(const acpi_table_header *mcfg);
|
|
||||||
|
|
||||||
/// Parse the ACPI HPET and initialize an HPET from it.
|
/// Parse the ACPI HPET and initialize an HPET from it.
|
||||||
/// \arg hpet Pointer to the HPET from the XSDT
|
/// \arg hpet Pointer to the HPET from the XSDT
|
||||||
void load_hpet(const acpi_table_header *hpet);
|
void load_hpet(const acpi::table_header *hpet);
|
||||||
|
|
||||||
/// Probe the PCIe busses and add found devices to our
|
|
||||||
/// device list. The device list is destroyed and rebuilt.
|
|
||||||
void probe_pci();
|
|
||||||
|
|
||||||
/// Handle a bad IRQ. Called when an interrupt is dispatched
|
/// Handle a bad IRQ. Called when an interrupt is dispatched
|
||||||
/// that has no callback.
|
/// that has no callback.
|
||||||
@@ -162,9 +127,6 @@ private:
|
|||||||
util::vector<apic_nmi> m_nmis;
|
util::vector<apic_nmi> m_nmis;
|
||||||
util::vector<irq_override> m_overrides;
|
util::vector<irq_override> m_overrides;
|
||||||
|
|
||||||
util::vector<pci_group> m_pci;
|
|
||||||
util::vector<pci_device> m_devices;
|
|
||||||
|
|
||||||
struct irq_binding
|
struct irq_binding
|
||||||
{
|
{
|
||||||
obj::event *target = nullptr;
|
obj::event *target = nullptr;
|
||||||
@@ -172,8 +134,6 @@ private:
|
|||||||
};
|
};
|
||||||
util::vector<irq_binding> m_irqs;
|
util::vector<irq_binding> m_irqs;
|
||||||
|
|
||||||
util::vector<block_device *> m_blockdevs;
|
|
||||||
|
|
||||||
static device_manager s_instance;
|
static device_manager s_instance;
|
||||||
|
|
||||||
device_manager(const device_manager &) = delete;
|
device_manager(const device_manager &) = delete;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <bootproto/kernel.h>
|
#include <bootproto/kernel.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
|
#include "debugcon.h"
|
||||||
#include "frame_allocator.h"
|
#include "frame_allocator.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
@@ -51,7 +52,7 @@ frame_allocator::allocate(size_t count, uintptr_t *address)
|
|||||||
unsigned frame = (o1 << 12) + (o2 << 6) + o3;
|
unsigned frame = (o1 << 12) + (o2 << 6) + o3;
|
||||||
|
|
||||||
// See how many contiguous pages are here
|
// See how many contiguous pages are here
|
||||||
unsigned n = bsf(~m3 >> o3);
|
unsigned n = bsf(~(m3 >> o3));
|
||||||
if (n > count)
|
if (n > count)
|
||||||
n = count;
|
n = count;
|
||||||
|
|
||||||
@@ -71,6 +72,7 @@ frame_allocator::allocate(size_t count, uintptr_t *address)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//debugcon::write("Allocated %2d frames at %016lx - %016lx", n, *address, *address + n * frame_size);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +90,8 @@ frame_allocator::free(uintptr_t address, size_t count)
|
|||||||
if (!count)
|
if (!count)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
//debugcon::write("Freeing %2d frames at %016lx - %016lx", count, address, address + count * frame_size);
|
||||||
|
|
||||||
for (long i = 0; i < m_count; ++i) {
|
for (long i = 0; i < m_count; ++i) {
|
||||||
frame_block &block = m_blocks[i];
|
frame_block &block = m_blocks[i];
|
||||||
uintptr_t end = block.base + block.count * frame_size;
|
uintptr_t end = block.base + block.count * frame_size;
|
||||||
@@ -101,9 +105,9 @@ frame_allocator::free(uintptr_t address, size_t count)
|
|||||||
unsigned o3 = frame & 0x3f;
|
unsigned o3 = frame & 0x3f;
|
||||||
|
|
||||||
while (count--) {
|
while (count--) {
|
||||||
block.map1 |= (1 << o1);
|
block.map1 |= (1ull << o1);
|
||||||
block.map2[o1] |= (1 << o2);
|
block.map2[o1] |= (1ull << o2);
|
||||||
block.bitmap[o2] |= (1 << o3);
|
block.bitmap[o2] |= (1ull << o3);
|
||||||
if (++o3 == 64) {
|
if (++o3 == 64) {
|
||||||
o3 = 0;
|
o3 = 0;
|
||||||
if (++o2 == 64) {
|
if (++o2 == 64) {
|
||||||
@@ -139,12 +143,12 @@ frame_allocator::used(uintptr_t address, size_t count)
|
|||||||
unsigned o3 = frame & 0x3f;
|
unsigned o3 = frame & 0x3f;
|
||||||
|
|
||||||
while (count--) {
|
while (count--) {
|
||||||
block.bitmap[o2] &= ~(1 << o3);
|
block.bitmap[o2] &= ~(1ull << o3);
|
||||||
if (!block.bitmap[o2]) {
|
if (!block.bitmap[o2]) {
|
||||||
block.map2[o1] &= ~(1 << o2);
|
block.map2[o1] &= ~(1ull << o2);
|
||||||
|
|
||||||
if (!block.map2[o1]) {
|
if (!block.map2[o1]) {
|
||||||
block.map1 &= ~(1 << o1);
|
block.map1 &= ~(1ull << o1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
#include <stdint.h>
|
#include <j6/memutils.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <util/no_construct.h>
|
#include <util/no_construct.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
@@ -24,6 +22,9 @@ static constexpr uint8_t tss_index = 6; // Note that this takes TWO GDT en
|
|||||||
static util::no_construct<GDT> __g_bsp_gdt_storage;
|
static util::no_construct<GDT> __g_bsp_gdt_storage;
|
||||||
GDT &g_bsp_gdt = __g_bsp_gdt_storage.value;
|
GDT &g_bsp_gdt = __g_bsp_gdt_storage.value;
|
||||||
|
|
||||||
|
static constexpr util::bitset8 ring3 = util::bitset8::of( GDT::type::ring1, GDT::type::ring2 );
|
||||||
|
static constexpr util::bitset8 rw = util::bitset8::of( GDT::type::read_write );
|
||||||
|
static constexpr util::bitset8 rwx = util::bitset8::of( GDT::type::read_write, GDT::type::execute );
|
||||||
|
|
||||||
GDT::GDT(TSS *tss) :
|
GDT::GDT(TSS *tss) :
|
||||||
m_tss(tss)
|
m_tss(tss)
|
||||||
@@ -34,13 +35,13 @@ GDT::GDT(TSS *tss) :
|
|||||||
m_ptr.base = &m_entries[0];
|
m_ptr.base = &m_entries[0];
|
||||||
|
|
||||||
// Kernel CS/SS - always 64bit
|
// Kernel CS/SS - always 64bit
|
||||||
set(kern_cs_index, 0, 0xfffff, true, type::read_write | type::execute);
|
set(kern_cs_index, 0, 0xfffff, true, rwx);
|
||||||
set(kern_ss_index, 0, 0xfffff, true, type::read_write);
|
set(kern_ss_index, 0, 0xfffff, true, rw);
|
||||||
|
|
||||||
// User CS32/SS/CS64 - layout expected by SYSRET
|
// User CS32/SS/CS64 - layout expected by SYSRET
|
||||||
set(user_cs32_index, 0, 0xfffff, false, type::ring3 | type::read_write | type::execute);
|
set(user_cs32_index, 0, 0xfffff, false, ring3 | rwx);
|
||||||
set(user_ss_index, 0, 0xfffff, true, type::ring3 | type::read_write);
|
set(user_ss_index, 0, 0xfffff, true, ring3 | rw);
|
||||||
set(user_cs64_index, 0, 0xfffff, true, type::ring3 | type::read_write | type::execute);
|
set(user_cs64_index, 0, 0xfffff, true, ring3 | rwx);
|
||||||
|
|
||||||
set_tss(tss);
|
set_tss(tss);
|
||||||
}
|
}
|
||||||
@@ -63,7 +64,7 @@ GDT::install() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GDT::set(uint8_t i, uint32_t base, uint64_t limit, bool is64, type t)
|
GDT::set(uint8_t i, uint32_t base, uint64_t limit, bool is64, util::bitset8 t)
|
||||||
{
|
{
|
||||||
m_entries[i].limit_low = limit & 0xffff;
|
m_entries[i].limit_low = limit & 0xffff;
|
||||||
m_entries[i].size = (limit >> 16) & 0xf;
|
m_entries[i].size = (limit >> 16) & 0xf;
|
||||||
@@ -73,7 +74,9 @@ GDT::set(uint8_t i, uint32_t base, uint64_t limit, bool is64, type t)
|
|||||||
m_entries[i].base_mid = (base >> 16) & 0xff;
|
m_entries[i].base_mid = (base >> 16) & 0xff;
|
||||||
m_entries[i].base_high = (base >> 24) & 0xff;
|
m_entries[i].base_high = (base >> 24) & 0xff;
|
||||||
|
|
||||||
m_entries[i].type = t | type::system | type::present;
|
static constexpr util::bitset8 sp = util::bitset8::of( type::system, type::present );
|
||||||
|
m_entries[i].type = t;
|
||||||
|
m_entries[i].type |= sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tss_descriptor
|
struct tss_descriptor
|
||||||
@@ -81,7 +84,7 @@ struct tss_descriptor
|
|||||||
uint16_t limit_low;
|
uint16_t limit_low;
|
||||||
uint16_t base_00;
|
uint16_t base_00;
|
||||||
uint8_t base_16;
|
uint8_t base_16;
|
||||||
GDT::type type;
|
util::bitset8 type;
|
||||||
uint8_t size;
|
uint8_t size;
|
||||||
uint8_t base_24;
|
uint8_t base_24;
|
||||||
uint32_t base_32;
|
uint32_t base_32;
|
||||||
@@ -104,11 +107,9 @@ GDT::set_tss(TSS *tss)
|
|||||||
tssd.base_32 = (base >> 32) & 0xffffffff;
|
tssd.base_32 = (base >> 32) & 0xffffffff;
|
||||||
tssd.reserved = 0;
|
tssd.reserved = 0;
|
||||||
|
|
||||||
tssd.type =
|
static constexpr util::bitset8 tss_mark =
|
||||||
type::accessed |
|
util::bitset8::of(type::accessed, type::execute, type::present);
|
||||||
type::execute |
|
tssd.type = ring3 | tss_mark;
|
||||||
type::ring3 |
|
|
||||||
type::present;
|
|
||||||
|
|
||||||
memcpy(&m_entries[tss_index], &tssd, sizeof(tss_descriptor));
|
memcpy(&m_entries[tss_index], &tssd, sizeof(tss_descriptor));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
/// Definitions relating to a CPU's GDT table
|
/// Definitions relating to a CPU's GDT table
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <util/enum_bitfields.h>
|
#include <util/bitset.h>
|
||||||
|
|
||||||
class TSS;
|
class TSS;
|
||||||
|
|
||||||
@@ -25,21 +25,20 @@ public:
|
|||||||
/// \arg index Which entry to print, or -1 for all entries
|
/// \arg index Which entry to print, or -1 for all entries
|
||||||
void dump(unsigned index = -1) const;
|
void dump(unsigned index = -1) const;
|
||||||
|
|
||||||
enum class type : uint8_t
|
enum class type
|
||||||
{
|
{
|
||||||
accessed = 0x01,
|
accessed,
|
||||||
read_write = 0x02,
|
read_write,
|
||||||
conforming = 0x04,
|
conforming,
|
||||||
execute = 0x08,
|
execute,
|
||||||
system = 0x10,
|
system,
|
||||||
ring1 = 0x20,
|
ring1,
|
||||||
ring2 = 0x40,
|
ring2,
|
||||||
ring3 = 0x60,
|
present
|
||||||
present = 0x80
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void set(uint8_t i, uint32_t base, uint64_t limit, bool is64, type t);
|
void set(uint8_t i, uint32_t base, uint64_t limit, bool is64, util::bitset8 t);
|
||||||
void set_tss(TSS *tss);
|
void set_tss(TSS *tss);
|
||||||
|
|
||||||
struct descriptor
|
struct descriptor
|
||||||
@@ -47,7 +46,7 @@ private:
|
|||||||
uint16_t limit_low;
|
uint16_t limit_low;
|
||||||
uint16_t base_low;
|
uint16_t base_low;
|
||||||
uint8_t base_mid;
|
uint8_t base_mid;
|
||||||
type type;
|
util::bitset8 type;
|
||||||
uint8_t size;
|
uint8_t size;
|
||||||
uint8_t base_high;
|
uint8_t base_high;
|
||||||
} __attribute__ ((packed, align(8)));
|
} __attribute__ ((packed, align(8)));
|
||||||
@@ -63,5 +62,3 @@ private:
|
|||||||
|
|
||||||
ptr m_ptr;
|
ptr m_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
is_bitfield(GDT::type);
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
#include <new>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
#include <j6/memutils.h>
|
||||||
#include <util/pointers.h>
|
#include <util/pointers.h>
|
||||||
#include <util/util.h>
|
#include <util/util.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "heap_allocator.h"
|
#include "heap_allocator.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
#include "objects/vm_area.h"
|
||||||
|
#include "vm_space.h"
|
||||||
|
|
||||||
uint32_t & get_map_key(heap_allocator::block_info &info) { return info.offset; }
|
uint32_t & get_map_key(heap_allocator::block_info &info) { return info.offset; }
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ struct heap_allocator::free_header
|
|||||||
|
|
||||||
inline free_header * buddy() const {
|
inline free_header * buddy() const {
|
||||||
return reinterpret_cast<free_header *>(
|
return reinterpret_cast<free_header *>(
|
||||||
reinterpret_cast<uintptr_t>(this) ^ (1 << order));
|
reinterpret_cast<uintptr_t>(this) ^ (1ull << order));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool eldest() const { return this < buddy(); }
|
inline bool eldest() const { return this < buddy(); }
|
||||||
@@ -46,7 +47,6 @@ heap_allocator::heap_allocator(uintptr_t start, size_t size, uintptr_t heapmap)
|
|||||||
m_maxsize {size},
|
m_maxsize {size},
|
||||||
m_allocated_size {0},
|
m_allocated_size {0},
|
||||||
m_map (reinterpret_cast<block_info*>(heapmap), 512)
|
m_map (reinterpret_cast<block_info*>(heapmap), 512)
|
||||||
|
|
||||||
{
|
{
|
||||||
memset(m_free, 0, sizeof(m_free));
|
memset(m_free, 0, sizeof(m_free));
|
||||||
}
|
}
|
||||||
@@ -57,6 +57,11 @@ heap_allocator::allocate(size_t length)
|
|||||||
if (length == 0)
|
if (length == 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
static constexpr unsigned min_order =
|
||||||
|
__debug_heap_allocation ?
|
||||||
|
12 : // allocating full pages in debug mode
|
||||||
|
heap_allocator::min_order;
|
||||||
|
|
||||||
unsigned order = util::log2(length);
|
unsigned order = util::log2(length);
|
||||||
if (order < min_order)
|
if (order < min_order)
|
||||||
order = min_order;
|
order = min_order;
|
||||||
@@ -67,7 +72,7 @@ heap_allocator::allocate(size_t length)
|
|||||||
|
|
||||||
util::scoped_lock lock {m_lock};
|
util::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
m_allocated_size += (1 << order);
|
m_allocated_size += (1ull << order);
|
||||||
|
|
||||||
free_header *block = pop_free(order);
|
free_header *block = pop_free(order);
|
||||||
if (!block && !split_off(order, block)) {
|
if (!block && !split_off(order, block)) {
|
||||||
@@ -95,7 +100,17 @@ heap_allocator::free(void *p)
|
|||||||
kassert(info, "Attempt to free pointer not known to the heap");
|
kassert(info, "Attempt to free pointer not known to the heap");
|
||||||
if (!info) return;
|
if (!info) return;
|
||||||
|
|
||||||
m_allocated_size -= (1 << info->order);
|
size_t size = (1ull << info->order);
|
||||||
|
m_allocated_size -= size;
|
||||||
|
|
||||||
|
if constexpr (__debug_heap_allocation) {
|
||||||
|
extern obj::vm_area_untracked &g_kernel_heap_area;
|
||||||
|
|
||||||
|
size_t offset = reinterpret_cast<uintptr_t>(p) - mem::heap_offset;
|
||||||
|
size_t pages = mem::bytes_to_pages(size);
|
||||||
|
vm_space::kernel_space().lock(g_kernel_heap_area, offset, pages);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
block->clear(info->order);
|
block->clear(info->order);
|
||||||
block = merge_block(block);
|
block = merge_block(block);
|
||||||
@@ -118,15 +133,15 @@ heap_allocator::reallocate(void *p, size_t old_length, size_t new_length)
|
|||||||
if (!info)
|
if (!info)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (new_length <= (1 << info->order))
|
if (new_length <= (1ull << info->order))
|
||||||
return p;
|
return p;
|
||||||
|
|
||||||
lock.release();
|
lock.release();
|
||||||
void *new_block = allocate(new_length);
|
void *reallocated = allocate(new_length);
|
||||||
memcpy(new_block, p, old_length);
|
memcpy(reallocated, p, old_length);
|
||||||
free(p);
|
free(p);
|
||||||
|
|
||||||
return new_block;
|
return reallocated;
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_allocator::free_header *
|
heap_allocator::free_header *
|
||||||
@@ -180,13 +195,15 @@ heap_allocator::new_block(unsigned order)
|
|||||||
unsigned current = address_order(m_end);
|
unsigned current = address_order(m_end);
|
||||||
while (current < order) {
|
while (current < order) {
|
||||||
register_free_block(reinterpret_cast<free_header*>(m_end), current);
|
register_free_block(reinterpret_cast<free_header*>(m_end), current);
|
||||||
m_end += 1 << current;
|
m_end += 1ull << current;
|
||||||
current = address_order(m_end);
|
current = address_order(m_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *block = reinterpret_cast<void*>(m_end);
|
void *block = reinterpret_cast<void*>(m_end);
|
||||||
m_end += 1 << order;
|
m_end += 1ull << order;
|
||||||
m_map[map_key(block)].order = order;
|
block_info &info = m_map[map_key(block)];
|
||||||
|
info.order = order;
|
||||||
|
info.free = false;
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,8 +34,9 @@ public:
|
|||||||
/// allocation with the contents copied over.
|
/// allocation with the contents copied over.
|
||||||
void * reallocate(void *p, size_t old_length, size_t new_length);
|
void * reallocate(void *p, size_t old_length, size_t new_length);
|
||||||
|
|
||||||
/// Minimum block size is (2^min_order). Must be at least 6.
|
/// Minimum block size is (2^min_order). Must be at least 5 in
|
||||||
static const unsigned min_order = 6; // 2^6 == 64 B
|
/// order to hold a free_header.
|
||||||
|
static const unsigned min_order = 5; // 2^5 == 32 B
|
||||||
|
|
||||||
/// Maximum block size is (2^max_order). Must be less than 32 + min_order.
|
/// Maximum block size is (2^max_order). Must be less than 32 + min_order.
|
||||||
static const unsigned max_order = 22; // 2^22 == 4 MiB
|
static const unsigned max_order = 22; // 2^22 == 4 MiB
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "device_manager.h"
|
#include "device_manager.h"
|
||||||
#include "hpet.h"
|
#include "hpet.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#include <string.h>
|
#include <j6/memutils.h>
|
||||||
|
|
||||||
#include <util/no_construct.h>
|
#include <util/no_construct.h>
|
||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
/// \file idt.h
|
/// \file idt.h
|
||||||
/// Definitions relating to a CPU's IDT table
|
/// Definitions relating to a CPU's IDT table
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
|
|
||||||
class IDT
|
class IDT
|
||||||
{
|
{
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user