# 68KOS core functionality This document specifies the functions of the 68KOS core kernel, which is loaded from `0:\68KOS.SYS`. Additional functionality is loaded dynamically from other files, and the APIs of those are specified in other documents. ## The SDLL When possible, APIs are provided in file format a la Unix. When they can't be, they are provided by `0:\SYSTEM.DLL`, also known as the SDLL. This is a dynamic library provided in the ROM filesystem that is linked into every process. It is the primary interface to communicate with the kernel. Unlike other operating systems, there is no standardized system call interface; there may be one but it is accessed by the functions inside the SDLL rather than directly by processes. All function-type APIs specified in this file are provided in the SDLL. Additionally, the SDLL provides a system libc and libm that may be used by all processes. ## Filesystem 68kos paths take a DOS-like format, with a drive letter followed by a colon and then a local path. Generally, file systems will either be FAT or tmpfs. No 8.3 limit is imposed, but is generally followed by convention. The following drive letters are suggested: - `0:` (required) — The ROM filesystem. This is mounted by the early kernel loader from address `000000`, which should either be a MBR-partitioned (32-bit LBA) disk image with one partition set active, or a bare FAT filesystem (these are distinguished by the partition entry region of the latter being all zero). - `$:` (required) — The device filesystem. This is a tmpfs in which device nodes are created; it roughly corresponds to `/dev` on a Linux system. - `A:` — Reserve for first user disk, such as an SD card or flash stick inserted into a front panel connector. - `B:` — Reserve for second user disk, such as an SD card or flash stick inserted into a front panel connector. - `C:` — System disk, such as an SD card on the motherboard or a second ROM partition. `0:\CONFIG.SYS` should mount this and then chain-load `C:\CONFIG.SYS`. ### Filesystem APIs TBD: Exact APIs, POSIX-inspired. Also, define the API by which filesystem providers are registered to the kernel. ## ROM filesystem At least the following paths should exist on the ROM filesystem: - `0:\68KOS.DLL` — 68KOS core kernel binary. Contains the filesystem driver, the memory allocator, the task scheduler, the ELF loader, and the CONFIG.SYS loader. On boot, it should initialize all of these, then begin loading CONFIG.SYS. All other boot steps are specified by CONFIG.SYS. Like other executables on this system this is an ELF file, however it must be a Direct Executable and will configure its own writable section. - `0:\SH.EXE` — lightweight shell. Has a special mode accessible by the kernel for loading CONFIG.SYS (containing additional builtins). - `0:\SYSTEM.DLL` — The SDLL, providing APIs to be linked into other applications. Also used by the kernel itself when feasible. - `0:\CONFIG.SYS` — First CONFIG.SYS fragment. It should set up RAM, MPU, system console, OS timer, and any other hardware located on the motherboard itself. Next, it should mount `C:` and chain-load `C:\CONFIG.SYS`. - `0:\example.DRV` — Any driver files referenced by `0:\CONFIG.SYS`. ### Boot sector 68KOS boots from ROM, directly out of the ROM filesystem `0:`. The FAT/MBR boot sector is used to support this direct boot, and so the hardware implementation must ensure that the ROM resides starting at address `000000` as this is where the M68k expects to find the reset vector. Note that the M68k vector table is 1024 bytes long, but the boot sector is 218 to 446 bytes long. The M68k starts up with interrupts disabled (priority mask = 7), so only the reset vector and initial stack pointer (8 bytes in total) need to be present. The reset handler must relocate the vector table somewhere the entire table can fit. While implementations using the 68000 (which has no vector base register) are discouraged, they are not forbidden; these must use external logic such as in the address decoder to allow the address range `000000` to `0003FF` to be relocated elsewhere. The boot image pointed to by the reset vector must correspond to the entry point of the file `0:\68KOS.DLL`. Because it executes directly from ROM, it must be a Direct Executable. The stack pointer in the boot record should point to the highest usable address in the implementation's RAM. The kernel will calculate the initial RAM region as being the region from this address rounded down to a 16kB multiple up to this address, unless that provides less than 10kB in which case the starting point will be decremented by another 16kB. In pseudocode: ```c ram_start = sp & ~0x4000; if (sp - ram_start + 1 < 0x2800) ram_start -= 0x4000; ``` Additional RAM present in the system is not automatically detected by the kernel, and should be added to the allocator pool by `0:\CONFIG.SYS`. ## Device filesystem The following are provided by the 68KOS core: - `$:\null` — disappears all writes, EOFs immediately on read - `$:\zero` — disappears all writes, returns 00 bytes on read - `$:\full` — returns ENOSPC on writes, returns 00 bytes on read - `$:\console` — system console device (usually a symlink into `$:\board`) - `$:\dbgcon` — debug console - `$:\urandom` — pseudorandom number generator. Entropy sources are loaded via ioctls - `$:\disk0` — system ROM as a block device - `$:\tcp` — TCP connections as a directory device node. Open `$:\tcp\addr:port` to make a connection to that address and port, and open `$:\tcp\:port` to listen on the local port. Listing the directory shows open connections. - `$:\udp` — UDP connections. See `$:\tcp`. The following are suggested names, to be used by the board implementer. Also soft-reserved are all of these names with numeric suffixes attached, to allow multiple instances. - `$:\random` — reserved for system RNG, may not exist. For systems with - `$:\disk` (disk0, etc) — disks integrated into the motherboard. Note `$:\diskU` is not a reserved name and is suggested for user-provided disks on the external implementation. Note that no device node names are truly reserved; an implementer may shadow any device node by loading a kernel module in CONFIG.SYS. This ensures that upgrading the kernel does not break software by adding new device nodes at names an implementer was already using. ## Executable formats All 68KOS executables are in ELF format, with the extension identifying the purpose, as follows: - `.EXE` — Normal executables. These have a single entry point, `_start`. - `.DLL` — Dynamic link libraries. These have no canonical single entry point. - `.DRV` — Supervisor modules. These are loaded and run as threads within supervisor space. Entry points TBD. All of these formats must be fully position-independent or have relocation data, since AVL68K has no memory management unit. ### Direct executables To support executables running from ROM without relocations, 68KOS has a variant called the Direct Executable. All types (EXE, DLL, DRV) may be Direct Executables. These are signified by the presence of `EF_68KOS_DIRECT`, equal to `0x80000000`, in the ELF header `e_flags` field. Direct Executables have been pre-relocated to the address at which they reside in their file system, assuming that file system itself resides at `000000`. Any RAM sections required must also be pre-allocated and pre-relocated. This pre-relocation is performed by a rootfs builder tool, which will subtract these from the initial RAM pointer. Running a Direct Executable out of anywhere but `0:`, or from an address it was not relocated to, is not supported. Running them from the correct location is supported directly by the system ELF loader; they are indistinguishable from normal elves by users. ## Boot process 1. CPU loads from `000000` into program counter and `000004` into stack pointer. 2. `0:\68KOS.DLL` begins to execute from its entry point. 3. Supervisor initializes the page allocator, which gives out memory in 2kB chunks. In doing so, it jumps its stack pointer back to the nearest 2048 byte boundary, plus another 2048 bytes if this does not leave enough room for a 1024 byte bitmap. The page allocator can track all pages for the 14 MB (24-bit address) variants in this block; in larger systems additional blocks will be linked in when they are registered by CONFIG.SYS. 4. Page allocator allocates the page in which the stack pointer resides to the system startup stack. 5. Supervisor initializes its own small allocation arena (used by malloc) with whatever RAM is left from `ram_start` (see above), at least 6 kB. 6. ELF loader is initialized. 7. Main filesystem driver (which recognizes mountpoints and branches to individual providers) is initialized. 8. tmpfs provider is loaded, $: is created, and the basic device nodes are created via devnode providers. 9. FAT provider (an API wrapper around FatFs) is loaded and 0: is mounted. 10. Lightweight command interpreter is loaded from `0:\SH.EXE` to execute `0:\CONFIG.SYS` in its special CONFIG.SYS mode. Once in CONFIG.SYS, the boot process should continue (but is defined by the implementer). Before calling `start_sched`, only commands explicitly allowing pre-scheduler use are permitted. 1. Load additional RAM. Config commands are provided to add RAM to the page pool, testing it in the process (optionally in "optional" mode, where RAM regions failing the test are considered to be unpopulated slots). 2. Load driver for the OS timer (this is usually a 68681, also containing UARTs and GPIOs). 3. Start the scheduler. The entire loader process will be moved into a thread, reusing the initial boot stack page. 4. Initialize necessary board GPIOs as required. 5. Initialize the system console UART, and symlink it to `$:\console`. 6. Call `set_console $:\console` to switch in the system UART in addition to the Debug Console (this will remain tee'd in forever, though). 7. Initialize all other motherboard hardware. 8. Mount `C:`, then `chain_config C:\CONFIG.SYS C:\AUTOEXEC.BAT`. ### Debug Console In addition to the main system console, there is a special Debug Console to be used with system debuggers. This is accessed through a reserved final 32-bit word in supervisor space. During boot, messages will be written to this window one character at a time. The hardware implementation must permit writes to this location without raising a bus error. Debuggers may intercept these writes and report them to the user.