Rename Schunix to SchOS; the kernel becomes SchIFT

Removes the "-unix" element and with it any trademark exposure to The
Open Group.

The split follows the ecosystem layout: SchOS is the system, and the
kernel has its own name. Kernel-identity strings are the only places
that take SchIFT -- uname(2) sysname, /proc/version, and the two licence
sentences that say "kernel" outright. That is what every Unix does here:
`uname -s` on Linux reports the kernel, not the distribution. Everything
a user reads as the product -- panic screen, boot menu, error prefixes,
docs, LICENSE, NOTICE -- is SchOS.

schunix.img is schos.img, the logo assets and the musl TLS patch are
renamed, and __SCHUNIX__ is __SCHOS__ (the define and the patch that
consumes it moved together).

Two things the rename broke, both found by the bootcheck suite:

  - shmtest wrote "SCHUNIX-MMAP-OK" with a hardcoded length of 15 and
    compared it back by hand-counted offsets (m[3]=='U', m[14]=='K').
    The shorter marker left the write running two bytes past the literal
    and the compare reading past the data, failing a file-backed mmap
    that was working correctly. Now written and compared through one
    constant with sizeof.
  - bootcheck asserted a 31-byte file after appending to
    "hello-from-schunix"; the shorter string makes it 29.

Both are the same mistake: a string literal whose length is written out
somewhere else. Full suite green -- base, Tty, Ps, Sock, Fb, Usb, Evdev.
This commit is contained in:
Nexoniarz 2026-08-09 14:09:59 +02:00
commit e04ca28812
83 changed files with 520 additions and 601 deletions

4
.gitignore vendored
View file

@ -1,7 +1,7 @@
# Build output. Everything here is reproducible from `make`. # Build output. Everything here is reproducible from `make`.
build/ build/
schunix.img schos.img
schunix.iso schos.iso
*.o *.o
*.d *.d
*.asm *.asm

BIN
Assets/SchOS Full Logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

138
Assets/SchOS Full Logo.svg Normal file
View file

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="1920"
height="1080"
viewBox="0 0 1920 1080"
version="1.1"
id="svg1"
inkscape:version="1.4.4 (dcaf3e7, 2026-05-05)"
sodipodi:docname="SchOS Full Logo.svg"
inkscape:export-filename="SchOS Full Logo.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#000000"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="0.68489583"
inkscape:cx="960"
inkscape:cy="516.13688"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="g8" />
<defs
id="defs1">
<rect
x="-11.054408"
y="184.24013"
width="818.02616"
height="644.84044"
id="rect9" />
<linearGradient
id="linearGradient2"
inkscape:collect="always">
<stop
style="stop-color:#c4c4c4;stop-opacity:1;"
offset="0"
id="stop2" />
<stop
style="stop-color:#949494;stop-opacity:1;"
offset="0.20117648"
id="stop4" />
<stop
style="stop-color:#454545;stop-opacity:1;"
offset="0.50764704"
id="stop5" />
<stop
style="stop-color:#808080;stop-opacity:1;"
offset="0.78088236"
id="stop9" />
<stop
style="stop-color:#363636;stop-opacity:1;"
offset="1"
id="stop3" />
</linearGradient>
<linearGradient
id="linearGradient5"
inkscape:collect="always">
<stop
style="stop-color:#c9c9c9;stop-opacity:1;"
offset="0"
id="stop6" />
<stop
style="stop-color:#636363;stop-opacity:1;"
offset="0.5"
id="stop8" />
<stop
style="stop-color:#a2a2a2;stop-opacity:1;"
offset="1"
id="stop7" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5"
id="linearGradient7"
x1="354.53467"
y1="585.88361"
x2="968.30945"
y2="585.88361"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.9035284,0,0,1.9035284,85.366084,-529.36246)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2"
id="linearGradient3"
x1="502.47748"
y1="461.89429"
x2="822.14758"
y2="730.12933"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.9035284,0,0,1.9035284,85.366084,-529.36246)" />
</defs>
<g
inkscape:label="logo"
inkscape:groupmode="layer"
id="layer1"
transform="matrix(0.9235878,0,0,0.9235878,-243.88631,0.4743235)">
<g
id="g8"
inkscape:label="SmallLogo">
<g
id="text1"
style="font-size:426.811px;line-height:0.8;font-family:miracode;-inkscape-font-specification:miracode;text-align:center;text-anchor:middle;fill:url(#linearGradient3);stroke-width:22.2296;paint-order:markers fill stroke"
aria-label="Sch&#10;OS"
inkscape:label="1">
<path
d="m 1163.8119,274.38449 10.3739,10.37388 v 14.81982 l -10.3739,10.37388 h -7.4099 -7.4099 -40.0135 -47.4235 -40.0135 l -29.63964,29.63965 29.63964,29.63966 h 40.0135 40.0136 7.4099 7.4099 l 5.1869,5.18694 5.187,5.18694 37.0495,37.04956 5.187,5.18694 5.1869,5.18694 v 7.40991 7.40992 40.01353 40.01353 7.40991 7.40992 l -5.1869,5.18694 -5.187,5.18694 -37.0495,37.04956 -5.187,5.18694 -5.1869,5.18694 h -7.4099 -7.4099 -40.0136 -40.0135 -7.4099 -7.4099 l -5.187,-5.18694 -5.18689,-5.18694 -37.04957,-37.04956 -5.18694,-5.18694 -5.18694,-5.18694 v -14.81983 l 10.37388,-10.37388 h 14.81983 l 5.18694,5.18694 5.18694,5.18694 37.04955,37.04957 h 40.0135 40.0136 l 37.0495,-37.04957 v -40.01353 -40.01353 l -37.0495,-37.04957 h -40.0136 -40.0135 -7.4099 -7.4099 l -5.187,-5.18694 -5.18689,-5.18694 -37.04957,-37.04956 -5.18694,-5.18694 -5.18694,-5.18694 v -14.81983 l 5.18694,-5.18694 5.18694,-5.18694 37.04957,-37.04956 5.18689,-5.18694 5.187,-5.18694 h 7.4099 7.4099 40.0135 47.4235 40.0135 7.4099 z m 284.5405,237.11722 10.3738,10.37388 v 14.81983 l -5.1869,5.18694 -5.1869,5.18694 -37.0496,37.04956 -5.187,5.18694 -5.1869,5.18694 h -7.4099 -7.4099 -40.0136 -40.0135 -7.4099 -7.4099 l -5.1869,-5.18694 -5.187,-5.18694 -37.0496,-37.04956 -5.1869,-5.18694 -5.1869,-5.18694 v -7.40992 -7.40991 -40.01353 -40.01353 -7.40992 -7.40991 l 5.1869,-5.18694 5.1869,-5.18694 37.0496,-37.04956 5.187,-5.18694 5.1869,-5.18694 h 7.4099 7.4099 40.0135 40.0136 7.4099 7.4099 l 5.1869,5.18694 5.187,5.18694 37.0496,37.04956 5.1869,5.18694 5.1869,5.18694 v 14.81983 l -10.3738,10.37388 h -14.8199 l -5.1869,-5.18694 -5.187,-5.18694 -37.0495,-37.04957 h -40.0136 -40.0135 l -37.0495,37.04957 v 40.01353 40.01353 l 37.0495,37.04957 h 40.0135 40.0136 l 37.0495,-37.04957 5.187,-5.18694 5.1869,-5.18694 z m 94.8466,-237.11722 10.3739,10.37388 v 7.40991 7.40991 40.01353 47.42345 47.42344 4.44595 l 11.8558,-11.85586 5.187,-5.18694 5.1869,-5.18694 37.0496,-37.04956 5.1869,-5.18694 5.1869,-5.18694 h 7.41 7.4099 32.6036 7.4099 7.4099 l 5.187,5.18694 5.1869,5.18694 37.0496,37.04956 5.1869,5.18694 5.1869,5.18694 v 7.40991 7.40992 40.01353 47.42344 40.01354 7.40991 7.40991 l -10.3738,10.37388 h -14.8199 l -10.3738,-10.37388 v -7.40991 -7.40991 -40.01354 -47.42344 -40.01353 l -37.0496,-37.04957 h -32.6036 l -37.0496,37.04957 -5.1869,5.18694 -5.187,5.18694 -37.0495,37.04956 v 40.01353 40.01354 7.40991 7.40991 l -10.3739,10.37388 h -14.8198 l -10.3739,-10.37388 v -7.40991 -7.40991 -40.01354 -40.01353 -7.40991 -7.40991 -40.01354 -47.42344 -47.42345 -40.01353 -7.40991 -7.40991 l 10.3739,-10.37388 z"
id="path2"
inkscape:label="2" />
<path
d="m 1203.8253,615.8333 h 40.0136 7.4099 7.4099 l 5.1869,5.18694 5.187,5.18693 37.0495,37.04957 5.187,5.18694 5.1869,5.18694 v 7.40991 7.40992 40.01353 47.42344 47.42345 40.01353 7.40991 7.40992 l -5.1869,5.18694 -5.187,5.18693 -37.0495,37.04957 -5.187,5.18694 -5.1869,5.18694 h -7.4099 -7.4099 -40.0136 -40.0135 -7.4099 -7.4099 l -5.187,-5.18694 -5.1869,-5.18694 -37.0496,-37.04957 -5.1869,-5.18693 -5.1869,-5.18694 v -7.40992 -7.40991 -40.01353 -47.42345 -47.42344 -40.01353 -7.40992 -7.40991 l 5.1869,-5.18694 5.1869,-5.18694 37.0496,-37.04957 5.1869,-5.18693 5.187,-5.18694 h 7.4099 7.4099 z m 0,35.56758 h -40.0135 l -37.0496,37.04957 v 40.01353 47.42344 47.42345 40.01353 l 37.0496,37.04957 h 40.0135 40.0136 l 37.0495,-37.04957 v -40.01353 -47.42345 -47.42344 -40.01353 l -37.0495,-37.04957 z m 386.7973,-35.56758 10.3738,10.37387 V 641.027 l -10.3738,10.37388 h -7.41 -7.4099 -40.0135 -47.4235 -40.0135 l -29.6396,29.63965 29.6396,29.63966 h 40.0135 40.0136 7.4099 7.4099 l 5.1869,5.18694 5.187,5.18693 37.0496,37.04957 5.1869,5.18694 5.1869,5.18694 v 7.40991 7.40992 40.01353 40.01353 7.40991 7.40992 l -5.1869,5.18694 -5.1869,5.18693 -37.0496,37.04957 -5.187,5.18694 -5.1869,5.18694 h -7.4099 -7.4099 -40.0136 -40.0135 -7.4099 -7.4099 l -5.1869,-5.18694 -5.187,-5.18694 -37.0496,-37.04957 -5.1869,-5.18693 -5.1869,-5.18694 V 863.3244 l 10.3738,-10.37388 h 14.8199 l 5.1869,5.18694 5.187,5.18694 37.0495,37.04957 h 40.0135 40.0136 l 37.0495,-37.04957 v -40.01353 -40.01353 l -37.0495,-37.04957 h -40.0136 -40.0135 -7.4099 -7.4099 l -5.1869,-5.18694 -5.187,-5.18694 -37.0496,-37.04957 -5.1869,-5.18693 -5.1869,-5.18694 v -14.81983 l 5.1869,-5.18694 5.1869,-5.18694 37.0496,-37.04957 5.187,-5.18693 5.1869,-5.18694 h 7.4099 7.4099 40.0135 47.4235 40.0135 7.4099 z"
id="path3"
inkscape:label="1" />
</g>
<path
id="path1"
style="fill:none;stroke:url(#linearGradient7);stroke-width:67.0141;paint-order:markers fill stroke"
d="m 1895.0629,585.88361 c 0,304.12212 -246.5396,550.66179 -550.6618,550.66179 -304.1222,0 -550.66125,-246.53967 -550.66125,-550.66179 0,-304.12212 246.53905,-550.661802 550.66125,-550.661802 208.3753,0 389.7181,115.740002 483.2487,286.440342 42.9766,78.43538 67.4131,168.47469 67.4131,264.22146 z"
sodipodi:nodetypes="ssssss"
inkscape:label="2" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
Assets/SchOS Text Logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

130
Assets/SchOS Text Logo.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

View file

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="1920"
height="1080"
viewBox="0 0 1920 1080"
version="1.1"
id="svg1"
inkscape:version="1.4.4 (dcaf3e7, 2026-05-05)"
sodipodi:docname="Schunix Small Logo.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#000000"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="0.54276993"
inkscape:cx="982.92107"
inkscape:cy="614.44082"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1">
<linearGradient
id="linearGradient5"
inkscape:collect="always">
<stop
style="stop-color:#c9c9c9;stop-opacity:1;"
offset="0"
id="stop6" />
<stop
style="stop-color:#636363;stop-opacity:1;"
offset="0.5"
id="stop8" />
<stop
style="stop-color:#a2a2a2;stop-opacity:1;"
offset="1"
id="stop7" />
</linearGradient>
<linearGradient
id="linearGradient1"
inkscape:collect="always">
<stop
style="stop-color:#444444;stop-opacity:1;"
offset="0"
id="stop1" />
<stop
style="stop-color:#b2b2b2;stop-opacity:1;"
offset="0.25"
id="stop5" />
<stop
style="stop-color:#909090;stop-opacity:1;"
offset="0.5"
id="stop3" />
<stop
style="stop-color:#4c4c4c;stop-opacity:1;"
offset="0.75"
id="stop4" />
<stop
style="stop-color:#808080;stop-opacity:1;"
offset="1"
id="stop2" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1"
id="linearGradient2"
x1="480.19177"
y1="439.3587"
x2="819.08807"
y2="723.7265"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5"
id="linearGradient7"
x1="354.53467"
y1="585.88361"
x2="968.30945"
y2="585.88361"
gradientUnits="userSpaceOnUse" />
</defs>
<g
inkscape:label="logo"
inkscape:groupmode="layer"
id="layer1"
transform="matrix(0.9235878,0,0,0.9235878,-243.88631,0.4743235)">
<g
id="g8"
inkscape:label="SmallLogo"
transform="matrix(1.8840278,0,0,1.8840278,58.429052,-517.93737)">
<path
id="path1"
style="fill:none;stroke:url(#linearGradient7);stroke-width:35.2052;paint-order:markers fill stroke"
d="m 950.70685,585.88361 c 0,159.76758 -129.51721,289.28479 -289.28479,289.28479 -159.76758,0 -289.28479,-129.51721 -289.28479,-289.28479 0,-159.76758 129.51721,-289.28479 289.28479,-289.28479 109.46795,0 204.73463,60.80288 253.87001,150.47863 22.5773,41.20526 35.41478,88.50653 35.41478,138.80616 z"
sodipodi:nodetypes="ssssss"
inkscape:label="2" />
<path
d="m 614.91693,442.64998 9.0023,9.00229 v 12.86042 l -9.0023,9.00229 h -6.4302 -6.43021 -34.72313 -41.15333 -34.72313 l -25.72083,25.72083 25.72083,25.72084 h 34.72313 34.72312 6.43021 6.43021 l 4.50115,4.50114 4.50114,4.50115 32.15104,32.15104 4.50115,4.50115 4.50115,4.50114 v 6.43021 6.43021 34.72312 34.72313 6.43021 6.43021 l -4.50115,4.50114 -4.50115,4.50115 -32.15104,32.15104 -4.50114,4.50115 -4.50115,4.50114 h -6.43021 -6.43021 -34.72312 -34.72313 -6.43021 -6.4302 l -4.50115,-4.50114 -4.50115,-4.50115 -32.15104,-32.15104 -4.50114,-4.50115 -4.50115,-4.50114 v -12.86042 l 9.00229,-9.00229 h 12.86042 l 4.50115,4.50114 4.50114,4.50115 32.15104,32.15104 h 34.72313 34.72312 l 32.15105,-32.15104 v -34.72313 -34.72312 l -32.15105,-32.15104 h -34.72312 -34.72313 -6.43021 -6.4302 l -4.50115,-4.50115 -4.50115,-4.50114 -32.15104,-32.15105 -4.50114,-4.50114 -4.50115,-4.50115 V 492.8056 l 4.50115,-4.50114 4.50114,-4.50115 32.15104,-32.15104 4.50115,-4.50115 4.50115,-4.50114 h 6.4302 6.43021 34.72313 41.15333 34.72313 6.43021 z m 246.91977,0 9.0023,9.00229 v 12.86042 l -4.50115,4.50114 -4.50115,4.50115 -32.15104,32.15104 -4.50114,4.50115 -4.50115,4.50114 -25.72083,25.72084 25.72083,25.72083 4.50115,4.50115 4.50114,4.50114 32.15104,32.15104 4.50115,4.50115 4.50115,4.50115 v 6.4302 6.43021 34.72313 34.72312 6.43021 6.43021 l -9.0023,9.00229 h -12.86041 l -9.00229,-9.00229 v -6.43021 -6.43021 -34.72312 -34.72313 l -32.15105,-32.15104 -4.50114,-4.50115 -4.50115,-4.50114 -25.72083,-25.72083 -25.72084,25.72083 -4.50114,4.50114 -4.50115,4.50115 -32.15104,32.15104 v 34.72313 34.72312 6.43021 6.43021 l -9.00229,9.00229 h -12.86042 l -9.00229,-9.00229 v -6.43021 -6.43021 -34.72312 -34.72313 -6.43021 -6.4302 l 4.50115,-4.50115 4.50114,-4.50115 32.15104,-32.15104 4.50115,-4.50114 4.50115,-4.50115 25.72083,-25.72083 -25.72083,-25.72084 -4.50115,-4.50114 -4.50115,-4.50115 -32.15104,-32.15104 -4.50114,-4.50115 -4.50115,-4.50114 v -12.86042 l 9.00229,-9.00229 h 12.86042 l 4.50114,4.50114 4.50115,4.50115 32.15104,32.15104 4.50115,4.50115 4.50114,4.50114 25.72084,25.72084 25.72083,-25.72084 4.50115,-4.50114 4.50114,-4.50115 32.15105,-32.15104 4.50114,-4.50115 4.50115,-4.50114 z"
id="text1"
style="font-size:370.38px;font-family:miracode;-inkscape-font-specification:miracode;text-align:center;text-anchor:middle;fill:url(#linearGradient2);stroke-width:11.801;paint-order:markers fill stroke"
aria-label="SX"
inkscape:label="1" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.9 KiB

View file

@ -181,7 +181,7 @@
removed. Third-party software redistributed in a built image -- musl, removed. Third-party software redistributed in a built image -- musl,
toybox and mksh, all under ports/ -- keeps its own license; see NOTICE. toybox and mksh, all under ports/ -- keeps its own license; see NOTICE.
Which outside code may be copied into Schunix and which may not -- the Which outside code may be copied into SchOS and which may not -- the
BSD/GPL rules, the NetBSD advertising clause, and what is deliberately BSD/GPL rules, the NetBSD advertising clause, and what is deliberately
never shipped -- is written up in docs/licensing.md. Read it before never shipped -- is written up in docs/licensing.md. Read it before
copying anyone else's code in. copying anyone else's code in.

View file

@ -1,7 +1,7 @@
The Schunix kernel is a derivative work of xv6, which carries the licence The SchIFT kernel is a derivative work of xv6, which carries the licence
below. The MIT licence requires this notice be preserved in all copies and below. The MIT licence requires this notice be preserved in all copies and
substantial portions of the software, so this file must survive any future substantial portions of the software, so this file must survive any future
change to the Schunix licence. See NOTICE and docs/licensing.md. change to the SchOS licence. See NOTICE and docs/licensing.md.
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View file

@ -277,16 +277,16 @@ endif
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# Top-level targets # Top-level targets
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
all: schunix.img all: schos.img
schunix.img: $(BUILD)/boot/bootblock $(BUILD)/boot/stage2 $(BUILD)/kernel/kernel $(BUILD)/schfs.img schos.img: $(BUILD)/boot/bootblock $(BUILD)/boot/stage2 $(BUILD)/kernel/kernel $(BUILD)/schfs.img
dd if=/dev/zero of=schunix.img count=10000 dd if=/dev/zero of=schos.img count=10000
dd if=$(BUILD)/boot/bootblock of=schunix.img conv=notrunc dd if=$(BUILD)/boot/bootblock of=schos.img conv=notrunc
dd if=$(BUILD)/boot/stage2 of=schunix.img seek=1 conv=notrunc dd if=$(BUILD)/boot/stage2 of=schos.img seek=1 conv=notrunc
# seek is 1 + STAGE2_SECTORS, not a literal. It was 25 against a 24-sector # seek is 1 + STAGE2_SECTORS, not a literal. It was 25 against a 24-sector
# stage2; raising STAGE2_SECTORS for the boot logo without touching it wrote # stage2; raising STAGE2_SECTORS for the boot logo without touching it wrote
# the kernel straight over stage2's own tail. # the kernel straight over stage2's own tail.
dd if=$(BUILD)/kernel/kernel of=schunix.img seek=$$(( 1 + $(STAGE2_SECTORS) )) conv=notrunc dd if=$(BUILD)/kernel/kernel of=schos.img seek=$$(( 1 + $(STAGE2_SECTORS) )) conv=notrunc
kernel: $(BUILD)/kernel/kernel kernel: $(BUILD)/kernel/kernel
@ -315,17 +315,17 @@ ports:
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
iso: iso:
rm -rf $(BUILD)/kernel $(BUILD)/lib $(BUILD)/cmd rm -rf $(BUILD)/kernel $(BUILD)/lib $(BUILD)/cmd
$(MAKE) RAMROOT=1 schunix.iso $(MAKE) RAMROOT=1 schos.iso
schunix.iso: $(BUILD)/boot/cdboot $(BUILD)/boot/stage2 $(BUILD)/kernel/kernel schos.iso: $(BUILD)/boot/cdboot $(BUILD)/boot/stage2 $(BUILD)/kernel/kernel
STAGE2_SECTORS=$(STAGE2_SECTORS) sh tools/mkiso.sh $@ STAGE2_SECTORS=$(STAGE2_SECTORS) sh tools/mkiso.sh $@
# Boot the ISO the way a machine booting off a disc would: no hard disk at # Boot the ISO the way a machine booting off a disc would: no hard disk at
# all, so a kernel that still secretly depends on one fails here rather than # all, so a kernel that still secretly depends on one fails here rather than
# in someone's optical drive. # in someone's optical drive.
qemu-iso: schunix.iso qemu-iso: schos.iso
$(QEMU) -serial mon:stdio $(QEMU_DISPLAY) -cpu qemu64,+rdtscp \ $(QEMU) -serial mon:stdio $(QEMU_DISPLAY) -cpu qemu64,+rdtscp \
-cdrom schunix.iso -boot d \ -cdrom schos.iso -boot d \
-m 1G -smp 2 -machine pc-i440fx-9.2 -m 1G -smp 2 -machine pc-i440fx-9.2
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
@ -665,10 +665,10 @@ $(BUILD)/sysroot.stamp: sysroot-install
$(BUILD)/fs.img: $(MKFS) $(BUILD)/sysroot.stamp $(BUILD)/fs.img: $(MKFS) $(BUILD)/sysroot.stamp
@mkdir -p $(BUILD) @mkdir -p $(BUILD)
@echo "Creating Schunix File System Image..." @echo "Creating SchOS File System Image..."
@# A running QEMU holds this file open, and on Windows that makes rm fail @# A running QEMU holds this file open, and on Windows that makes rm fail
@# with "Device or resource busy" -- which stops the build *after* the @# with "Device or resource busy" -- which stops the build *after* the
@# kernel has already relinked, leaving schunix.img stale. The next test run @# kernel has already relinked, leaving schos.img stale. The next test run
@# then boots the previous kernel and the change appears to have done @# then boots the previous kernel and the change appears to have done
@# nothing, which has cost several debugging cycles. Say so plainly. @# nothing, which has cost several debugging cycles. Say so plainly.
@rm -f $@ || { \ @rm -f $@ || { \
@ -684,9 +684,9 @@ $(BUILD)/fs.img: $(MKFS) $(BUILD)/sysroot.stamp
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# QEMU # QEMU
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
qemu: schunix.img $(BUILD)/schfs.img qemu: schos.img $(BUILD)/schfs.img
$(QEMU) -serial mon:stdio $(QEMU_DISPLAY) -cpu qemu64,+rdtscp \ $(QEMU) -serial mon:stdio $(QEMU_DISPLAY) -cpu qemu64,+rdtscp \
-hda schunix.img -hdb $(BUILD)/schfs.img \ -hda schos.img -hdb $(BUILD)/schfs.img \
-m 1G -smp 2 -machine pc-i440fx-9.2 -m 1G -smp 2 -machine pc-i440fx-9.2
# The root filesystem. Built from the staged sysroot; the kernel mounts it as # The root filesystem. Built from the staged sysroot; the kernel mounts it as
@ -694,7 +694,7 @@ qemu: schunix.img $(BUILD)/schfs.img
$(BUILD)/schfs.img: $(MKSCHFS) $(BUILD)/sysroot.stamp $(BUILD)/schfs.img: $(MKSCHFS) $(BUILD)/sysroot.stamp
@mkdir -p $(BUILD) @mkdir -p $(BUILD)
@rm -f $@ @rm -f $@
./$(MKSCHFS) $@ --size 8000 --label schunix --sysroot $(SYSROOT) ./$(MKSCHFS) $@ --size 8000 --label schos --sysroot $(SYSROOT)
# Boot with a SchFS volume attached as the second disk. # Boot with a SchFS volume attached as the second disk.
# #
@ -705,15 +705,15 @@ $(BUILD)/schfs.img: $(MKSCHFS) $(BUILD)/sysroot.stamp
# the live v1 root and the SchFS probe correctly finds nothing there. # the live v1 root and the SchFS probe correctly finds nothing there.
# #
# Once up: cat /proc/schfs # Once up: cat /proc/schfs
qemu-schfs: schunix.img $(BUILD)/schfs.img qemu-schfs: schos.img $(BUILD)/schfs.img
$(QEMU) -serial mon:stdio $(QEMU_DISPLAY) -cpu qemu64,+rdtscp \ $(QEMU) -serial mon:stdio $(QEMU_DISPLAY) -cpu qemu64,+rdtscp \
-hda schunix.img -hdb $(BUILD)/schfs.img \ -hda schos.img -hdb $(BUILD)/schfs.img \
-m 1G -smp 2 -machine pc-i440fx-9.2 -m 1G -smp 2 -machine pc-i440fx-9.2
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# Misc # Misc
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# schunix.img is deliberately NOT here. It is a real file with real # schos.img is deliberately NOT here. It is a real file with real
# prerequisites; listing it as phony made make skip the timestamp check and # prerequisites; listing it as phony made make skip the timestamp check and
# re-run the four dd commands -- including zeroing five megabytes -- on every # re-run the four dd commands -- including zeroing five megabytes -- on every
# single invocation, including ones where nothing had changed. # single invocation, including ones where nothing had changed.
@ -721,7 +721,7 @@ qemu-schfs: schunix.img $(BUILD)/schfs.img
# derives from art that changes about never, and making it a build dependency # derives from art that changes about never, and making it a build dependency
# would put Python on the critical path of every clean build for no benefit. # would put Python on the critical path of every clean build for no benefit.
# Run this by hand after changing the art. # Run this by hand after changing the art.
LOGO_SRC = Assets/Schunix Small Logo.png LOGO_SRC = Assets/SchOS Small Logo.png
LOGO_PX = 128 LOGO_PX = 128
logo: logo:
@ -729,7 +729,7 @@ logo:
# The USB vendor/product name database, from linux-usb.org. # The USB vendor/product name database, from linux-usb.org.
# #
# Dual-licensed GPL-2.0-or-later **or** 3-clause BSD; Schunix takes the BSD # Dual-licensed GPL-2.0-or-later **or** 3-clause BSD; SchOS takes the BSD
# option, which is what makes it usable at all. See NOTICE. # option, which is what makes it usable at all. See NOTICE.
# #
# Cached in dist/ and refreshed only when you ask, NOT on every build. That was # Cached in dist/ and refreshed only when you ask, NOT on every build. That was
@ -789,7 +789,7 @@ qrcheck: $(QRTEST)
# 'clean' removes generated output only. dist/ (upstream tarballs) survives, # 'clean' removes generated output only. dist/ (upstream tarballs) survives,
# so a rebuild never needs the network. # so a rebuild never needs the network.
clean: clean:
rm -rf $(BUILD) schunix.img schunix.iso kernel/arch/x86_64/vectors.S rm -rf $(BUILD) schos.img schos.iso kernel/arch/x86_64/vectors.S
distclean: clean distclean: clean
rm -rf dist rm -rf dist

22
NOTICE
View file

@ -1,16 +1,16 @@
Schunix SchOS
Copyright 2026 Nexoniarz Copyright 2026 Nexoniarz
This product includes software developed as part of the Schunix project, This product includes software developed as part of the SchOS project,
licensed under the Apache License, Version 2.0. See LICENSE. licensed under the Apache License, Version 2.0. See LICENSE.
================================================================================ ================================================================================
Third-party software Third-party software
================================================================================ ================================================================================
Schunix incorporates and redistributes software written by others. Their SchOS incorporates and redistributes software written by others. Their
licences apply to their code and are NOT superseded by the Schunix licence. licences apply to their code and are NOT superseded by the SchOS licence.
A built Schunix image contains binaries derived from all of the following. A built SchOS image contains binaries derived from all of the following.
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
xv6-x86_64 / xv6 MIT License xv6-x86_64 / xv6 MIT License
@ -18,7 +18,7 @@ xv6-x86_64 / xv6 MIT License
Copyright (c) 2006-2019 Frans Kaashoek, Robert Morris, Russ Cox, Copyright (c) 2006-2019 Frans Kaashoek, Robert Morris, Russ Cox,
Massachusetts Institute of Technology CSAIL Massachusetts Institute of Technology CSAIL
The Schunix kernel is a derivative work of xv6. Substantial portions of The SchIFT kernel is a derivative work of xv6. Substantial portions of
kernel/ -- notably the process, trap, virtual memory, buffer cache and v1 kernel/ -- notably the process, trap, virtual memory, buffer cache and v1
filesystem code -- descend from it, however heavily rewritten. The MIT licence filesystem code -- descend from it, however heavily rewritten. The MIT licence
requires that this notice be preserved in all copies; see LICENSE.MIT. requires that this notice be preserved in all copies; see LICENSE.MIT.
@ -76,7 +76,7 @@ Maintained by Stephen J. Gowdy <linux.usb.ids@gmail.com>
http://www.linux-usb.org/usb.ids http://www.linux-usb.org/usb.ids
Distributed by its maintainer under the terms of *either* the GNU General Distributed by its maintainer under the terms of *either* the GNU General
Public License version 2 or later, *or* the 3-clause BSD Licence. Schunix takes Public License version 2 or later, *or* the 3-clause BSD Licence. SchOS takes
the BSD option; the GPL option is not exercised and could not be, since the BSD option; the GPL option is not exercised and could not be, since
Apache-2.0 and GPL-2.0-only cannot be combined (see docs/licensing.md section Apache-2.0 and GPL-2.0-only cannot be combined (see docs/licensing.md section
2). 2).
@ -91,7 +91,7 @@ Roboto Apache-2.0
Copyright the Roboto Project Authors (https://github.com/googlefonts/roboto) Copyright the Roboto Project Authors (https://github.com/googlefonts/roboto)
Shipped as /usr/share/fonts/Roboto-Regular.ttf, from ports/Roboto. Licensed Shipped as /usr/share/fonts/Roboto-Regular.ttf, from ports/Roboto. Licensed
under Apache-2.0 -- the same licence as Schunix itself, so it carries no under Apache-2.0 -- the same licence as SchOS itself, so it carries no
obligation beyond this notice. Intended for the desktop, window manager and obligation beyond this notice. Intended for the desktop, window manager and
compositor. compositor.
@ -106,7 +106,7 @@ Shipped as /usr/share/fonts/JetBrainsMono-Regular.ttf, from ports/JetBrains_Mono
and TTY. and TTY.
Under the SIL Open Font License 1.1 the font remains under OFL even inside this Under the SIL Open Font License 1.1 the font remains under OFL even inside this
Apache-2.0 system -- that does not reach any other part of Schunix -- and it may Apache-2.0 system -- that does not reach any other part of SchOS -- and it may
not be sold on its own. Bundling it with an operating system is expressly not be sold on its own. Bundling it with an operating system is expressly
permitted. JetBrains Mono declares no Reserved Font Name, so a modified version permitted. JetBrains Mono declares no Reserved Font Name, so a modified version
(a pre-rasterised bitmap, for instance) may keep the name. (a pre-rasterised bitmap, for instance) may keep the name.
@ -117,7 +117,7 @@ permitted. JetBrains Mono declares no Reserved Font Name, so a modified version
Copyright (c) Qi Ma, Leyi Pan, Ao Sun, Peiran Xu Copyright (c) Qi Ma, Leyi Pan, Ao Sun, Peiran Xu
kernel/fs/fs.c and parts of tools/mkfs.c derive from this project, which extends kernel/fs/fs.c and parts of tools/mkfs.c derive from this project, which extends
xv6's file system with features Schunix still uses today: xv6's file system with features SchOS still uses today:
- the HTree hashed directory index (BKDRHash, HASHRANGE, the primary/overflow - the HTree hashed directory index (BKDRHash, HASHRANGE, the primary/overflow
bucket layout), after Daniel Phillips, "A Directory Index for EXT2", bucket layout), after Daniel Phillips, "A Directory Index for EXT2",
@ -137,7 +137,7 @@ Distinct from xv6 itself (LICENSE.MIT), which this project in turn derives from.
================================================================================ ================================================================================
The build downloads upstream tarballs into dist/ and applies the patches in The build downloads upstream tarballs into dist/ and applies the patches in
ports/<name>/patches/. Nothing in ports/ is Schunix code; do not add first-party ports/<name>/patches/. Nothing in ports/ is SchOS code; do not add first-party
work there. See docs/layout.md. work there. See docs/layout.md.
Licence questions -- what may be copied in, what may never be, and how to check Licence questions -- what may be copied in, what may never be, and how to check

View file

@ -100,7 +100,7 @@ print16:
ret ret
bootmsg: bootmsg:
.asciz "Schunix booting...\r\n" .asciz "SchOS booting...\r\n"
.code32 .code32
start32: start32:

View file

@ -469,8 +469,8 @@ static int
boot_menu(void) boot_menu(void)
{ {
const char *items[] = { const char *items[] = {
"Boot Schunix", "Boot SchOS",
"Boot Schunix (verbose)", "Boot SchOS (verbose)",
"Reboot to firmware setup", "Reboot to firmware setup",
}; };
int nitems = 3; int nitems = 3;
@ -481,7 +481,7 @@ boot_menu(void)
for (;;) { for (;;) {
fill_rect(0, 0, g_width, g_height, SCH_BG); fill_rect(0, 0, g_width, g_height, SCH_BG);
draw_centered(60, "Schunix Boot Manager", SCH_ACCENT); draw_centered(60, "SchOS Boot Manager", SCH_ACCENT);
draw_memory_line(84, SCH_DIM); draw_memory_line(84, SCH_DIM);
for (int i = 0; i < nitems; i++) { for (int i = 0; i < nitems; i++) {
@ -547,7 +547,7 @@ splash(void)
// The product, not the loader. // The product, not the loader.
// //
// This used to read "Schunix Boot Manager / version 1.0 / Memory: 1023 MB / // This used to read "SchOS Boot Manager / version 1.0 / Memory: 1023 MB /
// Press F8 for boot menu...", centred, in gold on purple. Every part of that // Press F8 for boot menu...", centred, in gold on purple. Every part of that
// is something a system shows its developer rather than its user: the name // is something a system shows its developer rather than its user: the name
// of the component doing the work, its version, and a memory figure nobody // of the component doing the work, its version, and a memory figure nobody
@ -605,7 +605,7 @@ stage2main(void)
if (g_have_fb) { if (g_have_fb) {
fill_rect(0, 0, g_width, g_height, SCH_BG); fill_rect(0, 0, g_width, g_height, SCH_BG);
draw_string((g_width - 7 * 8) / 2, g_height / 2 - 50, "SCHUNIX", SCH_ACCENT, SCH_BG); draw_string((g_width - 7 * 8) / 2, g_height / 2 - 50, "SCHOS", SCH_ACCENT, SCH_BG);
} }
// Booted from a disc we then could not read. Falling through would send // Booted from a disc we then could not read. Falling through would send
@ -646,7 +646,7 @@ stage2main(void)
stosb((void*) hdr->load_end_addr, 0, hdr->bss_end_addr - hdr->load_end_addr); stosb((void*) hdr->load_end_addr, 0, hdr->bss_end_addr - hdr->load_end_addr);
if (g_have_fb) if (g_have_fb)
progress_label("Starting Schunix..."); progress_label("Starting SchOS...");
// Jump to kernel entry. NOT a normal C call: kernel/arch/x86_64/ // Jump to kernel entry. NOT a normal C call: kernel/arch/x86_64/
// entry.S's mboot_entry reads its "argument" (the framebuffer // entry.S's mboot_entry reads its "argument" (the framebuffer

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Schunix — minimal init (PID 1) // SchOS — minimal init (PID 1)
#include "types.h" #include "types.h"
#include "user.h" #include "user.h"
@ -89,7 +89,7 @@ main(void)
mkdir("/sys"); mkdir("/sys");
xputs(1, "\nSchunix\n"); xputs(1, "\nSchOS\n");
xputs(1, "init: ready (pid 1)\n"); xputs(1, "init: ready (pid 1)\n");
for (;;) { for (;;) {
@ -102,7 +102,7 @@ main(void)
if (pid == 0) { if (pid == 0) {
// exec.c auto-enables Linux ABI for musl binaries (entry >= 0x100000). // exec.c auto-enables Linux ABI for musl binaries (entry >= 0x100000).
// Do NOT call enable_linux_abi() here — it corrupts Schunix syscall // Do NOT call enable_linux_abi() here — it corrupts SchOS syscall
// numbers for the exec/exit calls that follow in this child. // numbers for the exec/exit calls that follow in this child.
// Standardized naming: the shell is always /bin/sh, regardless of // Standardized naming: the shell is always /bin/sh, regardless of
// which implementation backs it (dash, mksh, etc.) — no ksh/mksh/ // which implementation backs it (dash, mksh, etc.) — no ksh/mksh/

View file

@ -77,19 +77,29 @@ main(void)
check(p[100] == 'X', "and so is one further into the segment"); check(p[100] == 'X', "and so is one further into the segment");
// --- file-backed mmap -------------------------------------------------- // --- file-backed mmap --------------------------------------------------
// Written and compared through one constant, and never by hand-counted
// offsets. Those offsets used to spell out SCHUNIX-MMAP-OK a character at a
// time -- m[3]=='U' and m[14]=='K' -- with the length 15 written out
// separately. Renaming the marker to SCHOS shortened it to 13 and left both
// behind: the write ran two bytes off the end of the literal and the
// compare read past the data, which failed a file-backed mmap that was
// working correctly.
static const char MARK[] = "SCHOS-MMAP-OK";
const int MARKLEN = (int)(sizeof(MARK) - 1);
int fd = open("/tmp/shmtest.dat", O_CREATE | O_RDWR); int fd = open("/tmp/shmtest.dat", O_CREATE | O_RDWR);
check(fd >= 0, "created a file to map"); check(fd >= 0, "created a file to map");
if (fd >= 0) { if (fd >= 0) {
write(fd, "SCHUNIX-MMAP-OK", 15); write(fd, MARK, MARKLEN);
close(fd); close(fd);
} }
fd = open("/tmp/shmtest.dat", O_RDONLY); fd = open("/tmp/shmtest.dat", O_RDONLY);
if (fd >= 0) { if (fd >= 0) {
char *m = mmap(0, 4096, PROT_READ, MAP_PRIVATE, fd, 0); char *m = mmap(0, 4096, PROT_READ, MAP_PRIVATE, fd, 0);
int ok = ((long)m > 0) && int ok = ((long)m > 0);
m[0]=='S' && m[1]=='C' && m[2]=='H' && m[3]=='U' && for (int i = 0; ok && i < MARKLEN; i++)
m[8]=='M' && m[13]=='O' && m[14]=='K'; ok = (m[i] == MARK[i]);
check(ok, "mmap of a file returns the file, not zeros"); check(ok, "mmap of a file returns the file, not zeros");
close(fd); close(fd);
} else { } else {

View file

@ -77,7 +77,7 @@ Bringing in toybox (see "Coreutils" below) surfaced four more, all fixed:
all (`kernel/sys/linux_abi.c`) — every external command spawn from a all (`kernel/sys/linux_abi.c`) — every external command spawn from a
program that prefers `vfork()` over `fork()` failed outright. Mapped to program that prefers `vfork()` over `fork()` failed outright. Mapped to
the existing `fork()` (a fully correct, if slightly slower, substitute). the existing `fork()` (a fully correct, if slightly slower, substitute).
- `sys_stat`/`fstat`/`fstatat` (`kernel/sys/sys_fs.c`) filled in Schunix's - `sys_stat`/`fstat`/`fstatat` (`kernel/sys/sys_fs.c`) filled in SchOS's
own native `struct stat` layout regardless of the caller — musl/toybox own native `struct stat` layout regardless of the caller — musl/toybox
parse a fixed Linux ABI byte layout instead, so `st_mode` was garbage and parse a fixed Linux ABI byte layout instead, so `st_mode` was garbage and
tools like `ls` couldn't tell files from directories, or executables from tools like `ls` couldn't tell files from directories, or executables from
@ -110,7 +110,7 @@ programs, pipes, and `ls`/`mkdir`/`grep` without issue.
## 2. Naming standardization ## 2. Naming standardization
Schunix standardizes on exactly one name per role, regardless of the SchOS standardizes on exactly one name per role, regardless of the
underlying implementation: the shell is always installed and exec'd as underlying implementation: the shell is always installed and exec'd as
`/bin/sh` (currently mksh, built from `ports/mksh/`), and PID 1 is always `/bin/sh` (currently mksh, built from `ports/mksh/`), and PID 1 is always
`/bin/init`. `cmd/init/main.c`'s exec loop only ever tries `/bin/sh` — no `/bin/init`. `cmd/init/main.c`'s exec loop only ever tries `/bin/sh` — no
@ -161,7 +161,7 @@ Split into two stages, the standard way real bootloaders solve this:
compiled size, and errors out (like `tools/sign.pl` does for stage 1) if compiled size, and errors out (like `tools/sign.pl` does for stage 1) if
it ever grows past that budget instead of silently corrupting the layout. it ever grows past that budget instead of silently corrupting the layout.
The kernel now starts at disk sector 17 instead of 1 (`schunix.img`'s `dd The kernel now starts at disk sector 17 instead of 1 (`schos.img`'s `dd
... seek=17` in the root `Makefile`, and the equivalent `+(1+STAGE2_SECTORS)` ... seek=17` in the root `Makefile`, and the equivalent `+(1+STAGE2_SECTORS)`
in `stage2main.c`'s `readseg()` — all three places that encode in `stage2main.c`'s `readseg()` — all three places that encode
`STAGE2_SECTORS` have to agree, or the kernel won't be found on disk at `STAGE2_SECTORS` have to agree, or the kernel won't be found on disk at
@ -184,7 +184,7 @@ renderer in `stage2main.c` (not the kernel's `vga.c` — paging isn't set up
yet, so the LFB physical address from the VBE block is used as a plain yet, so the LFB physical address from the VBE block is used as a plain
pointer) reusing the kernel's own font data (`include/font.h`) directly. pointer) reusing the kernel's own font data (`include/font.h`) directly.
It fills the framebuffer with PSOGM's purple (matching It fills the framebuffer with PSOGM's purple (matching
`kernel/core/console.c`'s panic screen) and draws "SCHUNIX" centered, then: `kernel/core/console.c`'s panic screen) and draws "SCHOS" centered, then:
- **Real-time loading bar**: `readsect()` (in `stage2main.c`, not the - **Real-time loading bar**: `readsect()` (in `stage2main.c`, not the
kernel) calls `progress_tick()` after every 512-byte disk read, updating kernel) calls `progress_tick()` after every 512-byte disk read, updating
@ -210,7 +210,7 @@ It fills the framebuffer with PSOGM's purple (matching
`sys_reboot()`); a real bootloader can't jump into BIOS/UEFI setup `sys_reboot()`); a real bootloader can't jump into BIOS/UEFI setup
directly, so this is the closest honest equivalent — it gives the user directly, so this is the closest honest equivalent — it gives the user
a fresh POST during which their firmware's own setup-menu key works. a fresh POST during which their firmware's own setup-menu key works.
- **Verbose boot**: picking "Boot Schunix (verbose)" writes a flag byte to - **Verbose boot**: picking "Boot SchOS (verbose)" writes a flag byte to
`BOOT_VERBOSE_FLAG_ADDR` (`VBE_INFO_ADDR + 0x100`, i.e. just past the VBE `BOOT_VERBOSE_FLAG_ADDR` (`VBE_INFO_ADDR + 0x100`, i.e. just past the VBE
block) before jumping to the kernel. `kernel/core/main.c`'s `kmain()` block) before jumping to the kernel. `kernel/core/main.c`'s `kmain()`
reads it into a global `boot_verbose` as its very first action and, if reads it into a global `boot_verbose` as its very first action and, if
@ -496,7 +496,7 @@ became an amber terminal. `include/theme.h` is now the one palette, and the
rule is: **normal states are calm and dark; only failure is loud.** PSOGM keeps rule is: **normal states are calm and dark; only failure is loud.** PSOGM keeps
the purple entirely to itself, which is what makes it mean something. the purple entirely to itself, which is what makes it mean something.
The splash copy went from "Schunix Boot Manager / version 1.0 / Memory: 1023 MB The splash copy went from "SchOS Boot Manager / version 1.0 / Memory: 1023 MB
/ Press F8 for boot menu..." to the product name, a rule in the accent colour, / Press F8 for boot menu..." to the product name, a rule in the accent colour,
and the one hint that is actionable — moved to the bottom, where a hint and the one hint that is actionable — moved to the bottom, where a hint
belongs. No shipping OS names its bootloader on the splash. belongs. No shipping OS names its bootloader on the splash.

View file

@ -1,4 +1,4 @@
# SchAPI, and Schunix as a system # SchAPI, and SchOS as a system
Status: **direction agreed, not yet implemented.** Nothing in this document Status: **direction agreed, not yet implemented.** Nothing in this document
changes what is being built this week; it changes what everything is being changes what is being built this week; it changes what everything is being
@ -8,7 +8,7 @@ built *towards*. See §7 for what actually happens now.
## 1. The decision ## 1. The decision
Schunix stops being "a Unix-like kernel with a userland bolted on" and becomes SchOS stops being "a Unix-like kernel with a userland bolted on" and becomes
a **system**: a kernel, a native API, and the services and applications that a **system**: a kernel, a native API, and the services and applications that
sit on it, designed together. sit on it, designed together.
@ -50,7 +50,7 @@ Linux made the opposite choice — the syscall ABI *is* the contract, "we do not
break userspace" — and consequently every syscall mistake ever made is still break userspace" — and consequently every syscall mistake ever made is still
there, with a `2` or a `64` suffixed to the name of its replacement. there, with a `2` or a `64` suffixed to the name of its replacement.
So, for Schunix: So, for SchOS:
``` ```
┌──────────────────────────────────────────────┐ ┌──────────────────────────────────────────────┐
@ -58,7 +58,7 @@ So, for Schunix:
├──────────────────────────────────────────────┤ ├──────────────────────────────────────────────┤
│ SchAPI │ POSIX / Linux personality│ ← THE STABLE BOUNDARY │ SchAPI │ POSIX / Linux personality│ ← THE STABLE BOUNDARY
├──────────────────┴───────────────────────────┤ ├──────────────────┴───────────────────────────┤
│ libschunix — the only thing that may syscall│ │ libschos — the only thing that may syscall│
├──────────────────────────────────────────────┤ ├──────────────────────────────────────────────┤
│ syscall table — PRIVATE, unstable, renumberable │ syscall table — PRIVATE, unstable, renumberable
├──────────────────────────────────────────────┤ ├──────────────────────────────────────────────┤
@ -69,11 +69,11 @@ So, for Schunix:
Rules that follow, and they are not negotiable if the promise is to hold: Rules that follow, and they are not negotiable if the promise is to hold:
1. **A program that issues `syscall` directly is unsupported.** It may break at 1. **A program that issues `syscall` directly is unsupported.** It may break at
any release. Only `libschunix` may. any release. Only `libschos` may.
2. `libschunix` exports versioned symbols. An entry point's behaviour never 2. `libschos` exports versioned symbols. An entry point's behaviour never
changes; a changed behaviour is a new version of the symbol. changes; a changed behaviour is a new version of the symbol.
3. The kernel may renumber, merge, split or delete syscalls at will, provided 3. The kernel may renumber, merge, split or delete syscalls at will, provided
`libschunix` still presents the same surface. `libschos` still presents the same surface.
This *reconciles* with the existing decision to adopt Linux syscall numbering This *reconciles* with the existing decision to adopt Linux syscall numbering
(`docs/roadmap.md`, and the reason musl/toybox/mksh work at all). Linux (`docs/roadmap.md`, and the reason musl/toybox/mksh work at all). Linux
@ -98,7 +98,7 @@ Every public interface carries exactly one tier:
| `provisional` | Until the next release | Freely | | `provisional` | Until the next release | Freely |
| `internal` | None | Freely, without notice | | `internal` | None | Freely, without notice |
**Everything in Schunix today is `provisional`.** The freeze starts at 1.0 and **Everything in SchOS today is `provisional`.** The freeze starts at 1.0 and
covers only what is marked `stable` at that moment. This is not a way of covers only what is marked `stable` at that moment. This is not a way of
dodging the commitment — it is the only way to make it, because a promise made dodging the commitment — it is the only way to make it, because a promise made
now would permanently enshrine, among other things, a `fcntl(F_SETFL)` that now would permanently enshrine, among other things, a `fcntl(F_SETFL)` that
@ -164,7 +164,7 @@ reasons that a single tree cannot give:
That table is the same lesson §1 of the roadmap already learned the hard way That table is the same lesson §1 of the roadmap already learned the hard way
with FreeBSD's `sys/dev/usb`: 100k lines welded to newbus, where porting the with FreeBSD's `sys/dev/usb`: 100k lines welded to newbus, where porting the
USB stack means porting the device framework first. Networking is the same USB stack means porting the device framework first. Networking is the same
shape. Read FreeBSD, lift NetBSD, write Schunix. shape. Read FreeBSD, lift NetBSD, write SchOS.
### Licensing — read this before copying anything ### Licensing — read this before copying anything
@ -181,7 +181,7 @@ Ranked by value, not by size:
1. **`sys/net`, `sys/netinet` — the TCP/IP stack.** The largest single win 1. **`sys/net`, `sys/netinet` — the TCP/IP stack.** The largest single win
available. Phase 2 of the roadmap wants ARP/IPv4/ICMP/UDP/TCP, and this is a available. Phase 2 of the roadmap wants ARP/IPv4/ICMP/UDP/TCP, and this is a
mature, clean, readable, 2-clause-heavy implementation of exactly that. mature, clean, readable, 2-clause-heavy implementation of exactly that.
2. **`sys/kern/subr_pool.c` — the pool/slab allocator.** Schunix has `kalloc` 2. **`sys/kern/subr_pool.c` — the pool/slab allocator.** SchOS has `kalloc`
and a page at a time. Every subsystem written since has invented its own and a page at a time. Every subsystem written since has invented its own
fixed-size table to work around that. fixed-size table to work around that.
3. **`autoconf` — the driver framework** (`config(1)`, `cfdriver`/`cfattach`, 3. **`autoconf` — the driver framework** (`config(1)`, `cfdriver`/`cfattach`,
@ -203,7 +203,7 @@ relicensed-in-notice, and maintained forever under the §3 promise.
Not yet designed. What is decided about it: Not yet designed. What is decided about it:
- It is the native interface; POSIX is available beneath it but not the idiom. - It is the native interface; POSIX is available beneath it but not the idiom.
- It is reached through `libschunix`, never by direct syscall. - It is reached through `libschos`, never by direct syscall.
- It is designed *with* Schcom in mind, because a compositor and its clients - It is designed *with* Schcom in mind, because a compositor and its clients
are the first real users and their needs (IPC, shared buffers, event streams, are the first real users and their needs (IPC, shared buffers, event streams,
object lifetimes) are what will shape it. object lifetimes) are what will shape it.
@ -234,6 +234,6 @@ What this document changes *today* is only this:
something to work with at 1.0. something to work with at 1.0.
3. When the network stack is written, NetBSD's is the starting point rather 3. When the network stack is written, NetBSD's is the starting point rather
than a blank file — with the licence check in §5 applied per file. than a blank file — with the licence check in §5 applied per file.
4. `libschunix` is created when there is a second personality to justify it. 4. `libschos` is created when there is a second personality to justify it.
Until then, the *rule* stands even though the library does not exist yet: Until then, the *rule* stands even though the library does not exist yet:
no new first-party program issues raw syscalls. no new first-party program issues raw syscalls.

View file

@ -42,7 +42,7 @@ end to end.
## 2. What is deliberately not taken ## 2. What is deliberately not taken
- **No ZFS storage pools / RAID-Z / vdevs.** Multi-disk redundancy is a large - **No ZFS storage pools / RAID-Z / vdevs.** Multi-disk redundancy is a large
subsystem that solves a problem Schunix does not have yet. subsystem that solves a problem SchOS does not have yet.
- **No btrfs-style rebalancing or online format conversion.** Enormous - **No btrfs-style rebalancing or online format conversion.** Enormous
complexity, and it is the historical source of btrfs's worst bugs. complexity, and it is the historical source of btrfs's worst bugs.
- **No actual SQL.** No parser, no query planner, no relational engine. See §6 — - **No actual SQL.** No parser, no query planner, no relational engine. See §6 —
@ -242,7 +242,7 @@ Phases 1-3 are roughly 3,000-4,000 lines and are the bulk of the work. Phase 1
alone (B-tree + torture harness) is worth doing carefully and unhurriedly; every alone (B-tree + torture harness) is worth doing carefully and unhurriedly; every
later phase compounds on it. later phase compounds on it.
This is the largest single piece of work in Schunix. It is also entirely This is the largest single piece of work in SchOS. It is also entirely
ordinary filesystem engineering with excellent published references ordinary filesystem engineering with excellent published references
(Giampaolo for BeFS; the btrfs design papers; the ZFS uberblock/checksum-in- (Giampaolo for BeFS; the btrfs design papers; the ZFS uberblock/checksum-in-
parent scheme) — there is no research risk here, only volume. parent scheme) — there is no research risk here, only volume.
@ -254,7 +254,7 @@ populate this format. Building it against v1 means building it twice.
Three different things get called "the limit", and they are worth keeping apart: Three different things get called "the limit", and they are worth keeping apart:
what the **on-disk format** can express, what **this implementation** can what the **on-disk format** can express, what **this implementation** can
currently mount, and what the **rest of Schunix** can carry. The smallest one is currently mount, and what the **rest of SchOS** can carry. The smallest one is
what you actually hit. what you actually hit.
### The format ### The format
@ -292,7 +292,7 @@ raising `SCHFS_SPACE_PAGES` to 4096 makes it 512 GiB at 64 KiB of pointers per
mount. It is set where it is because the page-pointer vector lives inside mount. It is set where it is because the page-pointer vector lives inside
`struct schfs_vol`, which the kernel holds as static storage. `struct schfs_vol`, which the kernel holds as static storage.
### The rest of Schunix ### The rest of SchOS
These are VFS and driver limits rather than SchFS ones: These are VFS and driver limits rather than SchFS ones:

View file

@ -75,9 +75,9 @@ need.
## 3. Linux drivers ## 3. Linux drivers
**Decided 2026-08-08.** Linux drivers are not shipped with Schunix and never **Decided 2026-08-08.** Linux drivers are not shipped with SchOS and never
will be. The user may install one on their own machine, through a device will be. The user may install one on their own machine, through a device
manager or equivalent, and Schunix will load it. manager or equivalent, and SchOS will load it.
The licensing reasoning matters and is worth stating exactly, because it is The licensing reasoning matters and is worth stating exactly, because it is
easy to get wrong in both directions: easy to get wrong in both directions:

View file

@ -9,7 +9,7 @@ that can't be rebuilt (except upstream tarballs, which live in `dist/` and are
deliberately kept out of `clean`). deliberately kept out of `clean`).
``` ```
schunix/ schos/
├─ boot/ Stage 1 MBR + stage 2 loader (splash, F8 menu, kernel load) ├─ boot/ Stage 1 MBR + stage 2 loader (splash, F8 menu, kernel load)
├─ kernel/ The kernel, by subsystem: arch/ core/ dev/ fs/ proc/ sys/ ├─ kernel/ The kernel, by subsystem: arch/ core/ dev/ fs/ proc/ sys/
├─ include/ Headers shared by kernel, userland, and tools/mkfs ├─ include/ Headers shared by kernel, userland, and tools/mkfs
@ -19,7 +19,7 @@ schunix/
│ cmd/<name>/main.c → sysroot/bin/<name> │ cmd/<name>/main.c → sysroot/bin/<name>
├─ ports/ Third-party software — one directory per port. ├─ ports/ Third-party software — one directory per port.
│ Contains ONLY a Makefile and optional patches/. │ Contains ONLY a Makefile and optional patches/.
├─ projects/ Things that run ON Schunix rather than things that ARE it: ├─ projects/ Things that run ON SchOS rather than things that ARE it:
│ the compositor, window manager, desktop, and installer. │ the compositor, window manager, desktop, and installer.
│ Not part of the kernel build. See projects/README.md. │ Not part of the kernel build. See projects/README.md.
├─ tools/ Host-side helpers, SOURCE ONLY: mkfs.c, the SchFS test ├─ tools/ Host-side helpers, SOURCE ONLY: mkfs.c, the SchFS test

View file

@ -1,13 +1,13 @@
# Licensing # Licensing
The one page to check before copying anyone else's code into Schunix. The one page to check before copying anyone else's code into SchOS.
Referenced from `LICENSE`, `LICENSE.MIT` and `NOTICE`, all three of which Referenced from `LICENSE`, `LICENSE.MIT` and `NOTICE`, all three of which
pointed here long before this file existed. pointed here long before this file existed.
--- ---
## 1. Schunix is Apache-2.0 ## 1. SchOS is Apache-2.0
Copyright Nexoniarz. See `LICENSE`. Copyright Nexoniarz. See `LICENSE`.
@ -19,7 +19,7 @@ outside contributions, that silence is the expensive kind.
What that grant means in practice: Apache-2.0 §2 gives everyone a perpetual, What that grant means in practice: Apache-2.0 §2 gives everyone a perpetual,
worldwide, irrevocable licence to reproduce, modify, sublicense and distribute worldwide, irrevocable licence to reproduce, modify, sublicense and distribute
Schunix. Any additional restriction stated elsewhere — in a README, a website, SchOS. Any additional restriction stated elsewhere — in a README, a website,
or a policy — does not narrow it. The licence text is what holds up. or a policy — does not narrow it. The licence text is what holds up.
If restricted distribution is ever genuinely wanted, that is a licence change If restricted distribution is ever genuinely wanted, that is a licence change
@ -57,7 +57,7 @@ licences at once.
GPL-3.0 fixed this in the other direction (Apache-2.0 is compatible *into* GPL-3.0 fixed this in the other direction (Apache-2.0 is compatible *into*
GPLv3), but that does not help: the result would have to ship under GPLv3, and GPLv3), but that does not help: the result would have to ship under GPLv3, and
Schunix does not. SchOS does not.
**Practical consequence:** BSD drivers can be adopted. Linux drivers cannot, **Practical consequence:** BSD drivers can be adopted. Linux drivers cannot,
ever, no matter how convenient. This is why the USB stack was written from the ever, no matter how convenient. This is why the USB stack was written from the
@ -113,7 +113,7 @@ sys/netinet6 51 files, 5 " " "
``` ```
Encouraging at first glance — the 25 in `sys/netinet` are almost all SCTP, Encouraging at first glance — the 25 in `sys/netinet` are almost all SCTP,
DCCP and multicast routing, none of which Schunix needs. `ip_input.c`, DCCP and multicast routing, none of which SchOS needs. `ip_input.c`,
`ip_output.c`, `udp_usrreq.c`, `if_arp.c`, `ip_icmp.c`, `if.c` and `route.c` `ip_output.c`, `udp_usrreq.c`, `if_arp.c`, `ip_icmp.c`, `if.c` and `route.c`
are all UC 3-clause, i.e. fine. are all UC 3-clause, i.e. fine.
@ -161,7 +161,7 @@ tables and FreeBSD's locking. Taking it means porting FreeBSD's kernel
infrastructure first and finding the TCP somewhere underneath, which is the same infrastructure first and finding the TCP somewhere underneath, which is the same
conclusion `docs/roadmap.md` §1 already reached about `sys/dev/usb`. conclusion `docs/roadmap.md` §1 already reached about `sys/dev/usb`.
lwIP was written for the case Schunix is in: a small operating system with a raw lwIP was written for the case SchOS is in: a small operating system with a raw
Ethernet driver and no infrastructure to speak of. Its port layer is a handful Ethernet driver and no infrastructure to speak of. Its port layer is a handful
of files, it has no dependency on the host kernel's allocator or locking, and it of files, it has no dependency on the host kernel's allocator or locking, and it
brings ARP, IPv4, ICMP, UDP, TCP, DHCP and DNS. brings ARP, IPv4, ICMP, UDP, TCP, DHCP and DNS.
@ -175,7 +175,7 @@ Chosen 2026-08-09, both licences checked at source rather than assumed:
| Roboto | desktop, window manager, compositor | **Apache-2.0** | | Roboto | desktop, window manager, compositor | **Apache-2.0** |
| JetBrains Mono | terminal, TTY | **SIL OFL 1.1** | | JetBrains Mono | terminal, TTY | **SIL OFL 1.1** |
Roboto is the same licence as Schunix, so it is the easy case: a NOTICE entry Roboto is the same licence as SchOS, so it is the easy case: a NOTICE entry
and nothing else. and nothing else.
OFL is permissive and bundling is precisely what it is for, with two conditions OFL is permissive and bundling is precisely what it is for, with two conditions
@ -195,7 +195,7 @@ worth knowing before anyone subsets or converts a font:
## 4. Things that are deliberately not shipped ## 4. Things that are deliberately not shipped
Some code is fine to *build and run locally* and impossible to *distribute* Some code is fine to *build and run locally* and impossible to *distribute*
with Schunix. Keeping the distinction sharp is what stops it eroding: with SchOS. Keeping the distinction sharp is what stops it eroding:
- **`Refrence/`** — a FreeBSD checkout (`Refrence/freebsd-src`), kept as - **`Refrence/`** — a FreeBSD checkout (`Refrence/freebsd-src`), kept as
reference material and a parts bin. Never built, never in an image. The reference material and a parts bin. Never built, never in an image. The

View file

@ -7,7 +7,7 @@ plus an installer and a `.sip` package format.
This file records two things that are easy to lose: the *order* the work has This file records two things that are easy to lose: the *order* the work has
to happen in, and the decisions that constrain it. to happen in, and the decisions that constrain it.
**Superseded in direction, not in order.** Schunix is now aimed at being a **Superseded in direction, not in order.** SchOS is now aimed at being a
*system* rather than a Unix-like kernel with a userland attached: a NeXTSTEP/ *system* rather than a Unix-like kernel with a userland attached: a NeXTSTEP/
macOS-shaped layering, with POSIX kept complete but demoted from identity to macOS-shaped layering, with POSIX kept complete but demoted from identity to
personality, and a native API (**SchAPI**) above it. See personality, and a native API (**SchAPI**) above it. See
@ -189,7 +189,7 @@ width text is not a font change, it is a text-rendering layer.
as-is if wanted; writing one is also reasonable and more interesting as-is if wanted; writing one is also reasonable and more interesting
- [ ] **The typefaces, decided 2026-08-09.** Both verified, not assumed: - [ ] **The typefaces, decided 2026-08-09.** Both verified, not assumed:
**Roboto** for the desktop, window manager and compositor -- **Roboto** for the desktop, window manager and compositor --
**Apache-2.0**, the same licence as Schunix, so it needs nothing beyond a **Apache-2.0**, the same licence as SchOS, so it needs nothing beyond a
NOTICE entry. NOTICE entry.
**JetBrains Mono** for the terminal and TTY -- **SIL OFL 1.1**, and **JetBrains Mono** for the terminal and TTY -- **SIL OFL 1.1**, and
notably with *no* Reserved Font Name declared, so it may be modified and notably with *no* Reserved Font Name declared, so it may be modified and
@ -205,7 +205,7 @@ width text is not a font change, it is a text-rendering layer.
**Font licensing: public domain or very permissive only.** No SIL OFL if it **Font licensing: public domain or very permissive only.** No SIL OFL if it
can be avoided, no "free for personal use", no CC-BY-SA. The constraint is can be avoided, no "free for personal use", no CC-BY-SA. The constraint is
the same one that governs drivers (§1): a font file is redistributed inside the same one that governs drivers (§1): a font file is redistributed inside
every Schunix image, so its licence attaches to the image. every SchOS image, so its licence attaches to the image.
Safe choices, in rough order of usefulness: Safe choices, in rough order of usefulness:
@ -237,7 +237,7 @@ key-down/key-up with modifiers and no line discipline at all — an evdev-style
### Phase 6 — Installer and `.sip` ### Phase 6 — Installer and `.sip`
`.sip` (Schunix Installation Package), the stated model being WIM in Windows `.sip` (SchOS Installation Package), the stated model being WIM in Windows
PE: a *file-based* image rather than a block image, so one file can hold a PE: a *file-based* image rather than a block image, so one file can hold a
whole filesystem, be applied to a partition of any size, and hold several whole filesystem, be applied to a partition of any size, and hold several
images that share their common files. images that share their common files.
@ -301,7 +301,7 @@ sysvinit is not the config format, it is *demand launching*: launchd holds the
listening socket or watches the path, and starts the job when something actually listening socket or watches the path, and starts the job when something actually
arrives. That inverts the dependency graph — jobs stop needing to declare what arrives. That inverts the dependency graph — jobs stop needing to declare what
must start before them, because the thing they depend on answers on first use. must start before them, because the thing they depend on answers on first use.
Schunix already has the two pieces that makes possible: `AF_UNIX` sockets SchOS already has the two pieces that makes possible: `AF_UNIX` sockets
(`kernel/net/unix.c`) and a real `/proc`. What is missing is a supervisor that (`kernel/net/unix.c`) and a real `/proc`. What is missing is a supervisor that
can hold a socket on a job's behalf and hand it over on exec, plus a job can hold a socket on a job's behalf and hand it over on exec, plus a job
description format. Prerequisite for this being worth anything: `ps` and `top` description format. Prerequisite for this being worth anything: `ps` and `top`
@ -360,7 +360,7 @@ palette and a layout, none of which care how the pixels were found. What does
not survive is every assumption in `stage2main.c` about where things live in low not survive is every assumption in `stage2main.c` about where things live in low
memory (see `docs/layout.md`). memory (see `docs/layout.md`).
### SchFS beyond Schunix ### SchFS beyond SchOS
Three ideas parked 2026-08-08, in the order they should happen. Three ideas parked 2026-08-08, in the order they should happen.
@ -447,7 +447,7 @@ Three details worth keeping:
- The ceiling is **3 GB**, because `kvmalloc()` maps 0–4 GB as four 1 GB pages - The ceiling is **3 GB**, because `kvmalloc()` maps 0–4 GB as four 1 GB pages
and marks the top one uncached for PCI BARs. and marks the top one uncached for PCI BARs.
- Below `PHYSTOP_MIN` it prints why and stops, rather than triple faulting in - Below `PHYSTOP_MIN` it prints why and stops, rather than triple faulting in
silence. At 24 MB: `e820: only 23 MB usable; Schunix needs at least 24 MB`. silence. At 24 MB: `e820: only 23 MB usable; SchOS needs at least 24 MB`.
The original text is kept below because the reasoning still applies to the SMP The original text is kept below because the reasoning still applies to the SMP
half of §3b, which is the same shape of bug: a constant nobody revisited. half of §3b, which is the same shape of bug: a constant nobody revisited.

View file

@ -1,8 +1,8 @@
// Error numbers, matching the Linux x86_64 ABI values so that musl-linked // Error numbers, matching the Linux x86_64 ABI values so that musl-linked
// programs interpret syscall failures correctly. Kernel code returns these // programs interpret syscall failures correctly. Kernel code returns these
// negated (e.g. `return -ENOSYS;`), exactly like Linux does internally. // negated (e.g. `return -ENOSYS;`), exactly like Linux does internally.
#ifndef SCHUNIX_ERRNO_H #ifndef SCHOS_ERRNO_H
#define SCHUNIX_ERRNO_H #define SCHOS_ERRNO_H
#define EPERM 1 // Operation not permitted #define EPERM 1 // Operation not permitted
#define ENOENT 2 // No such file or directory #define ENOENT 2 // No such file or directory
@ -57,4 +57,4 @@
#define ENOTCONN 107 // Transport endpoint is not connected #define ENOTCONN 107 // Transport endpoint is not connected
#define ECONNREFUSED 111 // Connection refused #define ECONNREFUSED 111 // Connection refused
#endif // SCHUNIX_ERRNO_H #endif // SCHOS_ERRNO_H

View file

@ -3,7 +3,7 @@
// Framebuffer device ABI -- /dev/fb0. // Framebuffer device ABI -- /dev/fb0.
// //
// These are Linux's fbdev request numbers and structure layouts, not ours. // These are Linux's fbdev request numbers and structure layouts, not ours.
// Schunix invented this device, so nothing forced the choice; matching Linux // SchOS invented this device, so nothing forced the choice; matching Linux
// was still the right one. A framebuffer is the first thing a graphics // was still the right one. A framebuffer is the first thing a graphics
// program looks for, and every such program already knows how to ask // program looks for, and every such program already knows how to ask
// FBIOGET_VSCREENINFO. Inventing a private struct would have meant patching // FBIOGET_VSCREENINFO. Inventing a private struct would have meant patching
@ -76,7 +76,7 @@ struct fb_var_screeninfo {
}; };
struct fb_fix_screeninfo { struct fb_fix_screeninfo {
char id[16]; // "schunixfb" char id[16]; // "schosfb"
unsigned long smem_start; // physical address of the framebuffer unsigned long smem_start; // physical address of the framebuffer
unsigned int smem_len; // its length in bytes unsigned int smem_len; // its length in bytes
unsigned int type; unsigned int type;

View file

@ -6,7 +6,7 @@
// the userland is built against a libc that sends Linux flag values, and the // the userland is built against a libc that sends Linux flag values, and the
// kernel reads them with these constants. They disagreed for a long time, with // kernel reads them with these constants. They disagreed for a long time, with
// results that looked like filesystem corruption rather than like a mistake -- // results that looked like filesystem corruption rather than like a mistake --
// Linux O_APPEND (0x400) landed on Schunix's O_TRUNC, so `cmd >> file` // Linux O_APPEND (0x400) landed on SchOS's O_TRUNC, so `cmd >> file`
// truncated the file it was meant to extend, and Linux O_TRUNC (0x200) landed // truncated the file it was meant to extend, and Linux O_TRUNC (0x200) landed
// on O_CREATE, so `cmd > file` left whatever was past the new end in place. // on O_CREATE, so `cmd > file` left whatever was past the new end in place.
// Neither failure pointed anywhere near a header. // Neither failure pointed anywhere near a header.
@ -29,7 +29,7 @@
#define O_NOFOLLOW 0x020000 /* Linux O_NOFOLLOW (0400000) */ #define O_NOFOLLOW 0x020000 /* Linux O_NOFOLLOW (0400000) */
#define O_CLOEXEC 0x080000 /* Linux O_CLOEXEC (02000000) */ #define O_CLOEXEC 0x080000 /* Linux O_CLOEXEC (02000000) */
// Schunix-only, placed above every flag Linux defines so it can never be // SchOS-only, placed above every flag Linux defines so it can never be
// mistaken for one. 0x40000 was used before and collides with Linux O_NOATIME. // mistaken for one. 0x40000 was used before and collides with Linux O_NOATIME.
#define O_EXTENT 0x8000000 /* sparse-extent hint */ #define O_EXTENT 0x8000000 /* sparse-extent hint */

View file

@ -1,4 +1,4 @@
/* Schunix OS System Font - 8x16, 256 glyphs. /* SchOS OS System Font - 8x16, 256 glyphs.
* *
* The upper half is CP437, the IBM PC character set: 0x82 is 'e' with an * The upper half is CP437, the IBM PC character set: 0x82 is 'e' with an
* acute, 0xE9 is a capital theta, 0xB0-0xDF are shading and box-drawing. * acute, 0xE9 is a capital theta, 0xB0-0xDF are shading and box-drawing.

View file

@ -81,7 +81,7 @@ struct input_event {
// EVIOCGRAB -- take/release exclusive access to a device. // EVIOCGRAB -- take/release exclusive access to a device.
// //
// Linux's _IOW('E', 0x90, int). Spelled as the resulting constant rather than // Linux's _IOW('E', 0x90, int). Spelled as the resulting constant rather than
// built from an _IOW macro because Schunix has no ioctl-encoding macros and // built from an _IOW macro because SchOS has no ioctl-encoding macros and
// inventing a set just for this would be a bigger change than the feature. // inventing a set just for this would be a bigger change than the feature.
// A non-zero argument grabs, zero releases; the argument is passed by value. // A non-zero argument grabs, zero releases; the argument is passed by value.
#define EVIOCGRAB 0x40044590 #define EVIOCGRAB 0x40044590

View file

@ -1,7 +1,7 @@
#pragma once #pragma once
// GENERATED by tools/mklogo.py -- do not edit. Run `make logo`. // GENERATED by tools/mklogo.py -- do not edit. Run `make logo`.
// source: Assets/Schunix Small Logo.png // source: Assets/SchOS Small Logo.png
// //
// An ink-coverage mask, not colour: 0 is background and full scale is // An ink-coverage mask, not colour: 0 is background and full scale is
// solid logo. Whoever draws it picks the colour, so the palette stays in // solid logo. Whoever draws it picks the colour, so the palette stays in

View file

@ -2,7 +2,7 @@
// PCI bus enumeration and driver binding. // PCI bus enumeration and driver binding.
// //
// Until this existed, every driver in Schunix found its hardware by knowing // Until this existed, every driver in SchOS found its hardware by knowing
// where it was: IDE at 0x1F0 because IDE has always been at 0x1F0, the // where it was: IDE at 0x1F0 because IDE has always been at 0x1F0, the
// framebuffer wherever the BIOS's VBE call said. That works for exactly the // framebuffer wherever the BIOS's VBE call said. That works for exactly the
// devices that predate PCI and for nothing else. A NIC, an AHCI controller, // devices that predate PCI and for nothing else. A NIC, an AHCI controller,

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Schunix — POSIX-compatibility types used by kernel syscall handlers. // SchOS — POSIX-compatibility types used by kernel syscall handlers.
#pragma once #pragma once
#include "types.h" #include "types.h"
#include "date.h" #include "date.h"

View file

@ -1,6 +1,6 @@
#pragma once #pragma once
// Schunix visual identity — one palette, shared by everything that draws. // SchOS visual identity — one palette, shared by everything that draws.
// //
// This header exists because there were three unrelated designs and the seams // This header exists because there were three unrelated designs and the seams
// showed. The bootloader splash was deep purple with gold text, deliberately // showed. The bootloader splash was deep purple with gold text, deliberately

View file

@ -11,13 +11,13 @@
// unrelated physical page at the next 4K boundary. Any multi-byte // unrelated physical page at the next 4K boundary. Any multi-byte
// access through it must stay within a single page. // access through it must stay within a single page.
// //
// These helpers encapsulate both rules. Because Schunix (like old x86 // These helpers encapsulate both rules. Because SchOS (like old x86
// without SMAP) keeps the user page table active in kernel mode, a raw // without SMAP) keeps the user page table active in kernel mode, a raw
// user virtual address is directly dereferenceable once the whole range // user virtual address is directly dereferenceable once the whole range
// has been validated — that is what user_ptr() hands back, and why the // has been validated — that is what user_ptr() hands back, and why the
// result is safe across page boundaries where a uva2ka() pointer is not. // result is safe across page boundaries where a uva2ka() pointer is not.
#ifndef SCHUNIX_UACCESS_H #ifndef SCHOS_UACCESS_H
#define SCHUNIX_UACCESS_H #define SCHOS_UACCESS_H
#include "types.h" #include "types.h"
@ -46,4 +46,4 @@ int copy_to_user(addr_t uaddr, const void *src, uint64 n);
// or exceeds USER_STR_MAX. // or exceeds USER_STR_MAX.
long strlen_user(addr_t uaddr); long strlen_user(addr_t uaddr);
#endif // SCHUNIX_UACCESS_H #endif // SCHOS_UACCESS_H

View file

@ -5,7 +5,7 @@
// it is an assertion that exactly that much exists. Boot a machine with less // it is an assertion that exactly that much exists. Boot a machine with less
// and kinit1() walks off the end of RAM into nothing; boot one with more and // and kinit1() walks off the end of RAM into nothing; boot one with more and
// every byte above 224 MB is invisible. Measured before this file existed: // every byte above 224 MB is invisible. Measured before this file existed:
// Schunix booted at 224 MB and triple faulted at 192 MB, for no reason at all. // SchOS booted at 224 MB and triple faulted at 192 MB, for no reason at all.
// //
// The firmware has known the answer the whole time. boot/stage2.S asks it with // The firmware has known the answer the whole time. boot/stage2.S asks it with
// INT 0x15 / E820 in real mode -- the same interface Linux's boot stub and GRUB // INT 0x15 / E820 in real mode -- the same interface Linux's boot stub and GRUB
@ -92,7 +92,7 @@ e820_init(void)
// Below this the kernel image, its page tables and the DMA arena do not fit, // Below this the kernel image, its page tables and the DMA arena do not fit,
// and continuing produces a failure much harder to read than this line. // and continuing produces a failure much harder to read than this line.
if (top < PHYSTOP_MIN) { if (top < PHYSTOP_MIN) {
cprintf("e820: only %d MB usable; Schunix needs at least %d MB\n", cprintf("e820: only %d MB usable; SchOS needs at least %d MB\n",
(int)(top / (1024 * 1024)), (int)(PHYSTOP_MIN / (1024 * 1024))); (int)(top / (1024 * 1024)), (int)(PHYSTOP_MIN / (1024 * 1024)));
// Left at the fallback deliberately rather than lowered: a machine this // Left at the fallback deliberately rather than lowered: a machine this
// small is going to fail, and it should fail having said why. // small is going to fail, and it should fail having said why.

View file

@ -142,7 +142,7 @@ seginit(void)
// and SS from +8, so the *slot* must exist to keep the // and SS from +8, so the *slot* must exist to keep the
// [UCODE32, UDATA, UCODE] triple consecutive. See syscallinit. // [UCODE32, UDATA, UCODE] triple consecutive. See syscallinit.
// SEG_KCPU is a leftover slot number from 32-bit xv6, where %gs held the // SEG_KCPU is a leftover slot number from 32-bit xv6, where %gs held the
// per-CPU pointer. Schunix uses FS_BASE/TLS instead, but the // per-CPU pointer. SchOS uses FS_BASE/TLS instead, but the
// index has to stay occupied or SEG_TSS stops landing at 7. // index has to stay occupied or SEG_TSS stops landing at 7.
// //
// Deleting either moves every descriptor after it and breaks sysret. // Deleting either moves every descriptor after it and breaks sysret.

View file

@ -13,7 +13,7 @@ static void mpmain(void) __attribute__((noreturn));
extern char end[]; // first address after kernel loaded from ELF file extern char end[]; // first address after kernel loaded from ELF file
// Set by stage2main.c (boot/stage2main.c, BOOT_VERBOSE_FLAG_ADDR) when the // Set by stage2main.c (boot/stage2main.c, BOOT_VERBOSE_FLAG_ADDR) when the
// user picks "Boot Schunix (verbose)" from the F8 boot menu; read once here, // user picks "Boot SchOS (verbose)" from the F8 boot menu; read once here,
// before anything else, so subsystem init can log its own steps. // before anything else, so subsystem init can log its own steps.
int boot_verbose; int boot_verbose;

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
// PSOGM — the Schunix crash screen. // PSOGM — the SchOS crash screen.
// //
// The name is a nod to the Amiga's "Guru Meditation", but nothing else about // The name is a nod to the Amiga's "Guru Meditation", but nothing else about
// this is a nod to 1985. Three things it is built around: // this is a nod to 1985. Three things it is built around:
@ -439,7 +439,7 @@ paint(char *reason, addr_t *pcs, int npcs)
// Left-aligned, not centred. Centred text reads as a poster; this is a // Left-aligned, not centred. Centred text reads as a poster; this is a
// report, and a report is read down the left edge. // report, and a report is read down the left edge.
vga_text_at(left, y, "Schunix ran into a problem and needs to restart.", vga_text_at(left, y, "SchOS ran into a problem and needs to restart.",
PSOGM_FG); PSOGM_FG);
y += ch + ch / 2; y += ch + ch / 2;
vga_text_at(left, y, "Nothing on your disks was touched by this.", vga_text_at(left, y, "Nothing on your disks was touched by this.",
@ -492,7 +492,7 @@ report_serial(char *reason, addr_t *pcs, int npcs)
{ {
cprintf("\n"); cprintf("\n");
cprintf(" :(\n\n"); cprintf(" :(\n\n");
cprintf(" Schunix ran into a problem and needs to restart.\n"); cprintf(" SchOS ran into a problem and needs to restart.\n");
cprintf(" PSOGM -- Purple Screen of Guru Meditation\n\n"); cprintf(" PSOGM -- Purple Screen of Guru Meditation\n\n");
for (int i = 0; i < nfields; i++) { for (int i = 0; i < nfields; i++) {

View file

@ -3,7 +3,7 @@
// The kernel has always known how long it had been running -- `ticks`, bumped // The kernel has always known how long it had been running -- `ticks`, bumped
// 100 times a second by the timer interrupt -- and has never known what time it // 100 times a second by the timer interrupt -- and has never known what time it
// was. sys_gettimeofday() returned `ticks / 100` as though it were seconds // was. sys_gettimeofday() returned `ticks / 100` as though it were seconds
// since the epoch, so every Schunix machine believed it was the 1st of January // since the epoch, so every SchOS machine believed it was the 1st of January
// 1970 and that the date advanced at the rate of its own uptime. `date` printed // 1970 and that the date advanced at the rate of its own uptime. `date` printed
// a number that barely moved, which is what it looks like when a clock is // a number that barely moved, which is what it looks like when a clock is
// counting from the wrong place rather than not counting at all. // counting from the wrong place rather than not counting at all.

View file

@ -281,7 +281,7 @@ text_selftest(void)
int line = f->ops->height(f) + 6; int line = f->ops->height(f) + 6;
int y = 80; int y = 80;
text_draw(&s, f, 60, y + base, "Schunix text rendering", SCH_FG); text_draw(&s, f, 60, y + base, "SchOS text rendering", SCH_FG);
y += line * 2; y += line * 2;
// Deliberately not on a multiple of eight. On the old console this string // Deliberately not on a multiple of eight. On the old console this string

View file

@ -179,7 +179,7 @@ fb_ioctl(int request, addr_t arg)
if (!f) if (!f)
return -EFAULT; return -EFAULT;
memset(f, 0, sizeof(*f)); memset(f, 0, sizeof(*f));
safestrcpy(f->id, "schunixfb", sizeof(f->id)); safestrcpy(f->id, "schosfb", sizeof(f->id));
f->smem_start = (unsigned long)vga_fb_phys(); f->smem_start = (unsigned long)vga_fb_phys();
f->smem_len = (unsigned int)vga_fb_size(); f->smem_len = (unsigned int)vga_fb_size();
f->type = FB_TYPE_PACKED_PIXELS; f->type = FB_TYPE_PACKED_PIXELS;

View file

@ -143,7 +143,7 @@ gen_cpuinfo(struct sbuf *sb)
// otherwise be told a VM with four processors has four to schedule on, when // otherwise be told a VM with four processors has four to schedule on, when
// three of them are enumerated and idle. "cpu cores" stays the present count, // three of them are enumerated and idle. "cpu cores" stays the present count,
// which is what that field means. // which is what that field means.
// Real values, from CPUID. These used to read "Schunix" and "Schunix virtual // Real values, from CPUID. These used to read "SchOS" and "SchOS virtual
// CPU" -- a thing to print when you have not asked the processor, and // CPU" -- a thing to print when you have not asked the processor, and
// actively unhelpful, because identifying the machine is the one question // actively unhelpful, because identifying the machine is the one question
// /proc/cpuinfo exists to answer. // /proc/cpuinfo exists to answer.
@ -204,7 +204,8 @@ gen_cpuinfo(struct sbuf *sb)
static void static void
gen_version(struct sbuf *sb) gen_version(struct sbuf *sb)
{ {
sb_puts(sb, "Schunix version 0.1.0 (schunix) #1 SMP x86_64\n"); // The kernel's name, not the system's -- same as "Linux version 6.x" here.
sb_puts(sb, "SchIFT version 0.1.0 (schift) #1 SMP x86_64\n");
} }
static void static void

View file

@ -200,7 +200,7 @@ load_outline(struct ttf *f, int gid, struct outline *o)
// A negative contour count means a composite: the glyph is other glyphs // A negative contour count means a composite: the glyph is other glyphs
// placed at offsets. This is not an exotic case to skip -- `i` is built from // placed at offsets. This is not an exotic case to skip -- `i` is built from
// a dotless i plus the dot, so skipping composites loses a letter from // a dotless i plus the dot, so skipping composites loses a letter from
// "Schunix", which is exactly how the gap was found. // "SchOS", which is exactly how the gap was found.
// //
// Only the translated case is handled: components with a scale or a 2x2 // Only the translated case is handled: components with a scale or a 2x2
// matrix are rare outside of synthesised obliques, and applying a transform // matrix are rare outside of synthesised obliques, and applying a transform

View file

@ -41,7 +41,7 @@ uartearlyinit(void)
// Announce that we're here. // Announce that we're here.
for(p="Schunix UART...\n"; *p; p++) for(p="SchOS UART...\n"; *p; p++)
uartputc(*p); uartputc(*p);
} }

View file

@ -11,7 +11,7 @@
#include "errno.h" #include "errno.h"
// Binaries with entry points at 0x100000+ are musl/Linux-ABI. // Binaries with entry points at 0x100000+ are musl/Linux-ABI.
// Schunix-native binaries (init) are linked at 0x4000. // SchOS-native binaries (init) are linked at 0x4000.
#define LINUX_ABI_ENTRY_THRESHOLD 0x100000UL #define LINUX_ABI_ENTRY_THRESHOLD 0x100000UL
extern int linux_syscall_map[]; extern int linux_syscall_map[];
extern int linux_syscall_map_size; extern int linux_syscall_map_size;
@ -158,7 +158,7 @@ exec(char *path, char **argv)
} }
// Auto-select syscall ABI: musl binaries have entry >= 0x100000; // Auto-select syscall ABI: musl binaries have entry >= 0x100000;
// Schunix-native binaries (init) are linked at 0x4000. // SchOS-native binaries (init) are linked at 0x4000.
if (elf.entry >= LINUX_ABI_ENTRY_THRESHOLD) { if (elf.entry >= LINUX_ABI_ENTRY_THRESHOLD) {
myproc()->syscall_map = linux_syscall_map; myproc()->syscall_map = linux_syscall_map;
myproc()->map_size = linux_syscall_map_size; myproc()->map_size = linux_syscall_map_size;

View file

@ -152,7 +152,7 @@ fileread(struct file *f, char *addr, int n)
} }
if((f->ip->rwmode & 2) == 0){ if((f->ip->rwmode & 2) == 0){
cprintf("Schunix: permission denied (read)\n"); cprintf("SchOS: permission denied (read)\n");
iunlock(f->ip); iunlock(f->ip);
return -1; return -1;
} }
@ -208,7 +208,7 @@ filewrite(struct file *f, char *addr, int n)
} }
if((f->ip->rwmode & 1) == 0){ if((f->ip->rwmode & 1) == 0){
cprintf("Schunix: permission denied (write)\n"); cprintf("SchOS: permission denied (write)\n");
iunlock(f->ip); iunlock(f->ip);
return -1; return -1;
} }

View file

@ -133,7 +133,7 @@ static void sbputi(struct sb *s, int64 v)
// Linux's /proc/<pid>/stat, as far as anything here reads it. // Linux's /proc/<pid>/stat, as far as anything here reads it.
// //
// The field order is not negotiable: ps counts fields by position, so a // The field order is not negotiable: ps counts fields by position, so a
// missing one silently shifts everything after it. Fields Schunix does not // missing one silently shifts everything after it. Fields SchOS does not
// track are zero, which is what Linux itself reports for things a given // track are zero, which is what Linux itself reports for things a given
// process has never done. // process has never done.
static char static char

View file

@ -532,7 +532,7 @@ schfs_kroot(void)
/* Phase 2 has no VFS integration -- SchFS files are not reachable */ /* Phase 2 has no VFS integration -- SchFS files are not reachable */
/* through open(2) yet -- so this is how the mount is observable from */ /* through open(2) yet -- so this is how the mount is observable from */
/* userland at all. It reports the volume and lists the root directory, */ /* userland at all. It reports the volume and lists the root directory, */
/* which is enough to confirm from inside a running Schunix that the */ /* which is enough to confirm from inside a running SchOS that the */
/* kernel really did parse an image mkschfs wrote. */ /* kernel really did parse an image mkschfs wrote. */
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Linux x86_64 syscall number -> Schunix syscall number translation. // Linux x86_64 syscall number -> SchOS syscall number translation.
// Enabled per process by sys_enable_linux_abi (see kernel/sys/sys_compat.c). // Enabled per process by sys_enable_linux_abi (see kernel/sys/sys_compat.c).
// //
// This file used to be the second half of a two-place registration scheme: a // This file used to be the second half of a two-place registration scheme: a
@ -16,7 +16,7 @@
#define LINUX_NSYSCALL NSYSCALLS #define LINUX_NSYSCALL NSYSCALLS
// Index: Linux x86_64 syscall number. Value: Schunix SYS_* number, or 0 for // Index: Linux x86_64 syscall number. Value: SchOS SYS_* number, or 0 for
// "not implemented" (syscall() then returns -ENOSYS). // "not implemented" (syscall() then returns -ENOSYS).
// //
// Syscalls declared NO_LINUX in table.inc all land on the single scratch index // Syscalls declared NO_LINUX in table.inc all land on the single scratch index

View file

@ -114,8 +114,8 @@ sys_uname(void)
struct utsname *u = (struct utsname*)user_ptr(ubuf, sizeof(*u)); struct utsname *u = (struct utsname*)user_ptr(ubuf, sizeof(*u));
if (!u) return -EFAULT; if (!u) return -EFAULT;
memset(u, 0, sizeof(*u)); memset(u, 0, sizeof(*u));
memmove(u->sysname, "Schunix", 8); memmove(u->sysname, "SchIFT", 7);
memmove(u->nodename, "schunix", 8); memmove(u->nodename, "schos", 6);
memmove(u->release, "0.1.0", 6); memmove(u->release, "0.1.0", 6);
memmove(u->version, "#1", 3); memmove(u->version, "#1", 3);
memmove(u->machine, "x86_64", 7); memmove(u->machine, "x86_64", 7);

View file

@ -18,7 +18,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Linux-ABI-compatible struct stat (x86_64 "struct stat" from // Linux-ABI-compatible struct stat (x86_64 "struct stat" from
// musl 1.2.5 bits/stat.h) — musl/toybox/dash parse st_mode directly // musl 1.2.5 bits/stat.h) — musl/toybox/dash parse st_mode directly
// out of this exact byte layout, which bears no resemblance to Schunix's // out of this exact byte layout, which bears no resemblance to SchOS's
// own native `struct stat` (stat.h). Without this, every Linux-ABI process // own native `struct stat` (stat.h). Without this, every Linux-ABI process
// reading stat() results (e.g. ls checking S_ISDIR to decide whether to // reading stat() results (e.g. ls checking S_ISDIR to decide whether to
// list a directory or just print its name) gets garbage. // list a directory or just print its name) gets garbage.
@ -825,7 +825,7 @@ sys_getdents64(void)
} }
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Custom SchunixFS ops // Custom SchOSFS ops
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
addr_t sys_delete(void) addr_t sys_delete(void)

View file

@ -1,7 +1,7 @@
// Segregated Kernel -- central syscall table. ONE line per syscall. // Segregated Kernel -- central syscall table. ONE line per syscall.
// //
// Format: SYSCALL(nr, linux_nr, name) // Format: SYSCALL(nr, linux_nr, name)
// nr Schunix native syscall number // nr SchOS native syscall number
// linux_nr Linux x86_64 syscall number, or NO_LINUX if none // linux_nr Linux x86_64 syscall number, or NO_LINUX if none
// name implemented as sys_<name>() in kernel/sys/sys_*.c // name implemented as sys_<name>() in kernel/sys/sys_*.c
// //
@ -120,7 +120,7 @@ SYSCALL( 60, 16, ioctl)
// translation answered "bad syscall" before the stub could answer ENOSYS. // translation answered "bad syscall" before the stub could answer ENOSYS.
// Now that they do something they need the numbers programs actually use. // Now that they do something they need the numbers programs actually use.
// //
// `shutdown` is deliberately not the name here: Schunix already has a native // `shutdown` is deliberately not the name here: SchOS already has a native
// shutdown() that powers the machine off (syscall 32), and two syscalls // shutdown() that powers the machine off (syscall 32), and two syscalls
// cannot share a sys_ function name. Linux 48 maps to sockshutdown instead. // cannot share a sys_ function name. Linux 48 maps to sockshutdown instead.
SYSCALL( 40, 41, socket) SYSCALL( 40, 41, socket)

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Schunix — first-party userland runtime: _start entry and exit. // SchOS — first-party userland runtime: _start entry and exit.
#include "types.h" #include "types.h"
#include "user.h" #include "user.h"

View file

@ -1,5 +1,5 @@
/* SPDX-License-Identifier: Apache-2.0 /* SPDX-License-Identifier: Apache-2.0
* Schunix — process entry point. * SchOS — process entry point.
* *
* This has to be assembly, and the reason is worth recording. * This has to be assembly, and the reason is worth recording.
* *

View file

@ -1,5 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# Schunix ports — third-party software, one directory per port. # SchOS ports — third-party software, one directory per port.
# All ports are permissive-licensed (MIT, BSD, 0BSD, Apache 2.0). # All ports are permissive-licensed (MIT, BSD, 0BSD, Apache 2.0).
# #
# ports/musl/ libc — installs headers/libs to build/ports/musl/prefix # ports/musl/ libc — installs headers/libs to build/ports/musl/prefix
@ -15,7 +15,7 @@
# Ports that live in this directory but are deliberately not built by `make`. # Ports that live in this directory but are deliberately not built by `make`.
# Empty for now; the filter stays because the reason it existed will recur -- # Empty for now; the filter stays because the reason it existed will recur --
# a port whose licence cannot be combined with Apache-2.0 can be kept here for # a port whose licence cannot be combined with Apache-2.0 can be kept here for
# local testing but must never be built into a Schunix image. # local testing but must never be built into a SchOS image.
NOTPORTS := NOTPORTS :=
PORTS := $(filter-out $(NOTPORTS), \ PORTS := $(filter-out $(NOTPORTS), \
$(patsubst %/,%,$(sort $(dir $(wildcard */Makefile))))) $(patsubst %/,%,$(sort $(dir $(wildcard */Makefile)))))

View file

@ -1,5 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# Shared definitions for all Schunix ports. # Shared definitions for all SchOS ports.
# Include this at the top of each port's Makefile: include ../mk/port.mk # Include this at the top of each port's Makefile: include ../mk/port.mk
# #
# Layout contract — a port directory contains ONLY hand-written files: # Layout contract — a port directory contains ONLY hand-written files:

View file

@ -1,6 +1,6 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# mksh (MirBSD Korn Shell) — permissive: https://www.mirbsd.org/mksh.htm # mksh (MirBSD Korn Shell) — permissive: https://www.mirbsd.org/mksh.htm
# Installed as /bin/sh — Schunix standardizes on "sh" as the one shell name; # Installed as /bin/sh — SchOS standardizes on "sh" as the one shell name;
# no ksh/dash/other aliases are installed or looked up by init. # no ksh/dash/other aliases are installed or looked up by init.
include ../mk/port.mk include ../mk/port.mk
@ -10,7 +10,7 @@ MKSH_URL := http://www.mirbsd.org/MirOS/dist/mir/mksh/mksh-$(MKSH_VERSION).t
TARBALL := $(DISTDIR)/mksh-$(MKSH_VERSION).tgz TARBALL := $(DISTDIR)/mksh-$(MKSH_VERSION).tgz
CFLAGS := -static -D__SCHUNIX__ -I$(MUSL)/include -fno-stack-protector CFLAGS := -static -D__SCHOS__ -I$(MUSL)/include -fno-stack-protector
LDFLAGS := -static -L$(MUSL)/lib -lc LDFLAGS := -static -L$(MUSL)/lib -lc
$(TARBALL): | $(DISTDIR) $(TARBALL): | $(DISTDIR)

View file

@ -27,8 +27,8 @@ $(SRCDIR): $(TARBALL)
# so creating it bumps that directory's mtime — making the directory forever # so creating it bumps that directory's mtime — making the directory forever
# newer than the stamp it contains, and re-running this rule on every single # newer than the stamp it contains, and re-running this rule on every single
# build. The second run then fails, because the patch does not apply twice. # build. The second run then fails, because the patch does not apply twice.
$(SRCDIR)/.patched: patches/0001-schunix-tls.patch | $(SRCDIR) $(SRCDIR)/.patched: patches/0001-schos-tls.patch | $(SRCDIR)
cd $(SRCDIR) && patch -p1 < $(CURDIR)/patches/0001-schunix-tls.patch cd $(SRCDIR) && patch -p1 < $(CURDIR)/patches/0001-schos-tls.patch
touch $@ touch $@
$(BUILDDIR)/config.mak: $(SRCDIR)/.patched $(BUILDDIR)/config.mak: $(SRCDIR)/.patched
@ -37,7 +37,7 @@ $(BUILDDIR)/config.mak: $(SRCDIR)/.patched
--prefix=$(PREFIX) \ --prefix=$(PREFIX) \
--disable-shared \ --disable-shared \
CC=$(CC) \ CC=$(CC) \
CFLAGS="-D__SCHUNIX__ -fno-stack-protector" CFLAGS="-D__SCHOS__ -fno-stack-protector"
$(BUILDDIR)/lib/libc.a: $(BUILDDIR)/config.mak $(BUILDDIR)/lib/libc.a: $(BUILDDIR)/config.mak
$(MAKE) -C $(BUILDDIR) $(MAKE) -C $(BUILDDIR)

View file

@ -1,13 +1,13 @@
From: Schunix Project <kernel@schunix.org> From: SchOS Project <kernel@schos.org>
Subject: [PATCH] schunix: TLS via global, mallocng decls, optional malloc tracing Subject: [PATCH] schos: TLS via global, mallocng decls, optional malloc tracing
Three local changes to musl 1.2.5, kept in one patch because they are all Three local changes to musl 1.2.5, kept in one patch because they are all
"make musl work on Schunix" and share a lifetime. "make musl work on SchOS" and share a lifetime.
1. arch/x86_64/pthread_arch.h, src/env/__init_tls.c - TLS. 1. arch/x86_64/pthread_arch.h, src/env/__init_tls.c - TLS.
Schunix's kernel saves/restores FS_BASE at the syscall boundary, so SchOS's kernel saves/restores FS_BASE at the syscall boundary, so
arch_prctl(ARCH_SET_FS) is safe from userspace. __get_tp() is redirected arch_prctl(ARCH_SET_FS) is safe from userspace. __get_tp() is redirected
through a global uintptr_t (__schunix_tp) set at the START of __init_tp(), through a global uintptr_t (__schos_tp) set at the START of __init_tp(),
before __set_thread_area() is called. The rest of __init_tp() runs before __set_thread_area() is called. The rest of __init_tp() runs
normally so td->locale and the other pthread fields still initialise. normally so td->locale and the other pthread fields still initialise.
@ -20,17 +20,17 @@ Three local changes to musl 1.2.5, kept in one patch because they are all
3. src/malloc/mallocng/meta.h, malloc.c - diagnostics, inert by default. 3. src/malloc/mallocng/meta.h, malloc.c - diagnostics, inert by default.
get_meta()/alloc_group() tracing that dumps group/meta pointers to fd 2, get_meta()/alloc_group() tracing that dumps group/meta pointers to fd 2,
entirely inside #ifdef SCHUNIX_MALLOC_DEBUG, which nothing defines. Kept entirely inside #ifdef SCHOS_MALLOC_DEBUG, which nothing defines. Kept
because this is the instrumentation that resolved the boot-crash because this is the instrumentation that resolved the boot-crash
investigation in docs/architecture/kernel-history.md section 1; build investigation in docs/architecture/kernel-history.md section 1; build
with -DSCHUNIX_MALLOC_DEBUG to re-enable. with -DSCHOS_MALLOC_DEBUG to re-enable.
--- a/arch/x86_64/pthread_arch.h 2024-03-01 03:07:33.000000000 +0100 --- a/arch/x86_64/pthread_arch.h 2024-03-01 03:07:33.000000000 +0100
+++ b/arch/x86_64/pthread_arch.h 2026-08-01 19:11:51.533102649 +0200 +++ b/arch/x86_64/pthread_arch.h 2026-08-01 19:11:51.533102649 +0200
@@ -1,8 +1,13 @@ @@ -1,8 +1,13 @@
+#ifdef __SCHUNIX__ +#ifdef __SCHOS__
+extern uintptr_t __schunix_tp; +extern uintptr_t __schos_tp;
+static inline uintptr_t __get_tp() { return __schunix_tp; } +static inline uintptr_t __get_tp() { return __schos_tp; }
+#else +#else
static inline uintptr_t __get_tp() static inline uintptr_t __get_tp()
{ {
@ -47,18 +47,18 @@ Three local changes to musl 1.2.5, kept in one patch because they are all
volatile int __thread_list_lock; volatile int __thread_list_lock;
+#ifdef __SCHUNIX__ +#ifdef __SCHOS__
+uintptr_t __schunix_tp; +uintptr_t __schos_tp;
+#endif +#endif
+ +
int __init_tp(void *p) int __init_tp(void *p)
{ {
pthread_t td = p; pthread_t td = p;
td->self = td; td->self = td;
+ // Set __schunix_tp for __get_tp() before calling __set_thread_area. + // Set __schos_tp for __get_tp() before calling __set_thread_area.
+ // The kernel now correctly saves/restores FS_BASE at the syscall boundary. + // The kernel now correctly saves/restores FS_BASE at the syscall boundary.
+#ifdef __SCHUNIX__ +#ifdef __SCHOS__
+ __schunix_tp = (uintptr_t)TP_ADJ(p); + __schos_tp = (uintptr_t)TP_ADJ(p);
+#endif +#endif
int r = __set_thread_area(TP_ADJ(p)); int r = __set_thread_area(TP_ADJ(p));
if (r < 0) return -1; if (r < 0) return -1;
@ -82,20 +82,20 @@ Three local changes to musl 1.2.5, kept in one patch because they are all
#include <limits.h> #include <limits.h>
#include "glue.h" #include "glue.h"
+#ifdef SCHUNIX_MALLOC_DEBUG +#ifdef SCHOS_MALLOC_DEBUG
+static void schunix_hex(char *out, uint64_t v) { +static void schos_hex(char *out, uint64_t v) {
+ static const char digits[] = "0123456789abcdef"; + static const char digits[] = "0123456789abcdef";
+ for (int i = 15; i >= 0; i--) { out[i] = digits[v & 0xf]; v >>= 4; } + for (int i = 15; i >= 0; i--) { out[i] = digits[v & 0xf]; v >>= 4; }
+} +}
+static void schunix_dbg(const char *tag, uint64_t a, uint64_t b, uint64_t c) { +static void schos_dbg(const char *tag, uint64_t a, uint64_t b, uint64_t c) {
+ char buf[128]; + char buf[128];
+ int n = 0; + int n = 0;
+ buf[n++]='['; buf[n++]='D'; buf[n++]='B'; buf[n++]='G'; buf[n++]=']'; buf[n++]=' '; + buf[n++]='['; buf[n++]='D'; buf[n++]='B'; buf[n++]='G'; buf[n++]=']'; buf[n++]=' ';
+ for (const char *p = tag; *p; p++) buf[n++] = *p; + for (const char *p = tag; *p; p++) buf[n++] = *p;
+ buf[n++]=' '; + buf[n++]=' ';
+ schunix_hex(buf+n, a); n += 16; buf[n++]=' '; + schos_hex(buf+n, a); n += 16; buf[n++]=' ';
+ schunix_hex(buf+n, b); n += 16; buf[n++]=' '; + schos_hex(buf+n, b); n += 16; buf[n++]=' ';
+ schunix_hex(buf+n, c); n += 16; buf[n++]='\n'; + schos_hex(buf+n, c); n += 16; buf[n++]='\n';
+ __syscall(SYS_write, 2, buf, n); + __syscall(SYS_write, 2, buf, n);
+} +}
+#endif +#endif
@ -107,13 +107,13 @@ Three local changes to musl 1.2.5, kept in one patch because they are all
} }
const struct group *base = (const void *)(p - UNIT*offset - UNIT); const struct group *base = (const void *)(p - UNIT*offset - UNIT);
const struct meta *meta = base->meta; const struct meta *meta = base->meta;
+#ifdef SCHUNIX_MALLOC_DEBUG +#ifdef SCHOS_MALLOC_DEBUG
+ schunix_dbg("get_meta p", (uint64_t)p, (uint64_t)offset, (uint64_t)index); + schos_dbg("get_meta p", (uint64_t)p, (uint64_t)offset, (uint64_t)index);
+ { + {
+ volatile uint64_t *rawbase = (volatile uint64_t *)base; + volatile uint64_t *rawbase = (volatile uint64_t *)base;
+ schunix_dbg("get_meta RAW reread base[0..2]", rawbase[0], rawbase[1], rawbase[2]); + schos_dbg("get_meta RAW reread base[0..2]", rawbase[0], rawbase[1], rawbase[2]);
+ } + }
+ schunix_dbg("get_meta base/meta/meta->mem", (uint64_t)base, (uint64_t)meta, (uint64_t)meta->mem); + schos_dbg("get_meta base/meta/meta->mem", (uint64_t)base, (uint64_t)meta, (uint64_t)meta->mem);
+#endif +#endif
assert(meta->mem == base); assert(meta->mem == base);
assert(index <= meta->last_idx); assert(index <= meta->last_idx);
@ -124,9 +124,9 @@ Three local changes to musl 1.2.5, kept in one patch because they are all
m->last_idx = cnt-1; m->last_idx = cnt-1;
m->freeable = 1; m->freeable = 1;
m->sizeclass = sc; m->sizeclass = sc;
+#ifdef SCHUNIX_MALLOC_DEBUG +#ifdef SCHOS_MALLOC_DEBUG
+ schunix_dbg("alloc_group p/m/cnt", (uint64_t)p, (uint64_t)m, (uint64_t)cnt); + schos_dbg("alloc_group p/m/cnt", (uint64_t)p, (uint64_t)m, (uint64_t)cnt);
+ schunix_dbg("alloc_group readback mem->meta", (uint64_t)m->mem, (uint64_t)m->mem->meta, (uint64_t)sc); + schos_dbg("alloc_group readback mem->meta", (uint64_t)m->mem, (uint64_t)m->mem->meta, (uint64_t)sc);
+#endif +#endif
return m; return m;
} }

View file

@ -1,6 +1,6 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# toybox — 0BSD-licensed: https://landley.net/toybox/ # toybox — 0BSD-licensed: https://landley.net/toybox/
# Provides Schunix's core utilities (ls, cat, cp, mv, rm, mkdir, ...) as a # Provides SchOS's core utilities (ls, cat, cp, mv, rm, mkdir, ...) as a
# single multicall binary, installed under sysroot/bin/ once per applet name. # single multicall binary, installed under sysroot/bin/ once per applet name.
# #
# mkfs (tools/mkfs.c) doesn't understand symlinks or hardlink dedup — each # mkfs (tools/mkfs.c) doesn't understand symlinks or hardlink dedup — each
@ -16,7 +16,7 @@ TOYBOX_SHA256 := ad88a921133ae2231d9f2df875ec0bd42af4429145caea7d7db9e02208a6fd
TARBALL := $(DISTDIR)/toybox-$(TOYBOX_VERSION).tar.gz TARBALL := $(DISTDIR)/toybox-$(TOYBOX_VERSION).tar.gz
CFLAGS := -static -D__SCHUNIX__ -I$(MUSL)/include -fno-stack-protector CFLAGS := -static -D__SCHOS__ -I$(MUSL)/include -fno-stack-protector
LDFLAGS := -static -L$(MUSL)/lib -lc LDFLAGS := -static -L$(MUSL)/lib -lc
# The applet list is not hard-coded any more: `toybox` with no arguments prints # The applet list is not hard-coded any more: `toybox` with no arguments prints

View file

@ -1,6 +1,6 @@
# projects/ # projects/
Things that run **on** Schunix rather than things that **are** Schunix. Things that run **on** SchOS rather than things that **are** SchOS.
Everything above this directory — `kernel/`, `boot/`, `lib/`, `cmd/`, Everything above this directory — `kernel/`, `boot/`, `lib/`, `cmd/`,
`include/` — is the operating system: it boots, it owns the hardware, and it `include/` — is the operating system: it boots, it owns the hardware, and it
@ -11,7 +11,7 @@ The split exists because the alternative gets bad quickly. A compositor,
a window manager and a desktop are each larger than the kernel will be for a a window manager and a desktop are each larger than the kernel will be for a
long time. Grown inside the OS tree they would blur into it: a compositor long time. Grown inside the OS tree they would blur into it: a compositor
would start reaching into kernel headers because they are right there, the would start reaching into kernel headers because they are right there, the
build would grow a dependency from the kernel to a GUI, and "does Schunix build would grow a dependency from the kernel to a GUI, and "does SchOS
boot" would stop having a clear answer. Keeping them separate forces the boot" would stop having a clear answer. Keeping them separate forces the
boundary to be a real interface — syscalls and protocols — rather than a boundary to be a real interface — syscalls and protocols — rather than a
shared header nobody meant to share. shared header nobody meant to share.
@ -27,13 +27,13 @@ Concretely, code in here:
| Directory | What it is | | Directory | What it is |
|------------|-----------------------------------------------------------------| |------------|-----------------------------------------------------------------|
| `schcom/` | Schunix Compositor. Owns the display, composites clients, routes input. | | `schcom/` | SchOS Compositor. Owns the display, composites clients, routes input. |
| `schwm/` | Schunix Window Manager. Window placement, decoration, focus, on top of Schcom. | | `schwm/` | SchOS Window Manager. Window placement, decoration, focus, on top of Schcom. |
| `schde/` | Schunix Desktop Environment. Panel, launcher, settings, file manager. | | `schde/` | SchOS Desktop Environment. Panel, launcher, settings, file manager. |
| `schinst/` | The installer, the installation environment, and `.sip` tooling. | | `schinst/` | The installer, the installation environment, and `.sip` tooling. |
| `schfs-linux/` | SchFS as a filesystem for Linux. FUSE first, a kernel module later. | | `schfs-linux/` | SchFS as a filesystem for Linux. FUSE first, a kernel module later. |
**`schfs-linux/` is written to stand on its own.** It does not mention Schunix **`schfs-linux/` is written to stand on its own.** It does not mention SchOS
anywhere, and that is deliberate rather than an oversight: it is intended to be anywhere, and that is deliberate rather than an oversight: it is intended to be
the first piece released, and it has to make sense to somebody who has never the first piece released, and it has to make sense to somebody who has never
heard of the OS it came from — a filesystem is judged as a filesystem. The heard of the OS it came from — a filesystem is judged as a filesystem. The

View file

@ -1,4 +1,4 @@
# Schcom — the Schunix Compositor # Schcom — the SchOS Compositor
Owns the display. Every pixel that reaches the screen goes through it. Owns the display. Every pixel that reaches the screen goes through it.

View file

@ -1,4 +1,4 @@
# SchDE — the Schunix Desktop Environment # SchDE — the SchOS Desktop Environment
The parts you actually look at: a panel, a launcher, settings, a file The parts you actually look at: a panel, a launcher, settings, a file
manager, a terminal. manager, a terminal.

View file

@ -1,10 +1,10 @@
# schinst — the installer, the installation environment, and `.sip` # schinst — the installer, the installation environment, and `.sip`
Getting Schunix from an ISO onto a disk. Getting SchOS from an ISO onto a disk.
Three separate things live here: Three separate things live here:
1. **The installation environment.** A Schunix that boots from the ISO into a 1. **The installation environment.** A SchOS that boots from the ISO into a
known state with the installer running instead of a login shell. The ISO known state with the installer running instead of a login shell. The ISO
already boots to userspace without a hard disk (`make iso`), so this is a already boots to userspace without a hard disk (`make iso`), so this is a
different init and a different root, not a different kernel. different init and a different root, not a different kernel.
@ -17,7 +17,7 @@ Three separate things live here:
Not started. `.sip` needs its format written down before any code exists. Not started. `.sip` needs its format written down before any code exists.
## `.sip` — Schunix Installation Package ## `.sip` — SchOS Installation Package
The stated model is WIM, the image format Windows PE installs from, and the The stated model is WIM, the image format Windows PE installs from, and the
thing worth copying from WIM is that it is **file-based, not block-based**. thing worth copying from WIM is that it is **file-based, not block-based**.

View file

@ -1,4 +1,4 @@
# SchWM — the Schunix Window Manager # SchWM — the SchOS Window Manager
Policy. Where windows go, which one has focus, what happens when you drag a Policy. Where windows go, which one has focus, what happens when you drag a
title bar, how alt-tab behaves, what a window looks like at its edges. title bar, how alt-tab behaves, what a window looks like at its edges.

View file

@ -1,4 +1,4 @@
# Schunix launcher (Windows side). # SchOS launcher (Windows side).
# #
# Why this exists: without it you have to hand-type a QEMU command line, and a # Why this exists: without it you have to hand-type a QEMU command line, and a
# hand-typed one drifts -- notably onto a stale fs.img, which boots to # hand-typed one drifts -- notably onto a stale fs.img, which boots to
@ -35,7 +35,7 @@ $root = $PSScriptRoot
# The two images QEMU needs. These paths are the single source of truth -- # The two images QEMU needs. These paths are the single source of truth --
# keep them in sync with the 'qemu' and 'qemu-schfs' targets in the Makefile. # keep them in sync with the 'qemu' and 'qemu-schfs' targets in the Makefile.
$hda = Join-Path $root 'schunix.img' $hda = Join-Path $root 'schos.img'
$hdb = if ($SchFS) { Join-Path $root 'build\schfs.img' } $hdb = if ($SchFS) { Join-Path $root 'build\schfs.img' }
else { Join-Path $root 'build\fs.img' } else { Join-Path $root 'build\fs.img' }
@ -58,7 +58,7 @@ if (-not $NoBuild) {
# of memory, which leaves device 1 free for the SchFS volume. Booting the # of memory, which leaves device 1 free for the SchFS volume. Booting the
# normal kernel with a SchFS disk as hdb would leave it with no root. # normal kernel with a SchFS disk as hdb would leave it with no root.
$target = if ($SchFS) { 'make ramroot && make build/schfs.img' } else { 'make' } $target = if ($SchFS) { 'make ramroot && make build/schfs.img' } else { 'make' }
& $bash -lc "cd /d/DEV/Schunix && $target" & $bash -lc "cd /d/DEV/SchOS && $target"
if ($LASTEXITCODE -ne 0) { throw "build failed (exit $LASTEXITCODE)" } if ($LASTEXITCODE -ne 0) { throw "build failed (exit $LASTEXITCODE)" }
} }

View file

@ -1,4 +1,4 @@
# Headless boot check: run Schunix under QEMU, type commands at the shell, and # Headless boot check: run SchOS under QEMU, type commands at the shell, and
# assert on what actually comes back. # assert on what actually comes back.
# #
# Booting to a prompt proves nothing on its own -- a filesystem can mount and # Booting to a prompt proves nothing on its own -- a filesystem can mount and
@ -22,7 +22,7 @@
param( param(
[switch]$Fb, [switch]$Fb,
# Boot schunix.iso from an emulated optical drive with NO hard disk # Boot schos.iso from an emulated optical drive with NO hard disk
# attached, which is the only way to prove the ISO is self-contained. # attached, which is the only way to prove the ISO is self-contained.
# Needs `make iso` first. # Needs `make iso` first.
[switch]$Iso, [switch]$Iso,
@ -54,7 +54,7 @@ param(
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent $root = Split-Path $PSScriptRoot -Parent
$hda = Join-Path $root 'schunix.img' $hda = Join-Path $root 'schos.img'
# The root filesystem. SchFS is the only root there is, so this is not a # The root filesystem. SchFS is the only root there is, so this is not a
# choice -- a kernel handed anything else on device 1 panics in forkret(). # choice -- a kernel handed anything else on device 1 panics in forkret().
$hdb = Join-Path $root 'build\schfs.img' $hdb = Join-Path $root 'build\schfs.img'
@ -67,7 +67,7 @@ Remove-Item -Force $log -ErrorAction SilentlyContinue
# on its own, and every one of these has broken at some point while the boot # on its own, and every one of these has broken at some point while the boot
# still looked perfectly healthy. # still looked perfectly healthy.
$commands = @( $commands = @(
'echo hello-from-schunix > /tmp/bc.txt' 'echo hello-from-schos > /tmp/bc.txt'
'cat /tmp/bc.txt' 'cat /tmp/bc.txt'
'echo second-line >> /tmp/bc.txt' 'echo second-line >> /tmp/bc.txt'
'wc -c /tmp/bc.txt' 'wc -c /tmp/bc.txt'
@ -161,7 +161,7 @@ $commands += 'echo MARKER-DONE'
# The ISO run attaches no hard disk at all. That is the whole point: a kernel # The ISO run attaches no hard disk at all. That is the whole point: a kernel
# that still quietly needs one would boot happily here otherwise, and only # that still quietly needs one would boot happily here otherwise, and only
# fail on someone else's machine. # fail on someone else's machine.
$isoPath = Join-Path $root 'schunix.iso' $isoPath = Join-Path $root 'schos.iso'
if ($Iso -and -not (Test-Path $isoPath)) { throw "no $isoPath -- run 'make iso' first" } if ($Iso -and -not (Test-Path $isoPath)) { throw "no $isoPath -- run 'make iso' first" }
$drives = if ($Iso) { $drives = if ($Iso) {
@ -222,7 +222,7 @@ $psi.Arguments = ($drives + $usbDevices + $monitor + @(
$psi.RedirectStandardInput = $true $psi.RedirectStandardInput = $true
$psi.UseShellExecute = $false $psi.UseShellExecute = $false
$what = if ($Iso) { 'schunix.iso, no hard disk' } else { "hdb = $(Split-Path $hdb -Leaf)" } $what = if ($Iso) { 'schos.iso, no hard disk' } else { "hdb = $(Split-Path $hdb -Leaf)" }
Write-Host "==> booting ($what)" -ForegroundColor Cyan Write-Host "==> booting ($what)" -ForegroundColor Cyan
$p = [System.Diagnostics.Process]::Start($psi) $p = [System.Diagnostics.Process]::Start($psi)
@ -372,12 +372,16 @@ function Expect($pattern, $what) {
} }
Expect 'MARKER-DONE' 'shell stayed alive through every command' Expect 'MARKER-DONE' 'shell stayed alive through every command'
Expect 'hello-from-schunix' 'a file written on the root filesystem reads back' Expect 'hello-from-schos' 'a file written on the root filesystem reads back'
Expect 'second-line' 'appending to that file works' Expect 'second-line' 'appending to that file works'
# 19 bytes of "hello-from-schunix\n" plus 12 of "second-line\n". The exact # 17 bytes of "hello-from-schos\n" plus 12 of "second-line\n". The exact
# number is the point: an append that silently truncated still produced a file, # number is the point: an append that silently truncated still produced a file,
# and only the byte count said which one. # and only the byte count said which one.
Expect '(?m)^\s*31\s' 'append extended the file rather than replacing it' #
# It follows the string above, so changing that changes this -- the SchOS
# rename shortened "hello-from-schunix" by two characters and this check went
# red on a filesystem that was working perfectly.
Expect '(?m)^\s*29\s' 'append extended the file rather than replacing it'
Expect '(?m)^copy\.txt' 'a copied file appears in a new directory' Expect '(?m)^copy\.txt' 'a copied file appears in a new directory'
Expect '(?ms)copy\.txt.*rmdir' 'rmdir removed the directory without an error' Expect '(?ms)copy\.txt.*rmdir' 'rmdir removed the directory without an error'
@ -393,7 +397,7 @@ Expect 'vga: display controller' 'the display driver found its aperture'
Expect 'schfs: mounted' 'the kernel mounted SchFS as the root filesystem' Expect 'schfs: mounted' 'the kernel mounted SchFS as the root filesystem'
Expect 'init: ready' 'init came up on a SchFS root' Expect 'init: ready' 'init came up on a SchFS root'
Expect 'label:\s*schunix' '/proc/schfs reports the volume label' Expect 'label:\s*schos' '/proc/schfs reports the volume label'
Expect 'root_objectid:\s*16' '/proc/schfs reports the root object id' Expect 'root_objectid:\s*16' '/proc/schfs reports the root object id'
Expect 'dir\s+bin' 'the root directory really contains bin/' Expect 'dir\s+bin' 'the root directory really contains bin/'
# / is the mounted volume, so mounting that same device again must be # / is the mounted volume, so mounting that same device again must be
@ -415,7 +419,7 @@ if ($gens.Count -ge 2 -and
} }
if ($Fb) { if ($Fb) {
Expect 'id\s+schunixfb' 'FBIOGET_FSCREENINFO identifies the device' Expect 'id\s+schosfb' 'FBIOGET_FSCREENINFO identifies the device'
# 800x600 is what boot/stage2.S asks VBE for. Asserting the numbers rather # 800x600 is what boot/stage2.S asks VBE for. Asserting the numbers rather
# than just "the ioctl returned" is the point: the old code path returned # than just "the ioctl returned" is the point: the old code path returned
# success with an untouched buffer, i.e. a 0x0 screen. # success with an untouched buffer, i.e. a 0x0 screen.

View file

@ -1,4 +1,4 @@
# Boot Schunix, crash it on purpose, and capture the crash screen as an image. # Boot SchOS, crash it on purpose, and capture the crash screen as an image.
# #
# The crash screen is the one part of the system you cannot look at by using # The crash screen is the one part of the system you cannot look at by using
# the system, so it is the one part that quietly rots. This drives it through # the system, so it is the one part that quietly rots. This drives it through
@ -21,7 +21,7 @@ param(
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent $root = Split-Path $PSScriptRoot -Parent
$hda = Join-Path $root 'schunix.img' $hda = Join-Path $root 'schos.img'
$hdb = if ($SchFS) { Join-Path $root 'build\schfs.img' } else { Join-Path $root 'build\fs.img' } $hdb = if ($SchFS) { Join-Path $root 'build\schfs.img' } else { Join-Path $root 'build\fs.img' }
$log = Join-Path $root 'build\crashshot.log' $log = Join-Path $root 'build\crashshot.log'
$ppm = Join-Path $root $Out $ppm = Join-Path $root $Out
@ -96,7 +96,7 @@ if (Test-Path $log) {
$text = Get-Content $log -Raw $text = Get-Content $log -Raw
Write-Host "==> serial transcript" -ForegroundColor Cyan Write-Host "==> serial transcript" -ForegroundColor Cyan
# Only the crash report, not the whole boot. # Only the crash report, not the whole boot.
$idx = $text.IndexOf('Schunix stopped') $idx = $text.IndexOf('SchOS stopped')
if ($idx -ge 0) { Write-Host $text.Substring($idx) } else { Write-Host $text } if ($idx -ge 0) { Write-Host $text.Substring($idx) } else { Write-Host $text }
} }

View file

@ -1,4 +1,4 @@
# Boot Schunix, run the display self-test, and capture the result as an image. # Boot SchOS, run the display self-test, and capture the result as an image.
# #
# The display class cannot be checked without a display: the assertion is "did # The display class cannot be checked without a display: the assertion is "did
# the right pixels reach the screen", and the only instrument for that is a # the right pixels reach the screen", and the only instrument for that is a
@ -26,7 +26,7 @@ param(
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent $root = Split-Path $PSScriptRoot -Parent
$hda = Join-Path $root 'schunix.img' $hda = Join-Path $root 'schos.img'
$hdb = if ($SchFS) { Join-Path $root 'build\schfs.img' } else { Join-Path $root 'build\fs.img' } $hdb = if ($SchFS) { Join-Path $root 'build\schfs.img' } else { Join-Path $root 'build\fs.img' }
$log = Join-Path $root 'build\crashshot.log' $log = Join-Path $root 'build\crashshot.log'
$ppm = Join-Path $root $Out $ppm = Join-Path $root $Out

View file

@ -18,7 +18,7 @@ param(
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent $root = Split-Path $PSScriptRoot -Parent
$hda = Join-Path $root 'schunix.img' $hda = Join-Path $root 'schos.img'
$hdb = Join-Path $root 'build\fs.img' $hdb = Join-Path $root 'build\fs.img'
$log = Join-Path $root 'build\fbshot.log' $log = Join-Path $root 'build\fbshot.log'
$ppm = Join-Path $root "build\fb-$Mode.ppm" $ppm = Join-Path $root "build\fb-$Mode.ppm"

View file

@ -1,4 +1,4 @@
# How much of Schunix is actually Schunix. # How much of SchOS is actually SchOS.
# #
# `wc -l` over the whole tree answers a question nobody asked: it counts musl, # `wc -l` over the whole tree answers a question nobody asked: it counts musl,
# toybox, mksh and a NetBSD checkout, which between them are # toybox, mksh and a NetBSD checkout, which between them are
@ -136,13 +136,13 @@ $fmt = @(
) )
Write-Host '' Write-Host ''
Write-Host ' Schunix — first-party source' -ForegroundColor Cyan Write-Host ' SchOS — first-party source' -ForegroundColor Cyan
Write-Host '' Write-Host ''
Write-Host (($results | Where-Object { $_.Files -gt 0 } | Sort-Object Lines -Descending | Format-Table $fmt -AutoSize | Out-String)) Write-Host (($results | Where-Object { $_.Files -gt 0 } | Sort-Object Lines -Descending | Format-Table $fmt -AutoSize | Out-String))
# Two totals, because they answer different questions and conflating them # Two totals, because they answer different questions and conflating them
# flatters the number. "The OS" is what boots and runs on the machine; docs, # flatters the number. "The OS" is what boots and runs on the machine; docs,
# host-side tools and the projects/ stubs are first-party but are not Schunix # host-side tools and the projects/ stubs are first-party but are not SchOS
# running on hardware. Linux 0.01's 10,239 lines were kernel, headers and boot # running on hardware. Linux 0.01's 10,239 lines were kernel, headers and boot
# -- no documentation and no build tooling -- so only the first total is a fair # -- no documentation and no build tooling -- so only the first total is a fair
# comparison. # comparison.
@ -182,7 +182,7 @@ Write-Host ''
# measure -- every line of every file in the tarball, comments included. # measure -- every line of every file in the tarball, comments included.
$lin = 10239 $lin = 10239
Write-Host (' For scale: Linux 0.01 was {0:N0} lines (kernel, headers, boot -- the' -f $lin) -ForegroundColor DarkGray Write-Host (' For scale: Linux 0.01 was {0:N0} lines (kernel, headers, boot -- the' -f $lin) -ForegroundColor DarkGray
Write-Host (' same things counted above as THE OS ITSELF). Schunix is {0:N1}x that.' -f ($osT / $lin)) -ForegroundColor DarkGray Write-Host (' same things counted above as THE OS ITSELF). SchOS is {0:N1}x that.' -f ($osT / $lin)) -ForegroundColor DarkGray
Write-Host '' Write-Host ''
if ($PerFile) { if ($PerFile) {

View file

@ -1,4 +1,4 @@
# Build a bootable Schunix ISO, ready for VMware or a real machine. # Build a bootable SchOS ISO, ready for VMware or a real machine.
# #
# Wraps `make iso`, which builds the ramdisk-root variant and wraps it in an # Wraps `make iso`, which builds the ramdisk-root variant and wraps it in an
# El Torito image. The ramdisk root is the point: the ISO carries a complete # El Torito image. The ramdisk root is the point: the ISO carries a complete
@ -8,7 +8,7 @@
# tools\makeiso.ps1 -Run build it, then boot it under QEMU to check # tools\makeiso.ps1 -Run build it, then boot it under QEMU to check
# tools\makeiso.ps1 -Clean force a full rebuild first # tools\makeiso.ps1 -Clean force a full rebuild first
# #
# Afterwards the ISO is schunix.iso in the repository root; point a VM's optical # Afterwards the ISO is schos.iso in the repository root; point a VM's optical
# drive at it and boot from CD. # drive at it and boot from CD.
param( param(
@ -88,8 +88,8 @@ if ($code -ne 0) {
Fail "make iso returned $code" Fail "make iso returned $code"
} }
$iso = Join-Path $root 'schunix.iso' $iso = Join-Path $root 'schos.iso'
if (-not (Test-Path $iso)) { Fail "schunix.iso was not produced" } if (-not (Test-Path $iso)) { Fail "schos.iso was not produced" }
# `make iso` leaves the tree holding objects compiled with -DRAMDISK_ROOT. A # `make iso` leaves the tree holding objects compiled with -DRAMDISK_ROOT. A
# following plain `make` would then fail to link, on a missing ramdisk symbol, # following plain `make` would then fail to link, on a missing ramdisk symbol,
@ -106,7 +106,7 @@ Write-Host " New VM -> I will install the OS later -> Other / Other 64-bit"
Write-Host " CD/DVD -> Use ISO image file -> $iso, and tick Connect at power on" Write-Host " CD/DVD -> Use ISO image file -> $iso, and tick Connect at power on"
Write-Host " Boot order: CD-ROM first (F2 at power on for the firmware setup)" Write-Host " Boot order: CD-ROM first (F2 at power on for the firmware setup)"
Write-Host "" Write-Host ""
Write-Host " Set the VM to BIOS, not UEFI. Schunix's loader is 16-bit real" Write-Host " Set the VM to BIOS, not UEFI. SchOS's loader is 16-bit real"
Write-Host " mode and there is no EFI stub yet, so a UEFI-only VM will not boot." Write-Host " mode and there is no EFI stub yet, so a UEFI-only VM will not boot."
Write-Host "" Write-Host ""
Write-Host " Processors: as many as you like. SMP works as of 2026-08-08;" Write-Host " Processors: as many as you like. SMP works as of 2026-08-08;"

View file

@ -1,15 +1,15 @@
#!/bin/sh #!/bin/sh
# Build a bootable Schunix ISO. # Build a bootable SchOS ISO.
# #
# tools/mkiso.sh [output.iso] # tools/mkiso.sh [output.iso]
# #
# The disc boots through El Torito's "no emulation" mode, which is the only # The disc boots through El Torito's "no emulation" mode, which is the only
# one of the three that fits how Schunix actually loads itself. # one of the three that fits how SchOS actually loads itself.
# #
# floppy emulation caps the image at 2.88 MB; the ramdisk-root kernel # floppy emulation caps the image at 2.88 MB; the ramdisk-root kernel
# alone is bigger than that. # alone is bigger than that.
# hard disk emulation presents the image through the BIOS's INT 13h, and # hard disk emulation presents the image through the BIOS's INT 13h, and
# Schunix's loader does not use INT 13h -- it drives # SchOS's loader does not use INT 13h -- it drives
# the IDE controller's registers directly, which # the IDE controller's registers directly, which
# cannot reach a BIOS-emulated drive. # cannot reach a BIOS-emulated drive.
# no emulation the BIOS loads a chosen run of sectors at 0x7C00 # no emulation the BIOS loads a chosen run of sectors at 0x7C00
@ -23,7 +23,7 @@
# #
# STAGE2_SECTORS comes from the environment, set by the Makefile, because this # STAGE2_SECTORS comes from the environment, set by the Makefile, because this
# same number also lives in boot/bootasm.S, boot/stage2main.c and the dd offsets # same number also lives in boot/bootasm.S, boot/stage2main.c and the dd offsets
# in schunix.img's recipe. It was previously written out by hand in three # in schos.img's recipe. It was previously written out by hand in three
# separate spots in this file alone, and raising it for the boot logo is what # separate spots in this file alone, and raising it for the boot logo is what
# turned that from a latent hazard into a broken image. # turned that from a latent hazard into a broken image.
# #
@ -34,7 +34,7 @@
set -e set -e
BUILD=${BUILD:-build} BUILD=${BUILD:-build}
OUT=${1:-schunix.iso} OUT=${1:-schos.iso}
STAGE2_SECTORS=${STAGE2_SECTORS:-48} STAGE2_SECTORS=${STAGE2_SECTORS:-48}
STAGE2_BYTES=$((STAGE2_SECTORS * 512)) STAGE2_BYTES=$((STAGE2_SECTORS * 512))
LOAD_SIZE=$((1 + STAGE2_SECTORS)) LOAD_SIZE=$((1 + STAGE2_SECTORS))
@ -59,7 +59,7 @@ stage2_sz=$(wc -c < "$STAGE2")
rm -rf "$STAGING" rm -rf "$STAGING"
mkdir -p "$STAGING/boot" mkdir -p "$STAGING/boot"
cat "$CDBOOT" "$STAGE2" "$KERNEL" > "$STAGING/boot/schunix.bin" cat "$CDBOOT" "$STAGE2" "$KERNEL" > "$STAGING/boot/schos.bin"
# xorriso if it is here, mkisofs otherwise. Both accept the El Torito flags # xorriso if it is here, mkisofs otherwise. Both accept the El Torito flags
# below unchanged -- xorriso's -as mkisofs mode exists precisely to be # below unchanged -- xorriso's -as mkisofs mode exists precisely to be
@ -79,9 +79,9 @@ fi
$MKISOFS \ $MKISOFS \
-quiet \ -quiet \
-V SCHUNIX \ -V SCHOS \
-A "Schunix" \ -A "SchOS" \
-b boot/schunix.bin \ -b boot/schos.bin \
-no-emul-boot \ -no-emul-boot \
-boot-load-size "$LOAD_SIZE" \ -boot-load-size "$LOAD_SIZE" \
-o "$OUT" \ -o "$OUT" \

View file

@ -13,7 +13,7 @@ is ink -- which lets the kernel composite it in whatever the theme's accent
happens to be, anti-aliased, at one byte per pixel. Storing RGB would be four happens to be, anti-aliased, at one byte per pixel. Storing RGB would be four
times the size and would hardcode a colour into the kernel image. times the size and would hardcode a colour into the kernel image.
python3 tools/mklogo.py "Assets/Schunix Small Logo.png" include/logo.h 128 python3 tools/mklogo.py "Assets/SchOS Small Logo.png" include/logo.h 128
""" """
import sys, zlib, struct import sys, zlib, struct

View file

@ -547,7 +547,7 @@ add_tree(uint64_t dirino, const char *hostdir)
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
const char *out = NULL, *sysroot = NULL, *label = "schunix"; const char *out = NULL, *sysroot = NULL, *label = "schos";
uint64_t nblocks = 6000; uint64_t nblocks = 6000;
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; i++) {

View file

@ -8,7 +8,7 @@
# say -- would otherwise look exactly like a passing mutation test, which is # say -- would otherwise look exactly like a passing mutation test, which is
# the same failure this script exists to catch. # the same failure this script exists to catch.
set -e set -e
cd /mnt/d/DEV/Schunix cd /mnt/d/DEV/SchOS
OBJ=kernel/fs/schfs/obj.c OBJ=kernel/fs/schfs/obj.c
OBJW=kernel/fs/schfs/objw.c OBJW=kernel/fs/schfs/objw.c

View file

@ -126,10 +126,10 @@ alpha = lambda n: "".join(chr(65 + i % 26) for i in range(n))
CASES = [ CASES = [
"HELLO", "HELLO",
"SCHUNIX", "SCHOS",
"a", "a",
"0123456789", "0123456789",
"SCHUNIX PANIC\ntrap 14 err 4 cpu 0\nrip ffffffff80104e2a", "SCHOS PANIC\ntrap 14 err 4 cpu 0\nrip ffffffff80104e2a",
bytes(range(1, 40)).decode("latin-1"), # non-printable payload bytes(range(1, 40)).decode("latin-1"), # non-printable payload
] ]
# One payload that exactly fills each version, and one just under, so both the # One payload that exactly fills each version, and one just under, so both the

View file

@ -297,7 +297,7 @@ main(int argc, char **argv)
const char *out = argc > 1 ? argv[1] : "build/qr.png"; const char *out = argc > 1 ? argv[1] : "build/qr.png";
const char *text = argc > 2 ? argv[2] : const char *text = argc > 2 ? argv[2] :
"SCHUNIX PANIC\n" "SCHOS PANIC\n"
"build 8f2a91c4\n" "build 8f2a91c4\n"
"trap 14 err 4 cpu 0\n" "trap 14 err 4 cpu 0\n"
"rip ffffffff80104e2a\n" "rip ffffffff80104e2a\n"

View file

@ -29,7 +29,7 @@ Remove-Item -Recurse -Force $dir -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Force $dir | Out-Null New-Item -ItemType Directory -Force $dir | Out-Null
Remove-Item -Force $log -ErrorAction SilentlyContinue Remove-Item -Force $log -ErrorAction SilentlyContinue
$hda = Join-Path $root 'schunix.img' $hda = Join-Path $root 'schos.img'
$hdb = Join-Path $root 'build\fs.img' $hdb = Join-Path $root 'build\fs.img'
$monPort = 55556 # not crashshot's port, so the two can run back to back $monPort = 55556 # not crashshot's port, so the two can run back to back

View file

@ -1,4 +1,4 @@
# Boot Schunix, run the text-rendering self-test, and capture the result as an image. # Boot SchOS, run the text-rendering self-test, and capture the result as an image.
# #
# The display class cannot be checked without a display: the assertion is "did # The display class cannot be checked without a display: the assertion is "did
# the right pixels reach the screen", and the only instrument for that is a # the right pixels reach the screen", and the only instrument for that is a
@ -26,7 +26,7 @@ param(
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent $root = Split-Path $PSScriptRoot -Parent
$hda = Join-Path $root 'schunix.img' $hda = Join-Path $root 'schos.img'
$hdb = if ($SchFS) { Join-Path $root 'build\schfs.img' } else { Join-Path $root 'build\fs.img' } $hdb = if ($SchFS) { Join-Path $root 'build\schfs.img' } else { Join-Path $root 'build\fs.img' }
$log = Join-Path $root 'build\crashshot.log' $log = Join-Path $root 'build\crashshot.log'
$ppm = Join-Path $root $Out $ppm = Join-Path $root $Out

View file

@ -17,7 +17,7 @@ param(
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent $root = Split-Path $PSScriptRoot -Parent
$hda = Join-Path $root 'schunix.img' $hda = Join-Path $root 'schos.img'
$hdb = Join-Path $root 'build\fs.img' $hdb = Join-Path $root 'build\fs.img'
$log = Join-Path $root 'build\ttyshot.log' $log = Join-Path $root 'build\ttyshot.log'
$ppm = Join-Path $root $Out $ppm = Join-Path $root $Out