3 Commits
v0.6.0 ... vdso

Author SHA1 Message Date
Justin C. Miller
dd73cf833f Change initrd 'executable' bool to type enum. 2019-10-10 23:09:40 -07:00
Justin C. Miller
71fe3d733b Add the VDSO to the initrd 2019-10-10 00:14:46 -07:00
Justin C. Miller
991b13424e Initial building of the vdso.
Not actually integrating with the kernel yet.
2019-10-09 22:29:45 -07:00
563 changed files with 31098 additions and 38572 deletions

21
.clang-format Normal file
View File

@@ -0,0 +1,21 @@
---
Language: Cpp
BasedOnStyle: LLVM
ColumnLimit: 100
IndentWidth: 4
TabWidth: 4
UseTab: Always
AccessModifierOffset: -4
AlignEscapedNewlinesLeft: true
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterReturnType: AllDefinitions
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BreakBeforeBraces: Linux

View File

@@ -1,11 +0,0 @@
[section] Imperative-voiced title in less than 50
# Body describes what was done, and why. New obviously-needed features
# don't necessarily require a why.
# Links to relevant bugs or web pages
See: Github bug #242
See: [frobozz blog post](https://jsix.dev/posts/frobozz/)
# Tags and keywords useful for searching
Tags:

5
.gitignore vendored
View File

@@ -1,15 +1,10 @@
.cache
.lock*
/build*
*.bak
tags
jsix.log
*.out
*.o
*.a
sysroot
.gdb_history
.peru
__pycache__
/venv
compile_commands.json

38
NOTES.md Normal file
View File

@@ -0,0 +1,38 @@
# Design / WIP notes
## TODO
- Paging manager
- Copy-on-write pages
- Better page-allocation model?
- Allow for more than one IOAPIC in ACPI module
- The objects get created, but GSI lookup only uses the one at index 0
- mark kernel memory pages global
- Serial out based on circular/bip biffer and interrupts, not spinning on
`write_ready()`
- Split out more code into kutil for testing
- AHCI / MSI interrupts on Vbox break?
- FXSAVE to save XMM registers.
- optimization using #NM (0x7) to detect SSE usage
- Clean up of process memory maps
- Better stack tracer
- Bootloader rewrite
- C++ and sharing library code for ELF, initrd, etc
- Parse initrd and pre-load certain ELF images, eg the process loader process?
- Do initial memory bootstrap?
- Calling global ctors
- Device Tree
- Actual serial driver
- Disk driver
- File system
- Multiprocessing
- Fast syscalls using syscall/sysret
### Build
- Clean up build generator and its templates
- More robust objects to represent modules & targets to pass to templates
- Read project setup from a simple JSON/TOML/etc
- Better compartmentalizing when doing template inheritance
- Move to LLD as sysroot linker

185
README.md
View File

@@ -1,19 +1,15 @@
![jsix](assets/jsix.svg)
# jsix: A toy OS kernel
# The jsix operating system
**jsix** is a custom multi-core x64 operating system that I am building from
scratch. It's far from finished, or even being usable (see the *Status and
Roadmap* section, below) but all currently-planned major kernel features are
now implemented to at least a passable level.
**jsix** is the kernel for the hobby OS that I am currently building. It's
far from finished, or even being usable. Instead, it's a sandbox for me to play
with kernel-level code and explore architectures.
The design goals of the project are:
* Modernity - I'm not interested in designing for legacy systems, or running on
all hardware out there. My target is only 64 bit architectures, and modern
all hardware out there. My target is only 64 bit architecutres, and modern
commodity hardware. Currently that means x64 systems with Nehalem or newer
CPUs and UEFI firmware. (See [this list][cpu_features] for the currently
required CPU features.) Eventually I'd like to work on an AArch64 port,
CPUs and UEFI firmware. Eventually I'd like to work on an AArch64 port,
partly to force myself to factor out the architecture-dependent pieces of the
code base.
@@ -21,11 +17,13 @@ The design goals of the project are:
processes as possible, in the microkernel fashion. A sub-goal of this is to
explore where the bottlenecks of such a microkernel are now, and whether
eschewing legacy hardware will let me design a system that's less bogged down
by the traditional microkernel problems.
by the traditional microkernel problems. Given that there are no processes
yet, the kernel is monolithic by default.
* Exploration - I'm really mostly doing this to have fun learning and exploring
modern OS development. Initial feature implementations may temporarily throw
away modular design to allow for exploration of the related hardware.
modern OS development. Modular design may be tossed out (hopefully
temporarily) in some places to allow me to play around with the related
hardware.
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
@@ -33,149 +31,48 @@ name, started around the same time as this project. So I've renamed this kernel
jsix (Always styled _jsix_ or `j6`, never capitalized) as an homage to L4, xv6,
and my wonderful wife.
[cpu_features]: https://github.com/justinian/jsix/blob/master/src/libraries/cpu/include/cpu/features.inc
## Status and Roadmap
The following major feature areas are targets for jsix development:
#### UEFI boot loader
_Done._ The bootloader loads the kernel and initial userspace programs, and
sets up necessary kernel arguments about the memory map and EFI GOP
framebuffer. Possible future ideas:
- take over more init-time functions from the kernel
- rewrite it in Zig
#### Memory
_Virtual memory: Sufficient._ The kernel manages virtual memory with a number
of kinds of `vm_area` objects representing mapped areas, which can belong to
one or more `vm_space` objects which represent a whole virtual memory space.
(Each process has a `vm_space`, and so does the kernel itself.)
Remaining to do:
- TLB shootdowns
- Page swapping
- Large / huge page support
_Physical page allocation: Sufficient._ The current physical page allocator
implementation uses a group of blocks representing up-to-1GiB areas of usable
memory as defined by the bootloader. Each block has a three-level bitmap
denoting free/used pages.
Future work:
- Align blocks so that their first page is 1GiB-aligned, making finding free
large/huge pages easier.
#### Multitasking
_Sufficient._ The global scheduler object keeps separate ready/blocked lists
per core. Cores periodically attempt to balance load via work stealing.
User-space tasks are able to create threads as well as other processes.
#### API
_Syscalls: Sufficient._ User-space tasks are able to make syscalls to the
kernel via fast SYSCALL/SYSRET instructions. Syscalls made via `libj6` look to
both the callee and the caller like standard SysV ABI function calls. The
implementations are wrapped in generated wrapper functions which validate the
request, check capabilities, and find the appropriate kernel objects or handles
before calling the implementation functions.
_IPC: Working, needs optimization._ The current IPC primitives are:
- _Mailboxes_: endpoints for asynchronously-delivered small messages. Currently
these messages are double-copied - once from the caller into a kernel buffer,
and once from the kernel to the receiver. This works and is not a major cause
of slowdown, but will need to be optimized in the future.
- _Channels_: endpoints for asynchronous uni-directional streams of bytes.
Currently these also suffer from a double-copy problem, and should probably
be replaced eventually by userspace shared memory communication.
- _Events_: objects that can be signalled to send asynchronous notifications to
waiting threads.
#### Hardware Support
- Framebuffer driver: _In progress._ Currently on machines with a video
device accessible by UEFI, jsix starts a user-space framebuffer driver that
only prints out kernel logs.
- Serial driver: _In progress._ The current UART currently only exposes COM1
as an output channel, but no input or other serial ports are exposed.
- USB driver: _To do_
- AHCI (SATA) driver: _To do_
## Building
jsix uses the [Ninja][] build tool, and generates the build files for it with
the `configure` script. The build also relies on a custom toolchain sysroot, which can be
downloaded or built using the scripts in [jsix-os/toolchain][].
jsix uses the [Ninja][] build tool, and generates the build files for it with a
custom tool called [Bonnibel][]. Bonnibel can be installed with [Cargo][], or
downloaded as a prebuilt binary from its Github repository.
[Ninja]: https://ninja-build.org
[jsix-os/toolchain]: https://github.com/jsix-os/toolchain
[Ninja]: https://ninja-build.org
[Bonnibel]: https://github.com/justinian/bonnibel
[Cargo]: https://crates.io/crates/bonnibel
Other build dependencies:
Requrirements:
* [clang][]: the C/C++ compiler
* [nasm][]: the assembler
* [lld][]: the linker
* [mtools][]: for creating the FAT image
* bonnibel
* ninja
* clang
* nasm
* mtools
* curl for downloading the toolchain
[clang]: https://clang.llvm.org
[nasm]: https://www.nasm.us
[lld]: https://lld.llvm.org
[mtools]: https://www.gnu.org/software/mtools/
### Setting up the cross toolchain
The `configure` script has some Python dependencies - these can be installed via
`pip`, though doing so in a python virtual environment is recommended.
Installing via `pip` will also install `ninja`.
Running `pb sync` will download and unpack the toolchain into `sysroot`.
A Debian 11 (Bullseye) system can be configured with the necessary build
dependencies by running the following commands from the jsix repository root:
#### Compiling the toolchain yourself
```bash
sudo apt install clang lld nasm mtools python3-pip python3-venv
python3 -m venv ./venv
source venv/bin/activate
pip install -r requirements.txt
peru sync
```
### Setting up the sysroot
Build or download the toolchain sysroot as mentioned above with
[jsix-os/toolchain][], and symlink the built toolchain directory as `sysroot`
at the root of this project.
```bash
# Example if both the toolchain and this project are cloned under ~/src
ln -s ~/src/toolchain/toolchains/llvm-13 ~/src/jsix/sysroot
```
If you have `clang` and `curl` installed, runing the `scripts/build_sysroot.sh`
script will download and build a LLVM toolchain configured for building jsix
host binaries.
### Building and running jsix
Once the toolchain has been set up, running the `./configure` script (see
`./configure --help` for available options) will set up the build configuration,
and `ninja -C build` (or wherever you put the build directory) will actually run
the build. If you have `qemu-system-x86_64` installed, the `qemu.sh` script will
to run jsix in QEMU `-nographic` mode.
Once the toolchain has been set up, running Bonnibel's `pb init` command will
set up the build configuration, and `pb build` will actually run the build. If
you have `qemu-system-x86_64` installed, the `qemu.sh` script will to run jsix
in QEMU `-nographic` mode.
I personally run this either from a real debian amd64 bullseye machine or
a windows WSL debian bullseye installation. Your mileage may vary with other
setups and distros.
I personally run this either from a real debian amd64 testing/buster machine or
a windows WSL debian testing/buster installation. The following should be
enough to set up such a system to build the kernel:
### Running the test suite
sudo apt install qemu-system-x86 nasm clang-6.0 mtools curl
sudo update-alternatives /usr/bin/clang clang /usr/bin/clang-6.0 1000
sudo update-alternatives /usr/bin/clang++ clang++ /usr/bin/clang++-6.0 1000
curl -L -o pb https://github.com/justinian/bonnibel/releases/download/2.0.0/pb_linux_amd64 && chmod a+x pb
jsix now has the `test_runner` userspace program that runs various automated
tests. It is not included in the default build, but if you use the `test.yml`
manifest it will be built, and can be run with the `test.sh` script or the
`qemu.sh` script.
```bash
./configure --manifest=assets/manifests/test.yml
if ./test.sh; then echo "All tests passed!"; else echo "Failed."; fi
```

View File

@@ -2,7 +2,7 @@ import gdb
class PrintStackCommand(gdb.Command):
def __init__(self):
super().__init__("j6stack", gdb.COMMAND_DATA)
super().__init__("popc_stack", gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
args = gdb.string_to_argv(arg)
@@ -10,260 +10,22 @@ class PrintStackCommand(gdb.Command):
base = "$rsp"
if len(args) > 0:
base = args[0]
base = int(gdb.parse_and_eval(base))
depth = 22
if len(args) > 1:
depth = int(args[1])
for i in range(depth-1, -1, -1):
try:
offset = i * 8
value = gdb.parse_and_eval(f"*(uint64_t*)({base:#x} + {offset:#x})")
print("{:016x} (+{:04x}): {:016x}".format(base + offset, offset, int(value)))
except Exception as e:
print(e)
continue
offset = i * 8
base_addr = gdb.parse_and_eval(base)
value = gdb.parse_and_eval(f"*(uint64_t*)({base} + {offset})")
print("{:016x} (+{:04x}): {:016x}".format(int(base_addr) + offset, offset, int(value)))
def stack_walk(frame, depth):
for i in range(depth-1, -1, -1):
ret = gdb.parse_and_eval(f"*(uint64_t*)({frame:#x} + 0x8)")
name = ""
try:
block = gdb.block_for_pc(int(ret))
if block:
name = block.function or ""
except RuntimeError:
pass
try:
print("{:016x}: {:016x} {}".format(int(frame), int(ret), name))
frame = int(gdb.parse_and_eval(f"*(uint64_t*)({frame:#x})"))
except gdb.MemoryError:
return
if frame == 0 or ret == 0:
return
class PrintBacktraceCommand(gdb.Command):
def __init__(self):
super().__init__("j6bt", gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
args = gdb.string_to_argv(arg)
frame = "$rbp"
if len(args) > 0:
frame = args[0]
frame = int(gdb.parse_and_eval(f"{frame}"))
depth = 30
if len(args) > 1:
depth = int(gdb.parse_and_eval(args[1]))
stack_walk(frame, depth)
class TableWalkCommand(gdb.Command):
def __init__(self):
super().__init__("j6tw", gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
args = gdb.string_to_argv(arg)
if len(args) < 2:
raise Exception("Must be: j6tw <pml4> <addr>")
pml4 = int(gdb.parse_and_eval(args[0]))
addr = int(gdb.parse_and_eval(args[1]))
indices = [
(addr >> 39) & 0x1ff,
(addr >> 30) & 0x1ff,
(addr >> 21) & 0x1ff,
(addr >> 12) & 0x1ff,
]
names = ["PML4", "PDP", "PD", "PT"]
table_flags = [
(0x0001, "present"),
(0x0002, "write"),
(0x0004, "user"),
(0x0008, "pwt"),
(0x0010, "pcd"),
(0x0020, "accessed"),
(0x0040, "dirty"),
(0x0080, "largepage"),
(0x0100, "global"),
(0x1080, "pat"),
((1<<63), "xd"),
]
page_flags = [
(0x0001, "present"),
(0x0002, "write"),
(0x0004, "user"),
(0x0008, "pwt"),
(0x0010, "pcd"),
(0x0020, "accessed"),
(0x0040, "dirty"),
(0x0080, "pat"),
(0x0100, "global"),
((1<<63), "xd"),
]
flagsets = [table_flags, table_flags, table_flags, page_flags]
table = pml4
entry = 0
for i in range(len(indices)):
entry = int(gdb.parse_and_eval(f'((uint64_t*)0x{table:x})[0x{indices[i]:x}]'))
flagset = flagsets[i]
flag_names = " | ".join([f[1] for f in flagset if (entry & f[0]) == f[0]])
print(f"{names[i]:>4}: {table:016x}")
print(f" index: {indices[i]:3} {entry:016x}")
print(f" flags: {flag_names}")
if (entry & 1) == 0 or (i < 3 and (entry & 0x80)):
break
table = (entry & 0x7ffffffffffffe00) | 0xffffc00000000000
class GetThreadsCommand(gdb.Command):
FLAGS = {
"ready": 0x01,
"loading": 0x02,
"exited": 0x04,
"constant": 0x80,
}
def __init__(self):
super().__init__("j6threads", gdb.COMMAND_DATA)
def get_flags(self, bitset):
flags = []
for k, v in GetThreadsCommand.FLAGS.items():
if bitset & v:
flags.append(k)
return " ".join(flags)
def print_thread(self, addr):
if addr == 0:
print(" <no thread>\n")
return
tcb = f"((TCB*){addr:#x})"
thread = f"({tcb}->thread)"
stack = int(gdb.parse_and_eval(f"{tcb}->kernel_stack"))
rsp = int(gdb.parse_and_eval(f"{tcb}->rsp"))
pri = int(gdb.parse_and_eval(f"{tcb}->priority"))
flags = int(gdb.parse_and_eval(f"{thread}->m_state"))
koid = int(gdb.parse_and_eval(f"{thread}->m_koid"))
proc = int(gdb.parse_and_eval(f"{thread}->m_parent.m_koid"))
creator = int(gdb.parse_and_eval(f"{thread}->m_creator"))
if creator != 0:
creator_koid = int(gdb.parse_and_eval(f"{thread}->m_creator->m_koid"))
creator = f"{creator_koid:x}"
else:
creator = "<no thread>"
print(f" Thread {proc:x}:{koid:x}")
print(f" creator: {creator}")
print(f" priority: {pri}")
print(f" flags: {self.get_flags(flags)}")
print(f" kstack: {stack:#x}")
print(f" rsp: {rsp:#x}")
print("------------------------------------")
if stack != 0:
rsp = int(gdb.parse_and_eval(f"{tcb}->rsp"))
stack_walk(rsp + 5*8, 5)
print("")
def print_thread_list(self, addr, name):
if addr == 0:
return
print(f"=== {name} ===")
while addr != 0:
self.print_thread(addr)
addr = int(gdb.parse_and_eval(f"((tcb_node*){addr:#x})->m_next"))
def invoke(self, arg, from_tty):
args = gdb.string_to_argv(arg)
if len(args) > 1:
raise RuntimeError("Usage: j6threads [cpu]")
ncpus = int(gdb.parse_and_eval("g_num_cpus"))
cpus = list(range(ncpus))
if len(args) == 1:
cpus = [int(args[0])]
for cpu in cpus:
runlist = f"scheduler::s_instance->m_run_queues.m_elements[{cpu:#x}]"
print(f"=== CPU {cpu:2}: CURRENT ===")
current = int(gdb.parse_and_eval(f"{runlist}.current"))
self.print_thread(current)
for pri in range(8):
ready = int(gdb.parse_and_eval(f"{runlist}.ready[{pri:#x}].m_head"))
self.print_thread_list(ready, f"CPU {cpu:2}: PRIORITY {pri}")
blocked = int(gdb.parse_and_eval(f"{runlist}.blocked.m_head"))
self.print_thread_list(blocked, f"CPU {cpu:2}: BLOCKED")
class PrintProfilesCommand(gdb.Command):
def __init__(self):
super().__init__("j6prof", gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
args = gdb.string_to_argv(arg)
if len(args) != 1:
raise RuntimeError("Usage: j6prof <profiler class>")
profclass = args[0]
root_type = f"profile_class<{profclass}>"
try:
baseclass = gdb.lookup_type(root_type)
except Exception as e:
print(e)
return
results = {}
max_len = 0
count = gdb.parse_and_eval(f"{profclass}::count")
for i in range(count):
name = gdb.parse_and_eval(f"{root_type}::function_names[{i:#x}]")
if name == 0: continue
call_counts = gdb.parse_and_eval(f"{root_type}::call_counts[{i:#x}]")
call_durations = gdb.parse_and_eval(f"{root_type}::call_durations[{i:#x}]")
results[name.string()] = float(call_durations) / float(call_counts)
max_len = max(max_len, len(name.string()))
for name, avg in results.items():
print(f"{name:>{max_len}}: {avg:15.3f}")
PrintStackCommand()
PrintBacktraceCommand()
TableWalkCommand()
GetThreadsCommand()
PrintProfilesCommand()
import time
time.sleep(3.5)
gdb.execute("target remote :1234")
gdb.execute("set waiting = false")
gdb.execute("display/i $rip")
if not gdb.selected_inferior().was_attached:
gdb.execute("add-symbol-file build/panic.serial.elf")
gdb.execute("target remote :1234")

Binary file not shown.

View File

@@ -1,47 +0,0 @@
start: import_statement* (object|interface)+
import_statement: "import" PATH
object: description? "object" name options? super? "{" uid cname? capabilities? method* "}"
interface: description? "interface" name options? "{" uid interface_param* "}"
?interface_param: expose | function
expose: "expose" type
uid: "uid" UID
cname: "cname" IDENTIFIER
capabilities: "capabilities" "[" IDENTIFIER+ "]"
super: ":" name
function: description? "function" name options? ("{" param* "}")?
method: description? "method" name options? ("{" param* "}")?
param: "param" name type options? description?
?type: PRIMITIVE | object_name
object_name: "ref" name
id: NUMBER
name: IDENTIFIER
options: "[" ( OPTION | IDENTIFIER )+ "]"
description: COMMENT+
PRIMITIVE: INT_TYPE | "size" | "string" | "buffer" | "address"
INT_TYPE: /u?int(8|16|32|64)?/
NUMBER: /(0x)?[0-9a-fA-F]+/
UID: /[0-9a-fA-F]{16}/
OPTION.2: IDENTIFIER ":" IDENTIFIER
COMMENT: /#.*/
PATH: /"[^"]*"/
%import common.LETTER
%import common.CNAME -> IDENTIFIER
%import common.WS
%ignore WS

28
assets/initrd.toml Normal file
View File

@@ -0,0 +1,28 @@
# This is the manifest for the initial ramdisk, read by the `makerd` tool.
# The contents should be a table array of files to add to the ramdistk:
#
# [[files]]
# dest = "foo.bar" # Name of the file in the ramdisk
# source = "build/foo/foo.bar" # Location of the file from the project root
# executable = true # Optional, default false. Whether this is an
# # initial application for the kernel to execute
# # on startup
[[files]]
dest = "vdso.so"
source = "host/libvdso.so"
type = "vdso"
[[files]]
dest = "screenfont.psf"
source = "../assets/fonts/tamsyn8x16r.psf"
[[files]]
dest = "nulldrv1"
source = "user/nulldrv"
type = "executable"
[[files]]
dest = "nulldrv2"
source = "user/nulldrv"
type = "executable"

View File

@@ -1 +0,0 @@
<?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><rect x="176.562" y="356.069" width="211.11" height="113" transform="matrix(1,0,0,1,0,0)" fill="rgb(255,255,255)"/><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>

Before

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -1,8 +0,0 @@
---
init: srv.init
programs:
- name: panic.serial
target: kernel
flags: panic
- name: srv.logger
- name: drv.uart

View File

@@ -1,9 +0,0 @@
---
init: srv.init
flags: ["test"]
programs:
- name: panic.serial
target: kernel
flags: panic
- name: drv.uart
- name: test_runner

View File

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

View File

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

View File

@@ -1,55 +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",
"-mno-sse",
"-fno-omit-frame-pointer",
"-mno-red-zone",
"-mcmodel=kernel",
"-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",
"-nostdlib",
"-Bstatic",
"--no-eh-frame-hdr",
"-z", "norelro",
"-z", "separate-code" ]

View File

@@ -1,81 +0,0 @@
# This file is automatically generated by bonnibel
rule compile.c
command = $cc -MMD -MF $out.d $cflags $ccflags -o $out -c $in
description = Compiling $name
depfile = $out.d
deps = gcc
rule dump_c_defs
command = echo | $cc $ccflags $cflags -dM -E - > $out
description = Dumping C defines for $target
rule dump_c_run
command = echo '#!/bin/bash' > $out; echo '$cc $ccflags $cflags $$*' >> $
$out; chmod a+x $out
description = Dumping C arguments for $target
rule compile.cpp
command = $cxx -MMD -MF $out.d $cxxflags $ccflags -o $out -c $in
description = Compiling $name
depfile = $out.d
deps = gcc
rule dump_cpp_defs
command = echo | $cxx -x c++ $ccflags $cxxflags -dM -E - > $out
description = Dumping C++ defines for $target
rule dump_cpp_run
command = echo '#!/bin/bash' > $out; echo '$cxx $ccflags $cxxflags $$*' $
>> $out; chmod a+x $out
description = Dumping C++ arguments for $target
rule compile.s
command = $nasm -o $out -felf64 -MD $out.d $asflags $in
description = Assembling $name
depfile = $out.d
deps = gcc
rule parse.cog
command = cog -o $out -d -D target=$target $cogflags $in
description = Parsing $name
rule exe
command = $ld $ldflags -o $out $in $libs
description = Linking $name
rule lib
command = $ar qcs $out $in
description = Archiving $name
rule cp
command = cp $in $out
description = Copying $name
rule dump
command = objdump -DSC -M intel $in > $out
description = Dumping decompiled $name
rule makest
description = Making symbol table
command = nm -n -S --demangle $in | ${source_root}/scripts/build_symbol_table.py $out
rule makefat
description = Creating $name
command = $
cp $in $out; $
mcopy -s -D o -i $out@@1M ${build_root}/fatroot/* ::/
rule strip
description = Stripping $name
command = $
cp $in $out; $
objcopy --only-keep-debug $out $debug; $
strip -g $out; $
objcopy --add-gnu-debuglink=$debug $out
rule touch
command = touch $out
rule compdb
command = ninja -t compdb > $out

View File

@@ -1,39 +0,0 @@
---
extends: base
variables:
asflags: [ "-I${source_root}/src/kernel/" ]
ccflags: [
"--target=x86_64-jsix-elf",
"-mno-sse",
"-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",
]

70
configure vendored
View File

@@ -1,70 +0,0 @@
#!/usr/bin/env python3
def generate(output, config, manifest):
from os import makedirs, walk
from pathlib import Path
from bonnibel.module import Module
from bonnibel.project import Project
root = Path(__file__).parent.resolve()
project = Project(root)
output = root / output
sources = root / "src"
manifest = root / manifest
modules = {}
for base, dirs, files in walk(sources):
path = Path(base)
for f in files:
if f.endswith(".module"):
fullpath = path / f
def module_init(name, **kwargs):
m = Module(name, fullpath, path, **kwargs)
modules[m.name] = m
return m
glo = {
"module": module_init,
"source_root": root,
"built_root": output,
"module_root": path,
}
code = compile(open(fullpath, 'r').read(), fullpath, "exec")
loc = {}
exec(code, glo, loc)
Module.update(modules)
makedirs(output.resolve(), exist_ok=True)
project.generate(root, output, modules, config, manifest)
for mod in modules.values():
mod.generate(output)
if __name__ == "__main__":
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent / "scripts"))
from argparse import ArgumentParser
from bonnibel import BonnibelError
p = ArgumentParser(description="Generate jsix build files")
p.add_argument("--manifest", "-m", metavar="FILE", default="assets/manifests/default.yaml",
help="File to use as the system manifest")
p.add_argument("--config", "-c", metavar="NAME", default="debug",
help="Configuration to build (eg, 'debug' or 'release')")
p.add_argument("output", metavar="DIR", default="build", nargs='?',
help="Where to create the build root")
args = p.parse_args()
try:
generate(args.output, args.config, args.manifest)
except BonnibelError as be:
import sys
print(f"Error: {be}", file=sys.stderr)
sys.exit(1)

View File

@@ -1,20 +0,0 @@
---
- name: linear
size: 64T
shared: true
- name: bitmap
size: 1T
shared: true
- name: heap
size: 64G
- name: stacks
size: 64G
- name: buffers
size: 64G
- name: slabs
size: 64G

View File

@@ -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
}
}

View File

@@ -1,22 +0,0 @@
object event : object {
uid f441e03da5516b1a
capabilities [
signal
wait
]
method create [constructor]
# Signal events on this object
method signal [cap:signal] {
param signals uint64 # A bitset of which events to signal
}
# Wait for signaled events on this object
method wait [cap:wait] {
param signals uint64 [out] # A bitset of which events were signaled
param timeout uint64 # Wait timeout in nanoseconds
}
}

View File

@@ -1,65 +0,0 @@
# Mailboxes are objects that enable synchronous or asynchronous
# IPC via short message-passing of bytes and handles.
object mailbox : object {
uid 99934ad04ece1e07
capabilities [
send
receive
close
]
method create [constructor]
method close [destructor cap:close]
# Asynchronously send a message to the reciever
method send [cap:send handle] {
param tag uint64
param data buffer [zero_ok]
param handles ref object [list]
}
# Receive a pending message, or block waiting for a message to
# arrive if block is true.
method receive [cap:receive] {
param tag uint64 [out]
param data buffer [out zero_ok]
param handles ref object [out list zero_ok]
param reply_tag uint16 [out optional]
param badge uint64 [out optional]
param flags uint64
}
# Send a message to the reciever, and block until a
# response is sent. Note that getting this response
# does not require the receive capability.
method call [cap:send handle] {
param tag uint64 [inout]
param data buffer [inout zero_ok]
param handles ref object [inout list zero_ok]
}
# Respond to a message sent using call. Note that this
# requires the receive capability and not the send capability.
method respond [cap:receive] {
param tag uint64
param data buffer [zero_ok]
param handles ref object [list zero_ok]
param reply_tag uint16
}
# Respond to a message sent using call, and wait for another
# message to arrive. Note that this does not require the send
# capability.
method respond_receive [cap:receive] {
param tag uint64 [inout]
param data buffer [inout zero_ok]
param data_in size
param handles ref object [inout list zero_ok]
param handles_in size
param reply_tag uint16 [inout]
param badge uint64 [out optional]
param flags uint64
}
}

View File

@@ -1,14 +0,0 @@
# The base type of all kernel-exposed objects
object object [virtual] {
uid 667f61fb2cd57bb4
cname kobject
capabilities [
clone
]
# Get the internal kernel object id of an object
method koid {
param koid uint64 [out]
}
}

View File

@@ -1,31 +0,0 @@
import "objects/object.def"
# Processes are a collection of handles and a virtual memory
# space inside which threads are run.
object process : object {
uid 0c69ee0b7502ba31
capabilities [
kill
create_thread
]
# Create a new empty process
method create [constructor]
# Stop all threads and exit the given process
method kill [destructor cap:kill]
# Stop all threads and exit the current process
method exit [static noreturn] {
param result int32 # The result to retrun to the parent process
}
# Give the given process a handle that points to the same
# object as the specified handle.
method give_handle {
param target ref object [handle] # A handle in the caller process to send
param received ref object [out optional] # The handle as the recipient will see it
}
}

View File

@@ -1,40 +0,0 @@
# The system object represents a handle to kernel functionality
# needed by drivers and other priviledged services
object system : object {
uid fa72506a2cf71a30
capabilities [
get_log
bind_irq
map_phys
change_iopl
]
# Get a log line from the kernel log
method get_log [cap:get_log] {
param buffer buffer [out zero_ok] # Buffer for the log message data structure
}
# Ask the kernel to send this process messages whenever
# the given IRQ fires
method bind_irq [cap:bind_irq] {
param dest ref event # Event object that will receive messages
param irq uint # IRQ number to bind
param signal uint # Signal number on the event to bind to
}
# Create a VMA and map an area of physical memory into it,
# also mapping that VMA into the current process
method map_phys [cap:map_phys] {
param area ref vma [out] # Receives a handle to the VMA created
param phys address # The physical address of the area
param size size # Size of the area, in pages
param flags uint32 # Flags to apply to the created VMA
}
# Request the kernel change the IOPL for this process. The only values
# that make sense are 0 and 3.
method request_iopl [cap:change_iopl] {
param iopl uint # The IOPL to set for this process
}
}

View File

@@ -1,23 +0,0 @@
object thread : object {
uid 11f23e593d5761bd
capabilities [
kill
]
method create [constructor] {
param process ref process [cap:create_thread]
param stack_top address
param entrypoint address
}
method kill [destructor cap:kill]
method exit [static] {
param status int32
}
method sleep [static] {
param duration uint64
}
}

View File

@@ -1,36 +0,0 @@
import "objects/process.def"
object vma : object {
uid d6a12b63b3ed3937
cname vm_area
capabilities [
map
unmap
resize
]
method create [constructor] {
param size size
param flags uint32
}
method create_map [constructor cap:map] {
param size size
param address address
param flags uint32
}
method map [cap:map] {
param process ref process
param address address
}
method unmap [cap:unmap] {
param process ref process
}
method resize [cap:resize] {
param size size [inout]
}
}

View File

@@ -1,50 +0,0 @@
import "objects/object.def"
import "objects/channel.def"
import "objects/event.def"
import "objects/mailbox.def"
import "objects/process.def"
import "objects/system.def"
import "objects/thread.def"
import "objects/vma.def"
interface syscalls [syscall] {
uid 01d9b6a948961097
expose ref object
expose ref system
expose ref event
expose ref process
expose ref thread
expose ref mailbox
expose ref channel
expose ref vma
# Simple no-op syscall for testing
function noop
# Write a message to the kernel log
function log {
param message string
}
# 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
function handle_list {
param handles ref object [list inout zero_ok] # A list of handles to be filled
}
# Create a clone of an existing handle, possibly with
# some capabilities masked out.
function handle_clone {
param orig ref object [handle cap:clone] # The handle to clone
param clone ref object [out] # The new handle
param mask uint32 # The capability bitmask
}
# Testing mode only: Have the kernel finish and exit QEMU with the given exit code
function test_finish [test] {
param exit_code uint32
}
}

View File

@@ -1,34 +0,0 @@
---
address: 0x6a360000
vars:
- name: version_major
section: kernel
type: uint8_t
- name: version_minor
section: kernel
type: uint8_t
- name: version_patch
section: kernel
type: uint16_t
- name: version_gitsha
section: kernel
type: uint32_t
- name: page_size
section: sys
type: size_t
- name: large_page_size
section: sys
type: size_t
- name: huge_page_size
section: sys
type: size_t
- name: num_cpus
section: sys
type: uint32_t

2389
external/catch/catch.hpp vendored

File diff suppressed because it is too large Load Diff

3669
external/cpptoml/cpptoml.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,103 +0,0 @@
#pragma once
#ifndef _uefi_boot_services_h_
#define _uefi_boot_services_h_
// This Source Code Form is part of the j6-uefi-headers project and is subject
// to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was
// not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.
#include <stdint.h>
#include <uefi/tables.h>
#include <uefi/types.h>
namespace uefi {
namespace bs_impl {
using allocate_pages = status (*)(allocate_type, memory_type, size_t, void**);
using free_pages = status (*)(void*, size_t);
using get_memory_map = status (*)(size_t*, memory_descriptor*, size_t*, size_t*, uint32_t*);
using allocate_pool = status (*)(memory_type, uint64_t, void**);
using free_pool = status (*)(void*);
using handle_protocol = status (*)(handle, const guid*, void**);
using create_event = status (*)(evt, tpl, event_notify, void*, event*);
using exit_boot_services = status (*)(handle, size_t);
using locate_protocol = status (*)(const guid*, void*, void**);
using copy_mem = void (*)(void*, void*, size_t);
using set_mem = void (*)(void*, uint64_t, uint8_t);
}
struct boot_services {
static constexpr uint64_t signature = 0x56524553544f4f42ull;
table_header header;
// Task Priority Level management
void *raise_tpl;
void *restore_tpl;
// Memory Services
bs_impl::allocate_pages allocate_pages;
bs_impl::free_pages free_pages;
bs_impl::get_memory_map get_memory_map;
bs_impl::allocate_pool allocate_pool;
bs_impl::free_pool free_pool;
// Event & Timer Services
bs_impl::create_event create_event;
void *set_timer;
void *wait_for_event;
void *signal_event;
void *close_event;
void *check_event;
// Protocol Handler Services
void *install_protocol_interface;
void *reinstall_protocol_interface;
void *uninstall_protocol_interface;
bs_impl::handle_protocol handle_protocol;
void *_reserved;
void *register_protocol_notify;
void *locate_handle;
void *locate_device_path;
void *install_configuration_table;
// Image Services
void *load_image;
void *start_image;
void *exit;
void *unload_image;
bs_impl::exit_boot_services exit_boot_services;
// Miscellaneous Services
void *get_next_monotonic_count;
void *stall;
void *set_watchdog_timer;
// DriverSupport Services
void *connect_controller;
void *disconnect_controller;
// Open and Close Protocol Services
void *open_protocol;
void *close_protocol;
void *open_protocol_information;
// Library Services
void *protocols_per_handle;
void *locate_handle_buffer;
bs_impl::locate_protocol locate_protocol;
void *install_multiple_protocol_interfaces;
void *uninstall_multiple_protocol_interfaces;
// 32-bit CRC Services
void *calculate_crc32;
// Miscellaneous Services
bs_impl::copy_mem copy_mem;
bs_impl::set_mem set_mem;
void *create_event_ex;
};
} // namespace uefi
#endif

View File

@@ -1,39 +0,0 @@
STATUS_WARNING( warn_unknown_glyph, 1)
STATUS_WARNING( warn_delete_failure, 2)
STATUS_WARNING( warn_write_failure, 3)
STATUS_WARNING( warn_buffer_too_small,4)
STATUS_WARNING( warn_stale_data, 5)
STATUS_WARNING( warn_file_system, 6)
STATUS_ERROR( load_error, 1)
STATUS_ERROR( invalid_parameter, 2)
STATUS_ERROR( unsupported, 3)
STATUS_ERROR( bad_buffer_size, 4)
STATUS_ERROR( buffer_too_small, 5)
STATUS_ERROR( not_ready, 6)
STATUS_ERROR( device_error, 7)
STATUS_ERROR( write_protected, 8)
STATUS_ERROR( out_of_resources, 9)
STATUS_ERROR( volume_corrupted, 10)
STATUS_ERROR( volume_full, 11)
STATUS_ERROR( no_media, 12)
STATUS_ERROR( media_changed, 13)
STATUS_ERROR( not_found, 14)
STATUS_ERROR( access_denied, 15)
STATUS_ERROR( no_response, 16)
STATUS_ERROR( no_mapping, 17)
STATUS_ERROR( timeout, 18)
STATUS_ERROR( not_started, 19)
STATUS_ERROR( already_started, 20)
STATUS_ERROR( aborted, 21)
STATUS_ERROR( icmp_error, 22)
STATUS_ERROR( tftp_error, 23)
STATUS_ERROR( protocol_error, 24)
STATUS_ERROR( incompatible_version, 25)
STATUS_ERROR( security_violation, 26)
STATUS_ERROR( crc_error, 27)
STATUS_ERROR( end_of_media, 28)
STATUS_ERROR( end_of_file, 31)
STATUS_ERROR( invalid_language, 32)
STATUS_ERROR( compromised_data, 33)
STATUS_ERROR( http_error, 35)

View File

@@ -1,92 +0,0 @@
#pragma once
#ifndef _uefi_graphics_h_
#define _uefi_graphics_h_
// This Source Code Form is part of the j6-uefi-headers project and is subject
// to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was
// not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.
#include <stdint.h>
#include <uefi/types.h>
namespace uefi {
struct text_output_mode
{
int32_t max_mode;
int32_t mode;
int32_t attribute;
int32_t cursor_column;
int32_t cursor_row;
bool cursor_visible;
};
struct pixel_bitmask
{
uint32_t red_mask;
uint32_t green_mask;
uint32_t blue_mask;
uint32_t reserved_mask;
};
enum class pixel_format
{
rgb8,
bgr8,
bitmask,
blt_only
};
struct graphics_output_mode_info
{
uint32_t version;
uint32_t horizontal_resolution;
uint32_t vertical_resolution;
pixel_format pixel_format;
pixel_bitmask pixel_information;
uint32_t pixels_per_scanline;
};
struct graphics_output_mode
{
uint32_t max_mode;
uint32_t mode;
graphics_output_mode_info *info;
uint64_t size_of_info;
uintptr_t frame_buffer_base;
uint64_t frame_buffer_size;
};
enum class attribute : uint64_t
{
black,
blue,
green,
cyan,
red,
magenta,
brown,
light_gray,
dark_gray,
light_blue,
light_green,
light_cyan,
light_red,
light_magenta,
yellow,
white,
background_black = 0x00,
background_blue = 0x10,
background_green = 0x20,
background_cyan = 0x30,
background_red = 0x40,
background_magenta = 0x50,
background_brown = 0x60,
background_light_gray = 0x70,
};
} // namespace uefi
#endif

29
external/uefi/guid.h vendored
View File

@@ -1,29 +0,0 @@
#pragma once
#ifndef _uefi_guid_h_
#define _uefi_guid_h_
// This Source Code Form is part of the j6-uefi-headers project and is subject
// to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was
// not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.
#include <stdint.h>
namespace uefi {
struct guid
{
uint32_t data1;
uint16_t data2;
uint16_t data3;
uint8_t data4[8];
inline bool operator==(const guid &other) const {
return reinterpret_cast<const uint64_t*>(this)[0] == reinterpret_cast<const uint64_t*>(&other)[0]
&& reinterpret_cast<const uint64_t*>(this)[1] == reinterpret_cast<const uint64_t*>(&other)[1];
}
};
} // namespace uefi
#endif

View File

@@ -1,390 +0,0 @@
#pragma once
#ifndef _uefi_networking_h_
#define _uefi_networking_h_
// This Source Code Form is part of the j6-uefi-headers project and is subject
// to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was
// not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.
#include <stdint.h>
#include <uefi/types.h>
namespace uefi {
//
// IPv4 definitions
//
struct ipv4_address
{
uint8_t addr[4];
};
//
// IPv6 definitions
//
struct ipv6_address
{
uint8_t addr[16];
};
struct ip6_address_info
{
ipv6_address address;
uint8_t prefix_length;
};
struct ip6_route_table
{
ipv6_address gateway;
ipv6_address destination;
uint8_t prefix_length;
};
enum class ip6_neighbor_state : int {
incomplete,
reachable,
stale,
delay,
probe,
}
struct ip6_neighbor_cache
{
ipv6_address neighbor;
mac_address link_address;
ip6_neighbor_state state;
};
enum class icmpv6_type : uint8_t
{
dest_unreachable = 0x1,
packet_too_big = 0x2,
time_exceeded = 0x3,
parameter_problem = 0x4,
echo_request = 0x80,
echo_reply = 0x81,
listener_query = 0x82,
listener_report = 0x83,
listener_done = 0x84,
router_solicit = 0x85,
router_advertise = 0x86,
neighbor_solicit = 0x87,
neighbor_advertise = 0x88,
redirect = 0x89,
listener_report_2 = 0x8f,
};
enum class icmpv6_code : uint8_t
{
// codes for icmpv6_type::dest_unreachable
no_route_to_dest = 0x0,
comm_prohibited = 0x1,
beyond_scope = 0x2,
addr_unreachable = 0x3,
port_unreachable = 0x4,
source_addr_failed = 0x5,
route_rejected = 0x6,
// codes for icmpv6_type::time_exceeded
timeout_hop_limit = 0x0,
timeout_reassemble = 0x1,
// codes for icmpv6_type::parameter_problem
erroneous_header = 0x0,
unrecognize_next_hdr = 0x1,
unrecognize_option = 0x2,
};
struct ip6_icmp_type
{
icmpv6_type type;
icmpv6_code code;
};
struct ip6_config_data
{
uint8_t default_protocol;
bool accept_any_protocol;
bool accept_icmp_errors;
bool accept_promiscuous;
ipv6_address destination_address;
ipv6_address station_address;
uint8_t traffic_class;
uint8_t hop_limit;
uint32_t flow_label;
uint32_t receive_timeout;
uint32_t transmit_timeout;
};
struct ip6_mode_data
{
bool is_started;
uint32_t max_packet_size;
ip6_config_data config_data;
bool is_configured;
uint32_t address_count;
ip6_address_info * address_list;
uint32_t group_count;
ipv6_address * group_table;
uint32_t route_count;
ip6_route_table * route_table;
uint32_t neighbor_count;
ip6_neighbor_cache * neighbor_cache;
uint32_t prefix_count;
ip6_address_info * prefix_table;
uint32_t icmp_type_count;
* icmp_type_list;
};
struct ip6_header
{
uint8_t traffic_class_h : 4;
uint8_t version : 4;
uint8_t flow_label_h : 4;
uint8_t traffic_class_l : 4;
uint16_t flow_label_l;
uint16_t payload_length;
uint8_t next_header;
uint8_t hop_limit;
ipv6_address source_address;
ipv6_address destination_address;
} __attribute__ ((packed));
struct ip6_fragment_data
{
uint32_t fragment_length;
void *fragment_buffer;
};
struct ip6_override_data
{
uint8_t protocol;
uint8_t hop_limit;
uint32_t flow_label;
};
struct ip6_receive_data
{
time time_stamp;
event recycle_signal;
uint32_t header_length;
ip6_header *header;
uint32_t data_length;
uint32_t fragment_count;
ip6_fragment_data fragment_table[1];
};
struct ip6_transmit_data
{
ipv6_address destination_address;
ip6_override_data *override_data;
uint32_t ext_hdrs_length;
void *ext_hdrs;
uint8_t next_header;
uint32_t data_length;
uint32_t fragment_count;
ip6_fragment_data fragment_table[1];
};
struct ip6_completion_token
{
event event;
status status;
union {
ip6_receive_data *rx_data;
ip6_transmit_data *tx_data;
} packet;
};
enum class ip6_config_data_type : int
{
interface_info,
alt_interface_id,
policy,
dup_addr_detect_transmits,
manual_address,
gateway,
dns_server,
maximum
};
struct ip6_config_interface_info
{
wchar_t name[32];
uint8_t if_type;
uint32_t hw_address_size;
mac_address hw_address;
uint32_t address_info_count;
ip6_address_info *address_info;
uint32_t route_count;
ip6_route_table *route_table;
};
struct ip6_config_interface_id
{
uint8_t id[8];
};
enum class ip6_config_policy : int
{
manual,
automatic
};
struct ip6_config_dup_addr_detect_transmits
{
uint32_t dup_addr_detect_transmits;
};
struct ip6_config_manual_address
{
ipv6_address address;
bool is_anycast;
uint8_t prefix_length;
};
//
// IP definitions
//
union ip_address
{
uint8_t addr[4];
ipv4_address v4;
ipv6_address v6;
};
//
// HTTP definitions
//
struct httpv4_access_point
{
bool use_default_address;
ipv4_address local_address;
ipv4_address local_subnet;
uint16_t local_port;
};
struct httpv6_access_point
{
ipv6_address local_address;
uint16_t local_port;
};
enum class http_version : int {
v10,
v11,
unsupported,
};
struct http_config_data
{
http_version http_version;
uint32_t time_out_millisec;
bool local_address_is_ipv6;
union {
httpv4_access_point *ipv4_node;
httpv6_access_point *ipv6_node;
} access_point;
};
enum class http_method : int {
get,
post,
patch,
options,
connect,
head,
put,
delete_,
trace,
};
struct http_request_data
{
http_method method;
wchar_t *url;
};
enum class http_status_code : int {
unsupported,
continue_,
switching_protocols,
ok,
created,
accepted,
non_authoritative_information,
no_content,
reset_content,
partial_content,
multiple_choices,
moved_permanently,
found,
see_other,
not_modified,
use_proxy,
temporary_redirect,
bad_request,
unauthorized,
payment_required,
forbidden,
not_found,
method_not_allowed,
not_acceptable,
proxy_authentication_required,
request_time_out,
conflict,
gone,
length_required,
precondition_failed,
request_entity_too_large,
request_uri_too_large,
unsupported_media_type,
requested_range_not_satisfied,
expectation_failed,
internal_server_error,
not_implemented,
bad_gateway,
service_unavailable,
gateway_timeout,
http_version_not_supported,
permanent_redirect, // I hate your decisions, uefi.
};
struct http_response_data
{
http_status_code status_code;
};
struct http_header
{
char *field_name;
char *field_value;
};
struct http_message
{
union {
http_request_data *request;
http_response_data *response;
} data;
size_t header_count;
http_header *headers;
size_t body_length;
void *body;
};
struct http_token
{
event event;
status status;
http_message *message;
};
} // namespace uefi
#endif

View File

@@ -1,31 +0,0 @@
#pragma once
#ifndef _uefi_protos_device_path_h_
#define _uefi_protos_device_path_h_
// This file was auto generated by the j6-uefi-headers project. Please see
// https://github.com/justinian/j6-uefi-headers for more information.
#include <uefi/guid.h>
#include <uefi/types.h>
namespace uefi {
namespace protos {
struct device_path;
struct device_path
{
static constexpr uefi::guid guid{ 0x09576e91,0x6d3f,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
uint8_t type;
uint8_t sub_type;
uint16_t length;
protected:
public:
};
} // namespace protos
} // namespace uefi
#endif // _uefi_protos_device_path_h_

View File

@@ -1,126 +0,0 @@
#pragma once
#ifndef _uefi_protos_file_h_
#define _uefi_protos_file_h_
// This file was auto generated by the j6-uefi-headers project. Please see
// https://github.com/justinian/j6-uefi-headers for more information.
#include <uefi/guid.h>
#include <uefi/types.h>
namespace uefi {
namespace protos {
struct file;
struct file
{
inline uefi::status open(file ** new_handle, const wchar_t * file_name, file_mode open_mode, file_attr attributes) {
return _open(this, new_handle, file_name, open_mode, attributes);
}
inline uefi::status close() {
return _close(this);
}
inline uefi::status delete_file() {
return _delete_file(this);
}
inline uefi::status read(uint64_t * buffer_size, void * buffer) {
return _read(this, buffer_size, buffer);
}
inline uefi::status write(uint64_t * buffer_size, void * buffer) {
return _write(this, buffer_size, buffer);
}
inline uefi::status get_position(uint64_t * position) {
return _get_position(this, position);
}
inline uefi::status set_position(uint64_t position) {
return _set_position(this, position);
}
inline uefi::status get_info(const guid * info_type, uint64_t * buffer_size, void * buffer) {
return _get_info(this, info_type, buffer_size, buffer);
}
inline uefi::status set_info(const guid * info_type, uint64_t buffer_size, void * buffer) {
return _set_info(this, info_type, buffer_size, buffer);
}
inline uefi::status flush() {
return _flush(this);
}
inline uefi::status open_ex(file ** new_handle, const wchar_t * file_name, uint64_t open_mode, uint64_t attributes, file_io_token * token) {
return _open_ex(this, new_handle, file_name, open_mode, attributes, token);
}
inline uefi::status read_ex(file_io_token * token) {
return _read_ex(this, token);
}
inline uefi::status write_ex(file_io_token * token) {
return _write_ex(this, token);
}
inline uefi::status flush_ex(file_io_token * token) {
return _flush_ex(this, token);
}
uint64_t revision;
protected:
using _open_def = uefi::status (*)(uefi::protos::file *, file **, const wchar_t *, file_mode, file_attr);
_open_def _open;
using _close_def = uefi::status (*)(uefi::protos::file *);
_close_def _close;
using _delete_file_def = uefi::status (*)(uefi::protos::file *);
_delete_file_def _delete_file;
using _read_def = uefi::status (*)(uefi::protos::file *, uint64_t *, void *);
_read_def _read;
using _write_def = uefi::status (*)(uefi::protos::file *, uint64_t *, void *);
_write_def _write;
using _get_position_def = uefi::status (*)(uefi::protos::file *, uint64_t *);
_get_position_def _get_position;
using _set_position_def = uefi::status (*)(uefi::protos::file *, uint64_t);
_set_position_def _set_position;
using _get_info_def = uefi::status (*)(uefi::protos::file *, const guid *, uint64_t *, void *);
_get_info_def _get_info;
using _set_info_def = uefi::status (*)(uefi::protos::file *, const guid *, uint64_t, void *);
_set_info_def _set_info;
using _flush_def = uefi::status (*)(uefi::protos::file *);
_flush_def _flush;
using _open_ex_def = uefi::status (*)(uefi::protos::file *, file **, const wchar_t *, uint64_t, uint64_t, file_io_token *);
_open_ex_def _open_ex;
using _read_ex_def = uefi::status (*)(uefi::protos::file *, file_io_token *);
_read_ex_def _read_ex;
using _write_ex_def = uefi::status (*)(uefi::protos::file *, file_io_token *);
_write_ex_def _write_ex;
using _flush_ex_def = uefi::status (*)(uefi::protos::file *, file_io_token *);
_flush_ex_def _flush_ex;
public:
};
} // namespace protos
} // namespace uefi
#endif // _uefi_protos_file_h_

View File

@@ -1,36 +0,0 @@
#pragma once
#ifndef _uefi_protos_file_info_h_
#define _uefi_protos_file_info_h_
// This file was auto generated by the j6-uefi-headers project. Please see
// https://github.com/justinian/j6-uefi-headers for more information.
#include <uefi/guid.h>
#include <uefi/types.h>
namespace uefi {
namespace protos {
struct file_info;
struct file_info
{
static constexpr uefi::guid guid{ 0x09576e92,0x6d3f,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
uint64_t size;
uint64_t file_size;
uint64_t physical_size;
time create_time;
time last_access_time;
time modification_time;
uint64_t attribute;
wchar_t file_name[];
protected:
public:
};
} // namespace protos
} // namespace uefi
#endif // _uefi_protos_file_info_h_

View File

@@ -1,51 +0,0 @@
#pragma once
#ifndef _uefi_protos_graphics_output_h_
#define _uefi_protos_graphics_output_h_
// This file was auto generated by the j6-uefi-headers project. Please see
// https://github.com/justinian/j6-uefi-headers for more information.
#include <uefi/guid.h>
#include <uefi/types.h>
#include <uefi/graphics.h>
namespace uefi {
namespace protos {
struct graphics_output;
struct graphics_output
{
static constexpr uefi::guid guid{ 0x9042a9de,0x23dc,0x4a38,{0x96,0xfb,0x7a,0xde,0xd0,0x80,0x51,0x6a} };
inline uefi::status query_mode(uint32_t mode_number, uint64_t * size_of_info, uefi::graphics_output_mode_info ** info) {
return _query_mode(this, mode_number, size_of_info, info);
}
inline uefi::status set_mode(uint32_t mode_number) {
return _set_mode(this, mode_number);
}
inline uefi::status blt() {
return _blt(this);
}
protected:
using _query_mode_def = uefi::status (*)(uefi::protos::graphics_output *, uint32_t, uint64_t *, uefi::graphics_output_mode_info **);
_query_mode_def _query_mode;
using _set_mode_def = uefi::status (*)(uefi::protos::graphics_output *, uint32_t);
_set_mode_def _set_mode;
using _blt_def = uefi::status (*)(uefi::protos::graphics_output *);
_blt_def _blt;
public:
uefi::graphics_output_mode * mode;
};
} // namespace protos
} // namespace uefi
#endif // _uefi_protos_graphics_output_h_

View File

@@ -1,72 +0,0 @@
#pragma once
#ifndef _uefi_protos_http_h_
#define _uefi_protos_http_h_
// This file was auto generated by the j6-uefi-headers project. Please see
// https://github.com/justinian/j6-uefi-headers for more information.
#include <uefi/guid.h>
#include <uefi/types.h>
#include <uefi/networking.h>
namespace uefi {
namespace protos {
struct http;
struct http
{
static constexpr uefi::guid guid{ 0x7a59b29b,0x910b,0x4171,{0x82,0x42,0xa8,0x5a,0x0d,0xf2,0x5b,0x5b} };
static constexpr uefi::guid service_binding{ 0xbdc8e6af,0xd9bc,0x4379,{0xa7,0x2a,0xe0,0xc4,0xe7,0x5d,0xae,0x1c} };
inline uefi::status get_mode_data(uefi::http_config_data * http_config_data) {
return _get_mode_data(this, http_config_data);
}
inline uefi::status configure(uefi::http_config_data * http_config_data) {
return _configure(this, http_config_data);
}
inline uefi::status request(uefi::http_token * token) {
return _request(this, token);
}
inline uefi::status cancel(uefi::http_token * token) {
return _cancel(this, token);
}
inline uefi::status response(uefi::http_token * token) {
return _response(this, token);
}
inline uefi::status poll() {
return _poll(this);
}
protected:
using _get_mode_data_def = uefi::status (*)(uefi::protos::http *, uefi::http_config_data *);
_get_mode_data_def _get_mode_data;
using _configure_def = uefi::status (*)(uefi::protos::http *, uefi::http_config_data *);
_configure_def _configure;
using _request_def = uefi::status (*)(uefi::protos::http *, uefi::http_token *);
_request_def _request;
using _cancel_def = uefi::status (*)(uefi::protos::http *, uefi::http_token *);
_cancel_def _cancel;
using _response_def = uefi::status (*)(uefi::protos::http *, uefi::http_token *);
_response_def _response;
using _poll_def = uefi::status (*)(uefi::protos::http *);
_poll_def _poll;
public:
};
} // namespace protos
} // namespace uefi
#endif // _uefi_protos_http_h_

View File

@@ -1,93 +0,0 @@
#pragma once
#ifndef _uefi_protos_ip6_h_
#define _uefi_protos_ip6_h_
// This file was auto generated by the j6-uefi-headers project. Please see
// https://github.com/justinian/j6-uefi-headers for more information.
#include <uefi/guid.h>
#include <uefi/types.h>
#include <uefi/networking.h>
namespace uefi {
namespace protos {
struct ip6;
struct ip6
{
static constexpr uefi::guid guid{ 0x2c8759d5,0x5c2d,0x66ef,{0x92,0x5f,0xb6,0x6c,0x10,0x19,0x57,0xe2} };
static constexpr uefi::guid service_binding{ 0xec835dd3,0xfe0f,0x617b,{0xa6,0x21,0xb3,0x50,0xc3,0xe1,0x33,0x88} };
inline uefi::status get_mode_data(uefi::ip6_mode_data * ip6_mode_data, uefi::managed_network_config_data * mnp_config_data, uefi::simple_network_mode * snp_config_data) {
return _get_mode_data(this, ip6_mode_data, mnp_config_data, snp_config_data);
}
inline uefi::status configure(uefi::ip6_config_data * ip6_config_data) {
return _configure(this, ip6_config_data);
}
inline uefi::status groups(bool join_flag, uefi::ipv6_address * group_address) {
return _groups(this, join_flag, group_address);
}
inline uefi::status routes(bool delete_route, uefi::ipv6_address * destination, uint8_t prefix_length, uefi::ipv6_address * gateway_address) {
return _routes(this, delete_route, destination, prefix_length, gateway_address);
}
inline uefi::status neighbors(bool delete_flag, uefi::ipv6_address * target_ip6_address, uefi::mac_address * target_link_address, uint32_t timeout, bool override) {
return _neighbors(this, delete_flag, target_ip6_address, target_link_address, timeout, override);
}
inline uefi::status transmit(uefi::ip6_completion_token * token) {
return _transmit(this, token);
}
inline uefi::status receive(uefi::ip6_completion_token * token) {
return _receive(this, token);
}
inline uefi::status cancel(uefi::ip6_completion_token * token) {
return _cancel(this, token);
}
inline uefi::status poll() {
return _poll(this);
}
protected:
using _get_mode_data_def = uefi::status (*)(uefi::protos::ip6 *, uefi::ip6_mode_data *, uefi::managed_network_config_data *, uefi::simple_network_mode *);
_get_mode_data_def _get_mode_data;
using _configure_def = uefi::status (*)(uefi::protos::ip6 *, uefi::ip6_config_data *);
_configure_def _configure;
using _groups_def = uefi::status (*)(uefi::protos::ip6 *, bool, uefi::ipv6_address *);
_groups_def _groups;
using _routes_def = uefi::status (*)(uefi::protos::ip6 *, bool, uefi::ipv6_address *, uint8_t, uefi::ipv6_address *);
_routes_def _routes;
using _neighbors_def = uefi::status (*)(uefi::protos::ip6 *, bool, uefi::ipv6_address *, uefi::mac_address *, uint32_t, bool);
_neighbors_def _neighbors;
using _transmit_def = uefi::status (*)(uefi::protos::ip6 *, uefi::ip6_completion_token *);
_transmit_def _transmit;
using _receive_def = uefi::status (*)(uefi::protos::ip6 *, uefi::ip6_completion_token *);
_receive_def _receive;
using _cancel_def = uefi::status (*)(uefi::protos::ip6 *, uefi::ip6_completion_token *);
_cancel_def _cancel;
using _poll_def = uefi::status (*)(uefi::protos::ip6 *);
_poll_def _poll;
public:
};
} // namespace protos
} // namespace uefi
#endif // _uefi_protos_ip6_h_

View File

@@ -1,57 +0,0 @@
#pragma once
#ifndef _uefi_protos_ip6_config_h_
#define _uefi_protos_ip6_config_h_
// This file was auto generated by the j6-uefi-headers project. Please see
// https://github.com/justinian/j6-uefi-headers for more information.
#include <uefi/guid.h>
#include <uefi/types.h>
#include <uefi/networking.h>
namespace uefi {
namespace protos {
struct ip6_config;
struct ip6_config
{
static constexpr uefi::guid guid{ 0x937fe521,0x95ae,0x4d1a,{0x89,0x29,0x48,0xbc,0xd9,0x0a,0xd3,0x1a} };
inline uefi::status set_data(uefi::ip6_config_data_type data_type, size_t data_size, void * data) {
return _set_data(this, data_type, data_size, data);
}
inline uefi::status get_data(uefi::ip6_config_data_type data_type, size_t data_size, void * data) {
return _get_data(this, data_type, data_size, data);
}
inline uefi::status register_data_notify(uefi::ip6_config_data_type data_type, uefi::event event) {
return _register_data_notify(this, data_type, event);
}
inline uefi::status unregister_data_notify(uefi::ip6_config_data_type data_type, uefi::event event) {
return _unregister_data_notify(this, data_type, event);
}
protected:
using _set_data_def = uefi::status (*)(uefi::protos::ip6_config *, uefi::ip6_config_data_type, size_t, void *);
_set_data_def _set_data;
using _get_data_def = uefi::status (*)(uefi::protos::ip6_config *, uefi::ip6_config_data_type, size_t, void *);
_get_data_def _get_data;
using _register_data_notify_def = uefi::status (*)(uefi::protos::ip6_config *, uefi::ip6_config_data_type, uefi::event);
_register_data_notify_def _register_data_notify;
using _unregister_data_notify_def = uefi::status (*)(uefi::protos::ip6_config *, uefi::ip6_config_data_type, uefi::event);
_unregister_data_notify_def _unregister_data_notify;
public:
};
} // namespace protos
} // namespace uefi
#endif // _uefi_protos_ip6_config_h_

View File

@@ -1,36 +0,0 @@
#pragma once
#ifndef _uefi_protos_load_file_h_
#define _uefi_protos_load_file_h_
// This file was auto generated by the j6-uefi-headers project. Please see
// https://github.com/justinian/j6-uefi-headers for more information.
#include <uefi/guid.h>
#include <uefi/types.h>
#include <uefi/protos/device_path.h>
namespace uefi {
namespace protos {
struct load_file;
struct load_file
{
static constexpr uefi::guid guid{ {0x56ec3091,0x954c,0x11d2,{0x8e,0x3f,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
inline uefi::status load_file(uefi::protos::device_path * file_path, bool boot_policy, size_t * buffer_size, void * buffer) {
return _load_file(this, file_path, boot_policy, buffer_size, buffer);
}
protected:
using _load_file_def = uefi::status (*)(uefi::protos::load_file *, uefi::protos::device_path *, bool, size_t *, void *);
_load_file_def _load_file;
public:
};
} // namespace protos
} // namespace uefi
#endif // _uefi_protos_load_file_h_

View File

@@ -1,49 +0,0 @@
#pragma once
#ifndef _uefi_protos_loaded_image_h_
#define _uefi_protos_loaded_image_h_
// This file was auto generated by the j6-uefi-headers project. Please see
// https://github.com/justinian/j6-uefi-headers for more information.
#include <uefi/guid.h>
#include <uefi/types.h>
#include <uefi/tables.h>
#include <uefi/protos/device_path.h>
namespace uefi {
namespace protos {
struct loaded_image;
struct loaded_image
{
static constexpr uefi::guid guid{ 0x5b1b31a1,0x9562,0x11d2,{0x8e,0x3f,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
inline uefi::status unload(uefi::handle image_handle) {
return _unload(image_handle);
}
uint32_t revision;
uefi::handle parent_handle;
uefi::system_table * system_table;
uefi::handle device_handle;
uefi::protos::device_path * file_path;
void * reserved;
uint32_t load_options_size;
void * load_options;
void * image_base;
uint64_t image_size;
uefi::memory_type image_code_type;
uefi::memory_type image_data_type;
protected:
using _unload_def = uefi::status (*)(uefi::handle);
_unload_def _unload;
public:
};
} // namespace protos
} // namespace uefi
#endif // _uefi_protos_loaded_image_h_

View File

@@ -1,41 +0,0 @@
#pragma once
#ifndef _uefi_protos_service_binding_h_
#define _uefi_protos_service_binding_h_
// This file was auto generated by the j6-uefi-headers project. Please see
// https://github.com/justinian/j6-uefi-headers for more information.
#include <uefi/guid.h>
#include <uefi/types.h>
namespace uefi {
namespace protos {
struct service_binding;
struct service_binding
{
inline uefi::status create_child(uefi::handle * child_handle) {
return _create_child(this, child_handle);
}
inline uefi::status destroy_child(uefi::handle child_handle) {
return _destroy_child(this, child_handle);
}
protected:
using _create_child_def = uefi::status (*)(uefi::protos::service_binding *, uefi::handle *);
_create_child_def _create_child;
using _destroy_child_def = uefi::status (*)(uefi::protos::service_binding *, uefi::handle);
_destroy_child_def _destroy_child;
public:
};
} // namespace protos
} // namespace uefi
#endif // _uefi_protos_service_binding_h_

View File

@@ -1,37 +0,0 @@
#pragma once
#ifndef _uefi_protos_simple_file_system_h_
#define _uefi_protos_simple_file_system_h_
// This file was auto generated by the j6-uefi-headers project. Please see
// https://github.com/justinian/j6-uefi-headers for more information.
#include <uefi/guid.h>
#include <uefi/types.h>
#include <uefi/protos/file.h>
namespace uefi {
namespace protos {
struct simple_file_system;
struct simple_file_system
{
static constexpr uefi::guid guid{ 0x0964e5b22,0x6459,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
inline uefi::status open_volume(uefi::protos::file ** root) {
return _open_volume(this, root);
}
uint64_t revision;
protected:
using _open_volume_def = uefi::status (*)(uefi::protos::simple_file_system *, uefi::protos::file **);
_open_volume_def _open_volume;
public:
};
} // namespace protos
} // namespace uefi
#endif // _uefi_protos_simple_file_system_h_

View File

@@ -1,93 +0,0 @@
#pragma once
#ifndef _uefi_protos_simple_text_output_h_
#define _uefi_protos_simple_text_output_h_
// This file was auto generated by the j6-uefi-headers project. Please see
// https://github.com/justinian/j6-uefi-headers for more information.
#include <uefi/guid.h>
#include <uefi/types.h>
#include <uefi/graphics.h>
namespace uefi {
namespace protos {
struct simple_text_output;
struct simple_text_output
{
static constexpr uefi::guid guid{ 0x387477c2,0x69c7,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
inline uefi::status reset(bool extended_verification) {
return _reset(this, extended_verification);
}
inline uefi::status output_string(const wchar_t * string) {
return _output_string(this, string);
}
inline uefi::status test_string(const wchar_t * string) {
return _test_string(this, string);
}
inline uefi::status query_mode(uint64_t mode_number, uint64_t * columns, uint64_t * rows) {
return _query_mode(this, mode_number, columns, rows);
}
inline uefi::status set_mode(uint64_t mode_number) {
return _set_mode(this, mode_number);
}
inline uefi::status set_attribute(uefi::attribute attribute) {
return _set_attribute(this, attribute);
}
inline uefi::status clear_screen() {
return _clear_screen(this);
}
inline uefi::status set_cursor_position(uint64_t column, uint64_t row) {
return _set_cursor_position(this, column, row);
}
inline uefi::status enable_cursor(bool visible) {
return _enable_cursor(this, visible);
}
protected:
using _reset_def = uefi::status (*)(uefi::protos::simple_text_output *, bool);
_reset_def _reset;
using _output_string_def = uefi::status (*)(uefi::protos::simple_text_output *, const wchar_t *);
_output_string_def _output_string;
using _test_string_def = uefi::status (*)(uefi::protos::simple_text_output *, const wchar_t *);
_test_string_def _test_string;
using _query_mode_def = uefi::status (*)(uefi::protos::simple_text_output *, uint64_t, uint64_t *, uint64_t *);
_query_mode_def _query_mode;
using _set_mode_def = uefi::status (*)(uefi::protos::simple_text_output *, uint64_t);
_set_mode_def _set_mode;
using _set_attribute_def = uefi::status (*)(uefi::protos::simple_text_output *, uefi::attribute);
_set_attribute_def _set_attribute;
using _clear_screen_def = uefi::status (*)(uefi::protos::simple_text_output *);
_clear_screen_def _clear_screen;
using _set_cursor_position_def = uefi::status (*)(uefi::protos::simple_text_output *, uint64_t, uint64_t);
_set_cursor_position_def _set_cursor_position;
using _enable_cursor_def = uefi::status (*)(uefi::protos::simple_text_output *, bool);
_enable_cursor_def _enable_cursor;
public:
uefi::text_output_mode * mode;
};
} // namespace protos
} // namespace uefi
#endif // _uefi_protos_simple_text_output_h_

View File

@@ -1,52 +0,0 @@
#pragma once
#ifndef _uefi_runtime_services_h_
#define _uefi_runtime_services_h_
// This Source Code Form is part of the j6-uefi-headers project and is subject
// to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was
// not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.
#include <stdint.h>
#include <uefi/tables.h>
namespace uefi {
namespace rs_impl {
using convert_pointer = uefi::status (*)(uint64_t, void **);
using set_virtual_address_map = uefi::status (*)(size_t, size_t, uint32_t, memory_descriptor *);
}
struct runtime_services {
static constexpr uint64_t signature = 0x56524553544e5552ull;
table_header header;
// Time Services
void *get_time;
void *set_time;
void *get_wakeup_time;
void *set_wakeup_time;
// Virtual Memory Services
rs_impl::set_virtual_address_map set_virtual_address_map;
rs_impl::convert_pointer convert_pointer;
// Variable Services
void *get_variable;
void *get_next_variable_name;
void *set_variable;
// Miscellaneous Services
void *get_next_high_monotonic_count;
void *reset_system;
// UEFI 2.0 Capsule Services
void *update_capsule;
void *query_capsule_capabilities;
// Miscellaneous UEFI 2.0 Service
void *query_variable_info;
};
} // namespace uefi
#endif

View File

@@ -1,73 +0,0 @@
#pragma once
#ifndef _uefi_tables_h_
#define _uefi_tables_h_
// This Source Code Form is part of the j6-uefi-headers project and is subject
// to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was
// not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.
#include <stdint.h>
#include <uefi/guid.h>
#include <uefi/types.h>
namespace uefi {
struct runtime_services;
struct boot_services;
namespace protos {
struct simple_text_input;
struct simple_text_output;
}
struct table_header
{
uint64_t signature;
uint32_t revision;
uint32_t header_size;
uint32_t crc32;
uint32_t reserved;
};
struct configuration_table
{
guid vendor_guid;
void *vendor_table;
};
struct system_table
{
table_header header;
char16_t *firmware_vendor;
uint32_t firmware_revision;
handle console_in_handle;
protos::simple_text_input *con_in;
handle console_out_handle;
protos::simple_text_output *con_out;
handle standard_error_handle;
protos::simple_text_output *std_err;
runtime_services *runtime_services;
boot_services *boot_services;
unsigned int number_of_table_entries;
configuration_table *configuration_table;
};
constexpr uint32_t make_system_table_revision(int major, int minor) {
return (major << 16) | minor;
}
constexpr uint64_t system_table_signature = 0x5453595320494249ull;
constexpr uint32_t system_table_revision = make_system_table_revision(2, 70);
constexpr uint32_t specification_revision = system_table_revision;
namespace vendor_guids {
constexpr guid acpi1{ 0xeb9d2d30,0x2d88,0x11d3,{0x9a,0x16,0x00,0x90,0x27,0x3f,0xc1,0x4d} };
constexpr guid acpi2{ 0x8868e871,0xe4f1,0x11d3,{0xbc,0x22,0x00,0x80,0xc7,0x3c,0x88,0x81} };
} // namespace vendor_guids
} // namespace uefi
#endif

157
external/uefi/types.h vendored
View File

@@ -1,157 +0,0 @@
#pragma once
#ifndef _uefi_types_h_
#define _uefi_types_h_
// This Source Code Form is part of the j6-uefi-headers project and is subject
// to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was
// not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.
#include <stdint.h>
namespace uefi {
using handle = void *;
//
// Error and status code definitions
//
constexpr uint64_t error_bit = 0x8000000000000000ull;
constexpr uint64_t make_error(uint64_t e) { return e|error_bit; }
enum class status : uint64_t
{
success = 0,
#define STATUS_WARNING(name, num) name = num,
#define STATUS_ERROR(name, num) name = make_error(num),
#include "uefi/errors.inc"
#undef STATUS_WARNING
#undef STATUS_ERROR
};
inline bool is_error(status s) { return static_cast<uint64_t>(s) & error_bit; }
inline bool is_warning(status s) { return !is_error(s) && s != status::success; }
//
// Time defitions
//
struct time
{
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t minute;
uint8_t second;
uint8_t _pad0;
uint32_t nanosecond;
int16_t time_zone;
uint8_t daylight;
uint8_t _pad1;
};
//
// Memory and allocation defitions
//
enum class memory_type : uint32_t
{
reserved,
loader_code,
loader_data,
boot_services_code,
boot_services_data,
runtime_services_code,
runtime_services_data,
conventional_memory,
unusable_memory,
acpi_reclaim_memory,
acpi_memory_nvs,
memory_mapped_io,
memory_mapped_io_port_space,
pal_code,
persistent_memory,
max_memory_type
};
enum class allocate_type : uint32_t
{
any_pages,
max_address,
address
};
struct memory_descriptor
{
memory_type type;
uintptr_t physical_start;
uintptr_t virtual_start;
uint64_t number_of_pages;
uint64_t attribute;
};
//
// Event handling defitions
//
using event = void *;
enum class evt : uint32_t
{
notify_wait = 0x00000100,
notify_signal = 0x00000200,
signal_exit_boot_services = 0x00000201,
signal_virtual_address_change = 0x60000202,
runtime = 0x40000000,
timer = 0x80000000
};
enum class tpl : uint64_t
{
application = 4,
callback = 8,
notify = 16,
high_level = 31
};
using event_notify = void (*)(event, void*);
//
// File IO defitions
//
struct file_io_token
{
event event;
status status;
uint64_t buffer_size;
void *buffer;
};
enum class file_mode : uint64_t
{
read = 0x0000000000000001ull,
write = 0x0000000000000002ull,
create = 0x8000000000000000ull
};
enum class file_attr : uint64_t
{
none = 0,
read_only = 0x0000000000000001ull,
hidden = 0x0000000000000002ull,
system = 0x0000000000000004ull,
reserved = 0x0000000000000008ull,
directory = 0x0000000000000010ull,
archive = 0x0000000000000020ull
};
} // namespace uefi
#endif

147
modules.yaml Normal file
View File

@@ -0,0 +1,147 @@
name: jsix
templates: scripts/templates
modules:
kernel:
kind: exe
output: jsix.elf
target: host
deps:
- elf
- initrd
- kutil
- vdso
includes:
- src/kernel
source:
- src/kernel/crti.s
- src/kernel/apic.cpp
- src/kernel/assert.cpp
- src/kernel/boot.s
- src/kernel/console.cpp
- src/kernel/cpprt.cpp
- src/kernel/cpu.cpp
- src/kernel/debug.cpp
- src/kernel/debug.s
- src/kernel/device_manager.cpp
- src/kernel/font.cpp
- src/kernel/frame_allocator.cpp
- src/kernel/fs/gpt.cpp
- src/kernel/gdt.cpp
- src/kernel/gdt.s
- src/kernel/interrupts.cpp
- src/kernel/interrupts.s
- src/kernel/io.cpp
- src/kernel/loader.s
- src/kernel/log.cpp
- src/kernel/main.cpp
- src/kernel/memory_bootstrap.cpp
- src/kernel/msr.cpp
- src/kernel/objects/handle.cpp
- src/kernel/objects/kobject.cpp
- src/kernel/page_manager.cpp
- src/kernel/pci.cpp
- src/kernel/process.cpp
- src/kernel/scheduler.cpp
- src/kernel/screen.cpp
- src/kernel/serial.cpp
- src/kernel/syscall.cpp
- src/kernel/syscall.s
- src/kernel/syscalls/object.cpp
- src/kernel/syscalls/process.cpp
- src/kernel/task.s
- src/kernel/crtn.s
boot:
kind: exe
target: boot
output: boot.elf
source:
- src/boot/crt0.s
- src/boot/console.cpp
- src/boot/guids.cpp
- src/boot/loader.cpp
- src/boot/main.cpp
- src/boot/memory.cpp
- src/boot/reloc.cpp
- src/boot/utility.cpp
vdso:
kind: exe
target: host
output: libvdso.so
extra:
- src/arch/x86_64/vdso.ld
source:
- src/vdso/syscalls.cpp
- src/vdso/overrides.cpp
nulldrv:
kind: exe
target: user
output: nulldrv
source:
- src/drivers/nulldrv/main.cpp
- src/drivers/nulldrv/main.s
elf:
kind: lib
output: libelf.a
deps:
- kutil
includes:
- src/libraries/elf/include
source:
- src/libraries/elf/elf.cpp
initrd:
kind: lib
output: libinitrd.a
deps:
- kutil
includes:
- src/libraries/initrd/include
source:
- src/libraries/initrd/initrd.cpp
kutil:
kind: lib
output: libkutil.a
includes:
- src/libraries/kutil/include
source:
- src/libraries/kutil/assert.cpp
- src/libraries/kutil/bip_buffer.cpp
- src/libraries/kutil/heap_allocator.cpp
- src/libraries/kutil/logger.cpp
- src/libraries/kutil/memory.cpp
- src/libraries/kutil/printf.c
- src/libraries/kutil/vm_space.cpp
makerd:
kind: exe
target: native
output: makerd
deps:
- initrd
source:
- src/tools/makerd/entry.cpp
- src/tools/makerd/main.cpp
tests:
kind: exe
target: native
output: tests
deps:
- kutil
source:
- src/tests/address_manager.cpp
- src/tests/constexpr_hash.cpp
- src/tests/linked_list.cpp
- src/tests/logger.cpp
- src/tests/heap_allocator.cpp
- src/tests/main.cpp
overlays:
- url: https://f000.backblazeb2.com/file/jsix-os/sysroot-llvm8-20190706.tar.bz2
path: sysroot
- url: https://f000.backblazeb2.com/file/jsix-os/sysroot-j6libc-8cb8ce7.tar.bz2
path: sysroot

View File

@@ -33,18 +33,42 @@ Boost Software license:
> ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> DEALINGS IN THE SOFTWARE.
## cpptoml
jsix uses the [cpptoml][] library for parsing TOML configuration files. cpptoml
is released under the terms of the MIT license:
[cpptoml]: https://github.com/skystrife/cpptoml
> Copyright (c) 2014 Chase Geigle
>
> Permission is hereby granted, free of charge, to any person obtaining a copy of
> this software and associated documentation files (the "Software"), to deal in
> the Software without restriction, including without limitation the rights to
> use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
> the Software, and to permit persons to whom the Software is furnished to do so,
> subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in all
> copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
> FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
> COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
> IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
## printf
The implementation of jsix's `*printf()` family of functions is derived from
Marco Paland and Eyal Rozenberg's tiny [printf][] library, which is also
released under the terms of the MIT license:
jsix uses Marco Paland's tiny [printf][] library for its `*printf()` functions,
which is also released under the terms of the MIT license:
[printf]: https://github.com/eyalroz/printf
[printf]: https://github.com/mpaland/printf
> The MIT License (MIT)
>
> Copyright (c) 2014 Marco Paland
> Copyright (c) 2021 Eyal Rozenberg
>
> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
@@ -63,3 +87,46 @@ released under the terms of the MIT license:
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> SOFTWARE.
## GNU-EFI
jsix's UEFI bootloader initially used [GNU-EFI][], and still uses one file (the
linker script for the bootloader) from that project. GNU-EFI claims to be
released under the BSD license. Again, I could not find its specific license
file, so I am reproducing a generic 3-clause BSD license (the most restrictive,
so as not to assume any extra rights that may not actually be granted) for it
here:
[GNU-EFI]: https://gnu-efi.sourceforge.net
> Copyright (c) Nigel Croxon
>
> Redistribution and use in source and binary forms, with or without
> modification, are permitted provided that the following conditions are met:
>
> 1. Redistributions of source code must retain the above copyright notice, this
> list of conditions and the following disclaimer.
>
> 2. Redistributions in binary form must reproduce the above copyright notice,
> this list of conditions and the following disclaimer in the documentation
> and/or other materials provided with the distribution.
>
> 3. Neither the name of the copyright holder nor the names of its contributors
> may be used to endorse or promote products derived from this software
> without specific prior written permission.
>
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
> ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
> WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
> FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
> DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
> OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
## Intel EFI Application Toolkit
jsix's UEFI loader uses code from Intel's EFI Application toolkit. Relevant
code includes license statements at the top of each file.

71
qemu.sh
View File

@@ -3,55 +3,26 @@
build="$(dirname $0)/build"
assets="$(dirname $0)/assets"
debug=""
isaexit='-device isa-debug-exit,iobase=0xf4,iosize=0x04'
debugtarget="${build}/jsix.elf"
flash_name="ovmf_vars"
gfx="-nographic"
vga="-vga none"
log=""
kvm=""
cpu="Broadwell,+pdpe1gb"
smp=4
while true; do
case "$1" in
-b | --debugboot)
debug="-s -S"
debugtarget="${build}/boot/boot.efi"
shift
for arg in $@; do
case "${arg}" in
--debug)
debug="-s"
flash_name="ovmf_vars_d"
;;
-d | --debug)
debug="-s -S"
isaexit=""
shift
;;
-g | --gfx)
--gfx)
gfx=""
vga=""
shift
;;
-v | --vga)
vga=""
shift
;;
-k | --kvm)
--kvm)
kvm="-enable-kvm"
cpu="host"
shift
;;
-c | --cpus)
smp=$2
shift 2
;;
-l | --log)
log="-d mmu,int,guest_errors -D jsix.log"
shift
;;
*)
if [ -d "$1" ]; then
build="$1"
shift
fi
break
build="${arg}"
;;
esac
done
@@ -66,33 +37,29 @@ fi
if [[ -n $TMUX ]]; then
if [[ -n $debug ]]; then
tmux split-window -h "gdb ${debugtarget}" &
tmux split-window "gdb ${build}/jsix.elf" &
else
tmux split-window -h -l 80 "sleep 1; telnet localhost 45455" &
tmux last-pane
tmux split-window -l 10 "sleep 1; telnet localhost 45454" &
fi
elif [[ $DESKTOP_SESSION = "i3" ]]; then
if [[ -n $debug ]]; then
i3-msg exec i3-sensible-terminal -- -e "gdb ${debugtarget}" &
i3-msg exec i3-sensible-terminal -- -e "gdb ${PWD}/${build}/jsix.elf" &
else
i3-msg exec i3-sensible-terminal -- -e 'telnet localhost 45454' &
fi
fi
qemu-system-x86_64 \
exec qemu-system-x86_64 \
-drive "if=pflash,format=raw,readonly,file=${assets}/ovmf/x64/ovmf_code.fd" \
-drive "if=pflash,format=raw,file=${build}/ovmf_vars.fd" \
-drive "if=pflash,format=raw,file=${build}/${flash_name}.fd" \
-drive "format=raw,file=${build}/jsix.img" \
-device "isa-debug-exit,iobase=0xf4,iosize=0x04" \
-monitor telnet:localhost:45454,server,nowait \
-serial stdio \
-serial telnet:localhost:45455,server,nowait \
-smp "${smp}" \
-m 4096 \
-smp 4 \
-m 512 \
-d mmu,int,guest_errors \
-D jsix.log \
-cpu "${cpu}" \
-M q35 \
-no-reboot \
$isaexit $log $gfx $vga $kvm $debug
((result = ($? >> 1) - 1))
exit $result
$gfx $kvm $debug

View File

@@ -1,5 +0,0 @@
cogapp >= 3
ninja >= 1.10.2
peru >= 1.2.1
pyyaml >= 5.4
lark == 0.12.0

View File

@@ -1,25 +0,0 @@
from os.path import join
class BonnibelError(Exception):
def __init__(self, message):
self.message = message
def load_config(filename):
from yaml import safe_load
with open(filename, 'r') as infile:
return safe_load(infile.read())
def mod_rel(path):
return join("${module_dir}", path)
def target_rel(path, module=None):
if module:
return join("${target_dir}", module + ".dir", path)
else:
return join("${target_dir}", path)
def include_rel(path, module=None):
if module:
return join("${build_root}", "include", module, path)
else:
return join("${build_root}", "include", path)

View File

@@ -1,103 +0,0 @@
from . import BonnibelError
class Manifest:
from collections import namedtuple
Entry = namedtuple("Entry", ("module", "target", "output", "location", "description", "flags"))
flags = {
"graphical": 0x01,
"panic": 0x02,
"symbols": 0x04,
}
boot_flags = {
"debug": 0x01,
"test": 0x02,
}
def __init__(self, path, modules):
from . import load_config
config = load_config(path)
self.kernel = self.__build_entry(modules,
config.get("kernel", dict()),
name="kernel", target="kernel")
self.init = self.__build_entry(modules,
config.get("init", None))
self.programs = [self.__build_entry(modules, i)
for i in config.get("programs", tuple())]
self.flags = config.get("flags", tuple())
self.data = []
for d in config.get("data", tuple()):
self.add_data(**d)
def __build_entry(self, modules, config, target="user", name=None):
flags = tuple()
if isinstance(config, str):
name = config
elif isinstance(config, dict):
name = config.get("name", name)
target = config.get("target", target)
flags = config.get("flags", tuple())
if isinstance(flags, str):
flags = flags.split()
mod = modules.get(name)
if not mod:
raise BonnibelError(f"Manifest specifies unknown module '{name}'")
for f in flags:
if not f in Manifest.flags:
raise BonnibelError(f"Manifest specifies unknown flag '{f}'")
return Manifest.Entry(name, target, mod.output, mod.location, mod.description, flags)
def add_data(self, output, location, desc, flags=tuple()):
e = Manifest.Entry(None, None, output, location, desc, flags)
self.data.append(e)
return e
def write_boot_config(self, path):
from os.path import join
import struct
with open(path, 'wb') as outfile:
magic = "jsixboot".encode("utf-8") # magic string
version = 0
reserved = 0
bootflags = sum([Manifest.boot_flags.get(s, 0) for s in self.flags])
outfile.write(struct.pack("<8sBBHHH",
magic, version, reserved,
len(self.programs), len(self.data),
bootflags))
def write_str(s):
outfile.write(struct.pack("<H", (len(s)+1)*2))
outfile.write(s.encode("utf-16le"))
outfile.write(b"\0\0")
def write_ent(ent):
flags = 0
for f in ent.flags:
flags |= Manifest.flags[f]
outfile.write(struct.pack("<H", flags))
write_str(join(ent.location, ent.output).replace('/','\\'))
write_str(ent.description)
write_ent(self.kernel)
write_ent(self.init)
for p in self.programs:
write_ent(p)
for d in self.data:
write_ent(d)

View File

@@ -1,276 +0,0 @@
from . import include_rel, mod_rel, target_rel
def resolve(path):
if path.startswith('/') or path.startswith('$'):
return path
from pathlib import Path
return str(Path(path).resolve())
class BuildOptions:
def __init__(self, includes=tuple(), libs=tuple(), order_only=tuple()):
self.includes = list(includes)
self.libs = list(libs)
self.order_only = list(order_only)
class Module:
__fields = {
# name: (type, default)
"kind": (str, "exe"),
"output": (str, None),
"targets": (set, ()),
"deps": (set, ()),
"public_headers": (set, ()),
"includes": (tuple, ()),
"sources": (tuple, ()),
"variables": (dict, ()),
"default": (bool, False),
"location": (str, "jsix"),
"description": (str, None),
"no_libc": (bool, False),
}
def __init__(self, name, modfile, root, **kwargs):
from .source import make_source
# Required fields
self.root = root
self.name = name
self.modfile = modfile
for name, data in self.__fields.items():
ctor, default = data
value = kwargs.get(name, default)
if value is not None:
value = ctor(value)
setattr(self, name, value)
for name in kwargs:
if not name in self.__fields:
raise AttributeError(f"No attribute named {name} on Module")
# Turn strings into real Source objects
self.sources = [make_source(root, f) for f in self.sources]
self.public_headers = [make_source(root, f) for f in self.public_headers]
# Filled by Module.update
self.depmods = set()
def __str__(self):
return "Module {} {}\n\t{}".format(self.kind, self.name, "\n\t".join(map(str, self.sources)))
@property
def output(self):
if self.__output is not None:
return self.__output
if self.kind == "lib":
return f"lib{self.name}.a"
else:
return f"{self.name}.elf"
@output.setter
def output(self, value):
self.__output = value
@classmethod
def update(cls, mods):
from . import BonnibelError
def resolve(source, modlist):
resolved = set()
for dep in modlist:
if not dep in mods:
raise BonnibelError(f"module '{source.name}' references unknown module '{dep}'")
mod = mods[dep]
resolved.add(mod)
return resolved
for mod in mods.values():
mod.depmods = resolve(mod, mod.deps)
target_mods = [mod for mod in mods.values() if mod.targets]
for mod in target_mods:
closed = set()
children = set(mod.depmods)
while children:
child = children.pop()
closed.add(child)
child.targets |= mod.targets
children |= {m for m in child.depmods if not m in closed}
def generate(self, output):
from pathlib import Path
from collections import defaultdict
from ninja.ninja_syntax import Writer
def walk_deps(deps):
open_set = set(deps)
closed_set = set()
while open_set:
dep = open_set.pop()
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)
def gather_phony(build, deps, child_rel, add_headers=False):
phony = ".headers.phony"
child_phony = [child_rel(phony, module=c.name)
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(
rule = "touch",
outputs = [mod_rel(phony)],
implicit = child_phony + header_targets,
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")
with open(filename, "w") as buildfile:
build = Writer(buildfile)
build.comment("This file is automatically generated by bonnibel")
build.newline()
build.variable("module_dir", target_rel(self.name + ".dir"))
modopts = BuildOptions(
includes = [self.root, "${module_dir}"],
)
if self.public_headers:
modopts.includes += [f"${{build_root}}/include/{self.name}"]
for key, value in self.variables.items():
build.variable(key, value)
build.newline()
for include in self.includes:
p = Path(include)
if p.is_absolute():
if not p in modopts.includes:
modopts.includes.append(str(p.resolve()))
elif include != ".":
incpath = self.root / p
destpath = mod_rel(p)
for header in incpath.rglob("*.h"):
dest_header = f"{destpath}/" + str(header.relative_to(incpath))
modopts.includes.append(str(incpath))
modopts.includes.append(destpath)
all_deps = walk_deps(self.depmods)
for dep in all_deps:
if dep.public_headers:
modopts.includes += [f"${{build_root}}/include/{dep.name}"]
if dep.kind == "lib":
modopts.libs.append(target_rel(dep.output))
else:
modopts.order_only.append(target_rel(dep.output))
if modopts.includes:
build.variable("ccflags", ["${ccflags}"] + [f"-I{i}" for i in modopts.includes])
build.variable("asflags", ["${asflags}"] + [f"-I{i}" for i in modopts.includes])
if modopts.libs:
build.variable("libs", ["${libs}"] + modopts.libs)
header_deps = []
inputs = []
sources = set(self.sources)
while sources:
source = sources.pop()
sources.update(source.next)
if source.action:
build.newline()
build.build(rule=source.action, **source.args)
if source.gather:
header_deps += list(source.outputs)
if source.input:
inputs.extend(map(mod_rel, source.outputs))
build.newline()
gather_phony(build, header_deps, target_rel, add_headers=True)
output = target_rel(self.output)
dump = output + ".dump"
build.newline()
build.build(
rule = self.kind,
outputs = output,
inputs = inputs,
implicit = modopts.libs,
order_only = modopts.order_only,
)
build.newline()
build.build(
rule = "dump",
outputs = dump,
inputs = output,
variables = {"name": self.name},
)
if self.default:
build.newline()
build.default(output)
build.default(dump)
def add_input(self, path, **kwargs):
from .source import Source
s = Source(self.root, path, **kwargs)
self.sources.append(s)
return s.outputs
def add_depends(self, paths, deps):
for source in self.sources:
if source.path in paths:
source.add_deps(deps)
for source in self.public_headers:
if source.path in paths:
source.add_deps(deps)

View File

@@ -1,234 +0,0 @@
from . import BonnibelError
class Project:
def __init__(self, root):
from .version import git_version
self.root = root
self.version = git_version(root)
def __str__(self):
return f"{self.name} {self.version.major}.{self.version.minor}.{self.version.patch}-{self.version.sha}"
def generate(self, root, output, modules, config, manifest_file):
import sys
import bonnibel
from os.path import join
from ninja.ninja_syntax import Writer
from .target import Target
targets = set()
for mod in modules.values():
targets.update({Target.load(root, t, config) for t in mod.targets})
with open(output / "build.ninja", "w") as buildfile:
build = Writer(buildfile)
build.comment("This file is automatically generated by bonnibel")
build.variable("ninja_required_version", "1.3")
build.variable("build_root", output)
build.variable("source_root", root)
build.newline()
build.include(root / "configs" / "rules.ninja")
build.newline()
build.variable("version_major", self.version.major)
build.variable("version_minor", self.version.minor)
build.variable("version_patch", self.version.patch)
build.variable("version_sha", self.version.sha)
build.newline()
build.variable("cogflags", [
"-I", "${source_root}/scripts",
"-D", "definitions_path=${source_root}/definitions",
])
build.newline()
for target in targets:
build.subninja(output / target.name / "target.ninja")
build.newline()
for mod in modules.values():
build.subninja(output / f"headers.{mod.name}.ninja")
build.newline()
build.build(
rule = "touch",
outputs = "${build_root}/.all_headers",
implicit = [f"${{build_root}}/include/{m.name}/.headers.phony"
for m in modules.values() if m.public_headers],
)
build.build(
rule = "phony",
outputs = ["all-headers"],
inputs = ["${build_root}/.all_headers"])
debugroot = output / ".debug"
debugroot.mkdir(exist_ok=True)
fatroot = output / "fatroot"
fatroot.mkdir(exist_ok=True)
fatroot_content = []
def add_fatroot(source, entry):
output = join(entry.location, entry.output)
fatroot_output = f"${{build_root}}/fatroot/{output}"
build.build(
rule = "cp",
outputs = [fatroot_output],
inputs = [source],
variables = {
"name": f"Installing {output}",
})
fatroot_content.append(fatroot_output)
build.newline()
def add_fatroot_exe(entry):
input_path = f"${{build_root}}/{entry.target}/{entry.output}"
intermediary = f"${{build_root}}/{entry.output}"
build.build(
rule = "strip",
outputs = [intermediary],
inputs = [input_path],
implicit = [f"{input_path}.dump"],
variables = {
"name": f"Stripping {entry.module}",
"debug": f"${{build_root}}/.debug/{entry.output}.debug",
})
add_fatroot(intermediary, entry)
from .manifest import Manifest
manifest = Manifest(manifest_file, modules)
add_fatroot_exe(manifest.kernel)
add_fatroot_exe(manifest.init)
for program in manifest.programs:
add_fatroot_exe(program)
syms = manifest.add_data("symbol_table.dat",
manifest.kernel.location, "Symbol table", ("symbols",))
sym_out = f"${{build_root}}/symbol_table.dat"
build.build(
rule = "makest",
outputs = [sym_out],
inputs = [f"${{build_root}}/{modules['kernel'].output}"],
)
add_fatroot(sym_out, syms)
bootloader = "${build_root}/fatroot/efi/boot/bootx64.efi"
build.build(
rule = "cp",
outputs = [bootloader],
inputs = ["${build_root}/boot/boot.efi"],
variables = {
"name": "Installing bootloader",
})
build.newline()
boot_config = join(fatroot, "jsix_boot.dat")
manifest.write_boot_config(boot_config)
build.build(
rule = "makefat",
outputs = ["${build_root}/jsix.img"],
inputs = ["${source_root}/assets/diskbase.img"],
implicit = fatroot_content + [bootloader],
variables = {"name": "jsix.img"},
)
build.newline()
default_assets = {
"UEFI Variables": ("ovmf/x64/ovmf_vars.fd", "ovmf_vars.fd"),
"GDB Debug Helpers": ("debugging/jsix.elf-gdb.py", "jsix.elf-gdb.py"),
}
for name, assets in default_assets.items():
p = root / "assets" / assets[0]
out = f"${{build_root}}/{assets[1]}"
build.build(
rule = "cp",
outputs = [out],
inputs = [str(p)],
variables = {"name": name},
)
build.default([out])
build.newline()
compdb = "${source_root}/compile_commands.json"
build.rule("regen",
command = " ".join([str(root / 'configure')] + sys.argv[1:]),
description = "Regenerate build files",
generator = True,
)
build.newline()
regen_implicits = \
[f"{self.root}/configure", str(manifest_file)] + \
[str(mod.modfile) for mod in modules.values()]
for target in targets:
regen_implicits += target.depfiles
build.build(
rule = "compdb",
outputs = [compdb],
implicit = regen_implicits,
)
build.default([compdb])
build.newline()
build.build(
rule = "regen",
outputs = ['build.ninja'],
implicit = regen_implicits,
implicit_outputs =
[f"module.{mod.name}.ninja" for mod in modules.values()] +
[f"{target.name}/target.ninja" for target in targets] +
[boot_config],
)
build.newline()
build.default(["${build_root}/jsix.img"])
for target in targets:
mods = [m.name for m in modules.values() if target.name in m.targets]
targetdir = output / target.name
targetdir.mkdir(exist_ok=True)
buildfilename = str(targetdir / "target.ninja")
with open(buildfilename, "w") as buildfile:
build = Writer(buildfile)
build.comment("This file is automatically generated by bonnibel")
build.newline()
build.variable("target", target.name)
build.variable("target_dir", output / target.name)
build.newline()
for name, value in target.items():
build.variable(name, value)
build.newline()
for kind in ('defs', 'run'):
for lang in ('c', 'cpp'):
deffile = str(output / target.name / f"{lang}.{kind}")
build.build(
rule = f"dump_{lang}_{kind}",
outputs = [deffile],
implicit = [buildfilename],
)
build.default(deffile)
build.newline()
for mod in mods:
build.subninja(f"module.{mod}.ninja")

View File

@@ -1,119 +0,0 @@
from os.path import join, splitext
from . import mod_rel
def _resolve(path):
if path.startswith('/') or path.startswith('$'):
return path
from pathlib import Path
return str(Path(path).resolve())
def _dynamic_action(name):
def prop(self):
root, suffix = splitext(self.path)
return f"{name}{suffix}"
return prop
class Source:
next = tuple()
action = None
args = dict()
gather = False
outputs = tuple()
input = False
def __init__(self, path, root = "${module_dir}", deps=tuple()):
self.path = path
self.root = root
self.deps = deps
def add_deps(self, deps):
self.deps += tuple(deps)
@property
def fullpath(self):
return join(self.root, self.path)
class ParseSource(Source):
action = property(_dynamic_action("parse"))
@property
def output(self):
root, _ = splitext(self.path)
return root
@property
def outputs(self):
return (self.output,)
@property
def gather(self):
_, suffix = splitext(self.output)
return suffix in (".h", ".inc")
@property
def next(self):
_, suffix = splitext(self.output)
nextType = {
".s": CompileSource,
".cpp": CompileSource,
}.get(suffix)
if nextType:
return (nextType(self.output),)
return tuple()
@property
def args(self):
return dict(
outputs = list(map(mod_rel, self.outputs)),
inputs = [self.fullpath],
implicit = list(map(_resolve, self.deps)),
variables = dict(name=self.path),
)
class HeaderSource(Source):
action = "cp"
gather = True
@property
def outputs(self):
return (self.path,)
@property
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):
action = property(_dynamic_action("compile"))
input = True
@property
def outputs(self):
return (self.path + ".o",)
@property
def args(self):
return dict(
outputs = list(map(mod_rel, self.outputs)),
inputs = [join(self.root, self.path)],
implicit = list(map(_resolve, self.deps)) + [mod_rel(".headers.phony")],
variables = dict(name=self.path),
)
def make_source(root, path):
_, suffix = splitext(path)
if suffix in (".s", ".c", ".cpp"):
return CompileSource(path, root)
elif suffix in (".cog",):
return ParseSource(path, root)
elif suffix in (".h", ".inc"):
return HeaderSource(path, root)
else:
raise RuntimeError(f"{path} has no Source type")

View File

@@ -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 / "configs"
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)

View File

@@ -1,41 +0,0 @@
from collections import namedtuple as _namedtuple
version = _namedtuple('version', [
'major',
'minor',
'patch',
'sha',
'dirty',
])
def _run_git(root, *args):
from subprocess import run
git = run(['git', '-C', root] + list(args),
check=True, capture_output=True)
return git.stdout.decode('utf-8').strip()
def git_version(root):
full_version = _run_git(root, 'describe', '--dirty')
full_sha = _run_git(root, 'rev-parse', 'HEAD')
dirty = False
parts1 = full_version.split('-')
if parts1[-1] == "dirty":
dirty = True
parts1 = parts1[:-1]
if parts1[0][0] == 'v':
parts1[0] = parts1[0][1:]
parts2 = parts1[0].split('.')
return version(
parts2[0],
parts2[1],
parts2[2],
full_sha[:7],
dirty)

View File

@@ -1,72 +0,0 @@
#!/usr/bin/env python3
#
# Generate the jsix style symbol table. The format in memory of this table
# is as follows:
#
# <num_entires> : 8 bytes
# <index> : 24 * N bytes
# <name data> : variable
#
# Each index entry has the format
# <symbol address> : 8 bytes
# <symbol size> : 8 bytes
# <offset of name> : 8 bytes
#
# Name offsets are from the start of the symbol table as a whole. (ie,
# where <num_entries> is located.)
import re
sym_re = re.compile(r'([0-9a-fA-F]{16}) ([0-9a-fA-F]{16}) [tTvVwW] (.*)')
def parse_syms(infile):
"""Take the output of the `nm` command, and parse it into a tuple
representing the symbols in the text segment of the binary. Returns
a list of (address, symbol_name)."""
syms = []
for line in sys.stdin:
match = sym_re.match(line)
if not match: continue
addr = int(match.group(1), base=16)
size = int(match.group(2), base=16)
name = match.group(3)
syms.append([addr, size, name, 0])
return syms
def write_table(syms, outfile):
"""Write the given symbol table as generated by parse_syms()
to the outfile, index first, and then name character data."""
import struct
outfile.write(struct.pack("@Q", len(syms)))
index_pos = outfile.tell()
outfile.seek(struct.calcsize("@QQQ") * len(syms), 1)
nul = b'\0'
for s in syms:
s[3] = outfile.tell()
outfile.write(s[2].encode('utf-8'))
outfile.write(nul)
outfile.seek(index_pos)
for s in syms:
addr = s[0]
size = s[1]
pos = s[3]
outfile.write(struct.pack("@QQQ", addr, size, pos))
if __name__ == "__main__":
import sys
if len(sys.argv) != 2:
print(f"Usage: nm -n -S --demangle | {sys.argv[0]} <output>")
sys.exit(1)
outfile = open(sys.argv[1], "wb")
write_table(parse_syms(sys.stdin), outfile)

131
scripts/build_sysroot.sh Executable file
View File

@@ -0,0 +1,131 @@
#!/usr/bin/env bash
TARGET="x86_64-elf"
LLVM_BRANCH="release_80"
TOOLS="clang lld" # lld libunwind libcxxabi libcxx"
PROJECTS="compiler-rt libcxxabi libcxx libunwind"
#RUNTIMES="compiler-rt libcxxabi libcxx libunwind"
set -e
README=$(realpath "$(dirname $0)/readme_for_prebuilt_sysroots.md")
SYSROOT=$(realpath "$(dirname $0)/../sysroot")
WORK=$(realpath "$(dirname $0)/sysroot")
mkdir -p "${SYSROOT}"
mkdir -p "${WORK}"
export CC=clang
export CXX=clang++
if [[ ! -d "${WORK}/llvm" ]]; then
echo "Downloading LLVM..."
git clone -q \
--branch "${LLVM_BRANCH}" \
--depth 1 \
"https://git.llvm.org/git/llvm.git" "${WORK}/llvm"
fi
for tool in ${TOOLS}; do
if [[ ! -d "${WORK}/llvm/tools/${tool}" ]]; then
echo "Downloading ${tool}..."
git clone -q \
--branch "${LLVM_BRANCH}" \
--depth 1 \
"https://git.llvm.org/git/${tool}.git" "${WORK}/llvm/tools/${tool}"
fi
done
if [[ ! -d "${WORK}/llvm/tools/clang/tools/extra" ]]; then
echo "Downloading clang-tools-extra..."
git clone -q \
--branch "${LLVM_BRANCH}" \
--depth 1 \
"https://git.llvm.org/git/clang-tools-extra.git" "${WORK}/llvm/tools/clang/tools/extra"
fi
for proj in ${PROJECTS}; do
if [[ ! -d "${WORK}/llvm/projects/${proj}" ]]; then
echo "Downloading ${proj}..."
git clone -q \
--branch "${LLVM_BRANCH}" \
--depth 1 \
"https://git.llvm.org/git/${proj}.git" "${WORK}/llvm/projects/${proj}"
fi
done
for proj in ${RUNTIMES}; do
if [[ ! -d "${WORK}/llvm/runtimes/${proj}" ]]; then
echo "Downloading ${proj}..."
git clone -q \
--branch "${LLVM_BRANCH}" \
--depth 1 \
"https://git.llvm.org/git/${proj}.git" "${WORK}/llvm/runtime/${proj}"
fi
done
mkdir -p "${WORK}/build/llvm"
pushd "${WORK}/build/llvm"
echo "Configuring LLVM..."
cmake -G Ninja \
-DCLANG_DEFAULT_RTLIB=compiler-rt \
-DCLANG_DEFAULT_STD_C=c11 \
-DCLANG_DEFAULT_STD_CXX=cxx14 \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER="clang" \
-DCMAKE_CXX_COMPILER="clang++" \
-DCMAKE_CXX_FLAGS="-Wno-unused-parameter -D_LIBCPP_HAS_NO_ALIGNED_ALLOCATION -D_LIBUNWIND_IS_BAREMETAL=1 -U_LIBUNWIND_SUPPORT_DWARF_UNWIND" \
-DCMAKE_INSTALL_PREFIX="${SYSROOT}" \
-DCMAKE_MAKE_PROGRAM=`which ninja` \
-DDEFAULT_SYSROOT="${SYSROOT}" \
-DLIBCXX_CXX_ABI=libcxxabi \
-DLIBCXX_CXX_ABI_INCLUDE_PATHS="${WORK}/llvm/projects/libcxxabi/include" \
-DLIBCXX_CXX_ABI_LIBRARY_PATH=lib \
-DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=OFF \
-DLIBCXX_ENABLE_NEW_DELETE_DEFINITIONS=ON \
-DLIBCXX_ENABLE_SHARED=OFF \
-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON \
-DLIBCXX_ENABLE_THREADS=OFF \
-DLIBCXX_INCLUDE_BENCHMARKS=OFF \
-DLIBCXX_USE_COMPILER_RT=ON \
-DLIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS=OFF \
-DLIBCXXABI_ENABLE_SHARED=OFF \
-DLIBCXXABI_ENABLE_STATIC_UNWINDER=ON \
-DLIBCXXABI_ENABLE_THREADS=OFF \
-DLIBCXXABI_LIBCXX_PATH="${WORK}/llvm/projects/libcxx" \
-DLIBCXXABI_USE_COMPILER_RT=ON \
-DLIBCXXABI_USE_LLVM_UNWINDER=ON \
-DLIBUNWIND_ENABLE_SHARED=OFF \
-DLIBUNWIND_ENABLE_THREADS=OFF \
-DLIBUNWIND_USE_COMPILER_RT=ON \
-DLLVM_CONFIG_PATH="${SYSROOT}/bin/llvm-config" \
-DLLVM_DEFAULT_TARGET_TRIPLE="x86_64-unknown-elf" \
-DLLVM_ENABLE_LIBCXX=ON \
-DLLVM_ENABLE_LLD=ON \
-DLLVM_ENABLE_PIC=OFF \
-DLLVM_ENABLE_THREADS=OFF \
-DLLVM_INSTALL_BINUTILS_SYMLINKS=ON \
-DLLVM_TARGETS_TO_BUILD="X86" \
${WORK}/llvm > cmake_configure.log
# -DCMAKE_ASM_COMPILER=nasm \
# -DCMAKE_LINKER="${SYSROOT}/bin/ld.lld" \
# -DCOMPILER_RT_ENABLE_LLD=ON \
# -DLIBCXX_ENABLE_LLD=ON \
# -DLIBCXX_ENABLE_STATIC_UNWINDER=ON \
# -DLIBCXXABI_ENABLE_LLD=ON \
# -DLIBUNWIND_ENABLE_LLD=ON \
# -DLLVM_ENABLE_PROJECTS="libcxx;libcxxabi;libunwind;compiler-rt" \
# -DCOMPILER_RT_BAREMETAL_BUILD=ON \
# -DLIBCXXABI_BAREMETAL=ON \
echo "Building LLVM..."
ninja && ninja install
ninja cxx cxxabi compiler-rt
ninja install-compiler-rt install-cxx install-cxxabi
popd
cp "${README}" "${SYSROOT}/README.md"

View File

@@ -1,83 +0,0 @@
class NotFound(Exception): pass
class Context:
def __init__(self, path, verbose=False):
if isinstance(path, str):
self.__paths = [path]
else:
self.__paths = path
self.__closed = set()
self.__verbose = verbose
self.__deps = {}
self.objects = dict()
self.interfaces = dict()
verbose = property(lambda self: self.__verbose)
def find(self, filename):
from os.path import exists, isabs, join
if exists(filename) or isabs(filename):
return filename
for path in self.__paths:
full = join(path, filename)
if exists(full):
return full
raise NotFound(filename)
def parse(self, filename):
pending = set()
pending.add(filename)
from .parser import LarkError
from .parser import Lark_StandAlone as Parser
from .transformer import DefTransformer
objects = {}
interfaces = {}
while pending:
name = pending.pop()
self.__closed.add(name)
path = self.find(name)
parser = Parser(transformer=DefTransformer(name))
try:
imps, objs, ints = parser.parse(open(path, "r").read())
except LarkError as e:
import sys
import textwrap
print(f"\nError parsing {name}:", file=sys.stderr)
print(textwrap.indent(str(e), " "), file=sys.stderr)
sys.exit(1)
objects.update(objs)
interfaces.update(ints)
self.__deps[name] = imps
pending.update(imps.difference(self.__closed))
from .types import ObjectRef
ObjectRef.connect(objects)
for obj in objects.values():
for method in obj.methods:
caps = method.options.get("cap", list())
for cap in caps:
if not cap in obj.caps:
from .errors import UnknownCapError
raise UnknownCapError(f"Unknown capability {cap} on {obj.name}::{method.name}")
self.objects.update(objects)
self.interfaces.update(interfaces)
def deps(self):
return {self.find(k): tuple(map(self.find, v)) for k, v in self.__deps.items()}

View File

@@ -1,3 +0,0 @@
class InvalidType(Exception): pass
class UnknownTypeError(Exception): pass
class UnknownCapError(Exception): pass

File diff suppressed because one or more lines are too long

View File

@@ -1,23 +0,0 @@
%macro SYSCALL 2
global __syscall_%1
__syscall_%1:
push rbp
mov rbp, rsp
; args should already be in rdi, etc, but rcx will
; get stomped, so stash it in r10, which isn't a
; callee-saved register, but also isn't used in the
; function call ABI.
mov r10, rcx
mov rax, %2
syscall
; result is now already in rax, so just return
pop rbp
ret
%endmacro
{% for id, scope, method in interface.methods %}
SYSCALL {% if scope %}{{ scope.name }}_{% endif %}{{ method.name }} {{ id }}
{% endfor %}

View File

@@ -1,41 +0,0 @@
#pragma once
/// \file {{filename}}
{% if object.super %}
#include <j6/{{ object.super.name }}.hh>
{% endif %}
namespace j6 {
{% if object.desc %}
{{ object.desc|indent('/// ', first=True) }}
{% endif %}
class {{ object.name }}
{% if object.super %} : public {{ object.super.name }}
{% endif %}
{
public:
{% macro argument(type, name, first, options=False) -%}
{%- for ctype, suffix in type.c_names(options) -%}
{%- if not first or not loop.first %}, {% endif %}{{ ctype }} {{ name }}{{ suffix }}
{%- endfor -%}
{%- endmacro -%}
{% for method in object.methods %}
{% if method.desc %} /// {{ method.desc|indent(' /// ') }}{% endif %}
{% for param in method.params %}
{% if param.desc %} /// \arg {{ "%-10s"|format(param.name) }} {{ param.desc }}
{% endif %}
{% endfor %}
{%+ if method.static %}static {% endif %}j6_status_t {{ method.name }} (
{%- for param in method.params %}{{ argument(param.type, param.name, loop.first, options=param.options) }}{% endfor -%});
{% endfor %}
~{{ object.name }}();
private:
{{ object.name }}(j6_handle_t handle) : m_handle {handle} {}
j6_handle_t m_handle;
}
} // namespace j6

View File

@@ -1,25 +0,0 @@
#pragma once
#include <j6/types.h>
#ifdef __cplusplus
extern "C" {
#endif
{% macro argument(type, name, first, options=False) -%}
{%- for ctype, suffix in type.c_names(options) -%}
{%- if not first or not loop.first %}, {% endif %}{{ ctype }} {{ name }}{{ suffix }}
{%- endfor -%}
{%- endmacro %}
{% for id, scope, method in interface.methods %}
j6_status_t __syscall_{% if scope %}{{ scope.name }}_{% endif %}{{ method.name }} (
{%- if not method.static -%}{{ argument(scope.reftype, "self", True) }}{% endif -%}
{%- set first = method.static -%}
{%- for param in method.params %}{{ argument(param.type, param.name, first, options=param.options) }}{% set first = False %}{% endfor -%}
);
{% endfor %}
#ifdef __cplusplus
}
#endif

View File

@@ -1,156 +0,0 @@
from .parser import Transformer, v_args
def get_opts(args):
from .types import Caps, CName, Description, Options, Type, UID
kinds = {
Description: "desc",
Options: "opts",
CName: "cname",
Caps: "caps",
UID: "uid",
Type: "typename",
}
result = dict()
outargs = []
for a in args:
for kind, name in kinds.items():
if isinstance(a, kind):
result[name] = a
break
else:
outargs.append(a)
return result, outargs
class DefTransformer(Transformer):
def __init__(self, filename):
self.filename = filename
def start(self, args):
from .types import Import, Interface, Object
imports = set()
objects = dict()
interfaces = dict()
for o in args:
if isinstance(o, Object):
objects[o.name] = o
elif isinstance(o, Interface):
interfaces[o.name] = o
elif isinstance(o, Import):
imports.add(o)
return imports, objects, interfaces
@v_args(inline=True)
def import_statement(self, path):
from .types import Import
return Import(path)
def object(self, args):
from .types import Object
specials, args = get_opts(args)
name, args = args[0], args[1:]
return Object(name, children=args, **specials)
def interface(self, args):
from .types import Interface
specials, args = get_opts(args)
name, args = args[0], args[1:]
return Interface(name, children=args, **specials)
def method(self, args):
from .types import Method
specials, args = get_opts(args)
name, args = args[0], args[1:]
return Method(name, children=args, **specials)
def function(self, args):
from .types import Function
specials, args = get_opts(args)
name, args = args[0], args[1:]
return Function(name, children=args, **specials)
def param(self, args):
from .types import Param
specials, args = get_opts(args)
name = args[0]
return Param(name, **specials)
@v_args(inline=True)
def expose(self, s):
from .types import Expose
return Expose(s)
@v_args(inline=True)
def uid(self, s):
return s
@v_args(inline=True)
def cname(self, s):
from .types import CName
return CName(s)
@v_args(inline=True)
def name(self, s):
return s
@v_args(inline=True)
def type(self, s):
return s
@v_args(inline=True)
def super(self, s):
from .types import ObjectRef
return ObjectRef(s, self.filename)
def options(self, args):
from .types import Options
return Options([str(s) for s in args])
def capabilities(self, args):
from .types import Caps
return Caps([str(s) for s in args])
def description(self, s):
from .types import Description
return Description("\n".join(s))
@v_args(inline=True)
def object_name(self, n):
from .types import ObjectRef
return ObjectRef(n, self.filename)
def PRIMITIVE(self, s):
from .types import get_primitive
return get_primitive(s)
def UID(self, s):
from .types import UID
return UID(int(s, base=16))
def INT_TYPE(self, s):
return s
def NUMBER(self, s):
if s.startswith("0x"):
return int(s,16)
return int(s)
def COMMENT(self, s):
return s[2:].strip()
def OPTION(self, s):
return str(s)
def IDENTIFIER(self, s):
return str(s)
def PATH(self, s):
return str(s[1:-1])

View File

@@ -1,26 +0,0 @@
def _indent(x):
from textwrap import indent
return indent(str(x), ' ')
class CName(str): pass
class Description(str): pass
class Import(str): pass
class Caps(list): pass
class Options(dict):
def __init__(self, opts = tuple()):
for opt in opts:
parts = opt.split(":", 1)
self[parts[0]] = self.get(parts[0], []) + ["".join(parts[1:])]
class UID(int):
def __str__(self):
return f"{self:016x}"
from .object import Object
from .interface import Interface, Expose
from .function import Function, Method, Param
from .type import Type
from .primitive import get_primitive
from .objref import ObjectRef

View File

@@ -1,68 +0,0 @@
from . import _indent
from . import Options
def _hasopt(opt):
def test(self):
return opt in self.options
return test
class Function:
typename = "function"
def __init__(self, name, opts=Options(), desc="", children=tuple()):
self.name = name
self.options = opts
self.desc = desc
self.params = [c for c in children if isinstance(c, Param)]
self.id = -1
def __str__(self):
parts = ["{} {}".format(self.typename, self.name)]
if self.desc:
parts.append(_indent(self.desc))
if self.options:
parts.append(f" Options: {self.options}")
parts.extend(map(_indent, self.params))
return "\n".join(parts)
static = property(lambda x: True)
constructor = property(lambda x: False)
class Method(Function):
typename = "method"
static = property(_hasopt("static"))
constructor = property(_hasopt("constructor"))
class Param:
def __init__(self, name, typename, opts=Options(), desc=""):
self.name = name
self.type = typename
self.options = opts
self.desc = desc
self.caps = set()
for key, values in opts.items():
if key == "cap":
self.caps.update(values)
def __str__(self):
return "param {} {} {} {}".format(
self.name, repr(self.type), self.options, self.desc or "")
@property
def outparam(self):
return "out" in self.options or "inout" in self.options
@property
def refparam(self):
return self.type.reference or self.outparam
@property
def optional(self):
if "optional" in self.options: return "optional"
elif "zero_ok" in self.options: return "zero_ok"
else: return "required"

View File

@@ -1,46 +0,0 @@
from . import _indent
from . import Options
class Expose(object):
def __init__(self, type):
self.type = type
def __repr__(self):
return f'expose {repr(self.type)}'
class Interface:
def __init__(self, name, uid, opts=Options(), desc="", children=tuple()):
from .function import Function
self.name = name
self.uid = uid
self.options = opts
self.desc = desc
self.functions = [c for c in children if isinstance(c, Function)]
self.__exposes = [e.type for e in children if isinstance(e, Expose)]
def __str__(self):
parts = [f"interface {self.name}: {self.uid}"]
if self.desc:
parts.append(_indent(self.desc))
if self.options:
parts.append(f" Options: {self.options}")
parts.extend(map(_indent, self.exposes))
parts.extend(map(_indent, self.functions))
return "\n".join(parts)
@property
def methods(self):
mm = [(i, None, self.functions[i]) for i in range(len(self.functions))]
base = len(mm)
for o in self.exposes:
mm.extend([(base + i, o, o.methods[i]) for i in range(len(o.methods))])
base += len(o.methods)
return mm
@property
def exposes(self):
return [ref.object for ref in self.__exposes]

View File

@@ -1,33 +0,0 @@
from . import _indent
from . import Caps, Options
class Object:
def __init__(self, name, uid, typename=None, opts=Options(), caps=Caps(), desc="", children=tuple(), cname=None):
self.name = name
self.uid = uid
self.options = opts
self.desc = desc
self.methods = children
self.cname = cname or name
self.caps = caps
self.__super = typename
from . import ObjectRef
self.__ref = ObjectRef(name)
def __str__(self):
parts = [f"object {self.name}: {self.uid}"]
if self.desc:
parts.append(_indent(self.desc))
if self.options:
parts.append(f" Options: {self.options}")
parts.extend(map(_indent, self.methods))
return "\n".join(parts)
reftype = property(lambda self: self.__ref)
@property
def super(self):
if self.__super is not None:
return self.__super.object

View File

@@ -1,49 +0,0 @@
from .type import Type
class ObjectRef(Type):
all_refs = {}
def __init__(self, name, filename=None):
super().__init__(name)
self.__c_type = "j6_handle_t"
self.__object = None
ObjectRef.all_refs[self] = filename
def __repr__(self):
return f'ObjectRef({self.name})'
object = property(lambda self: self.__object)
def c_names(self, options):
one = self.__c_type
out = bool({"out", "inout"}.intersection(options))
if "list" in options:
two = "size_t"
one = f"{one} *"
if out:
two += " *"
return ((one, ""), (two, "_count"))
else:
if out:
one += " *"
return ((one, ""),)
def cxx_names(self, options):
if not self.needs_object(options):
return self.c_names(options)
return ((f"obj::{self.name} *", ""),)
def needs_object(self, options):
return not bool({"out", "inout", "list", "handle"}.intersection(options))
@classmethod
def connect(cls, objects):
for ref, filename in cls.all_refs.items():
ref.__object = objects.get(ref.name)
if ref.__object is None:
from ..errors import UnknownTypeError
raise UnknownTypeError(ref.name, filename)

View File

@@ -1,72 +0,0 @@
from .type import Type
class Primitive(Type):
def __init__(self, name, c_type):
super().__init__(name)
self.c_type = c_type
def __repr__(self):
return f'Primitive({self.name})'
def c_names(self, options=dict()):
one = self.c_type
if "out" in options or "inout" in options:
one += " *"
return ((one, ""),)
def cxx_names(self, options):
return self.c_names(options)
class PrimitiveRef(Primitive):
def __init__(self, name, c_type, counted=False):
super().__init__(name, c_type)
self.__counted = counted
reference = property(lambda self: True)
def c_names(self, options=dict()):
one = f"{self.c_type} *"
two = "size_t"
if "out" in options or "inout" in options:
two += " *"
else:
one = "const " + one
if self.__counted:
return ((one, ""), (two, "_len"))
else:
return ((one, ""),)
def cxx_names(self, options):
return self.c_names(options)
_primitives = {
"string": PrimitiveRef("string", "char"),
"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):
p = _primitives.get(name)
if not p:
from ..errors import InvalidType
raise InvalidType(name)
return p

View File

@@ -1,15 +0,0 @@
class Type:
def __init__(self, name):
self.__name = name
name = property(lambda self: self.__name)
reference = property(lambda self: False)
def c_names(self, options):
raise NotImplemented("Call to base Type.c_names")
def cxx_names(self, options):
raise NotImplemented("Call to base Type.c_names")
def needs_object(self, options):
return False

View File

@@ -1,75 +0,0 @@
_MAGIC = (0x72, 0xb5, 0x4a, 0x86)
_VERSION = 0
class PSF2:
from collections import namedtuple
Header = namedtuple("PSF2Header",
["version", "offset", "flags", "count", "charsize", "height", "width"])
def __init__(self, filename, header, data):
self.__filename = filename
self.__header = header
self.__data = data
data = property(lambda self: self.__data)
header = property(lambda self: self.__header)
count = property(lambda self: self.__header.count)
charsize = property(lambda self: self.__header.charsize)
dimension = property(lambda self: (self.__header.width, self.__header.height))
filename = property(lambda self: self.__filename)
@classmethod
def load(cls, filename):
from os.path import basename
from struct import unpack_from
data = open(filename, 'rb').read()
fmt = "BBBBIIIIIII"
values = unpack_from(fmt, data)
if values[:len(_MAGIC)] != _MAGIC:
raise Exception("Bad magic number in header")
header = PSF2.Header(*values[len(_MAGIC):])
if header.version != _VERSION:
raise Exception(f"Bad version {header.version} in header")
return cls(basename(filename), header, data)
class Glyph:
__slots__ = ['index', 'data']
def __init__(self, i, data):
self.index = i
self.data = data
def __index__(self):
return self.index
def empty(self):
return not bool([b for b in self.data if b != 0])
def description(self):
c = chr(self.index)
if c.isprintable():
return "Glyph {:02x}: '{}'".format(self.index, c)
else:
return "Glyph {:02x}".format(self.index)
def __getitem__(self, i):
c = self.__header.charsize
n = i * c + self.__header.offset
return PSF2.Glyph(i, self.__data[n:n+c])
class __iter:
__slots__ = ['font', 'n']
def __init__(self, font):
self.font = font
self.n = 0
def __next__(self):
if self.n < self.font.count:
glyph = self.font[self.n]
self.n += 1
return glyph
else:
raise StopIteration
def __iter__(self):
return PSF2.__iter(self)

View File

@@ -1,11 +0,0 @@
#!/usr/bin/env python3
def hashid(s):
from hashlib import shake_128 as sh
return sh(s.encode('utf-8')).hexdigest(8)
import sys
for arg in sys.argv[1:]:
id = hashid(arg)
print(f"{arg}: {id}")

View File

@@ -1,56 +0,0 @@
import cog
supported_architectures = {
"amd64": "__amd64__",
}
def arch_includes(header):
prefix = "if"
for arch, define in supported_architectures.items():
cog.outl(f"#{prefix} defined({define})")
cog.outl(f"#include <__j6libc/arch/{arch}/{header}>")
prefix = "elif"
cog.outl("#endif")
int_widths = (8, 16, 32, 64)
int_mods = ("fast", "least")
int_types = {
# type: abbrev
"char": "char",
"short": "short",
"int": "int",
"long": "long",
"long long": "llong",
}
def definition(kind, name, val, width=24):
cog.outl(f"{kind} {name:{width}} {val}")
atomic_types = {
"_Bool": "bool",
"signed char": "schar",
"char16_t": "char16_t",
"char32_t": "char32_t",
"wchar_t": "wchar_t",
"wchar_t": "wchar_t",
"size_t": "size_t",
"ptrdiff_t": "ptrdiff_t",
"intptr_t": "intptr_t",
"uintptr_t": "uintptr_t",
"intmax_t": "intmax_t",
"uintmax_t": "uintmax_t",
}
for name, abbrev in int_types.items():
atomic_types.update({name: abbrev, f"unsigned {name}": f"u{abbrev}"})
for width in int_widths:
atomic_types.update({t: t for t in (
f"int_least{width}_t",
f"uint_least{width}_t",
f"int_fast{width}_t",
f"uint_fast{width}_t")})

View File

@@ -1,32 +0,0 @@
class Layout:
from collections import namedtuple
Region = namedtuple("Region", ("name", "start", "size", "shared"))
sizes = {'G': 1024 ** 3, 'T': 1024 ** 4}
@staticmethod
def get_size(desc):
size, mag = int(desc[:-1]), desc[-1]
try:
mult = Layout.sizes[mag]
except KeyError:
raise RuntimeError(f"No magnitude named '{mag}'.")
return size * mult
def __init__(self, path):
from yaml import safe_load
regions = []
addr = 1 << 64
with open(path, 'r') as infile:
data = safe_load(infile.read())
for r in data:
size = Layout.get_size(r["size"])
addr -= size
regions.append(Layout.Region(r["name"], addr, size,
r.get("shared", False)))
self.regions = tuple(regions)

34
scripts/parse_font.py Executable file → Normal file
View File

@@ -1,6 +1,21 @@
#!/usr/bin/env python3
from fontpsf import PSF2
MAGIC = (0x72, 0xb5, 0x4a, 0x86)
from collections import namedtuple
PSF2 = namedtuple("PSF2", ["version", "offset", "flags", "count", "charsize", "height", "width"])
def read_header(data):
from struct import unpack_from, calcsize
fmt = "BBBBIIIIIII"
values = unpack_from(fmt, data)
if values[:len(MAGIC)] != MAGIC:
raise Exception("Bad magic number in header")
return PSF2(*values[len(MAGIC):])
def print_glyph(header, data):
bw = (header.width + 7) // 8
@@ -13,15 +28,16 @@ def print_glyph(header, data):
def display_font(filename):
font = PSF2.load(filename)
print(font.header)
data = open(filename, 'rb').read()
for glyph in font:
if glyph.empty():
print("{}: BLANK".format(glyph.description()))
else:
print("{}:".format(glyph.description()))
print_glyph(font.header, glyph.data)
header = read_header(data)
print(header)
c = header.charsize
for i in range(0, header.count):
n = i * c + header.offset
print("Glyph {}:".format(i))
print_glyph(header, data[n:n+c])
if __name__ == "__main__":

10
scripts/parse_syms.py Executable file
View File

@@ -0,0 +1,10 @@
#!/usr/bin/env python3
def parse_elf(filename):
import struct
with open(filename, 'rb') as elf:
if __name__ == "__main__":
import sys
for arg in sys.argv[1:]:
parse_elf(arg)

View File

@@ -0,0 +1,14 @@
# jsix OS sysroot
This is a pre-built sysroot for building the jsix operating system kernel,
bootloader, and utilities. This package is provided as a convenience, and
contains software from the following repositories.
## The LLVM toolchain
The LLVM sources as downloaded via git from [llvm.org][llvm] under the terms of
the [Apache License v2.0][apache2], modified [as described here][llvmlic].
[llvm]: https://llvm.org
[apache2]: https://www.apache.org/licenses/LICENSE-2.0
[llvmlic]: https://llvm.org/docs/DeveloperPolicy.html#new-llvm-project-license-framework

View File

@@ -1,17 +0,0 @@
class Sysconf:
from collections import namedtuple
Var = namedtuple("Var", ("name", "section", "type"))
def __init__(self, path):
from yaml import safe_load
sys_vars = []
with open(path, 'r') as infile:
data = safe_load(infile.read())
self.address = data["address"]
for v in data["vars"]:
sys_vars.append(Sysconf.Var(v["name"], v["section"], v["type"]))
self.vars = tuple(sys_vars)

View File

@@ -0,0 +1,208 @@
ninja_required_version = 1.3
builddir = {{ buildroot }}
srcroot = {{ srcroot }}
modulefile = {{ modulefile }}
{%- for var, value in vars %}
{{ var }} = {{ value }}
{%- endfor %}
warnflags = $
-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 $
-Werror
ccflags = $
-I${srcroot}/src/include $
-I${srcroot}/src/include/x86_64 $
-fcolor-diagnostics $
-DVERSION_MAJOR={{ version_major }} $
-DVERSION_MINOR={{ version_minor }} $
-DVERSION_PATCH={{ version_patch }} $
-DVERSION_GITSHA=0x0{{ version_sha }} $
-DGIT_VERSION=\"{{ version }}\" $
-DGIT_VERSION_WIDE=L\"{{ version }}\" $
$warnflags
asflags = $
-I${srcroot}/src/include $
-DVERSION_MAJOR={{ version_major }} $
-DVERSION_MINOR={{ version_minor }} $
-DVERSION_PATCH={{ version_patch }} $
-DVERSION_GITSHA=0x{{ version_sha }}
cflags = -std=c11
cxxflags = -std=c++14
libs =
rule c
deps = gcc
depfile = $out.d
description = Compiling $name
command = $cc -MMD -MF $out.d $ccflags $cflags -o $out -c $in
rule dump_c_defs
description = Dumping C defines for $target
command = echo "" | $cc $ccflags $cflags -dM -E - > $out
rule dump_c_run
description = Dumping C arguments for $target
command = $
echo "#!/bin/bash" > $out; $
echo '$cc $ccflags $cflags $$*' > $out; $
chmod a+x $out
rule cpp
deps = gcc
depfile = $out.d
description = Compiling $name
command = $cxx -MMD -MF $out.d $cxxflags $ccflags -o $out -c $in
rule dump_cpp_defs
description = Dumping C++ defines for $target
command = echo "" | $cxx -x c++ $cxxflags $ccflags -dM -E - > $out
rule dump_cpp_run
description = Dumping C++ arguments for $target
command = $
echo "#!/bin/bash" > $out; $
echo '$cc $cxxflags $ccflags $$*' > $out; $
chmod a+x $out
rule s
deps = gcc
depfile = $out.d
description = Assembling $name
command = $nasm -o $out -felf64 -MD $out.d $asflags $in
rule exe
description = Linking $name
command = $ld $ldflags -o $out $in $libs
rule lib
description = Archiving $name
command = $ar qcs $out $in
rule regen
generator = true
description = Regenrating build files
command = $
{{ generator }} $
--file $modulefile $
--dir $builddir $
generate
rule cp
description = Copying $name
command = cp $in $out
rule dump
description = Dumping decompiled $name
command = objdump -DSC -M intel $in > $out
rule makerd
description = Making init ramdisk
command = $builddir/native/makerd $in $out
rule makeefi
description = Converting $name
command = objcopy $
-j .text $
-j .sdata $
-j .data $
-j .dynamic $
-j .dynsym $
-j .rel $
-j .rela $
-j .reloc $
--target=efi-app-x86_64 $
$in $out
rule makefat
description = Creating $name
command = $
cp $srcroot/assets/diskbase.img $out; $
mcopy -s -D o -i $out@@1M $builddir/fatroot/* ::/
rule strip
description = Stripping $name
command = $
cp $in $out; $
objcopy --only-keep-debug $out $out.debug; $
strip -g $out; $
objcopy --add-gnu-debuglink=$out.debug $out
{% for target in targets %}
subninja {{ target }}/target.ninja
{% endfor %}
build $
{%- for buildfile in buildfiles %}
{{ buildfile }} $
{%- endfor %}
: regen | $
{%- for template in templates %}
{{ template }} $
{%- endfor %}
$modulefile $
{{ generator }}
build $builddir/ovmf_vars.fd : cp $srcroot/assets/ovmf/x64/ovmf_vars.fd
name = ovmf_vars.fd
build $builddir/ovmf_vars_d.fd : cp $srcroot/assets/ovmf/x64/ovmf_vars_d.fd
name = ovmf_vars_d.fd
build $builddir/jsix.elf | $builddir/jsix.elf.debug : strip $builddir/host/jsix.elf
name = kernel
build $builddir/jsix.dump : dump $builddir/host/jsix.elf
name = kernel
build $builddir/jsix.elf-gdb.py : cp ${srcroot}/assets/debugging/jsix.elf-gdb.py
name = kernel debug python scripts
build $builddir/fatroot/jsix.elf : cp $builddir/jsix.elf
name = kernel to FAT image
build $builddir/fatroot/efi/boot/bootx64.efi : cp $builddir/boot/boot.efi
name = bootloader to FAT image
build $builddir/fatroot/initrd.img : makerd ${srcroot}/assets/initrd.toml | $
${builddir}/host/libvdso.so $
${builddir}/native/makerd $
${builddir}/user/nulldrv
build $builddir/jsix.img : makefat | $
$builddir/fatroot/initrd.img $
$builddir/fatroot/jsix.elf $
$builddir/fatroot/efi/boot/bootx64.efi
name = jsix.img
default $
$builddir/ovmf_vars.fd $
$builddir/ovmf_vars_d.fd $
$builddir/jsix.dump $
$builddir/jsix.elf-gdb.py $
$builddir/jsix.img
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -0,0 +1,27 @@
{% extends "exe.default.j2" %}
{% block variables %}
{{ super() }}
ccflags = $ccflags $
-DKERNEL_FILENAME=L\"jsix.elf\" $
-DGNU_EFI_USE_MS_ABI $
-DHAVE_USE_MS_ABI $
-DEFI_DEBUG=0 $
-DEFI_DEBUG_CLEAR_MEMORY=0 $
-DBOOTLOADER_DEBUG
ldflags = $ldflags $
-T ${srcroot}/src/arch/x86_64/boot.ld $
-shared
{% endblock %}
{% block extra %}
build $builddir/boot.efi : makeefi ${builddir}/{{ module.output }}
name = boot.efi
{% endblock %}
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -0,0 +1,8 @@
{% extends "module.base.j2" %}
{% block variables %}
{{ super() }}
{% endblock %}
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -0,0 +1,12 @@
{% extends "exe.default.j2" %}
{% block variables %}
{{ super() }}
asflags = $asflags -I${srcroot}/src/kernel/
libs = $libs
ldflags = $ldflags -T ${srcroot}/src/arch/x86_64/kernel.ld
{% endblock %}
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -0,0 +1,10 @@
{% extends "exe.default.j2" %}
{% block variables %}
{{ super() }}
ccflags = $ccflags -I${srcroot}/external/cpptoml
{% endblock %}
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -0,0 +1,10 @@
{% extends "exe.default.j2" %}
{% block variables %}
{{ super() }}
ccflags = $ccflags -ggdb -I${srcroot}/external/catch
{% endblock %}
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -0,0 +1,9 @@
{% extends "exe.default.j2" %}
{% block variables %}
{{ super() }}
ccflags = $ccflags -fPIC -mcmodel=large
ldflags = $ldflags -shared -znotext -T ${srcroot}/src/arch/x86_64/vdso.ld
{% endblock %}
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -0,0 +1,4 @@
{% extends "module.base.j2" %}
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -0,0 +1,45 @@
moddir = ${builddir}/{{ name }}.dir
{% block variables %}
ccflags = $ccflags $
{%- for dep in depmods %}
{%- for inc in dep.includes %}
-I${srcroot}/{{ inc }} $
{%- endfor %}
{%- endfor %}
{%- for inc in module.includes %}
-I${srcroot}/{{ inc }} $
{%- endfor %}
{%- for define in module.defines %}
-D{{ define }} $
{%- endfor %}
{% endblock %}
{% for source in module.source %}
build ${moddir}/{{ source.output }} : {{ source.action }} ${srcroot}/{{ source.input }} || {{ buildfile }}
name = {{ source.name }}
{% endfor %}
build ${builddir}/{{ module.output }} : {{ module.kind }} $
{%- for source in module.source %}
${moddir}/{{ source.output }} $
{%- endfor -%}
{%- for dep in deplibs %}
${builddir}/{{ dep.output }} $
{%- endfor %}
| $
{%- for dep in depexes %}
${builddir}/{{ dep.output }} $
{%- endfor %}
{{ buildfile }}
name = {{ name }}
{% if module.default %}
default ${builddir}/{{ module.output }}
{% endif %}
{% block extra %}
{% endblock %}
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -0,0 +1,40 @@
{% extends "target.default.j2" %}
{% block binaries %}
cc = clang
cxx = clang++
ld = ld
ar = ar
nasm = nasm
objcopy = objcopy
{% endblock %}
{% block variables %}
ccflags = $ccflags $
-ggdb $
-nostdlib $
-ffreestanding $
-nodefaultlibs $
-fno-builtin $
-mno-sse $
-fno-omit-frame-pointer $
-mno-red-zone $
-fshort-wchar $
-D__ELF__ $
-fPIC
cxxflags = $cxxflags $
-fno-exceptions $
-fno-rtti $
ldflags = $ldflags $
-g $
-nostdlib $
-Bsymbolic $
-nostartfiles
{% endblock %}
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -0,0 +1,26 @@
builddir = $builddir/{{ target }}
target = {{ target }}
{% block variables %}
{% endblock %}
{% block binaries %}
cc = clang
cxx = clang++
ld = ld
ar = ar
nasm = nasm
objcopy = objcopy
{% endblock %}
{% for module in modules %}
subninja {{ module }}.ninja
{% endfor %}
build ${builddir}/c.defs : dump_c_defs | {{ buildfile }}
build ${builddir}/cpp.defs : dump_cpp_defs | {{ buildfile }}
build ${builddir}/c.run : dump_c_run | {{ buildfile }}
build ${builddir}/cpp.run : dump_cpp_run | {{ buildfile }}
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -0,0 +1,43 @@
{% extends "target.default.j2" %}
{% block binaries %}
cc = ${srcroot}/sysroot/bin/clang
cxx = ${srcroot}/sysroot/bin/clang++
ld = ${srcroot}/sysroot/bin/ld.lld
ar = ${srcroot}/sysroot/bin/ar
nasm = nasm
objcopy = ${srcroot}/sysroot/bin/objcopy
{% endblock %}
{% block variables %}
ccflags = $ccflags $
-nostdlib $
-ffreestanding $
-nodefaultlibs $
-fno-builtin $
-mno-sse $
-fno-omit-frame-pointer $
-mno-red-zone $
-g $
-mcmodel=large $
-D__ELF__ $
-D__JSIX__ $
-isystem${srcroot}/sysroot/include $
--sysroot="${srcroot}/sysroot"
cxxflags = $cxxflags $
-fno-exceptions $
-fno-rtti $
-isystem${srcroot}/sysroot/include/c++/v1
ldflags = $ldflags $
-g $
-nostdlib $
-Bsymbolic $
-Bstatic
{% endblock %}
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -0,0 +1,15 @@
{% extends "target.default.j2" %}
{% block binaries %}
{{ super() }}
ld = clang++
{% endblock %}
{% block variables %}
ccflags = $ccflags -g -ggdb
{% endblock %}
# vim: ft=ninja et ts=4 sts=4 sw=4

Some files were not shown because too many files have changed in this diff Show More