Skip to content

Commit

Permalink
Update README.md and documentation in general (#93)
Browse files Browse the repository at this point in the history
* Update the main `README.md` file.
* Add `README.md` files to some directories.
* General documentation improvements.
  • Loading branch information
phaubertin authored Dec 3, 2024
1 parent 899726d commit 3a01b50
Show file tree
Hide file tree
Showing 11 changed files with 234 additions and 89 deletions.
92 changes: 73 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ The main build artifact that can be built from the code in this
repository is the kernel image, which contains the kernel proper as well
as the user space loader. The kernel image conforms to the
[Linux x86 boot protocol](https://www.kernel.org/doc/Documentation/x86/boot.rst),
which means it can be loaded by a bootloader intended
for the Linux kernel, such as GRUB.
which means it can be loaded by a bootloader intended for the Linux
kernel, such as GRUB.

During the boot process, the user space loader expects an initial RAM
disk to have been loaded in memory by the bootloader. This would usually
Expand All @@ -27,19 +27,19 @@ that contains the kernel image and the initial RAM disk.
Build Requirements
------------------

To build the kernel image and test application, you will need a Linux
machine with GNU make and a C compiler that can create 32-bit x86 ELF
binaries. This software is known to build with GCC and clang.
To build the kernel image and test application, you need a Linux machine
with GNU make and a C compiler that can create 32-bit x86 ELF binaries.
This software is known to build with GCC and clang.

You will also need the Netwide Assembler (NASM).
You also need the Netwide Assembler (NASM).

If you wish to build the ISO image for use with QEMU, which is optional,
you will need GRUB and GNU xorriso in addition to the above.
you need GRUB and GNU xorriso in addition to the above.

Run Time Requirements
---------------------

To boot the Jinue microkernel, you will need either:
To run this software, you need either:
* QEMU; or
* A x86 PC on which you have sufficient privileges to configure the boot
manager to load Jinue.
Expand All @@ -54,71 +54,124 @@ the `--recurse-submodules` option when you clone the repository.
```
git clone --recurse-submodules https://github.com/phaubertin/jinue.git
```

Alternatively, if you already cloned the repository without passing this
option, you can clone and initialize the submodules separately with the
following command:
option, you can initialize the submodules separately with the following
command:

```
git submodule update --init
```

Then, configure the source code and its dependencies. You only need to
do this oncen not each time you build.
do this once, not each time you build.

```
./configure
```

To build the ISO image for use with QEMU, build the `qemu` target with
make:

```
make qemu
```

This builds the kernel image and the test application, and then creates
a bootable ISO image.

If you will not be using QEMU and only want to build the kernel image,
this can be done with the default make target:

```
make
```

Similarly, the test application can be built separately with the
`testapp` make target:

```
make testapp
```

How to Run in QEMU
-------------------
You can run the kernel and test application in QEMU using the `qemu-run`
make target:

```
make qemu-run
```

Alternatively, if you don't want QEMU to show a window with the video
output, or if you are on a machine without graphics capabilities, use
the `qemu-run-no-display` target instead. The kernel logs to the serial
port, which QEMU redirects to standard output.

```
make qemu-run-no-display
```

In either case, this generates a log file called `run-jinue.log` in
`devel/qemu/` with the full kernel and test application output.

Finally, you can run the kernel and test application, and then run a
script that performs checks on the log file by using the `qemu-check`
make target:

```
make qemu-check
```

How to Install
--------------

If you will not be using QEMU for testing, you can copy the kernel image
to `/boot` by running the following:

```
sudo make install
```
The file name and path of the installed kernel image file is

The full file path of the kernel image installed in this way is
`/boot/jinue`.

Optionally, if you will not be providing your own initial RAM disk file,
you can install the test application initial RAM disk to `/boot` as
well.

```
sudo make install-testapp
```
The file name and path of the installed RAM disk file is

The full file path of the installed RAM disk file is
`/boot/jinue-testapp-initrd.tar.gz`.

Once this is done, you need to configure your boot loader/manager to
load this kernel. Jinue uses the 16-bit Linux boot protocol, so you can
configure your boot manager as if you were loading a Linux image with
the 16-bit boot protocol
([linux16 command](devel/virtualbox/grub.cfg#L29) if using GRUB).
load the installed kernel. Jinue uses the (32-bit or 16-bit) Linux x86
boot protocol, so you can configure your boot manager as if you were
loading a Linux image. This is system dependent but, with GRUB, the
configuration entry might look something like this:

```
menuentry 'Jinue (32-bit boot protocol, test app)' {
# Replace with the appropriate GRUB module for your filesystem.
insmod ext2
# Replace with the partition where you installed Jinue.
set root='hd0,msdos7'
set gfxpayload='text'
echo 'Loading Jinue microkernel...'
# See command line documentation for details on the command line options.
linux /boot/jinue vga_enable=yes serial_enable=no DEBUG_DUMP_MEMORY_MAP=1 DEBUG_DUMP_SYSCALL_IMPLEMENTATION=1 DEBUG_DUMP_RAMDISK=1 RUN_TEST_IPC=1
echo 'Loading test application initial RAM disk...'
initrd /boot/jinue-testapp-initrd.tar.gz
}
```

For detail on the command line options, see the [command line
documentation](doc/cmdline.md).

For detail on the Linux boot protocol, see
[Documentation/x86/boot.rst](https://www.kernel.org/doc/Documentation/x86/boot.rst)
Expand All @@ -127,5 +180,6 @@ in the Linux source tree.
Documentation
-------------

There is some documentation in the [doc/ directory](doc/README.md). It
is still very much a work in progress.
There is some documentation in the `doc/` directory. It is still a work
in progress and some of it is not up to date. The [documentation
README.md file](doc/README.md) links to the parts that are up to date.
92 changes: 52 additions & 40 deletions doc/syscalls/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,56 +9,66 @@
| 0 | - | Reserved |
| 1 | - | Reserved |
| 2 | [REBOOT](reboot.md) | Reboot the System |
| 3 | [PUTS](puts.md) | Write String to Console |
| 3 | [PUTS](puts.md) | Write string to console |
| 4 | [CREATE_THREAD](create-thread.md) | Create a thread |
| 5 | [YIELD_THREAD](yield-thread.md) | Yield the Current Thread |
| 6 | [SET_THREAD_LOCAL](set-thread-local.md) | Set Thread-Local Storage |
| 5 | [YIELD_THREAD](yield-thread.md) | Yield the current thread |
| 6 | [SET_THREAD_LOCAL](set-thread-local.md) | Set Thread-Local Storage (TLS) |
| 7 | - | Reserved |
| 8 | [GET_ADDRESS_MAP](get-address-map.md) | Get Memory Address Map |
| 9 | [CREATE_ENDPOINT](create-endpoint.md) | Create IPC Endpoint |
| 10 | [RECEIVE](receive.md) | Receive Message |
| 11 | [REPLY](reply.md) | Reply to Message |
| 12 | [EXIT_THREAD](exit-thread.md) | Terminate the Current Thread |
| 13 | [MMAP](mmap.md) | Map Memory |
| 14 | [CREATE_PROCESS](create-process.md) | Create Process |
| 15 | [MCLONE](mclone.md) | Clone a Memory Mapping |
| 16 | [DUP](dup.md) | Duplicate a Descriptor |
| 17 | [CLOSE](close.md) | Close a Descriptor |
| 18 | [DESTROY](destroy.md) | Destroy a Kernel Object |
| 19 | [MINT](mint.md) | Mint a Descriptor |
| 20 | [START_THREAD](start-thread.md) | Start a Thread |
| 21 | [AWAIT_THREAD](await-thread.md) | Wait for a Thread to Exit |
| 22 | [REPLY_ERROR](reply-error.md) | Reply to Message with an Error |
| 23 | [SET_ACPI](set-acpi.md) | Provide Mapped ACPI Tables |
| 8 | [GET_ADDRESS_MAP](get-address-map.md) | Get memory address map |
| 9 | [CREATE_ENDPOINT](create-endpoint.md) | Create IPC endpoint |
| 10 | [RECEIVE](receive.md) | Receive message |
| 11 | [REPLY](reply.md) | Reply to message |
| 12 | [EXIT_THREAD](exit-thread.md) | Terminate the current thread |
| 13 | [MMAP](mmap.md) | Map memory |
| 14 | [CREATE_PROCESS](create-process.md) | Create a process |
| 15 | [MCLONE](mclone.md) | Clone a memory mapping |
| 16 | [DUP](dup.md) | Duplicate a descriptor |
| 17 | [CLOSE](close.md) | Close a descriptor |
| 18 | [DESTROY](destroy.md) | Destroy a kernel object |
| 19 | [MINT](mint.md) | Mint a descriptor |
| 20 | [START_THREAD](start-thread.md) | Start a thread |
| 21 | [AWAIT_THREAD](await-thread.md) | Wait for a thread to exit |
| 22 | [REPLY_ERROR](reply-error.md) | Reply to message with an error |
| 23 | [SET_ACPI](set-acpi.md) | Provide mapped ACPI tables |
| 24-4095 | - | Reserved |
| 4096+ | [SEND](send.md) | Send Message |
| 4096+ | [SEND](send.md) | Send a message |

#### Reserved Function Numbers

Any function marked as reserved returns -1 (in `arg0`) and sets error number
JINUE_ENOSYS (in `arg1`).
`JINUE_ENOSYS` (in `arg1`).

### Error Reference

| Number | Name | Description |
|--------|--------------|----------------------------------------|
| 1 | JINUE_ENOMEM | Not enough memory |
| 2 | JINUE_ENOSYS | Not supported |
| 3 | JINUE_EINVAL | Invalid argument |
| 4 | JINUE_EAGAIN | Currently unavailable, try again later |
| 5 | JINUE_EBADF | Bad/invalid descriptor |
| 6 | JINUE_EIO | Input/output error |
| 7 | JINUE_EPERM | Operation not permitted |
| 8 | JINUE_E2BIG | Not enough space in output buffer |
| 9 | JINUE_ENOMSG | No message |
| Number | Name | Description |
|--------|------------------|----------------------------------------|
| 1 |`JINUE_ENOMEM` | Not enough memory |
| 2 |`JINUE_ENOSYS` | Function not supported |
| 3 |`JINUE_EINVAL` | Invalid argument |
| 4 |`JINUE_EAGAIN` | Currently unavailable, try again later |
| 5 |`JINUE_EBADF` | Bad/invalid descriptor |
| 6 |`JINUE_EIO` | Input/output error |
| 7 |`JINUE_EPERM` | Operation not permitted |
| 8 |`JINUE_E2BIG` | Not enough space in output buffer |
| 9 |`JINUE_ENOMSG` | No message |
| 10 |`JINUE_ENOTSUP` | Not supported |
| 11 |`JINUE_EBUSY` | Device or resource busy |
| 12 |`JINUE_ESRCH` | No such thread/process |
| 13 |`JINUE_EDEADLK` | Resource deadlock would occur |
| 14 |`JINUE_EPROTO` | Protocol error |

## Overview

### System Call Registers

During a system call, information is passed back and forth between user space
and the microkernel through four pointer-sized logical registers named `arg0` to
`arg3`.
and the microkernel through four pointer-sized logical registers named `arg0`
to `arg3`.

The mapping of these four system call registers to actual CPU registers is
architecture dependent. However, the system call specification given in terms
arguments and return values set in the system call registers is independent of
the architecture.

### System Call Implementations

Expand All @@ -74,8 +84,9 @@ in `arg1` to `arg3`.

### Return Value

On return from a system call, the contents of arg0 to arg3 depends on the
function number.
On return from a system call, the contents of `arg0` to `arg3` is set according
to the result of the system call. The interpretation of the values set in these
registers depends on the function number.

Most *but not all* system calls follow the following convention:

Expand All @@ -93,17 +104,18 @@ inter-process communication. The client thread uses the [SEND](send.md) system
call to send a message to an IPC endpoint, which serves as a rendez-vous point
for IPC. The server thread uses the [RECEIVE](receive.md) system call to receive
a message from the IPC endpoint, and then the [REPLY](reply.md) call to send
the reply.
the reply or the [REPLY_ERROR](reply-error.md) call to send an error code.

System call function numbers 0 to 4095 inclusive are reserved by the microkernel
for the functions it implements. Function numbers 4096 and up all invoke the
[SEND](send.md) system call. The function number is passed as part of the
message, which allows a server thread to make use of it.
[SEND](send.md) system call. The function number, in that context called the
message number, is passed as part of the message, which allows a server thread
to distinguish between multiple message types.

### Descriptors

The system call interface uses descriptors to refer to kernel resources, such as
threads, processes and IPC endpoints. A descriptor, similar to a Unix
[file descriptor](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_166),
is a per-process unique, non-negative integer. It can be specified as an
argument to or be returned by system calls.
argument to system calls.
57 changes: 32 additions & 25 deletions doc/syscalls/implementations.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,52 @@
# System Call Implementations

The microkernel supports the following implementations to invoke system calls.
Not all implementations are available on all CPUs. On initialization, before
invoking any system call, an application should look at the value of auxiliary
vector number 8 (called `JINUE_AT_HOWSYSCALL`) to determine the best supported
system call implementation:
## Overview and Register Mapping

On 32-bit x86 there are three system call implementations: one interrupt-based
implementation and two that use different fast system call instructions.

All three implementations use the same system call register mappings:

* `arg0` maps to CPU register `eax`.
* `arg1` maps to CPU register `ebx`.
* `arg2` maps to CPU register `esi`.
* `arg3` maps to CPU register `edi`.

The microkernel uses auxiliary vector number 8 (called `JINUE_AT_HOWSYSCALL`)
to inform the user space loader and initial process of the implementation it
should use. (See the [Initial Process Execution
Environment](../init-process.md) for detail.)

The value of this auxiliary vector will be set to one of the following:

* 0 for the interrupt-based implementation
* 1 for the SYSCALL/SYSRET (fast AMD) implementation
* 2 for the SYSENTER/SYSEXIT (fast Intel) implementation

## Interrupt-Based Implementation

A system call can be invoked by generating a software interrupt to interrupt
vector 128 (80h). The argument registers are mapped as follow:
A system call is invoked by setting the correct arguments in the system call
registers and then generating a software interrupt to interrupt vector 128
(80h).

* `arg0` maps to CPU register `eax`.
* `arg1` maps to CPU register `ebx`.
* `arg2` maps to CPU register `esi`.
* `arg3` maps to CPU register `edi`.
On return, the return values are set in the system call registers.

## SYSCALL/SYSRET (Fast AMD) Implementation

A system call can be invoked by executing the `SYSCALL` CPU instruction.
A system call is invoked by setting the correct arguments in the system call
registers and then executing the `SYSCALL` CPU instruction.

* `arg0` maps to CPU register `eax`.
* `arg1` maps to CPU register `ebx`.
* `arg2` maps to CPU register `esi`.
* `arg3` maps to CPU register `edi`.
On return, the return values are set in the system call registers.

This system call is not supported by all CPUs.
This implementation is not supported by all CPUs. Only use this system call
implementation if the `JINUE_AT_HOWSYSCALL` auxiliary vector is set to 1.

## SYSENTER/SYSEXIT (Fast Intel) Implementation

A system call can be invoked by executing the `SYSENTER` CPU instruction.
A system call is invoked by setting the correct arguments in the system call
registers and then executing the `SYSENTER` CPU instruction.

* `arg0` maps to CPU register `eax`.
* `arg1` maps to CPU register `ebx`.
* `arg2` maps to CPU register `esi`.
* `arg3` maps to CPU register `edi`.
* The return address must be set in the `ecx` CPU register.
* The user stack pointer must be set in the `ebp` CPU register.
On return, the return values are set in the system call registers.

This system call is not supported by all CPUs.
This implementation is not supported by all CPUs. Only use this system call
implementation if the `JINUE_AT_HOWSYSCALL` auxiliary vector is set to 2.
Loading

0 comments on commit 3a01b50

Please sign in to comment.