duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

commit f5f3a967b7553515f82429f00f5f27cd932d9bd2
parent 0c76db4d8cfe5fda1ff9ebee84e7eb6cf634e194
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Wed,  5 Jul 2023 19:55:38 -0400

Simplify boot sequence and document it better

See doc/boot

Diffstat:
MMakefile | 2+-
Mfs/doc/arch.txt | 92++-----------------------------------------------------------------------------
Afs/doc/boot.txt | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mfs/doc/code.txt | 10+++++-----
Mfs/doc/deploy.txt | 14+++++++-------
Mfs/doc/design/speed.txt | 4++--
Mfs/doc/hw/i386/pc/deploy.txt | 2+-
Mfs/doc/index.txt | 1+
Mfs/doc/usage.txt | 2+-
Mfs/lib/diag.fs | 2+-
Mfs/xcomp/arm/rpi/build.fs | 3+--
Mfs/xcomp/arm/rpi/glue.fs | 3++-
Rfs/xcomp/bootlo.fs -> fs/xcomp/boot.fs | 0
Dfs/xcomp/boothi.fs | 3---
Mfs/xcomp/i386/pc/build.fs | 3+--
Mfs/xcomp/i386/pc/glue.fs | 3++-
Mfs/xcomp/init.fs | 2+-
Mposix/glue.fs | 3+++
18 files changed, 95 insertions(+), 118 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,5 +1,5 @@ TARGETS = dusk dis -BOOTFS_SRC = fs/xcomp/bootlo.fs posix/glue.fs fs/xcomp/boothi.fs +BOOTFS_SRC = fs/xcomp/boot.fs posix/glue.fs ALLSRCS = $(shell find fs) QEMU_FLAGS = -accel kvm -accel tcg -rtc base=utc QEMU_DRVOPTS = format=raw,index=0,if=ide diff --git a/fs/doc/arch.txt b/fs/doc/arch.txt @@ -7,6 +7,8 @@ complete picture, you'll also want to read the hardware-dependent part: * i386: hw/i386/arch +For information about the boot sequence, see doc/boot. + ## Linked lists The linked list is a data structure that is heavily used in Dusk: dictionaries @@ -94,96 +96,6 @@ ends up being metadata's MSB, which will very often be 0. When we use the word "cross-compiled" below, it means that the binary that is being run was not compiled by the system running it. -## The layers of the system - -A running Dusk OS instance has a few layers upon which the prompt is laid out. -We try to keep a consistent terminology for each of those layers, this -terminology is defined below. - -### Native Kernel (kernel) - -This is the very core of the system, written in assembler and cross-compiled. -Its role is to implement a core set of words such as "word", "runword", "parse", -etc.. It's not a minimal kernel (some Forth kernels boot from less than that), -but is a tradeoff between minimalism, simplicity and performance. - -From this small set of words, we can bootstrap ourselves to "higher planes of -being". - -The source for this kernel is posix/vm.c for the CVM and fs/xcomp/i386/kernel.fs -for the i386 kernel. - -### Boot layer (boot) - -At this point, we're done with cross-compiled binaries and we're now entirely -on our own. Let's pick ourselves up by the bootstraps! - -The boot layer is Forth code that has been embedded in the binary. loaded in -memory by the bootloader and thus directly available in Dusk's memory. Its -content depends on the target system and is assembled at build time. It has this -structure: - -1. bootlo -2. boot storage driver -3. fatlo (the "low" part of the FAT FS driver) -4. system-specific glue code -5. boothi - -The "bootlo" part bootstraps from where the kernel left off, implementing what -is considered the "core" set of words of Dusk. At build time, it is sourced from -/xcomp/bootlo.fs. It starts with the "tight bootstrapping" words, words that are -critically needed for further words. The order is important and, because we -can't have comments in early code, uncommented. The very early part is -especially hard to read because we don't even have ":" and ";" yet! - -Then, the rest of bootlo is a set of words that is considered minimal for a Dusk -environment. It's organized thematically. - -The boot storage driver depends on the target machine and has the responsibility -of providing a way to read sectors from mass storage. For the PC target machine, -it's sourced from drv/pc/int13h.fs. - -For now, Dusk can only boot from a FAT12 volume. To do so, it needs the "fatlo" -code, a read-only subset of its FAT implementation, to be embedded in the boot -code. This piece of code lives in fs/fatlo.fs - -The glue file creates a "bootfs" structbind from the Filesystem structure. It -also has the responsibility of adding references to embedded files in "floaded" -so that they aren't loaded twice in memory. In the PC target, this is sourced -from xcomp/pc/glue.fs - -The "boothi" part does very little: it loads /sys/file.fs and then /init.fs, and -then calls init. It ends with a failsafe to ensure that an interactive interpret -loop has been installed (rather than interpreting the whole memory contents). -This is sourced from xcomp/boothi.fs - -### Initialization layer (init) - -The 2 first layers are machine-dependent and will not change unless something -fundamental changes with your machine. The "init" layer, however, is -where you shape the system you want as a user. - -The file is called "/init.fs". It lives at the root of your filesystem and is -loaded at the end of "boothi". - -The role of this file is to load what it has to load and then define a word -called "init". When "boothi" has finished running "init.fs", its last act will -be to call the word "init". - -If you do your own deployment yourself, it is likely that you'll write the whole -"init.fs" file yourself. If your image came from one of the pre-defined builds -in the POSIX package, then this file has been constructed from two parts. A -machine- specific part and a machine-independent part. For the PC platform, -"init.fs" is constructed from xcomp/i386/pc/init.fs and xcomp/init.fs. - -One of the things that your "init" word has to do is to set up Console's readio, -which until now is still on BootIn, a structure that reads the embedded code -from memory. That code stream is about to run out. If your system is -interactive, you'll typically want to load sys/rdln and have init call "rdln$" -which sets Console's readio to RdlnIn, which then makes the system interactive. - -The system is yours. - ## What is a subsystem? What's the difference between a unit in /sys and a unit in other directories? diff --git a/fs/doc/boot.txt b/fs/doc/boot.txt @@ -0,0 +1,64 @@ +# Boot sequence + +One of Dusk OS' defining quality is the fact that it boots from a tiny kernel +and then builds the entirety of the system from source, at boot time. This page +describes the boot process. + +## Arch-specific bootloader + +When the machine powers up, what it does depends on that machine. Arch-specific +provisions have to be made to ensure that: + +1. The binary kernel is loaded in memory. +2. The "bootsrc" contents (see below) is loaded in memory and that the kernel + knows where to find it. +3. We jump to the kernel's first address in memory. + +At this point, we have a the HAL (doc/hal) as well as an interpret loop. After +having done its core initialization, the kernel makes starts its interpret loop +by feeding itself from "bootsrc". + +## bootsrc + +The "bootsrc" contents comes from /xcomp/boot.fs and is loaded, in its source +form, in memory by the arch-specific bootloader. + +Its role it to supply the system with Dusk's "base" set of words, which will be +used to by the next step of the boot sequence, the "glue code". + +## Glue code + +When we created Dusk's boot media, we didn't only write "bootsrc" to it, we +appended to it what we call the "glue code". Like "bootsrc", this glue code is +written verbatim right next to "bootsrc" and will be picked up by the interpet +loop once it's done compiling "bootsrc". + +That code is arch-specific and its role is to "glue" Dusk's base set of words to +"load init.fs from the boot filesystem". + +How it does this is open ended, but it almost invariably implies loading +/sys/file.fs, which then allows us to load /init.fs. + +For example, the "glue" code for the PC is a concatenation /drv/pc/int13h.fs, +/lib/drivelo.fs, /fs/fatlo.fs and then /xcomp/i386/pc/glue.fs, which puts it +all together, mounting the system fat into the "bootfs" structbind, and then +loading /sys/file.fs from that filesystem, and then, finally, /init.fs, which +brings us to the last boot sequence step. + +Another thing the "glue" code must do it to "register" the units it inlined in +it's boot sequence with "floaded," so that they aren't loaded twice through the +"?f<<" word. For example, in the case of the PC platform, if it didn't register +/fs/fatlo.fs, it would end up being loaded twice in memory. + +## init.fs + +The last step of the boot sequence has a base set of words, I/O, files. It's +pretty well set up. Its role is to get the system to its "final destination", +which depends on the will of the operator. + +Most of the time, the final destination is to get to an interactive prompt, +which is most often done through /sys/rdln. + +How it does this is very open ended and depends on the machine and the +operator's inclinations. It's also the part of the boot sequence that is the +easiest to change, and is likely to often be adjusted by the operator. diff --git a/fs/doc/code.txt b/fs/doc/code.txt @@ -100,19 +100,19 @@ not, that's not the only thing that "foo.fs" will do. It will also include words that are easier to implement in Forth than in C. If some structures in C are useful to have in Forth, then that unit will also export those structures. -## Understanding bootlo +## Understanding bootsrc -xcomp/bootlo.fs is one of the more complex units of Dusk and its trickiest +xcomp/boot.fs is one of the more complex units of Dusk and its trickiest parts, the beginning, can't be commented because we don't have comments yet. Here's a walkthrough to that code. -First, the context. When we begin running bootlo, all we have is the kernel and +First, the context. When we begin running bootsrc, all we have is the kernel and that's quite limited. We have literal parsing and memory (@ ! , etc.) words and constants to important memory areas (HERE and sysdict), we have the very important and arch-specific exit, and branchR, and we have the extremely important flow words [ and ] , but we don't have : or ; yet! -The first task of bootlo is thus to implement those 2 very important words. +The first task of bootsrc is thus to implement those 2 very important words. These first few words are a good lesson for what constitutes a word in Dusk. The very first word we want is the equivalent of ": w>e 5 - ;" @@ -161,7 +161,7 @@ first" basis, but soon enough, critical words have been implemented and we can begin organizing words in themes. We try to keep these words to a minimum. Some of these words might appear like -they don't belong in bootlo. The reason why they're there there is one of the +they don't belong in bootsrc. The reason why they're there there is one of the following: 1. They're needed in storage drivers or fatlo. diff --git a/fs/doc/deploy.txt b/fs/doc/deploy.txt @@ -58,12 +58,12 @@ at $b8000 (the vga text mode buffer) because I didn't have a word "emit" yet. If you're in an emulator, you have access to machine state, so you can debug through that too. -### Testing bootlo +### Testing bootsrc -Compiling and testing the "bootlo" layer is the best way to iron kinks out of +Compiling and testing the "bootsrc" layer is the best way to iron kinks out of the kernel. Even though all your words were tested in isolation as you built the kernel, it's likely that subtle bugs are still lurking in there, but if your -kernel can compile bootlo and, say, instantiate a dummy struct, then you can be +kernel can compile bootsrc and, say, instantiate a dummy struct, then you can be confident that your kernel is solid. Again, you don't have "emit" yet, so you need some tricks to visualize the @@ -71,7 +71,7 @@ results of your tests. A blinking LED maybe? So, what you do is that you begin with a dummy test right at "boot<". Something like "blink my LED and loop forever". We're good? alright. Now copy the first -few lines of bootlo (those that handle ":" and ";") and copy that into your +few lines of bootsrc (those that handle ":" and ";") and copy that into your bootloader stream. Then, create a word definition that blinks your LED. Still good? The hard part's over! Now let's get those other lines of code wiggling! @@ -86,7 +86,7 @@ should proceed in incremental steps. Read a sector, test it. Does it work for other sectors too? Well, that sounds good, it looks like you can plug fatlo in. For this, I recommend looking at how the PC platform does it. It should look the -same for all targets: we stream bootlo in, then the storage driver, then fatlo, +same for all targets: we stream bootsrc in, then the storage driver, then fatlo, then the "glue" file, which create an instance of Filesystem as well as a "bootfs" structbind to it. @@ -96,8 +96,8 @@ doesn't load them twice. ### init.fs -You're almost done! Your next step is to load "boothi", and then create a dummy -init.fs, again blinking your LED. Working? good! +You're almost done! Your next step is to create a dummy init.fs, again blinking +your LED. Working? good! Did you try a f<< call? Working too? You're on a roll! diff --git a/fs/doc/design/speed.txt b/fs/doc/design/speed.txt @@ -7,7 +7,7 @@ priotized. It doesn't mean, however, that we squander the computing ressources. As with anything in Dusk, we aim for efficient code as long as it doesn't hinder simplicity and grokkability. Where is the tradeoff cutoff? Difficult to say. Let's use an example: the word "fill". This word is not needed by the native -kernel, so it's implemented in Forth in xcomp/bootlo. The operation is simple: +kernel, so it's implemented in Forth in xcomp/boot. The operation is simple: we fill memory with a value. The Forth loop is very, very inefficient compared to a native loop. For each byte we copy, we have to play around with PS and RS a lot. An efficiency nightmare! @@ -41,7 +41,7 @@ a jump to themselves so that all previous word references are boosted up in speed. For example, we could have a i386 native implementation of "fill" living in -"/arch/i386/bootlo.fs" and the system operator would, if she wants, load that +"/arch/i386/boot.fs" and the system operator would, if she wants, load that unit as soon as possible in her "init.fs" file (loading it early allows further usages of the word to skip a jump instruction and thus be *slightly* faster). diff --git a/fs/doc/hw/i386/pc/deploy.txt b/fs/doc/hw/i386/pc/deploy.txt @@ -109,7 +109,7 @@ good to go, add things back one at a time and see when it breaks. at $b8000, the VGA text buffer. Each character in the screen is 2 bytes wide. The low byte is the character, the high byte is the color. To write a 'X', it's "$758 $b8000 w!". What you can do is insert these little snippets at different -stages of the boot process: right on top of bootlo.fs, at the end of it, right +stages of the boot process: right on top of boot.fs, at the end of it, right before the first "fload", right at the top of /init.fs. This gives you an idea of where to look for problems. diff --git a/fs/doc/index.txt b/fs/doc/index.txt @@ -24,6 +24,7 @@ deploy Deploy Dusk to another machine terms Terminology dirs Directory structure arch Architecture details +boot Boot Sequence code Understanding Dusk's code tips Tips and tricks asm/ Assemblers documentation diff --git a/fs/doc/usage.txt b/fs/doc/usage.txt @@ -490,7 +490,7 @@ All units have implicit import of sys/file and sys/io, so that should also be considered in your search. Then, look in doc/dict. If it's in there, then it's either defined in the native -kernel code or in xcomp/bootlo.fs. +kernel code or in xcomp/boot.fs. ## Alignment discipline diff --git a/fs/lib/diag.fs b/fs/lib/diag.fs @@ -5,7 +5,7 @@ : .S ( -- ) scnt rcnt swap S" PS %b RS %b -- " console :printf stack? psdump ; : .free - here ['] : ( first word in bootlo.fs ) - .sz ." used " + here ['] : ( first word in bootsrc ) - .sz ." used " HEREMAX @ here - .sz ." free" ; : dump ( a -- ) \ dump 8 lines of data after "a" diff --git a/fs/xcomp/arm/rpi/build.fs b/fs/xcomp/arm/rpi/build.fs @@ -7,10 +7,9 @@ org value kernel : spitBoot ( iohdl -- ) >r \ V1=iohdl ." Putting kernel in place\n" kernel kernellen V1 IO :write - S" /xcomp/bootlo.fs" V1 spitfile + S" /xcomp/boot.fs" V1 spitfile S" /drv/rpi/emmc.fs" V1 spitfile S" /lib/drivelo.fs" V1 spitfile S" /fs/fatlo.fs" V1 spitfile S" /xcomp/arm/rpi/glue.fs" V1 spitfile - S" /xcomp/boothi.fs" V1 spitfile r> IO :flush ; diff --git a/fs/xcomp/arm/rpi/glue.fs b/fs/xcomp/arm/rpi/glue.fs @@ -4,4 +4,5 @@ emmc :self FAT :mountvolume ( fs ) structbind FAT bootfs S" emmc.fs" bootfs :child floaded, 0 S" lib" bootfs :child S" drivelo.fs" bootfs :child floaded, 0 S" fs" bootfs :child S" fatlo.fs" bootfs :child floaded, - +bootfs :self 0 S" sys" bootfs :child S" file.fs" bootfs :child fload +f<< /init.fs diff --git a/fs/xcomp/bootlo.fs b/fs/xcomp/boot.fs diff --git a/fs/xcomp/boothi.fs b/fs/xcomp/boothi.fs @@ -1,3 +0,0 @@ -bootfs :self 0 S" sys" bootfs :child S" file.fs" bootfs :child fload -bootfs :self 0 S" init.fs" bootfs :child fload -init ." Booting error" bye diff --git a/fs/xcomp/i386/pc/build.fs b/fs/xcomp/i386/pc/build.fs @@ -21,10 +21,9 @@ org value kernel : spitBoot ( iohdl -- ) >r \ V1=iohdl ." Putting kernel in place\n" kernel kernellen V1 IO :write - S" /xcomp/bootlo.fs" V1 spitfile + S" /xcomp/boot.fs" V1 spitfile S" /drv/pc/int13h.fs" V1 spitfile S" /lib/drivelo.fs" V1 spitfile S" /fs/fatlo.fs" V1 spitfile S" /xcomp/i386/pc/glue.fs" V1 spitfile - S" /xcomp/boothi.fs" V1 spitfile r> IO :flush ; diff --git a/fs/xcomp/i386/pc/glue.fs b/fs/xcomp/i386/pc/glue.fs @@ -1,6 +1,7 @@ -\ Glue code that goes between the filesystem part and boothi INT13hDrive FAT :mountvolume ( fs ) structbind FAT bootfs 0 S" drv" bootfs :child S" pc" bootfs :child S" int13h.fs" bootfs :child floaded, 0 S" lib" bootfs :child S" drivelo.fs" bootfs :child floaded, 0 S" fs" bootfs :child S" fatlo.fs" bootfs :child floaded, +bootfs :self 0 S" sys" bootfs :child S" file.fs" bootfs :child fload +f<< /init.fs diff --git a/fs/xcomp/init.fs b/fs/xcomp/init.fs @@ -6,4 +6,4 @@ f<< /lib/fmt.fs f<< /lib/diag.fs f<< /sys/rdln.fs f<< /text/pager.fs -: init S" Dusk OS\n" stype .free rdln$ quit ; +: init S" Dusk OS\n" stype .free rdln$ quit ; init diff --git a/posix/glue.fs b/posix/glue.fs @@ -13,3 +13,6 @@ POSIXFS :new structbind POSIXFS bootfs : mountImage ( imgname -- drv ) _mountdrv here 512 , -1 , ['] _drv@ , ['] _drv! , ; + +bootfs :self 0 S" sys" bootfs :child S" file.fs" bootfs :child fload +f<< /init.fs