From d0f7acf9eb9314ffbea9f1f8951fd99cba7a5956 Mon Sep 17 00:00:00 2001 From: Nexoniarz Date: Sun, 9 Aug 2026 13:47:01 +0200 Subject: [PATCH] Initial commit: Schunix as it stands before the SchOS rename An x86-64 operating system built from xv6, now largely rewritten: SMP, a copy-on-write root filesystem (SchFS), PCI/USB/virtio drivers, a TTF rasteriser, and a Linux-numbered syscall ABI. No history before this point -- the tree was never under version control. This commit exists so the rename that follows has something to undo to. --- .#README | Bin 0 -> 82 bytes .gitattributes | 18 + .gitignore | 24 + Assets/Schunix Full Logo.png | Bin 0 -> 62691 bytes Assets/Schunix Full Logo.svg | 159 + Assets/Schunix Small Logo.png | Bin 0 -> 83048 bytes Assets/Schunix Small Logo.svg | 120 + Assets/Schunix Text Logo.png | Bin 0 -> 27296 bytes Assets/Schunix Text Logo.svg | 85 + LICENSE | 187 + LICENSE.MIT | 29 + Makefile | 806 +++ NOTICE | 145 + boot/bootasm.S | 101 + boot/cdboot.S | 48 + boot/stage2.S | 129 + boot/stage2main.c | 878 ++++ cmd/fbinfo/main.c | 219 + cmd/init/main.c | 124 + cmd/inputtest/main.c | 124 + cmd/shmtest/main.c | 112 + cmd/socktest/main.c | 305 ++ docs/architecture/kernel-history.md | 666 +++ docs/architecture/schapi.md | 239 + docs/architecture/schfs.md | 403 ++ docs/drivers.md | 130 + docs/layout.md | 175 + docs/licensing.md | 241 + docs/roadmap.md | 481 ++ include/asm.h | 21 + include/buf.h | 14 + include/config_sinit.h | 3 + include/date.h | 15 + include/defs.h | 466 ++ include/device.h | 89 + include/display.h | 56 + include/dma.h | 43 + include/e1000.h | 165 + include/elf.h | 35 + include/errno.h | 60 + include/fb.h | 95 + include/fcntl.h | 43 + include/file.h | 132 + include/font.h | 4627 +++++++++++++++++ include/fs.h | 203 + include/input.h | 93 + include/irq.h | 43 + include/kbd.h | 112 + include/logo.h | 534 ++ include/memlayout.h | 49 + include/mmu.h | 130 + include/mp.h | 54 + include/param.h | 28 + include/pci.h | 110 + include/posix.h | 289 + include/proc.h | 240 + include/qr.h | 42 + include/schfs.h | 246 + include/sleeplock.h | 9 + include/socket.h | 81 + include/spinlock.h | 9 + include/stat.h | 24 + include/syscall.h | 49 + include/text.h | 86 + include/theme.h | 57 + include/traps.h | 69 + include/ttf.h | 49 + include/types.h | 79 + include/uaccess.h | 49 + include/usb.h | 270 + include/user.h | 117 + include/virtio.h | 174 + include/x86.h | 219 + include/xhci.h | 161 + kernel/arch/x86_64/acpi.c | 264 + kernel/arch/x86_64/e820.c | 105 + kernel/arch/x86_64/entry.S | 174 + kernel/arch/x86_64/entryother.S | 78 + kernel/arch/x86_64/ioapic.c | 102 + kernel/arch/x86_64/lapic.c | 245 + kernel/arch/x86_64/mp.c | 159 + kernel/arch/x86_64/swtch.S | 30 + kernel/arch/x86_64/trap.c | 159 + kernel/arch/x86_64/trapasm.S | 257 + kernel/arch/x86_64/vectors.S | 1281 +++++ kernel/arch/x86_64/vm.c | 631 +++ kernel/core/console.c | 810 +++ kernel/core/dma.c | 191 + kernel/core/kalloc.c | 124 + kernel/core/main.c | 231 + kernel/core/panic.c | 543 ++ kernel/core/qr.c | 456 ++ kernel/core/sleeplock.c | 55 + kernel/core/spinlock.c | 115 + kernel/core/string.c | 113 + kernel/core/time.c | 116 + kernel/core/uaccess.c | 79 + kernel/dev/bio.c | 160 + kernel/dev/cdev.c | 107 + kernel/dev/device.c | 308 ++ kernel/dev/fb.c | 202 + kernel/dev/ide.c | 208 + kernel/dev/input.c | 394 ++ kernel/dev/irq.c | 214 + kernel/dev/kbd.c | 75 + kernel/dev/mouse.c | 214 + kernel/dev/pci.c | 492 ++ kernel/dev/procfs.c | 431 ++ kernel/dev/ramdisk.c | 92 + kernel/dev/text.c | 242 + kernel/dev/ttf.c | 606 +++ kernel/dev/uart.c | 95 + kernel/dev/vga.c | 555 ++ kernel/drivers/bus/xhci/xhci.c | 1365 +++++ kernel/drivers/gpu/vga/vga_pci.c | 95 + kernel/drivers/gpu/virtio_gpu/virtio_gpu.c | 435 ++ kernel/drivers/net/e1000/e1000.c | 456 ++ kernel/drivers/registry.c | 114 + kernel/drivers/usb/core/usb.c | 209 + kernel/drivers/usb/hid/usb_hid.c | 305 ++ kernel/drivers/usb/hub/usb_hub.c | 185 + kernel/drivers/usb/storage/usb_storage.c | 395 ++ kernel/fs/exec.c | 241 + kernel/fs/file.c | 294 ++ kernel/fs/fs.c | 1839 +++++++ kernel/fs/log.c | 255 + kernel/fs/pipe.c | 166 + kernel/fs/procfs.c | 524 ++ kernel/fs/schfs/btree.c | 1181 +++++ kernel/fs/schfs/btree.h | 215 + kernel/fs/schfs/kmount.c | 623 +++ kernel/fs/schfs/obj.c | 441 ++ kernel/fs/schfs/objw.c | 932 ++++ kernel/fs/schfs/schfs_int.h | 277 + kernel/fs/schfs/space.c | 314 ++ kernel/fs/schfs/vfs.c | 414 ++ kernel/fs/schfs/vol.c | 299 ++ kernel/kernel.ld | 104 + kernel/net/unix.c | 441 ++ kernel/proc/proc.c | 838 +++ kernel/sys/linux_abi.c | 33 + kernel/sys/sys_compat.c | 162 + kernel/sys/sys_fs.c | 1413 +++++ kernel/sys/sys_mem.c | 479 ++ kernel/sys/sys_net.c | 346 ++ kernel/sys/sys_poll.c | 292 ++ kernel/sys/sys_proc.c | 451 ++ kernel/sys/sys_sig.c | 296 ++ kernel/sys/sys_time.c | 139 + kernel/sys/syscall.c | 141 + kernel/sys/table.inc | 282 + lib/glue.c | 24 + lib/initcode.S | 25 + lib/start.S | 44 + lib/user.ld | 43 + lib/usys.S | 110 + ...JetBrainsMono-Italic-VariableFont_wght.ttf | Bin 0 -> 193160 bytes .../JetBrainsMono-VariableFont_wght.ttf | Bin 0 -> 189028 bytes ports/JetBrains_Mono/OFL.txt | 93 + ports/JetBrains_Mono/README.txt | 79 + .../static/JetBrainsMono-Bold.ttf | Bin 0 -> 114828 bytes .../static/JetBrainsMono-BoldItalic.ttf | Bin 0 -> 117920 bytes .../static/JetBrainsMono-ExtraBold.ttf | Bin 0 -> 114800 bytes .../static/JetBrainsMono-ExtraBoldItalic.ttf | Bin 0 -> 117952 bytes .../static/JetBrainsMono-ExtraLight.ttf | Bin 0 -> 115072 bytes .../static/JetBrainsMono-ExtraLightItalic.ttf | Bin 0 -> 118228 bytes .../static/JetBrainsMono-Italic.ttf | Bin 0 -> 117940 bytes .../static/JetBrainsMono-Light.ttf | Bin 0 -> 115020 bytes .../static/JetBrainsMono-LightItalic.ttf | Bin 0 -> 118124 bytes .../static/JetBrainsMono-Medium.ttf | Bin 0 -> 114920 bytes .../static/JetBrainsMono-MediumItalic.ttf | Bin 0 -> 118044 bytes .../static/JetBrainsMono-Regular.ttf | Bin 0 -> 114904 bytes .../static/JetBrainsMono-SemiBold.ttf | Bin 0 -> 114900 bytes .../static/JetBrainsMono-SemiBoldItalic.ttf | Bin 0 -> 118032 bytes .../static/JetBrainsMono-Thin.ttf | Bin 0 -> 114996 bytes .../static/JetBrainsMono-ThinItalic.ttf | Bin 0 -> 118156 bytes ports/Makefile | 34 + ports/Roboto/OFL.txt | 93 + ports/Roboto/README.txt | 118 + .../Roboto-Italic-VariableFont_wdth,wght.ttf | Bin 0 -> 530052 bytes .../Roboto/Roboto-VariableFont_wdth,wght.ttf | Bin 0 -> 487768 bytes ports/Roboto/static/Roboto-Black.ttf | Bin 0 -> 160316 bytes ports/Roboto/static/Roboto-BlackItalic.ttf | Bin 0 -> 166780 bytes ports/Roboto/static/Roboto-Bold.ttf | Bin 0 -> 159900 bytes ports/Roboto/static/Roboto-BoldItalic.ttf | Bin 0 -> 166256 bytes ports/Roboto/static/Roboto-ExtraBold.ttf | Bin 0 -> 160012 bytes .../Roboto/static/Roboto-ExtraBoldItalic.ttf | Bin 0 -> 166428 bytes ports/Roboto/static/Roboto-ExtraLight.ttf | Bin 0 -> 159200 bytes .../Roboto/static/Roboto-ExtraLightItalic.ttf | Bin 0 -> 164780 bytes ports/Roboto/static/Roboto-Italic.ttf | Bin 0 -> 165268 bytes ports/Roboto/static/Roboto-Light.ttf | Bin 0 -> 159200 bytes ports/Roboto/static/Roboto-LightItalic.ttf | Bin 0 -> 165052 bytes ports/Roboto/static/Roboto-Medium.ttf | Bin 0 -> 159296 bytes ports/Roboto/static/Roboto-MediumItalic.ttf | Bin 0 -> 165580 bytes ports/Roboto/static/Roboto-Regular.ttf | Bin 0 -> 159108 bytes ports/Roboto/static/Roboto-SemiBold.ttf | Bin 0 -> 159876 bytes ports/Roboto/static/Roboto-SemiBoldItalic.ttf | Bin 0 -> 166148 bytes ports/Roboto/static/Roboto-Thin.ttf | Bin 0 -> 158840 bytes ports/Roboto/static/Roboto-ThinItalic.ttf | Bin 0 -> 164132 bytes .../Roboto/static/Roboto_Condensed-Black.ttf | Bin 0 -> 160152 bytes .../static/Roboto_Condensed-BlackItalic.ttf | Bin 0 -> 166748 bytes ports/Roboto/static/Roboto_Condensed-Bold.ttf | Bin 0 -> 159656 bytes .../static/Roboto_Condensed-BoldItalic.ttf | Bin 0 -> 166156 bytes .../static/Roboto_Condensed-ExtraBold.ttf | Bin 0 -> 159948 bytes .../Roboto_Condensed-ExtraBoldItalic.ttf | Bin 0 -> 166504 bytes .../static/Roboto_Condensed-ExtraLight.ttf | Bin 0 -> 159344 bytes .../Roboto_Condensed-ExtraLightItalic.ttf | Bin 0 -> 165516 bytes .../Roboto/static/Roboto_Condensed-Italic.ttf | Bin 0 -> 165308 bytes .../Roboto/static/Roboto_Condensed-Light.ttf | Bin 0 -> 159200 bytes .../static/Roboto_Condensed-LightItalic.ttf | Bin 0 -> 165604 bytes .../Roboto/static/Roboto_Condensed-Medium.ttf | Bin 0 -> 159080 bytes .../static/Roboto_Condensed-MediumItalic.ttf | Bin 0 -> 165584 bytes .../static/Roboto_Condensed-Regular.ttf | Bin 0 -> 158972 bytes .../static/Roboto_Condensed-SemiBold.ttf | Bin 0 -> 159600 bytes .../Roboto_Condensed-SemiBoldItalic.ttf | Bin 0 -> 165788 bytes ports/Roboto/static/Roboto_Condensed-Thin.ttf | Bin 0 -> 159400 bytes .../static/Roboto_Condensed-ThinItalic.ttf | Bin 0 -> 165084 bytes .../static/Roboto_SemiCondensed-Black.ttf | Bin 0 -> 160388 bytes .../Roboto_SemiCondensed-BlackItalic.ttf | Bin 0 -> 166896 bytes .../static/Roboto_SemiCondensed-Bold.ttf | Bin 0 -> 159828 bytes .../Roboto_SemiCondensed-BoldItalic.ttf | Bin 0 -> 166256 bytes .../static/Roboto_SemiCondensed-ExtraBold.ttf | Bin 0 -> 159988 bytes .../Roboto_SemiCondensed-ExtraBoldItalic.ttf | Bin 0 -> 166524 bytes .../Roboto_SemiCondensed-ExtraLight.ttf | Bin 0 -> 159320 bytes .../Roboto_SemiCondensed-ExtraLightItalic.ttf | Bin 0 -> 165260 bytes .../static/Roboto_SemiCondensed-Italic.ttf | Bin 0 -> 165332 bytes .../static/Roboto_SemiCondensed-Light.ttf | Bin 0 -> 159264 bytes .../Roboto_SemiCondensed-LightItalic.ttf | Bin 0 -> 165484 bytes .../static/Roboto_SemiCondensed-Medium.ttf | Bin 0 -> 159260 bytes .../Roboto_SemiCondensed-MediumItalic.ttf | Bin 0 -> 165604 bytes .../static/Roboto_SemiCondensed-Regular.ttf | Bin 0 -> 159088 bytes .../static/Roboto_SemiCondensed-SemiBold.ttf | Bin 0 -> 159812 bytes .../Roboto_SemiCondensed-SemiBoldItalic.ttf | Bin 0 -> 165968 bytes .../static/Roboto_SemiCondensed-Thin.ttf | Bin 0 -> 159328 bytes .../Roboto_SemiCondensed-ThinItalic.ttf | Bin 0 -> 164788 bytes ports/mk/port.mk | 48 + ports/mksh/Makefile | 45 + ports/musl/Makefile | 54 + ports/musl/patches/0001-schunix-tls.patch | 133 + ports/toybox/Makefile | 82 + projects/README.md | 57 + projects/schcom/README.md | 42 + projects/schde/README.md | 27 + projects/schfs-linux/LICENSE | 178 + projects/schfs-linux/README.md | 72 + projects/schinst/README.md | 60 + projects/schwm/README.md | 27 + run.ps1 | 113 + tools/bootcheck.ps1 | 433 ++ tools/crashqr.py | 85 + tools/crashshot.ps1 | 115 + tools/dispshot.ps1 | 116 + tools/fbshot.ps1 | 87 + tools/loc.ps1 | 200 + tools/makeiso.ps1 | 153 + tools/mkfs.c | 1244 +++++ tools/mkiso.sh | 91 + tools/mklogo.py | 184 + tools/mkschfs.c | 650 +++ tools/mktree.sh | 38 + tools/mutate.sh | 136 + tools/padstage2.pl | 24 + tools/pr.pl | 36 + tools/qrcheck.py | 185 + tools/qrtest.c | 354 ++ tools/schfs_fsck.c | 720 +++ tools/schfs_objtest.c | 568 ++ tools/schfs_roundtrip.sh | 120 + tools/schfs_test.c | 617 +++ tools/sign.pl | 19 + tools/splashshot.ps1 | 134 + tools/textshot.ps1 | 116 + tools/ttftest.c | 81 + tools/ttyshot.ps1 | 92 + tools/vectors.pl | 27 + 275 files changed, 51417 insertions(+) create mode 100644 .#README create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 Assets/Schunix Full Logo.png create mode 100644 Assets/Schunix Full Logo.svg create mode 100644 Assets/Schunix Small Logo.png create mode 100644 Assets/Schunix Small Logo.svg create mode 100644 Assets/Schunix Text Logo.png create mode 100644 Assets/Schunix Text Logo.svg create mode 100644 LICENSE create mode 100644 LICENSE.MIT create mode 100644 Makefile create mode 100644 NOTICE create mode 100644 boot/bootasm.S create mode 100644 boot/cdboot.S create mode 100644 boot/stage2.S create mode 100644 boot/stage2main.c create mode 100644 cmd/fbinfo/main.c create mode 100644 cmd/init/main.c create mode 100644 cmd/inputtest/main.c create mode 100644 cmd/shmtest/main.c create mode 100644 cmd/socktest/main.c create mode 100644 docs/architecture/kernel-history.md create mode 100644 docs/architecture/schapi.md create mode 100644 docs/architecture/schfs.md create mode 100644 docs/drivers.md create mode 100644 docs/layout.md create mode 100644 docs/licensing.md create mode 100644 docs/roadmap.md create mode 100644 include/asm.h create mode 100644 include/buf.h create mode 100644 include/config_sinit.h create mode 100644 include/date.h create mode 100644 include/defs.h create mode 100644 include/device.h create mode 100644 include/display.h create mode 100644 include/dma.h create mode 100644 include/e1000.h create mode 100644 include/elf.h create mode 100644 include/errno.h create mode 100644 include/fb.h create mode 100644 include/fcntl.h create mode 100644 include/file.h create mode 100644 include/font.h create mode 100644 include/fs.h create mode 100644 include/input.h create mode 100644 include/irq.h create mode 100644 include/kbd.h create mode 100644 include/logo.h create mode 100644 include/memlayout.h create mode 100644 include/mmu.h create mode 100644 include/mp.h create mode 100644 include/param.h create mode 100644 include/pci.h create mode 100644 include/posix.h create mode 100644 include/proc.h create mode 100644 include/qr.h create mode 100644 include/schfs.h create mode 100644 include/sleeplock.h create mode 100644 include/socket.h create mode 100644 include/spinlock.h create mode 100644 include/stat.h create mode 100644 include/syscall.h create mode 100644 include/text.h create mode 100644 include/theme.h create mode 100644 include/traps.h create mode 100644 include/ttf.h create mode 100644 include/types.h create mode 100644 include/uaccess.h create mode 100644 include/usb.h create mode 100644 include/user.h create mode 100644 include/virtio.h create mode 100644 include/x86.h create mode 100644 include/xhci.h create mode 100644 kernel/arch/x86_64/acpi.c create mode 100644 kernel/arch/x86_64/e820.c create mode 100644 kernel/arch/x86_64/entry.S create mode 100644 kernel/arch/x86_64/entryother.S create mode 100644 kernel/arch/x86_64/ioapic.c create mode 100644 kernel/arch/x86_64/lapic.c create mode 100644 kernel/arch/x86_64/mp.c create mode 100644 kernel/arch/x86_64/swtch.S create mode 100644 kernel/arch/x86_64/trap.c create mode 100644 kernel/arch/x86_64/trapasm.S create mode 100644 kernel/arch/x86_64/vectors.S create mode 100644 kernel/arch/x86_64/vm.c create mode 100644 kernel/core/console.c create mode 100644 kernel/core/dma.c create mode 100644 kernel/core/kalloc.c create mode 100644 kernel/core/main.c create mode 100644 kernel/core/panic.c create mode 100644 kernel/core/qr.c create mode 100644 kernel/core/sleeplock.c create mode 100644 kernel/core/spinlock.c create mode 100644 kernel/core/string.c create mode 100644 kernel/core/time.c create mode 100644 kernel/core/uaccess.c create mode 100644 kernel/dev/bio.c create mode 100644 kernel/dev/cdev.c create mode 100644 kernel/dev/device.c create mode 100644 kernel/dev/fb.c create mode 100644 kernel/dev/ide.c create mode 100644 kernel/dev/input.c create mode 100644 kernel/dev/irq.c create mode 100644 kernel/dev/kbd.c create mode 100644 kernel/dev/mouse.c create mode 100644 kernel/dev/pci.c create mode 100644 kernel/dev/procfs.c create mode 100644 kernel/dev/ramdisk.c create mode 100644 kernel/dev/text.c create mode 100644 kernel/dev/ttf.c create mode 100644 kernel/dev/uart.c create mode 100644 kernel/dev/vga.c create mode 100644 kernel/drivers/bus/xhci/xhci.c create mode 100644 kernel/drivers/gpu/vga/vga_pci.c create mode 100644 kernel/drivers/gpu/virtio_gpu/virtio_gpu.c create mode 100644 kernel/drivers/net/e1000/e1000.c create mode 100644 kernel/drivers/registry.c create mode 100644 kernel/drivers/usb/core/usb.c create mode 100644 kernel/drivers/usb/hid/usb_hid.c create mode 100644 kernel/drivers/usb/hub/usb_hub.c create mode 100644 kernel/drivers/usb/storage/usb_storage.c create mode 100644 kernel/fs/exec.c create mode 100644 kernel/fs/file.c create mode 100644 kernel/fs/fs.c create mode 100644 kernel/fs/log.c create mode 100644 kernel/fs/pipe.c create mode 100644 kernel/fs/procfs.c create mode 100644 kernel/fs/schfs/btree.c create mode 100644 kernel/fs/schfs/btree.h create mode 100644 kernel/fs/schfs/kmount.c create mode 100644 kernel/fs/schfs/obj.c create mode 100644 kernel/fs/schfs/objw.c create mode 100644 kernel/fs/schfs/schfs_int.h create mode 100644 kernel/fs/schfs/space.c create mode 100644 kernel/fs/schfs/vfs.c create mode 100644 kernel/fs/schfs/vol.c create mode 100644 kernel/kernel.ld create mode 100644 kernel/net/unix.c create mode 100644 kernel/proc/proc.c create mode 100644 kernel/sys/linux_abi.c create mode 100644 kernel/sys/sys_compat.c create mode 100644 kernel/sys/sys_fs.c create mode 100644 kernel/sys/sys_mem.c create mode 100644 kernel/sys/sys_net.c create mode 100644 kernel/sys/sys_poll.c create mode 100644 kernel/sys/sys_proc.c create mode 100644 kernel/sys/sys_sig.c create mode 100644 kernel/sys/sys_time.c create mode 100644 kernel/sys/syscall.c create mode 100644 kernel/sys/table.inc create mode 100644 lib/glue.c create mode 100644 lib/initcode.S create mode 100644 lib/start.S create mode 100644 lib/user.ld create mode 100644 lib/usys.S create mode 100644 ports/JetBrains_Mono/JetBrainsMono-Italic-VariableFont_wght.ttf create mode 100644 ports/JetBrains_Mono/JetBrainsMono-VariableFont_wght.ttf create mode 100644 ports/JetBrains_Mono/OFL.txt create mode 100644 ports/JetBrains_Mono/README.txt create mode 100644 ports/JetBrains_Mono/static/JetBrainsMono-Bold.ttf create mode 100644 ports/JetBrains_Mono/static/JetBrainsMono-BoldItalic.ttf create mode 100644 ports/JetBrains_Mono/static/JetBrainsMono-ExtraBold.ttf create mode 100644 ports/JetBrains_Mono/static/JetBrainsMono-ExtraBoldItalic.ttf create mode 100644 ports/JetBrains_Mono/static/JetBrainsMono-ExtraLight.ttf create mode 100644 ports/JetBrains_Mono/static/JetBrainsMono-ExtraLightItalic.ttf create mode 100644 ports/JetBrains_Mono/static/JetBrainsMono-Italic.ttf create mode 100644 ports/JetBrains_Mono/static/JetBrainsMono-Light.ttf create mode 100644 ports/JetBrains_Mono/static/JetBrainsMono-LightItalic.ttf create mode 100644 ports/JetBrains_Mono/static/JetBrainsMono-Medium.ttf create mode 100644 ports/JetBrains_Mono/static/JetBrainsMono-MediumItalic.ttf create mode 100644 ports/JetBrains_Mono/static/JetBrainsMono-Regular.ttf create mode 100644 ports/JetBrains_Mono/static/JetBrainsMono-SemiBold.ttf create mode 100644 ports/JetBrains_Mono/static/JetBrainsMono-SemiBoldItalic.ttf create mode 100644 ports/JetBrains_Mono/static/JetBrainsMono-Thin.ttf create mode 100644 ports/JetBrains_Mono/static/JetBrainsMono-ThinItalic.ttf create mode 100644 ports/Makefile create mode 100644 ports/Roboto/OFL.txt create mode 100644 ports/Roboto/README.txt create mode 100644 ports/Roboto/Roboto-Italic-VariableFont_wdth,wght.ttf create mode 100644 ports/Roboto/Roboto-VariableFont_wdth,wght.ttf create mode 100644 ports/Roboto/static/Roboto-Black.ttf create mode 100644 ports/Roboto/static/Roboto-BlackItalic.ttf create mode 100644 ports/Roboto/static/Roboto-Bold.ttf create mode 100644 ports/Roboto/static/Roboto-BoldItalic.ttf create mode 100644 ports/Roboto/static/Roboto-ExtraBold.ttf create mode 100644 ports/Roboto/static/Roboto-ExtraBoldItalic.ttf create mode 100644 ports/Roboto/static/Roboto-ExtraLight.ttf create mode 100644 ports/Roboto/static/Roboto-ExtraLightItalic.ttf create mode 100644 ports/Roboto/static/Roboto-Italic.ttf create mode 100644 ports/Roboto/static/Roboto-Light.ttf create mode 100644 ports/Roboto/static/Roboto-LightItalic.ttf create mode 100644 ports/Roboto/static/Roboto-Medium.ttf create mode 100644 ports/Roboto/static/Roboto-MediumItalic.ttf create mode 100644 ports/Roboto/static/Roboto-Regular.ttf create mode 100644 ports/Roboto/static/Roboto-SemiBold.ttf create mode 100644 ports/Roboto/static/Roboto-SemiBoldItalic.ttf create mode 100644 ports/Roboto/static/Roboto-Thin.ttf create mode 100644 ports/Roboto/static/Roboto-ThinItalic.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-Black.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-BlackItalic.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-Bold.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-BoldItalic.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-ExtraBold.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-ExtraBoldItalic.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-ExtraLight.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-ExtraLightItalic.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-Italic.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-Light.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-LightItalic.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-Medium.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-MediumItalic.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-Regular.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-SemiBold.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-SemiBoldItalic.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-Thin.ttf create mode 100644 ports/Roboto/static/Roboto_Condensed-ThinItalic.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-Black.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-BlackItalic.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-Bold.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-BoldItalic.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-ExtraBold.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-ExtraBoldItalic.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-ExtraLight.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-ExtraLightItalic.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-Italic.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-Light.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-LightItalic.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-Medium.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-MediumItalic.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-Regular.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-SemiBold.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-SemiBoldItalic.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-Thin.ttf create mode 100644 ports/Roboto/static/Roboto_SemiCondensed-ThinItalic.ttf create mode 100644 ports/mk/port.mk create mode 100644 ports/mksh/Makefile create mode 100644 ports/musl/Makefile create mode 100644 ports/musl/patches/0001-schunix-tls.patch create mode 100644 ports/toybox/Makefile create mode 100644 projects/README.md create mode 100644 projects/schcom/README.md create mode 100644 projects/schde/README.md create mode 100644 projects/schfs-linux/LICENSE create mode 100644 projects/schfs-linux/README.md create mode 100644 projects/schinst/README.md create mode 100644 projects/schwm/README.md create mode 100644 run.ps1 create mode 100644 tools/bootcheck.ps1 create mode 100644 tools/crashqr.py create mode 100644 tools/crashshot.ps1 create mode 100644 tools/dispshot.ps1 create mode 100644 tools/fbshot.ps1 create mode 100644 tools/loc.ps1 create mode 100644 tools/makeiso.ps1 create mode 100644 tools/mkfs.c create mode 100644 tools/mkiso.sh create mode 100644 tools/mklogo.py create mode 100644 tools/mkschfs.c create mode 100644 tools/mktree.sh create mode 100644 tools/mutate.sh create mode 100644 tools/padstage2.pl create mode 100644 tools/pr.pl create mode 100644 tools/qrcheck.py create mode 100644 tools/qrtest.c create mode 100644 tools/schfs_fsck.c create mode 100644 tools/schfs_objtest.c create mode 100644 tools/schfs_roundtrip.sh create mode 100644 tools/schfs_test.c create mode 100644 tools/sign.pl create mode 100644 tools/splashshot.ps1 create mode 100644 tools/textshot.ps1 create mode 100644 tools/ttftest.c create mode 100644 tools/ttyshot.ps1 create mode 100644 tools/vectors.pl diff --git a/.#README b/.#README new file mode 100644 index 0000000000000000000000000000000000000000..d0971589da6f5d2b596045e156dfe43f04e9ca69 GIT binary patch literal 82 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Assets/Schunix Small Logo.png b/Assets/Schunix Small Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..35bf538996cbf66a8018e0d776765b724356e4df GIT binary patch literal 83048 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 z z^(xC40_|JhmX}14-tb?itGyUq{Z6~h z9~^v}+>>Wdu|6$He(A7T8NUVVXF(M4z0Y)q<@1)&)Y4jZ>`DH8!pF;bM|+?91e-gn zp(q!m&!4dVArZ7SzvgFoURY`BGNq5@L!TK?riv+&)$#{JAcX&dXhMgvX}eBT{2Vu| zlRt43zpkJ?JBf0N3zO%wAyYSM{ZS6Vqd-DV${FZ#Ov}>NoG~vs7y`8pAf%vZ?X~q- z{HDTieo&xW%0pRjL3iiX{@p|(d4eR zk!5ofnv(@S=cU`>!l=!1_Mu)+l2BXECkP`UQkVqIf0(4oU#44NIKLYhMCD6-FMD~e zVajU@dO+w;(8`tf4ftV{XP*)eET8K?wg2|@^p?H8+CP{MRy0G-KxK}3Nk9Y2t@?rv z(Om|<+!U4=z&^;1jpmduu7$s;U*OF0mG;enb>9s82|&BeP<0%Al*ij+SwUT+pJMpB zREO?CqT`enJr=@!sR=fVcJnkae=e3(GVh z2<;Ev0qsVpdDN5=aV9=4z|F_J`0g1e@GVI&{VOFg*68)i7|TM+RjHBBX6#=s07az@ zVq(|Y4vpUvW{>034IX}BSXC^*W_k)F|&J5a#1)>x!R3StMejj5* zJsGckJY0Xe-{aIb=2xAEyv+(+;9O0CS)6lnmnevpIJ|t44nE~1h-Y-a6`C`@A#=Op zCqrPGBquK6eu#bSy|&60uB|*S^jBIBL+UjO0QIA`pC}c(Eg>%sjR2fQmwGpgms)@? z9A2d(?`~LVr2n-bOGC*eR?vk0Ku@T(Ui6rPv~<(CL1pS-^!-o4!0S(N_=pYl{_H^BpfHGR<^HdVlhM{UDs6L>%I9Jl8<1uA<7zB^*Z8$d1FrJGN*1h3M`>khwEBYBOzMvDy%B)1&#n}zzA+sn zrH;h4qAS*tYUuWj;{oV{I~e!<8(N!{=Y2!@S^MNt9NknPv(j-ny^U zx4s=?E3U|+XJC;ImofLe-gI24I3hAr5MBT<#BK+M)ssb!V1edII)^?dh#C4c3)P`MPs9huge8MqG7HfovhI96PAMSX<8ZtQ_}+-^Ije zOTFVa-cSgMNUe^L%JFxe!^nU8U5(ag+GRIfyL9`yybaVsDIO-SZNj{0VTri0Miabr zA7+^oMQ+gSzjgm$^9*%EbNgMM2rsapDjA0%L+4*@4~UGw!;d!Gif1pYu3G)beJaX^ zIfMZdPnRg__1w`k)L;Dy<>oX^|5B#3b)Fo^X(`B|;}K|a+S;h8Q^Vqr#axdKNJvXB zK1yK?x$p|A*R9`$R(yrpCezqg%TG5#KO}S~Z$bArD6x*$Z-Xi_fb=Jl)F|JajEURd zvpI|wjrKm>KxP5zg^MkQ8_Pj-_vTH0K8v;DSbTIYz zCs@CJ%+zf?S~n4I_jGgMj&=Tg69*{V1x;Xsp%3d|Cfq)D4p|)b!Gt2NXBPV0Pi#$N z$Fyaz6Sm!JI@}B8_Y6~j=@#ja25nfgGRdou?nSJ_Xw11V+( z^Qdg*S>qV=ETvsqXi+vjL-S7BTQ~}MlQJ^<-hlcL=s*MGj4>#25}R3u;(zCS$Zyj# z5WHVoI>t61zE1h%@9-=#eseFmdxUuN-X?#%of*&uC&SXvTNb_VfV_o*iQ8L`sn47} zfQ?Bt-ZyhaMC?l1Y$f*XGX0fvjxe1hF6@)hxUBH&YndsM7-ohVr(Q>9JnkUxIPm$> z4d6r`0h<9*X@`}`eAu$LuPz9mg;0+b+kre?V3RiArnh(QY)S^RZoN#=6^5Fos}3bV zd1gGNniu%05pFBji4y4#6g)Dac#@f+lMlESy%!Q)I)aRv@z`pH7w|f+krmXL0G!Cu+E~?YT zgg#vS6Dw(8;FqHK=X2P=?uKhULU}(&Z`N@I`=HqVp72lMKqL=rOfyr&;n>J^Zy#>p z+VlaEs`i6g5-4?)?Y))BXN`*R@Oz6j{1O|cUPYedXxw`6Z&C7l%?}pG8L=W1)cm#u z+y=|#q5Ml4HlXq=J=~1NpZ{G($fmF3i6(8XI)@dhK_Hwh#Qb2JZ=)YH(7@5akXFiS zb_MQgNBAdY6XKPVhWh@3Y*=e1gm)IrBC?de3-2Ip2GE!Q_G5-rQ3I0X8ib{%Ll8}V zrS15kL5aQ3;LObNH66ylEs*LjPA@xf>Eeun@`|#rm+raaY=Pw3aM{`RDhCwE%bk%YUK@GL?xfkBzRfkMOwijuw%e%jn zF2ZV;qw3ITJCsfr2(K@J{PIO-2c#V`TpBlFk)h(B@^{L(^!Bm=UHbt*xjao_#rZQG zM4PVEkY*_fsiQzl6%g>2hn@&T=BJveTtD;+*ytV^El}m>Q~mc z!uSBcHY9~?CG8Nl8+w1--#gVKid$+}JIpIul>EwJb6=wC7}Rjc&nQ?l75r6TjS==8 z^X$9pUutkb+KW=1zoW6SQRI^Ud|P@}0*A_9D`vNvccrzZJD)f|54sg@v+`TWnCYcA zBvjV=F!144)`1jcq!?|p&Q-#jA#HUj2DEo~BCf%_cgA`Aq}2^DbU8DZ*KAF1-SYiA za2o#q>iwGUlwD@|DC7C@@$o!)fIJ+U7M?M-wi&D8S>REt2;UD#aY7_^B4PaU!3ZD! z0k#x!49EaF=waaZ6Fk6JW;HwN)Uc#atM-l^lP*em5lT21QaJ5d_{aSB6IO1WOY_ho zh}s98dHamo{$c~aL_VKpfxMn0%8u47XC+(+s|!##7!AxbMBKAyPe=AWFekRq z0QXh7jXp~Zf67LMW7MYdeWm9Ig0I6`ys*~Mpuyp3#r&V=FiI$T`Mj{-P!l{hW)X8! zSqsC8kOlBfE^|2@((N^-O|?G`xDrfL*33B;PkODPMx}u`2qnypa0J6rt5Z|SmI7km zwy#SM`-^UikNokg!hlUmXd~mP2O#A^qbEE1KEY6Ntt9&jksgMHPW+N65P5s49{k6lC_&tP5?pm8QHKyp4 z&(D_H(Q(VVK^48s@Bd|^nxg=+^jG@OJ%yhc+Ku46DN?$Z?2L+Z)|;RhWhlKnG=5V~ z*+x;d2ZE)BM+1&V5NgMbFM0jC1Em83pe&u8wer(7@ZiL5IG$!XJ9~=h-5LJ2wR$oh z02(t0L(ut(A}xxaPWIM!bQ%v^gfFttlc@S19OsRFdNz=6Pd!0TEcy z{*xRwAuMM8qGeAXaf3g@{tzP2$3B(4dqC*Tv5#*U)2jiS>KnPswOvf1fwAwjk}8x% zG`m&Rv zYTMb`zJS79GNh08$bWW(QmDKi#%?=Fpvi+y6}7r5(EyTyjV39=Z2iXcQ+!^9UW7&^ zG5TOa5NW2WCQaN-beGMhhVuJv>=>Unn{S+G9B?%xu8BB8dd{o@;Tjwt7LVb85OR~~ z4pNwgEgegViP5-`xAqA&L-ThJ4K`bp|GK+h2brfTkI^$rt++yf^qMxt6+u|d^r5;E z95#~Zv+e?|v2oq*=C9wLd+to7Ld7B5rNw=LrRxU4s$N@r_h}taw5WffSF0Y{Tf!?p zHqT)Ygd^GaUY|-H>6owY%QT`G?Zwsab(=Iq-B&7+OM1MOuuH|+rE?5$3U(&{GGpKqY8#wO$hu~k&veX1}0q+t#@ zM~W3X{MA% zRV(~EPDXj{`FGp>`ulH-jkOi~)^A?@37P9DP;rk1W+J632a5b}9ZhFB<>)ey1#4gb}{`hR#gk~DdQ~C;+lTlG9D*xyO%#vLPcg87En&MR0G8&<{ zqY&cnLaZ9|qQ2G;Lkp*&DbjB_2%DqKh1;+>ud%^r?(f{cg1Z6K@MuU!lHBl@Wgls zOD^c&=L=GHV^}9~p78_JMLwF*?x{tycmlrqgbFp5?=Jc^*4vy1Wp+Nhr;QmV??I&B zkSk#%Ly7hM-G6%6K^m%YgLH@i*Mc3O|KVZc7Eox^5aFOCd~U6B;)Yn^hHlqU$;SJA z4iJJ2Dv9cYt_@?~xp9?@ve2xeVFliJ$2Tr#rVp>9Gs_9ai6>DYQkNz}P}-Qvc;$4Y zE2S#b54@vCoddRCfBMJ#O>d|77qpPj3GnLAa1Die7At_Fw3)f+G>uxO_1cWOkLrvb zB?T@Io!E(lRXoD841E_3xlszME%hiC zGo1m_-<5j#BE7*r+9bKBL9?%vQ_<(Uc(P_P7VyHY1WoQ=t=CDR0rnlN!vfT^AY1>kF!Rq>T6pp8;~Vi*rA zdgJ4#m{QPHFuk9bNdBVQcM9BGsQRf|P%4}dTmh@O)irkc-sWJY`A2Fjq^X`zl@6Kp zG&zGPj^7$G&imGVT=z3CyF+(v*>Tyld{au&+{c%njG_I^K2{D6E66m_f56vUiBOt`P*d7q0t}M3g;Kib(yeqDfai!^sFN^e%NE2=tbBDYzrwm}*7gGC-S=BV(JMS2qVGw2TV!M+{(-v5Q^ zw#e3bk(o{1gz?jwG;59#moK!Xloe z3DBb0ypu$knM!_gRS-ND!`@Xjy)uwEV|TgRps`Ll(oM-zLq^6{%g}6BZ;YdCXIx~5}Ra2 zp`S*3L+gcLOZ(?V=b6}#zUr8ZKgFqheS0M1E0M|{-?rXi*VNj&Q)e_XcFX-NIq9SU z8+VuT47N?1$~2BR$0w3T78$q2J~&b0K121Z>Khr%n;%MaP5#an_t3a$(ea1|{lnK-%);C!X|rR<-wc7vlL%(~s5lMKw!(nqR1D zDoeS!ggr78CWci>ZD7(p+%aoI*_Plw$ve)V)w`nD4pZcqcQF7N|MntznoD!MQ)f+L zSfEEFX)-O;=FhLQSTb5Ul=OwU2$I|^$~(S>G&pKAZ(g1spHSMs8f)m9 zcycU1%<~&QN-B!_6A4|SB}d%KqP4EcFE5y=b!tj;dLI%?4?cU%!?SawiRzynU90qI zzQ4*G#;Hj%O`MJ|C#qt$#CXs(p0SL}kE^av zg?=vaPmBMCnxl_SaumCjUA&pMp}{GdpUTaN@knq0Qkgy;)mQc=jc4y)e&J8Q&|Bi+ zk@5txj-&-Nj$ixq;9x|xdgQ`%hi_l{bjiyf>&sf44pKVwrJ0`RB0Idu-^jX6?HgiY z@iZJGhJE5f_aq2SWXM|h<11TljC7l$N=Z)>&$-$s;@0t%i=y(JH+4f~nzyU4@rmg@ zFNBpj`ZiyDFIY!gdAXaOXFFP%CF&#eLsL`tdFXNPc`S_f$TLv`lk@@F_frFX{n-fj z$%J-JNdBbIkKe7@C+%`Eo$tCueXC{^A?O5L$F)n51c!ioHp-+1vg6@zBdTZOv5=1g zK2;Hf>FZ6Gta>b+`k;hv(fq&54p;U$!+(B}YL7eJa)UmK%vrv%t%fP$@cdQE#9@3) zv9NXo;mXz_*$c(M(M&chcPmdlf8gHa-&+2WBOS+pUERJBu&aYa|3D>~&Bl?AC0dgZ95*d}EIsL#S!8O5 zsi%osQ;%H_hE=Or1I}J;ht#R}DeBAIIPegS%r6sIzz4w}RlD=R>PTlh(iUx(SlgA?5c zbL1mzRwb1&o|m*|sdIQHN%?#zMWI3N#R0jf>LVNuzS+_BHuPs7l<&jI-@l$Z(dO^_ zy$G?JC1sld6VB^=lOT2_Yi{0eZ^+;*Og>BDb9mx$Pds;REB1*W5mVYWE(P*_d~*Jz z*n;?Ypqm4CkYWe@q(jSV7}avtl77%+(3NS>IFL_b(6##1-kS~c3Y%DpH7$s6n>xKK z*(ube&lb?dbnO}^I2Sk3mW<>Of6*rEndfm&fV8@4hr(3#bUWuTYI$!vasU?pWu4>> z$3LZ8-xtLTeZSj?6dh*m6TO{AQDTz`=&-p*NfOG-*=Vc7!=N{4C?2!S`F zJp%IwAM(o*S%x%mdHRzNl5#vWW@2F(778hfqc7t9eIyqava<--($!0?vo}LcKH&MO0|e&v zB|Wn@hHebLe(SO3D-C>RwtR&1+wDN%JAn={JWTN*J-qp?{Ns-k_{MpKD+{ z2^>KeF7!kaSfh(p%Sqz@c6TCB?C~s(ncbT%+4fleUHW)$hq5JlWC3_&jK8h5RpHQ) zaZ#4F8R`lN7w4h+>gItUeX-`);rx0s2cMYG3+X{uwIEov%5@JgcFgBy_kAiH04NPE zS#vxQ*AYmQ;^s!+X%<>LI+R`iZ}F(9Uc1#3-|#1D<(}c;9*L4czBRtenVFgQSvhQ4 zx}ZNuOmX(2;+8?zq2`4|29|rt5v37?(cwzndB^hP{Q ze_4?-kab2PY0QQa*>aa->j%UG2G& z?eXo|$#*$?7{;^#5sjMc>Rb!%kj};=;;`GpY(9oBb7KMg6m#1EiB*a7%J-%i|(SCkHQFrg%pi*&an#J?; zpJYdl6;8hSUAguG#?@iZEdjru1p{qN;J2H3a;y}tkO+i2IV&Cy8aW!FH%Yn%rrDxD zfaI1dl+5dFgRWZuCT4Ujc@lh%4;-ha5wkAOXBG-nzK5p?g2^(yj%cTc(N6#L`$He) zLi}-D4-aY8Y5Z6gYEjNeFp=S;I@^W=%^s4jLob zny?{=`s-v$0u~b9qF~nnX?!zs8Y5<&^gOe1ZV-~UN3Va=>c^WazWj=RH7J3UO>=|PR1ItO9u&t@338|4x5 zcwK&T`73DPFEq)X?Pqr2#EC0Pq$8o^vH*EYVDjG z`giKUv5{0z*>g7PK$&hcUpr@eqI+TXe&M#ZHc727HIhLMtu;)EtZLDO{B36J!3PFi zrS426PU=3aQKzqgJD9gMW2Eo@m7$*=&>{!s<+rP=%ixVTpv9YE+I+}omS^N*r%sa0 zSP&zZmo;=T63srH-3n{(2|uIJ`Ql|jzJ8Xo#$JeY zRg24v$UJ`ZNDF`Uu1Cn*C=z|shi@G%^+sc*4%ajr+<6=MoN<%B*`U&?|5DbKUy8gri{rzfo@d}j*PGHh$movPW_doFa3a-`cY2@7w_Ig-QYEKBP8b*ru~;{K?2=g)eM z$UyS6e_{YU(H^aRES5-#R}s02TaqC8_Q0gO=9EVYjE5&OG(|aaP1tj0{OuQ9wR^=iGuJFBYpJfkApcF|Fm%R<>fwr%++S-kI z0{(5~d>E-0Cc^cZsfD}%!tGM$Xd$b&RG*l?N!fPe+gPLj(H{8s*|c*sAx*bfdu z-}2N&6HoenEx>92Rzw}=#lbxJCQ)L_NI$S;Jn%tLbahpNBb`KZvq5hC_PLIIAEx$w z`PBUoo~0;!LRLilzy^n!#p~Cmy4xO^vO{)(fn;Y>$ZrYY- zJ7p4tmfps`I}!6F0r59?$5I8JDEuZv8yf9rhqB_2uV_a-@# z*6qKLY_KpdvXu%)=d|7^?A-&f; zALpMQ(9gurZ5|Kh02R}EKet1HqKoIUJoVOMJ_p!OkzawFqgj$$^oVCK)>&Xo(Th}} z%BlFH)RL9x{xDmfF5kU5RU`U;7M&Cv4^%lYQkmk&$r_IC&X*Ki z4hj;7LrdGEVmR>XzwPZzhidC5-lV(-CtBAZ!51Dui+0ZMkeWu|AKlZ=8Dx*zbZ%~E z&3__u!wQsib-w4rH{PAr?@MTwYBtJDnclO?`o+Cmc~CT14EwRpYqsW|A=SRnt(H50 zoYl?=lzbO4T$L7oPGJ;N%^N5u4v6gL}J*+!Hlr_m?Z-@cu)gx&i@us?-#3lnNM=Of)h{? z9ABNLZMtOEa-!Mj4eZaxdfvZ%Z|^o{Y}(}QwKhwQICD?>7qzmU?+{>#TOq*W2Ea<5 z>UBlDH+~mp0lk;wm4b9?r&ti&kx^YqMJHZ4{l}mMI`=DY6n(dJyReQdnmzbmw{ znf4c)_pgE14HVlIUR&WlsW~2XUS`Clzy*lUh;o}93k=u?8EYK^tDnmGSa8$Hixneu zK!d=tdmS8v)bx?ca@Ko5igmViv+flO#pSMA5HfsW2L|KH3dfSo?{NOfT6ULVEHVSUdmSP3BHe-6^NInpq zMHGj)6&Ocff#}4yzc?smI97U4@|8W<)og>JLP8psmtU&9LR{OM)4;=w{gR(=)fZ(a zQJv$4W|!L9AsA6Z6C20(!ZWOSkw}G;On2OKFYF}9PTrf;VeC1UIvpd}m9{JLKbEWb zGoks!*kz@r<5W5olPz~nHObb$!>w8V*DGUHkAP~gH_7#l3)3h0#lJt@lRZ@b3hE^O zNaWw#L7$e<6`gLMI~A-ceANOd_}$gg2!Djo7cc2OD>7cT3b7zR!?kY+Oq#d`H` z?LmyQM*hcS{a_$V@D%b_v;f@WFmde2tyHgAS+u8VRjHehc(jp%-lp>WtDrRiOAtdn zH^iMWCecrZ#z>iKAKB}0)C0bKA~dpST2|jzwfzG;;Ne|cWJ#;(KqoU@(6I9a@<=?O z;qjxND}8I!;HI(!^hXGtc&4~=#<2H9Rx`i&c}?@PdRKZHS2r-i$x-5>j-4>W6-;G` znOlkSa-fGG>eiIwY;SL$KM6+_K}UU!jdVxiw*xv{{SG-Cnb~~JR)DUJ_)@{^XXAb3 zsAuKY+2Z#Xcvm5uq6I9-VFKobrrt{rH5D_>S37a4p!4lT%Gvo1=_vuruKYdDJ**E( zKtTczKdVFY4f>{Lo_$s=D!3eU+_oC>R`+2a9j(WNWYIxUjJX0-3*CovMl|-Hd;*R7 ztPz5yZbrAa8{aT&WFj3>BfE$OOm8oqRDa0FH?>RSm35D3>aXU4BO(@#nrAx;`i$|3 z?zJFqv^a2AoF1p{NeN!{(;@urKN~!?r+k$j`^pTSHb*>H!Q|n>6az!UiQ=f&AuuX- z`*g2`br0)K(yHb-B-l06fO`wFya|U!_k)(`eLBM+-hnel3T9Mx@;bbrdnb6k9h}mV zhHl@q-ycaWQGymSY=G19tCul`FVJkRSaw8E{n`Z4y}X&!KT(?>3jjyF>8pa-DlL81 zRT3E$)>yOc(GygDJoii2e@vf{zda)aJ+!({65J|R;(rt@_5BDOgbr)q$8+}6xi_M~ zc~O*l0wQmuAzZJE=LH{}hlS2c#51QZ=+%$sXKStZq%*%rT;v!ewe=`*1eVp+)!FeU z<&f3-Q#9pX=I2je7=NH?QsUC{8BgwOdpYD*R*Q7RR94!B--I!_-G@dQ;pBUh0pv@f z)L%yNU1w+f{vclHMmM-%{awa>gPWPDxhYA$#GB;1s?*=ZvF$?yLFK9*R44jS9;bre z;iy1mb2%T6@)H>U7>vMVef`J7m5U8Ie01)^&|PlnmD;A8^E&-e;Dz+yL3df*?+$@o~$fn&XsB=70+uys^E zXvJr2B)R+E^qx<-OltkD(FFXXhT+_pn&Ioz{*gmTH=Cu9iq%ZBk+x)kcjV#Rrtzri zuU$Zp+@@-&ZI6!V%W;BG8g$fruWlX#7D&zSKdhyz#Z^&+#|J|8;)3Qv?dh9p$nR_$ zmlD?oA%c zI{h0;lU++n#HnX5W%m0~vq&uAW3;fI_ zpd+f>qF11^v!z@DWuouTokErV9Y$b?a~2`YY(zl9!2|v7v-lN3v3roX7?9zi+W9uR z8n1UlyPqWisOA&m7g&DxEf_0Qz)H5?sK_J%o8QyVl=yVo7!O{_Z3CWf)O@83L1f_y!XtIT{bw_)a4OpF|@mlbYB?{eIPRu z3)Ky|o#lKJ;MaclLEW+Cs^lMrfGuF6r8Wc3T2u&LUvVBTPj=OHv8HS)I26b#qd(~S z{5%KH3cIN%eOj$-Ni(ujg^@$d5(8D7(&@W)1_-5MqAf3A{^oe7u#6AAZR)nXBOxcH ztAR>VJAs2N4g@uLDE1|H*O9kgjr+xvm;v{3cL%pphwqy0cob|+N;^qTQi2HfkuZW; zv1;&0&o`CTl=Ja}K!MFI@{dOe|CvmxKDg~gzLX&ZNYIGee?fHxi@FZ({h=sBw!_7qn&YVoh*o^A%X3n{JZL-F)$R zS`}AG)(X8+^TKkKq7x`1X@9%R+!InEMn_Hjy=1a@g|g|J3#QipHIjfoVgK!!uGT(V zpmg~(?SusaLV&Ax#)+bDFifS-Z*|;a&7HIwjpz6N$!$G9)Du)$>B?WP@Q66lcdJQu zgi_EF{Om7;BE&8<4=vyhY4r6z=}i%To0n4fZg645uG?C2e#CL&^T;@vJV~9EZGY04 zkoQu0jq~wrev+izNC3!HZs4vUv5+tQ9ZLXYY9K zAH}zLM0SK~HP)J;Ji5>XiHX993B(FutjD{GMeYeNUw&)nGf_uIn`WEjU9Hj?;q9=% z>Kvd%u90r?=#y{yG%@|q zLoKlCQ$`B#s26%>4!0(MBhYU%k#if3C#$65)}v`uS3!3z{0x%kp+ z&y7IawTh6~P(hY9g~!lRG#XcJ=Pz$QVkp@ij-w|k0>3*`PK}4uVWAEzLD-8c#4%6v{TbM zq@(fxm!;Rf4U{iTH4#omm<0cu0N2#Y7Lp>#&A&`9!$1gW@DDuDz0#wogj(;4JSb*2 z%{)BjX)ps1dnv=9+^G3F`0je@-ohCBH#7}cC8}a8`HhE~eWLrU=S1hcG*Wq>8q96@ z3o9P1N%}wMl~M@p04Nv=%dbh=#XU10@zoD{hUbL`7 zP)1IUf446I(C~aX0&F$Jyckw6Qn%lgVomaYU(To6RQ9USw$Z1%d?Unp0+FP_hG&-q z@W};}Oy4v#@P6;nCNPx+a5EX=b&BA>vYo!m>`;L29!GN=2O<+RrU-0t)!vnGkUQSV zG(rjdYf|Pmya`_iusT*A#&$>vMFTJ@?N?N`!H8W34MOoGQ|p*jzSnKEZ!B=m90q8I zHI+REl=r#1MqQOgN^@Wwvio?>qwdl>G|lXLSYLO5e*@RKzPIIVdyfyf<1d5M;vMO> zV;45L{*88?U5NBI$S(~&bd8yl02|le3bNcF69Rq;dvN)vaqfX%i3#x8>lEs82cfD5 ztygh?_SJrIE7dF-z^WK(lxLU-|IRs$K19b+W}UbrlB)??^PNb@mxmRdzpIM zL+y3NqQw&_=T0z+F|0Zt$v2i5KczKUlz~D&CPP~F`N!ZYeo=|bOHvy3<|XuF(}2|D zh{aVF5gvr9g9#{sSArLLBXJ9+$9!CWU_Tw%;YYG4w#F(n(w)A4-@fFx=s-QRyE~qq z==Q}-LmAvz#J=iYFyq|gAtYe*^2;|R{|6&BMoD? z+P|q_ZzLcrhNFIju;6mCZj+O&nY_?6Tf|=I~dm6UkRNDbvA*% zjXg7$?!NxfNrM}7vmeHGU!UZ6pl#35=pn|f>5|A1^p`zwplQK%K>TF}oB>p#1%`k7 z?@Gc4+6O2t1B;OxjF8~M-^}t*tJYD+4=q^bKPlOcn4Km0)bsNKqqor2g?y3qwD$L3 z#hJh)@4#N#_N-p%jXuOD1K~Y(pWFy9D1;nN81`!~$lrAS)f`wc*~!77j0Q(@Tr@J0 zU-?^@f}b-5Fy9R(&%!^%{$+pdnhz)upkF)yPg}CQ=P}%MK+_P~Gj+G>m25|5w(R2ST~;|IcYrCzTd0N+=^#C__S)5_)K{RI*nzLQ(eYoeq_3 zO(C*G)1oZdm$7tC*$0_KmO-J(HY&@+F!OtV9_QZg{oQ;2IOm?4=kt7?&wGEpm(S}W zsQ1_oul6ecZt+`^-?yU5`LQdAzaG2dPg(&&57kyBp!N;l@XB7k9G+Oh+!Eg z=sa`n-js&Hugd%P??e`G;lZOfpi)_~_rWAMVrWC3Ak2k)GCy^gBG~k=KES!_hS9twhn&f_^?B8 za*xVSJF)0VwxB}U_eymQKne-Ltw@VLD(Cdx_xQuTMw9FAEk0fsa6wg1T3m|;_n6#h zVha)=U#JcObTl4r-BM6zd4bTeeK7A)JWqw&m->$4YyE4+=g(l$XN&%%`vs{$&`ub_ z0cS|KD)y=t^_EIr9rxwUur?v4hxUU+hm-)Xcxolsg6_N?E)JXr|HPRs#L3w?D29ju ze6S?z6L8Mi1aIy-Pgw*40Zv*Tzt@t zT_}&b@Gu`hDtU}@oMPk1TvuF3#K>(QKmJHq3yOrl}aw!4N=`x0QwB0K&17k-EbLD_Pt5x5uiB@-~b`yWrO~poqlyDpjOoz zuzvW)N>MeBOMf8?a7qA)l&lH}`aDLlg6zzVmqe^^tMBNp5bUp90BmB9JN0(Fw7dK7RQ6oY&;ZN1jEHeT5I zyc*s$XmopmlrLm}$3wTeY?d6_H4?emXPkenEyFx&VOO}})q$g5Alf2T?9tt-FCz=K z(BsO~@JH9lo?dwnq9c7>Q5w^qB5*GMiKM+Y8e|M;@ytN&GVI(;jTMHH1($J>^$h~O zm5U*-BQvz2O>XU_x;ld}*9RgvLq6}xM@A#pE;eYt% z4bB@k!GGyYbSDuD;3K|NU|$K41j*s!~2yJI;lWFcjJ#@4pi32j{f*V7`WEiJjx z?va&?#^cu$$9g~^?Z!_fc#mbyg{r-*Zd_5nd*fGm^(#GID<3i3Vw{s#?v627idijt z>Cp43t!=vM-x@ym1-KbW?v}*zx>6~DrV_r>l`GcvOwbkrxV9GA4^#CwvbvQpsgc;D z{_p(ws<_li+!YI$Y#EV?C}iJ0^2nW?8yXtA5uM}S?>HTbK`Xc#mV&>xv8m+beifCI zuW|OzwTFsU@rfQjeBzPV#)td*)e-gH;OA)M>^$;ZYCa0SKGEGpC+Do_d7Np2$GF5S_528> z6+OF#BHH9~zW1nnTwQoA6`WuKcI4102wd`z*?*0=oM3~P;8i(CD;IWYj`(s4*U8#j zG&tSv4N@P^dLJ36xwU#*X*IGIpO7O#Pw4syoi94b0?Df!x&$)=ply*V} zMBEAPS#XFuZrvxwQfTKDRS({M_SBf_;_)w|2IA^0Rw>x-5mKA8&$*?`Cr8GDC80 za{E9muH?ik^M8@l9&qIsFQHr|@# z&{Xyj9qymEKz$QL??UmDsg#Dxwsq@S-K{W$+xZ6WrmeX-*boK^Ef#N=PsQYOO!fkLK=DQysDO)&fOiSA_f>4bJj5N)MU2ZYv~?A!-8^2MoVl9Dh8< z_=%p}M9+8*ek231yZswhEDhuV0kn5QNYIUn$8{OKpyMu$!-1Va#w_^2cfq6Z*_IVA zUpl>{_MW|Ua3lH1{s#H zY3@6?AFSXFPNU678{!ly>-~aCJoW!v$Lg+uc@w;c=zDK3!#8}t<%zzQgd_ZQcp0Yw zZi`X~#G_Ec=H<}y{-`g}65RdtD!BBDhgXQ+7Q`RR`*1>iOk64eN;D3iU}Sp3wQ=za zXDkI>$QjkDMaFYtxe7eFl;$AZ(S3JIybR7DWucswa}8^@fFp?JRDA00o{RhEQUA|^ zw!fTN-K(*inU*^yp=$dHR0?FGzm?EL()!pIcz&LQkw9Fg!ibpIWfzygyEs!Boq!U@ zU!?K*IARjmImz+)MDslId2JychSX$*!HuxfHMe#ukGt7 z?NIS{5z8)gxzl>w{VRPY4XM=Io6xf|ccHZ?>kxy3Ui=I~Ds9ljWLy(Z)_@qCY-CMv z3}@GaL70F1^y%Pwq~|1D@ICKA)hw#4YD3@pQYpP2Zsp}GSD2Q2HlBQqtJK*GbrdOS z-*JwCFU`}CntXy{KljH{!PUr@4=zToaB!|FE73i0D3NxIQUsgxv$VAIh63bkxA8B3 zzcu9Wd85;(Kb~QA)8O17Ct&)u@exN5Nz588#3Dv#V1Xu=@p-6vx*gzy(xq@4O?EvF z_I$eorcVosfX63$+JP#UKLZl!jWebPa)$^Py#Y@5H(<1b)!xsBmWJ}vlsw#jFa0bQ z`0KN0Q;A@v&W`DmP*v-ShxNEaOQ_FU(2&+UhW3F5J&xM5Vi&x(nq2>xpIeE?3)r_m zJpu0{4iNB|3?1MQUu1-W!!|<)=93=o@03n3Q_~!{!t4AJ*ot;E4CE_>!RhCiYjgIq zy8nbBAcDqf2nBCx(?smBnDIDgYqpPuM$1|bL+ z(osO809=>qCPB03UEnjug3)_n)=i*&IXPioK|uV*BS)D<~&kzj5|o5 zo=V8h%1YijgZb zck=4XD`UH%4%Z!znxo}F)>Guu>q;fvdi=C5vb#(8j)+AW5%_b^Q&Bw{?Ey)#0nm_B zaFAp?UX<7h|95|tAAnvC%ylG|Re#y_i3NQ;gy1!TK&y_BMyrft5qgrkRmBxX0^yv; zxB{#jhn4EiiRDxlBKw5LkrG>f{e?PiUQ}0C6ER8@Hk;#VIN;V)(p7l5L$L~Hx}kg+ zp%ew;xS>*KG@B1hpIa;nf%0aFx$i({fo|xk<@k-)82VP1O1WLfid=fiu4gU0^&*@P zsf_bz>hI>nZ?xx0?kr^`rGt0?lY0|=>O;gmCjoL?f?PDHvF(1@_(-K058$=c_L%3| zx7~B*{iMC+VZ;FcrbJc#!owlrUqI&K(fJ1Az}(VA>N9xK7WcV=i{;F72gZ}!Rfa=S z_O)oGBtUv602g#WMAYDP7#$I4!(g^;lkFpBeu7g}#ueM`4~(aV*=|j8P*qzAmaq{r zPj?WhYjOK}u2CFfmjtS~#VzVP)_&KXxhULAy4?U*`)rZ2c7>FAQ^`2`5ryc=1cK(` zy!R09#qopiB9f|~VQKPZqNq2Jdja=E-<=;~JY70I?~ti(@t zvNy+*{V8q8XD(O2M3fu(*R-74*9YA9O$YC0Pv5CVGut#elAa$uU4tJ)&Pa2 zFEcISM{7b4r|!MKE+P>WrPJrpx7luQ%;5&?>P_He=3kaeqjpQ=*?m~JY5 z`mayR2uE&J^Z2$J6EASV1XfVSzXO-4Mbu z^^Q__0bxJFC`4d^d5WH85w%u@LX5wNLZGWkNVl$`LUHojD_5>;!e(tpVueLip+q4Y z*mdSK{{GEp1vkkb9D{NTK5=LqC^Z27o*86A6&8+78li{9* zVPy?|{3+nP${t)=7TeAI9CUs0^5twP)!PF0VA@pDvTD_;N?Z+pyN#HB$rVt2{IPQW z3+n!n*!=H3mC6{!70|@bnQe0Lq8AyucQ=-U!y2H&u!L<;p{wNwX!;;LoO+MLacjz; z-I@Ozt6Ov=^1<~0%@qDD_%db4(n+yt)S&Nr^4})e+nb zP9W&#deQOn-V#XW_~I_#gPJc@cclSMF;r_QmAcrbqNKD3H!|Pw2=MkD7&n~B=^4*o zjm4L7cweCkLB0^Nt2Td+P1!FeR`(SOaF7YP8PYOU7aid*g#ST*9-E;Qj8*z6-}ip} zBK_W;j%MZg61gWe-9Ep*e}(}!vu!7|5Qy{#$^;?j$Yrvpa)2)1RAQ%@MT>G@i7~w4 zj_s!6pY^+iJh;EZPZuFHo{)ynI0TNHG9Gog3i_Xo7!oGlAod z&d%KSE)aJ)oH@UBgKFx1K&)$*ig@jUrLv@wRDyVO{2X+E-{f%qE`TWsK{cpP65`C*DUv!u$cScTOqBo$2mFsh9+URgcnLhK0m(bVG)#p#1Yn$Jl6%`f~AYg&-|6B+;>bk-!Lbjv635g-fbk|{# z%QV@g6!iw!fQ*Cmx(;Hab3w08362Wc=bRndlGBfi==+6m85s1hr6e>(x zx|Vz1K!#Ska}Rt1AM2DHA_8r=aocr5!<|vd6Jib-X?*`CSAaIpAuSc;)>NK1Ul^R7 zxpiz`lDq9?XXi&Y_?a$)U{O2jpEIrK@Y9n0W8`bKe>h(z#y}as2cMT+D5ZM@)d~@) zJqV2K0zjsj(j!x)oT2AM7l#Tu!JQ|Q=Yo>NVDE&QeB`V{hG2}+BexW;3LV_6^$K(& z4Z2e13cJ9t5{}$9)dn}Rbt`fsORU(Elt4Qs#cg~~j6rY7V63Gk4u7qA1S&DfW>-wb zD@iEg`+Cnxp0gHe&j`_ETq&(@(&Ephz>7%4A9s`M)j(tNXQxK8arJV$3RrhUN<(Hy zX(aZ6U$?56x@%9FEv_q1t$Q8}#~beko&*%|WE=PnwiGQ3bQ(MxRdNyXX;TPu`7|UA zJFP7S9CMW>TpJwG!%a^LIQaU*&YHk*=|p!2dWsfbpBcCV$c01V!F1V;cgN|2ZbAlI z+5#=@-#Q(unX{n~H=%~J?jdP7#M&2d%N08cT%Y~e_}H-KZ{g1zRjWx&C3#<)Q}{+j zDZrW%OY!V@Z6eq$@uO<`jJ!5Ek?&dX?b##k+5BLf_A=;#u6uBD+qXg4b;n-Bb#$C( z;ypfxYzkC|4i{)SEV6&&48&G_Bksd-V${GA5BMP45$Oai?J!jn9A?0E`|Uzd0akv0Z@R%B3mH0(=$ zU5f!M;a#llA0dPGBNc2hQLJd3?U8J=<36 zEi$@~8Sv}@jG-cha6rk`>MZ#LtstJ3ImBgzv!8|E!@u;Q7R|V+WE(}GsCVPr^cXu; z@}?ArJWk*lNKQ;7>A_Eqyfl(onf~&n#ZcnNWK_>0jVo@WH3#+#{SA?ezjqN5j-&ff zrwrlh5o>E^95LV&vKf&ZlyR(fCJ@V>pS#xnOZpsUjO(^#@T(7GprQbJ&qN^ zA06-8X;n{vTY0T&gYD2Xd?Y~xhs558K;2I=yS!I&=-m@np(|%21|OFHI>|7>d>{99VpBTiyj%i+e^)r=-RXll8ZM*VzFZ9$~An6T`>)-YUR$&&ilKpy; zh;{RnQ0#Mg-u_s-=^qoL;6^1tk~IIhS^zLo@V$}jO5OmZ_92YDtIqX#GoEn#?Y`t| zO%bJYKN~8UV>e+b#oOKp8};b_TTo%ng+dg+H%aw06iDg?MRgNO{*zr0yS--YqvfIPNb2)YKe;y$nu6=lQ)jIRbel?!kYZW?>$mmir$?tU=I5=Sbq)-u`Wzm-S)5WauCo;2i7-&*-dL`Pho?+}B)pXD!M`u6qMt&<-esn9mrh9%d7{HTM z8z3M7TR5##;PMCdynp|lMxJI`G@I1$URcR%xy?_t^RY~1tY-4S)ewqp7#w%hp4q)^ zc5Bz(V)|uw$a<>`LPGD&z0a%8!QSlNcXX(BGRHkRasHy`YF$UpNaodZy4h^gXUF1m zpMQ~pSKb=xbk5eOc>dfWgmzN1HJ;FuuuAhSlb@NI`uUHqU%y(Xe}-TEQeN2EO4wO4 z0&AM%JWgghq`Rjm<%wGb%}_v;xcWOKaI`(O*psF_oLwaS}SjO+a}QM7Q-I zqHSKXZQHh0(60D*CfVy+uLZs*_uFh)!_vZ{qN3LBZvV$$Lg0mq!KR-#7LEZ2=hWt~ zq6>MmU#|!#?nh-*CZaXv>8bFW7q{V71H!rQpAg_^!cdYO%`My#uXB+5gdJFiW(QoY z0umFJ$ywxoOC(}0l*wlm1q8znW%k{#p&IP#fyn!<+VBI>b#Tu$;f(~B5m(VlCL8L= zJHNVTezRk}w`~y&p>Go*kw-IqfInL^k+JM8_w&9?CJ{Hxj{gw&{@&q;asK7be8)Uf zU=)}^i}v(*1xUD(21XgA*!+yidSlSq$4-CEv%}(!#VZcp2)hONIn(_0xxf5~nfE74 z4Y;Wfo~hPd#efqsQw&!Dh2NY{Md$T`g7D+@bp`JcT?l#S*TQ< zKIIRd(tu6+sV(QpX7L@zu$I)OrA7%~rJi)rcS6?s@-aX{U@`T9pl?8hzE4*EKdQEN z&)=jZXHV^k#u7%^T9;g1wJO`*0>7l1?TYESLhilay0c{1$YK1vpHsXdcZ+UIFSbQt>HNkkYdE6S=5ej}h;4mYT9L4sd;yhdA34=>$92v&Q^ zN^s69c|#AB7+SY&PtdZ(3a3Qx>kEebUGe}LIS3yYWKYK)qBpz7Q88>>tawwOWqy1) zOD365>*?ufcnpLq zrL1hd=^cv^KY{HZq^^7$8%t_qFn+!Y1N$0GKMPRTx2&uzXTa&wwXZ))Um2(5H#<4h z{tW4v;6pk{D;w#6@|}Aa&m3jH6<{y5NoyNTK181jp{9d=w9WE?c=82Q#!c?SUJ;WR zMH{tc)$F}n72ndQvDs7L=`hpbU4(N+_^GviLUVE=s!C$-C@%hQhjL zR$d(!qt2AU8&{&`1hAC2$yOG>VrRT+Z(d~AdS#sDOT$p#6M={XFM6@3W~bJ~oh za3wh3+zAeq@G|Y{)JL;+G;24wloMN2cCpVz_hu?^0O7Hd z56tZ*Na%ol6V%YqxJxV;9FyyecF2CsOCft*cXyvC+Ko8j=Cf0~%9+eAsdB@5J=uhU zFUpc4+n|KIWKU#&53YqyZ9rN`Ti^;H>$$X`Lnb=>sc6I2Xa}u#zR(y6ecSfzy?^sDb+5gWH^1gdgR;N>bJ#@iW|MxjM*D^39(l&o^zsOV+j zlmO7}eEN1+aGh(z1z5Pr8iO@h(5g(fE5VA+jS8eMqfkF;cl>%VN`e086Wb`N>{xt(nSpL zK=lsye1Y`{%9}o-VYCF%_>=x$*7IG+<5xMZ?Y5?@7dT}*H_W947DoFGeeeCH8>;|abWp7?(ec#q>Wtwy}Jt!*e zQWHQ&{LC*G!Q9l&%}g}kNxPIo<&eKcw9$L--3wm@Ies@o!vPOvQ-EIy0)np;-Uk1&|z{Y8-Wl0K{?F$dC! z*8*$+uw+g2%mgcCt!|4I21K6h6)Y3p#!z>9_#-3US_x_*gRoT)u50haHQ2yAFmKJ! zBy4+c(o5Da#Nh<^lw>c%*$X9BHU}Uh_k6b|{5Z4`;^O?nsaK!U_%Qfu1qD-gTF=2D*l)zyF|r%t!MABLPAYlL_L<-5=H`}-^m0lkjYcy=)c_@7 zu+ix4fJkbj8_Cd>@*1R81(oF8h)q*2c_JX9vU=J6(R)GX>6|~sTLoSLyaDt3{d0J5s#|`^HjA%NS8b1`iva!ULF^F>V zvdSQMghM!Y*QO&t?l_eBcF>!KEuRopE4pXXvb{M{{z^&&3BlP7m2#95-z=MrQq89j zZNf=fUK}k~Kz5 z@#z|D-Vg*REK?nLaE&mopwzAcYII_Mo|m_)XtDlpqE;YVBT!((01)=dtIaUQK|<{p zDe$?WQ>@Y#BbK7krPbzoGVWquj%8D4AO&s_i;MpsM{uJiji#l#OEIN}@_8e|Z~h{) zWAgPFo@HxS5?+Lwq$^d>Xnvvb*1H^!gbFrpZ(e?}X@x_em~Kl5iA?u7Fm(v_wd5}D z#6@;rXC-BSW3wxC7|UkcWP)!tkM7T-!SFXFU`+ATWpFoy70y_^y~$I{dO1qfn1C^ohEQIi$0f+V)63P!&p+HQY4@vkHtwYp`MPR0zw( zaBfH{1xzWhneO7v`LKJ;lyEDq!*%SCw=G1KUfD$6O>x5aTmWE#lBxSK@xT&ykzGp8 z$!p&yo-F1{Lsbw@4tFmG1n|YS(O|Laqr=gyN>`&69Vnx(aE^M|@e&G>uY~s(7kya+ zwiGmHT5@u-Pzl!`8(;qPJ>5W0!oBAM+=GjO4#+l9K;N5XguJOYFcBxVLCSi!sleyGR$uPb2j`p2!j58B_;oQ`ZGh{E4{uFA>=H@mp(Ot*oUsp z&NiwId~C2)8dAo=#Gy7zSB);__=8FEoka)U(cc!cu6tJ&SjlHUgyi7*4d6MtIYO<) zb0sCExdLi~RK(U|aRbMMnDCX&Grbgf7vNkQrvtF08%}6~!tm&*XoW*_@>8N4DF<0xxATyPTHkp2WqiOfleei&7mMH1?e#XYJUCszslAZZjvhz{Lj3aBYjMB~e7e5lCbd4wLP{D+m6D&#?#v?MqYC{JH)_2(b zJGQ2&No!GZ!Mglp(kq|l2@0FistH{N;%Ca15cU$kHYITdy!pGalzU1iUS1b5j}uW& z_#hRKb9PT*6C%yyM~nU*GrSnKOpX%D!yyK9PK| zPJl1~?rQ9Ti?ZE07}@I%^}dj&`~!y4Nf8~@ z=d_?Y`ZK_&{Pc0T4#ri*)s=18w!Oq5JxqGqwpm-%JTATT@{-Ds+^9HT*SD|Zc{ZYkG_G+y8QAb8co`W~l24sdXi97tkc8r#mYfh;~XBCES z1~{AVk{*#IEzTRKOa@6Y_e0_(s7+Ao)f&Rp%}}gJ+6VPwWUm}*KX?2hHJoU7X}q}7 zNah%TB5n86H-WQ2Sd2^fxxJqtOPbJlIfr^rL{8d0B|fJkh&c4st;F9?w5IaK=0yb0 zEU=3CP>^^szT>%6`DdiW^(gy1yhr!tsX|Rdg^j=D23Rn1f$jp0jViqdVLXB-o7Z#0 zPh_{WdwhILM+2q8gP!a#;kQ1)pT|%#pjijFHy6?%LeU{?lhx6A-Tqg=K33U;) z0}$M8x=)ng20ptk+|V2pM+;)mHNUbIc=MYL%rU*wb@s`8C%PsRBq7%i z+JJ1JkGE|{kX>OLXUu!qN(H1`t4`(#Nq9!f9`~_c>yGY^=P6 zF2A{WleVhJF>-Al$C95F&m3ZV*IX+r_;QF)`w(QYyp7I-Nm6$kM~i01FQ#S?CEZ0h zNToI+5Bfwogz$s|D{zt8tO&5qakAGYNUYcKH5@X>s{5EZI*id0ch=7~aCr$Yar}g!;{=7C(onQ=okTmj zqBN0i1-pEnq@1TO74XzbzBiyzx!phe0>UJqdJn2WpRjqxnCptC8R#%0Cs&hbIwlPe zAQs|&JY4*PE56nv`ua6~QknNAt8e(F#@sirTX}t2(x3O7JbjupQZ_sMO5B5Iy!de# zxj8w&3$kaF$$hJSsqcP}O9@XPUyf12t6CmzL2|!x-NKT`V9DhqT0PTJN_jGKnazo| zJ@D~SpJ$}$qvQ31Kigr5AvYpsw;4No^J>B^Xf%sJH%*M|8&96c#3>%LsZHdJOGLZn zq}BbAE+k7BNcvqDz>+y89PmFOQgFh^w{Jdq)U8l+VnjDpRi(ynZ`M2-&y~{n#^#iA z%}}1amv-M zu%vm7NjF}8N{iZB9Dma-cNmtoc}kaK^OP|TlrgwgU+cE~ae?3o9e=toLm}`{JY-wM zV<){Z1;>d+GF$3i7*}tf_Acdq9CRzu0I&itlX+}_OGLCR>Wh&DuP}xdl)?91-GHs= zOKtS8X7X(qTF_6(hcs4^nLhwWkgXpZ0RE_;1!*&uHI7pA9deCe>w2LySMbU|^dAV^ ziMwZy>lc>B(9J*N@f{J6s=N5|DE%_}Ps58L4Hvp&EB|uny1{m)u#!Bdz zp)|!!?#GOK17GM$igeU|E8-W^PR66O%2S&ah^A|Cn%cKP#1t9@BR8_BB5cjeeSvym z@96drI7g5;CEOw+Q+lYP>h31~o0(hd)`*hwz|kry<}T}=pEnjxl6L&n07YSRyH07z zN)d8lFFh7i#h(60x8V)Z$_vL{23qvk-n`QkUNPTS;O>zXeWLaW9UmxcL(0HbHZN1k zFm{f5;XrT#8qhQXh!?GKw45DSLA}qN&NW&`x!1hXo8LvmEWiP99M*-EwO8TVSYk6k zn*k}b>{yT32lG3wy&&l%YxKvTeAH1y)PT@$G34v#SGz7>T+q_lsdh-gKXC%aE6ELo z>m+4*Vn_AlNj&MWv~&nZ=5Mt^stWKX-0jjfQd3jg(j5>+Q@G0M-JLOYZw{1g6=X9)jfiI?L7a5z4!-L=feDpz-x>>R zjIxCktV<_n!WRE_fC^6JJ~r=!w-#*M+rT%D+7i=5&L@gH`F&#u=+j);np#oh z2i4w}$gEQCbxP9%VeGG%KkWxd{cB0i$>4G>PCt(bP`y9^pQk42K0oWE`2{pvNyp2} zbuTC@0u3I}?TQ_usEruqps;R>4tY8WO8a&p-+OefHrrsmag)|qR58~Z zyw9Lw->Kon8x#bbF2U%Lx6sEj^~hMb+?vtVJ)cSGxj>e*VVAryJgoRL?lXBB)Wt#d z$o|Z9RMtTF4G%`OT{59xPt?2e1cRn{>icOqocI}^N4tm`!)#0Xs4)irph2l&ujP;P z=hlGRTMf0Ol|A$(iiel5u0sj81JptK-tYbbf|`o82U_F#50vKXcW2L?!CfnD?S;eh zE`&~>%A*wf9IDw=Z|&K?HqkYv62Wz8pzzEXLidR?u2__walTYonz-r8{!4U(HuC1V zy`Rh`4Tib%%9OMU_Zo|erDs7HE5lO~Iudthm;IE-{LiD%x@5uODm4NxvL<3HM}>Tb zqGYimt*>DKUL#UJO7S|{*~vGf5aDxf!A!tT^B;#>L!jd~JVq%M+^nmd-zhtbxl2ee z07-?u$KcLm!cNJ7a1Bb9JLf6Fmu-;!U9w;LQ0Ag#2|Z=JFd@n1aW=j~w?XrU#wW=Soo4g4 zlBX>&a8uh8I*Q}`0%cZ|5eyK`T1MF002eibQcDNF;id3??LPc8jp91Hx|$X9LMXgb zjJvk7t4sO>uTL8R+s`j=(tJd$yHB3}lbVA0nlSDUy3II{r{BSSA3@hA8dWB~TCF;k zpyUWcH{YHB?w=%LP0^DtZ|aV}k}99=ONmPFdkSCfAmT#ymd4yJiq=Fu#XT-n9CZjT zMcIPY7Vad-IY4M#{^}mxWb*i6mmaPh>i+WrRz?W8k@!lsSxb7HDj^wfO?j z#!&}GQ+Ptq^_db1rKX}FiFe8S+vt(*oPEpq2dkMiqI11=^vmJY9Lg-;#iTGS&&lCW zMQM@0$aA--CD%lQNXp3M*UIAJ+{e#@okktCkQmC~ZQcIhn#k^Xw|J4Cqp9{{)f(!= zDTB^2wlzh7NB?5Ywh?<>*v0f)mZAKx;{{KUeC8@=y+Fn)mAv!I+VA?N=6?((ZE(<} zkft82txvRH5(jNnpg(v{co-M$j-SjM!c!Ajn0nr=&kVRjZ8s>9ZK_>4knGzeTHoLM>KisjqO==?X|&En&zFk6k;_SLctHtguv1Qgr=_cOlbTSs4***3G0*%M20O+|2L!$L{lqvd}4MH z=R5Uv+6}Lr$^Ng`+8fOwC8!^X2a^X3z@L_c0vXK_b{;VzZut3uSM9j5y}#%HAK)cS zuaT5|jT0k`(qM1y;l`5?Y3%36y~gInvBhZIUpKhd_cRSF9!CL7)zKJ%$OF$(7SB@BjDVeFGvVF^i45Et??xGFXMSd-do7 zc_bit5CM29qySXefn>3}dA^PRA7xgWSNBsopU7Ak!ZeRDi@W{L$-H#%Z)a+8V4@8(2Yg$%;hXS0Vf9wrlJ8xD>Vzf$T)jWJ9ordVo%qoi zH|5xGiF|-6iBFtFU{(MmODbY6fNo{%GizORqj9n=75Q|Tw>-NhUo+5bMOeJ@1r zP%BST?Em^ZM6fc+7u8_~+a1P<+4=@J!DhW~ixQR+qf`c1|CbCKsirRenWt!d^q04E{eh(V^rUGU6b;_!;ueGd9Cgh+c{d z_}lWcfUoR_IRS#qfCOsMX|?qRBAX8X=i?a@;p0awy57Hky)Uv~1Fx4LD2CvITzdzc zyc6MRmvX6<(Mq|%DT?xc{-+?D-x66y4ERV_Ljx=Rkw^N1zHuW%qrsCWGNrZ5M^f`- znTuA-|5It?MJfjF8QKXo3Q!BeGQq{d9>;?T(Y9V=1?{{FD!?2tCM?TU^6q~Ah8-R+o5)$-(o-f%c9zwXt&|J1RIn`I1VLuuY~!)BGGxS33kL*%Mmz%~gM z75+1_0F7>n?;v88AB)7??wyVJ&m$MPRBgu&gv4~w9w-cnOaBW!?RE#J*PCqU&ZtwD z3b116vIE_ol2V2Jx5wR|O87^itdy~P6we%FZ;jhy{xb!4`w4Cf0HC(+GOZo60pQ;B zlc(2W(vxE$Cf`G>PP94yV_Zo6BF!|e8U1p9f0Pz40>a%GJPYzKRF;qq9nG(y^EePY zPM$XQ7T@>%*hayM=!QDq#(xwzd2fF(mD^pO2M|a(Xp!;-*ZChSNr|Ac-Phj>gG%rj{WL#T&ocTm=r0)>Z$4Jz@rLf zB6GiC5dnS=?%R_;Cu@rA{%vFj*w$MTPxcILCygAV3}iWHmroDjh&JKC%7qnPIziKk zou99-{N6kOKEzA7wFa!iGOKjt&*;?sb9`rHpBOUcDHSjiO#>o`pq+S>Lx^01YpCGu zrjS&Jr?J`FHa;XDk6xSQPtVs@Im!I%3l7mg$qtD#=Up2|$K&KI3)QE#qwhZ;u&@QE zw7k5$*HBi^wSLJlSjpv-b)}xN#ta5*C&? zM*IG^pdgxXq6*=t5a1bXo;qd4eDgrge=t!9shm1ODaT@3pL-IQxHMU`k1o>D)CG2;kC+5H843uH?cozSxH=5W*pFCe}mU zxvj{YCLrHq|0hF=nk+F)2rF%;SCj(x1F(yjm!KGm^Pjeh72Jgx0+&;*shZ0Zs49ak&4by9_xM3kPZc&+faScA?6xWX=-dEfd6f zXtfaYk-s}=Urt7T-jix~_I-$Xg^n0|@PUkCxBH8CDI0e!YKOnSY?Zn)Ysdp%W zmdk=7ul}2bH@{Q&m6|`xAY(#DeXoKww@g&;HX3DQNDbV5xV~5!5?yfWI-eL z5pS(#y3GgvF_{pD<+vOi2vvu$itOEcnJfgOML4~1H8M?M;roXdY(03pu#pddT7fqh zN%bz~T1su}<%2eBUV}U9*B*M0QYNiQ+(Md`Jy{5R(Vyw9sIZYhSP-SXn;|b*{ix#z z>5+`%1sH@WmDI^Umie#ejn4<&qRRPxev+u7Z=8R9@>>gkTg^3!8Zst?J}LY(#I|OD zXe|yva{&mC4Nyj-joA#HerfT?Jves|j5C$=dr3y79_VK_3BKuTg)K$Q8iL}sRwyun z|J_>1f zi7_jK_#8A|%pZ@E|Lr&uL{Pdo2dvZjG#RxnX0sb7Pbx{u@o;bap4b<{Z#+`~4BzM- zbc(T& zye%ZZ7+Oj)vF_Cq8Q%h0io9dugL1T>lSs3HFN2=EH!r1xi?9G1-&I&w%e>roYPuCa z>VIkx;9f$Hp{H?Z+VMM)Wp_VAO(Vbn28>q}qAHVqBG%(V@AVaZPkP1w2xk#B?8qmN z0;JH)oM%yzVbJbLNFmQ%9;}bynxb3+l&UPk^%0>j8VX(&_lKqZU~9rZO{F5@l+G~H zDNz2?n_?@KekhF~Mh)LaDcm+Uzll<)Yn=a<8FZf9MI5`zu{{VwiB7t7=BKNB;)`lC z7vd$T$0Owd`j`Wbk{vN3BJEOmd;|uqPSkyD&1!meF?TZte-3|=5g!q&WWrdE)eKSz zni7sFR1HdUT>ihXfX30PUZJdUz@i*djXudb)db=+GHyzP?siR zjA&xrH|Vf9Dx?Y|O7;{^EsoS^v9FUQfuqw^KQ(#m1JAQYtdv2L%G^fk-2DIa;rKZ$>B z-{u9&g#QOY`^1p~DC_?B|MnhO;Dd!fkdXfW|BEO7GQW(kUM?qs{vOjkaU|>Txj+6N DFNjK5 literal 0 HcmV?d00001 diff --git a/Assets/Schunix Small Logo.svg b/Assets/Schunix Small Logo.svg new file mode 100644 index 0000000..e880a33 --- /dev/null +++ b/Assets/Schunix Small Logo.svg @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Assets/Schunix Text Logo.png b/Assets/Schunix Text Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..12d839e19c842996cccb6fbcc6848b3dde7d37f2 GIT binary patch literal 27296 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 literal 0 HcmV?d00001 diff --git a/Assets/Schunix Text Logo.svg b/Assets/Schunix Text Logo.svg new file mode 100644 index 0000000..d27a639 --- /dev/null +++ b/Assets/Schunix Text Logo.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c53f721 --- /dev/null +++ b/LICENSE @@ -0,0 +1,187 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship made available under + the License, as indicated by a copyright notice that is included in + or attached to the work (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean, as submitted to the Licensor for inclusion + in the Work by the copyright owner or by an individual or Legal Entity + authorized to submit on behalf of the copyright owner. For the purposes + of this definition, "contribution" means any work of authorship, + including the original version of the Work and any modifications or + additions to that Work or Derivative Works of the Work. + + "Contributor" shall mean Licensor and any Legal Entity on behalf of + whom a Contribution has been received by the Licensor and included + within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by the combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a cross-claim + or counterclaim in a lawsuit) alleging that the Work or any + Contribution embodied within the Work constitutes patent or + contributory patent infringement, then any patent licenses granted to + You under this License for that Work shall terminate as of the date + such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, You must include a readable copy of the + attribution notices contained within such NOTICE file, in + at least one of the following places: within a NOTICE text + file distributed as part of the Derivative Works; within + the Source form or documentation, if provided along with the + Derivative Works; or, within a display generated by the + Derivative Works, if and wherever such third-party notices + normally appear. The contents of the NOTICE file are for + informational purposes only and do not modify the License. + You may add Your own attribution notices within Derivative + Works that You distribute, alongside or in addition to the + NOTICE text from the Work, provided that such additional + attribution notices cannot be construed as modifying the License. + + You may add Your own license statement for Your modifications and + may provide additional grant of rights to use, copy, modify, and + distribute those modifications as a separate work, subject to the + terms and conditions of this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any conditions of TITLE, + NONINFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + You are solely responsible for determining the appropriateness of + using or reproducing the Work and assume any risks associated with + Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or exemplary damages of any character arising as a + result of this License or out of the use or inability to use the + Work (even if such Contributor has been advised of the possibility + of such damages). + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may offer such + obligations only on Your behalf and on Your sole responsibility, + not on behalf of any other Contributor, and only if You agree to + indemnify, defend, and hold each Contributor harmless for any + liability incurred by, or claims asserted against, such Contributor + by reason of your accepting any warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2026 Nexoniarz + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + NOTE: The kernel (kernel/) is derived from xv6 (MIT License, Copyright + 2006-2019 Frans Kaashoek, Robert Morris, Russ Cox, M.I.T. CSAIL). + The MIT license notice is preserved in LICENSE.MIT and must not be + removed. Third-party software redistributed in a built image -- musl, + 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 + BSD/GPL rules, the NetBSD advertising clause, and what is deliberately + never shipped -- is written up in docs/licensing.md. Read it before + copying anyone else's code in. diff --git a/LICENSE.MIT b/LICENSE.MIT new file mode 100644 index 0000000..d9726b6 --- /dev/null +++ b/LICENSE.MIT @@ -0,0 +1,29 @@ +The Schunix kernel is a derivative work of xv6, which carries the licence +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 +change to the Schunix licence. See NOTICE and docs/licensing.md. + +-------------------------------------------------------------------------------- + +The xv6 software is: + +Copyright (c) 2006-2019 Frans Kaashoek, Robert Morris, Russ Cox, + Massachusetts Institute of Technology + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5282139 --- /dev/null +++ b/Makefile @@ -0,0 +1,806 @@ +BUILD = build +SYSROOT = sysroot + +# ----------------------------------------------------------------------- +# Parallelism +# +# Nothing here is order-dependent beyond what the rules already declare, so +# there is no reason to compile one file at a time. Override with `make -j1` +# when you want readable output from a failing build. +# ----------------------------------------------------------------------- +NPROC := $(shell nproc 2>/dev/null || echo 4) +MAKEFLAGS += -j$(NPROC) + +# Kernel object files — organized by subsystem +KERN_ARCH = $(addprefix $(BUILD)/kernel/arch/x86_64/, \ + acpi.o e820.o entry.o trapasm.o swtch.o \ + trap.o vm.o lapic.o ioapic.o mp.o) + +KERN_CORE = $(addprefix $(BUILD)/kernel/core/, \ + main.o kalloc.o dma.o spinlock.o sleeplock.o string.o console.o \ + panic.o uaccess.o qr.o time.o) + +KERN_DEV = $(addprefix $(BUILD)/kernel/dev/, \ + bio.o cdev.o device.o fb.o ide.o input.o irq.o kbd.o mouse.o \ + pci.o text.o ttf.o uart.o vga.o ramdisk.o procfs.o) + +# Drivers for hardware that has to be *found* rather than assumed. Anything +# discovered by walking a bus belongs here; the fixed-address legacy devices +# (console, keyboard, PIT, the IDE ports) stay in dev/. +# +# drivers/// -- one directory per driver, so a driver that grows +# a register header, a second source file or a firmware blob has somewhere to +# put it. Classes match include/device.h's DEVCLASS_*. Everything flat was +# already eight files with four called usb_something, and each driver added made +# the directory harder to read. The compile rule uses `mkdir -p $(dir $@)`, so +# the depth costs nothing. +KERN_DRIVERS = $(BUILD)/kernel/drivers/registry.o +KERN_DRIVERS += $(BUILD)/kernel/drivers/gpu/vga/vga_pci.o +KERN_DRIVERS += $(BUILD)/kernel/drivers/gpu/virtio_gpu/virtio_gpu.o +KERN_DRIVERS += $(BUILD)/kernel/drivers/net/e1000/e1000.o +KERN_DRIVERS += $(BUILD)/kernel/drivers/bus/xhci/xhci.o +KERN_DRIVERS += $(BUILD)/kernel/drivers/usb/core/usb.o +KERN_DRIVERS += $(BUILD)/kernel/drivers/usb/hid/usb_hid.o +KERN_DRIVERS += $(BUILD)/kernel/drivers/usb/storage/usb_storage.o +KERN_DRIVERS += $(BUILD)/kernel/drivers/usb/hub/usb_hub.o + +KERN_FS = $(addprefix $(BUILD)/kernel/fs/, \ + exec.o file.o fs.o log.o pipe.o procfs.o) + +# SchFS. Every one of these is the very same source the host tools compile, so +# the kernel and mkschfs cannot disagree about the on-disk format: there is one +# implementation, found and fixed on the host where a test takes a second. +KERN_FS += $(addprefix $(BUILD)/kernel/fs/schfs/, \ + btree.o space.o vol.o obj.o objw.o kmount.o vfs.o) + +# Sockets. Unix domain only for now; an IP stack becomes more files here +# rather than a reshaping of what is already written. +KERN_NET = $(addprefix $(BUILD)/kernel/net/, \ + unix.o) + +KERN_PROC = $(addprefix $(BUILD)/kernel/proc/, \ + proc.o) + +KERN_SYS = $(addprefix $(BUILD)/kernel/sys/, \ + syscall.o sys_proc.o sys_fs.o sys_mem.o sys_net.o \ + sys_time.o sys_sig.o sys_compat.o sys_poll.o linux_abi.o) + +# vectors.o lives alongside trapasm in the arch dir +KERN_ARCH += $(BUILD)/kernel/arch/x86_64/vectors.o + +KERNOBJS = $(KERN_ARCH) $(KERN_CORE) $(KERN_DEV) $(KERN_DRIVERS) \ + $(KERN_FS) $(KERN_NET) $(KERN_PROC) $(KERN_SYS) +# entry.o must be first in link order; remove it from KERNOBJS for the rule +KERN_NOENTRY = $(filter-out $(BUILD)/kernel/arch/x86_64/entry.o, $(KERNOBJS)) + +# ----------------------------------------------------------------------- +# First-party userland +# +# lib/ startup glue + syscall stubs every cmd/ program links against +# cmd/ one directory per program: cmd//main.c -> sysroot/bin/ +# +# To add a program: mkdir cmd/foo, write cmd/foo/main.c, add "foo" to CMDS. +# Third-party software does NOT go here — see ports/. +# ----------------------------------------------------------------------- +ULIB = $(addprefix $(BUILD)/lib/, start.o glue.o usys.o) +CMDS = init fbinfo shmtest socktest inputtest +CMDBINS = $(addprefix $(BUILD)/cmd/, $(CMDS)) + +# ----------------------------------------------------------------------- +# Toolchain +# ----------------------------------------------------------------------- +UNAME_S := $(shell uname -s) +UNAME_P := $(shell uname -p) + +# Windows, under Git Bash or MSYS2 — WINHOST. +# +# Building natively on Windows rather than in WSL, because WSL2 is a real Linux +# kernel in a Hyper-V VM and so hard-requires virtualisation; turning that on +# puts the Hyper-V hypervisor underneath the whole machine and demotes VMware +# to running nested on top of it, which is a real and permanent cost to pay for +# a build environment. +# +# The usual answer is a cross binutils+gcc, which is a day of work that then +# rots. clang does not need any of it: it is a cross-compiler by construction, +# so one ordinary LLVM install targets both the bare-metal kernel and Linux +# userland, and llvm-objcopy/objdump stand in for binutils. Everything else the +# build shells out to — perl, sed, dd, sha256sum — comes with Git Bash. +ifneq (,$(filter MINGW% MSYS% CYGWIN%,$(UNAME_S))) + WINHOST := 1 +endif + +ifeq ($(UNAME_S),Linux) + ifeq ($(UNAME_P),aarch64) + TOOLPREFIX = x86_64-linux-gnu- + else + TOOLPREFIX = + endif +else ifeq ($(UNAME_S),Darwin) + TOOLPREFIX = x86_64-elf- +endif + +QEMU = qemu-system-x86_64 + +# Display for every QEMU target. +# +# virtio-gpu is what the display class binds, and what a compositor should be +# developed against: presenting is explicit, so the host never shows a +# half-drawn frame. +# +# stdvga stays alongside it and is not optional. The bootloader draws the splash +# through VBE in 16-bit real mode and there is no virtio path that early, so a +# machine with only virtio-gpu boots blind until the kernel is up. Both devices: +# virtio-gpu wins the display class, stdvga carries the splash and text console. +QEMU_DISPLAY = -vga std -device virtio-gpu-pci + +ifdef WINHOST + # An explicit --target is what makes clang emit ELF instead of the COFF it + # would default to on this host. Without it every object is silently the + # wrong format and the first thing to complain is the linker. + CC = clang --target=x86_64-elf + CC32 = clang --target=i386-elf + LD = ld.lld + OBJCOPY = llvm-objcopy + OBJDUMP = llvm-objdump + # ld.lld has no --no-warn-rwx-segments: it does not emit that warning, so + # there is nothing to suppress and the flag is a hard error. + LDFLAGS = -m elf_x86_64 -nostdlib + # The bootloader, the AP trampoline, initcode and the cmd/ programs are all + # linked at addresses below one megabyte. GNU ld places a section wherever + # -Ttext says; lld first checks it against a default image base of 0x400000 + # and refuses, because for a hosted program that would be a bug. Saying the + # base is zero is how you tell it this is not a hosted program. + LD_LOWBASE = --image-base=0 + # Host tools (mkfs, mkschfs, the SchFS suites) are ordinary Windows programs. + # They must be built with mingw-w64 rather than clang's default MSVC target: + # tools/mkfs.c includes and , and the Windows SDK has + # neither. + HOSTCC = gcc + # mingw-w64's gcc warns about things glibc's does not (notably %lld/%zu in + # printf against msvcrt). Those warnings are about the host build only and + # say nothing about the image, so they must not stop it. + HOSTWARN = -Wall + # MinGW gcc appends .exe when the -o name has no extension, so a rule + # whose target lacks it is never considered built -- mkfs was recompiled on + # every single invocation of make, forever, because of this. + EXE = .exe + # `python3` is not on PATH from the python.org installer; `python` is. + PYTHON = python + # Compiler for ports/, which build *Linux userland* against musl -- a third + # target, distinct from both the kernel (bare-metal ELF) and the host tools + # (Windows PE). mingw's gcc cannot do it: it targets Windows, so linking it + # against musl gives undefined `stderr` and `__errno_location`. + # + # -nostdlib with the crt files named explicitly, because clang otherwise + # reaches for gcc's crtbeginT.o and libgcc, which do not exist on this host. + MUSLPREFIX = $(abspath $(BUILD))/ports/musl/prefix + PORTCC = clang --target=x86_64-unknown-linux-musl -fuse-ld=lld + PORTCRT = -nostdlib $(MUSLPREFIX)/lib/crt1.o $(MUSLPREFIX)/lib/crti.o + PORTEND = $(MUSLPREFIX)/lib/crtn.o +else + CC = $(TOOLPREFIX)gcc + CC32 = $(CC) -m32 + LD = $(TOOLPREFIX)ld + OBJCOPY = $(TOOLPREFIX)objcopy + OBJDUMP = $(TOOLPREFIX)objdump + LDFLAGS = -m elf_x86_64 -nostdlib --no-warn-rwx-segments + HOSTCC = gcc + HOSTWARN = -Werror -Wall + EXE = + PYTHON = python3 + LD_LOWBASE = + PORTCC = gcc + PORTCRT = + PORTEND = +endif + +# Host tools are generated output and live under build/, per docs/layout.md. +# $(EXE) matters: MinGW appends it, and a rule whose target lacks it never +# looks satisfied. +MKFS = $(BUILD)/tools/mkfs$(EXE) +MKSCHFS = $(BUILD)/tools/mkschfs$(EXE) +SCHFS_TEST = $(BUILD)/tools/schfs_test$(EXE) +SCHFS_OBJT = $(BUILD)/tools/schfs_objtest$(EXE) +SCHFS_FSCK = $(BUILD)/tools/schfs_fsck$(EXE) + +OPT ?= -O0 +# -ftls-model=local-exec: the kernel is *the* executable, never a shared +# object, so its __thread variables (cpu, proc) are always at a fixed negative +# offset from the thread pointer. Saying so lets the compiler emit a direct +# `movq %rcx, %fs:-0x10` and never materialise the thread pointer as a value. +# +# GCC picked local-exec on its own for this code; clang did not, and generated +# `movq %fs:0x0, %rax; addq $-0x10, %rax; ...` instead -- which reads the TCB +# self-pointer at %fs:0, a word this kernel does not maintain and something +# else has apparently always been scribbling on. Harmless for fifteen years +# because nothing ever read it; instant triple fault the moment a compiler did. +XFLAGS = -m64 -DX64 -mcmodel=large -mtls-direct-seg-refs -mno-red-zone +XFLAGS += -ftls-model=local-exec + +# Probed once, with :=, not on every expansion of CFLAGS. CFLAGS is a +# recursively-expanded variable, so a $(shell) appended to it re-ran the probe +# on every single compile -- one extra gcc process per object file, for an +# answer that cannot change during a build. +NO_SSP := $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector) + +CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -MD -ggdb -fno-omit-frame-pointer +CFLAGS += -ffreestanding -fno-common -nostdlib -I./include $(XFLAGS) $(OPT) +CFLAGS += $(NO_SSP) $(CFLAGS_EXTRA) + +# sys/ also needs to find table.inc via a relative include +CFLAGS_SYS = $(CFLAGS) -I./kernel/sys + + + +# ----------------------------------------------------------------------- +# Ramdisk root (opt-in): make RAMROOT=1 +# +# Links a complete SCHFS image into the kernel and boots from it instead of +# the IDE disk, so the physical disk can be reformatted from a running system. +# Off by default because it adds RAMDISK_BLOCKS KB to the kernel, and stage2 +# loads the kernel by PIO one sector at a time -- a 6 MB kernel takes visibly +# longer to boot than a 350 KB one. +# ----------------------------------------------------------------------- +RAMDISK_BLOCKS ?= 6000 + +# Inodes for the ramdisk root. The inode table is preallocated, so mkfs's +# default of 12000 cost 1501 of those 6000 blocks -- a quarter of the image, to +# describe about 260 files. 2000 is still an order of magnitude of headroom and +# costs 251 blocks. +RAMDISK_NINODES ?= 2000 + +# Kept out of the ramdisk root. +# +# Empty right now, and the machinery is kept anyway, because this is a licensing +# rule before it is a size one: the ramdisk image is linked *into the kernel +# binary*, so anything staged in sysroot/ when it is built becomes part of a +# distributable artifact. Anything that arrives in sysroot/ under a licence that +# cannot be combined with Apache-2.0, or that simply is not ours to redistribute, +# belongs on this list rather than in someone's memory. +# +# This is not hypothetical: a 33 MB test payload once landed here and overflowed +# the 6 MB image, and mkfs's "increase FSSIZE" message then pointed at a constant +# that had nothing to do with it. +# usb.ids is 730 KB of a 6 MB image -- 12% of the ramdisk root -- and nothing +# needs it to boot. It is a lookup table for a userspace tool, so it stays on +# the disk image and out of the kernel binary. +RAMDISK_EXCLUDE = usr/share/usb.ids +RAMDISK_EXCLUDE_ARGS = $(foreach p,$(RAMDISK_EXCLUDE),--exclude $(p)) + +ifdef RAMROOT +CFLAGS += -DRAMDISK_ROOT +RAMDISK_OBJ = $(BUILD)/kernel/ramdisk_obj +else +RAMDISK_OBJ = +endif + +# ----------------------------------------------------------------------- +# Top-level targets +# ----------------------------------------------------------------------- +all: schunix.img + +schunix.img: $(BUILD)/boot/bootblock $(BUILD)/boot/stage2 $(BUILD)/kernel/kernel $(BUILD)/schfs.img + dd if=/dev/zero of=schunix.img count=10000 + dd if=$(BUILD)/boot/bootblock of=schunix.img conv=notrunc + dd if=$(BUILD)/boot/stage2 of=schunix.img seek=1 conv=notrunc + # 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 + # the kernel straight over stage2's own tail. + dd if=$(BUILD)/kernel/kernel of=schunix.img seek=$$(( 1 + $(STAGE2_SECTORS) )) conv=notrunc + +kernel: $(BUILD)/kernel/kernel + +# Build the ramdisk-root variant. This is a target rather than just +# "make RAMROOT=1" because toggling RAMROOT changes CFLAGS (-DRAMDISK_ROOT), +# and make has no way to notice that: objects compiled for one setting would be +# silently reused for the other, leaving ROOTDEV pointing at the wrong device. +# Dropping the compiled objects first makes the switch always correct. +ramroot: + rm -rf $(BUILD)/kernel $(BUILD)/lib $(BUILD)/cmd + $(MAKE) RAMROOT=1 + +cmd: $(CMDBINS) + +ports: + $(MAKE) -C ports + +# ----------------------------------------------------------------------- +# Bootable ISO +# +# Always a ramdisk-root build. An ISO that needed a second disk to find its +# root filesystem would not be an install medium, it would be a puzzle -- and +# read-only media cannot host a writable root anyway. Same object-wiping +# preamble as the `ramroot` target, for the same reason: RAMROOT changes +# CFLAGS and make cannot see that. +# ----------------------------------------------------------------------- +iso: + rm -rf $(BUILD)/kernel $(BUILD)/lib $(BUILD)/cmd + $(MAKE) RAMROOT=1 schunix.iso + +schunix.iso: $(BUILD)/boot/cdboot $(BUILD)/boot/stage2 $(BUILD)/kernel/kernel + STAGE2_SECTORS=$(STAGE2_SECTORS) sh tools/mkiso.sh $@ + +# 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 +# in someone's optical drive. +qemu-iso: schunix.iso + $(QEMU) -serial mon:stdio $(QEMU_DISPLAY) -cpu qemu64,+rdtscp \ + -cdrom schunix.iso -boot d \ + -m 1G -smp 2 -machine pc-i440fx-9.2 + +# ----------------------------------------------------------------------- +# Bootloader — two stages. Stage 1 (bootblock) is the actual 512-byte MBR +# sector: BIOS-imposed hard limit, so it only loads stage 2 off disk and +# jumps to it. Stage 2 does VBE/A20/protected-mode setup, draws the boot +# splash, and loads the kernel — not size-constrained the same way, just +# padded out to a fixed STAGE2_SECTORS*512 bytes so the kernel's starting +# sector on disk is predictable (kept in sync with STAGE2_SECTORS in +# boot/bootasm.S and boot/stage2main.c). +# ----------------------------------------------------------------------- +# STAGE2_SECTORS used to be written out three times -- here, in boot/bootasm.S +# and in boot/stage2main.c -- and docs/layout.md carried a warning about keeping +# them in step. They are now all fed from this one variable via -D, so the +# warning describes a problem that can no longer happen. Both C/asm files keep +# an #ifndef fallback purely so they still read sensibly on their own. +# +# The ceiling is memory, not disk: stage2 is loaded at 0x7E00 and the multiboot +# kernel-search buffer begins at 0x10000, so 65 sectors is the hard maximum. +# stage2main.c static-asserts this. padstage2.pl fails the build if the compiled +# binary overflows the budget, rather than truncating it -- a short stage2 would +# shift the kernel's start sector and fail in a way that looks nothing like its +# cause. +STAGE2_SECTORS = 48 +STAGE2_DEF = -DSTAGE2_SECTORS=$(STAGE2_SECTORS) +# Byte budget is computed in the recipe with shell arithmetic, not $(shell expr +# ... \* 512): make hands the backslash through untouched, sh then treats the +# `*` as a glob, and expr gets a directory listing. It "worked" to the extent +# that make carried on and padstage2.pl received nonsense. +STAGE2_BYTES = $$(( $(STAGE2_SECTORS) * 512 )) + +$(BUILD)/boot/bootblock: boot/bootasm.S + @mkdir -p $(BUILD)/boot + $(CC32) $(STAGE2_DEF) -fno-builtin -fno-pic -nostdinc -I./include -c boot/bootasm.S -o $(BUILD)/boot/bootasm.o + $(LD) -m elf_i386 -nostdlib $(LD_LOWBASE) -n -N -e start -Ttext 0x7C00 \ + -o $(BUILD)/boot/bootblocktmp.o $(BUILD)/boot/bootasm.o + $(OBJCOPY) -S -O binary -j .text $(BUILD)/boot/bootblocktmp.o $(BUILD)/boot/bootblock + ./tools/sign.pl $(BUILD)/boot/bootblock + +# Stage 1 for optical media. Same job as bootblock, far less of it: El Torito +# has already loaded stage2 alongside this sector by the time it runs, so it +# only records that we came from a CD and jumps. See boot/cdboot.S. +$(BUILD)/boot/cdboot: boot/cdboot.S + @mkdir -p $(BUILD)/boot + $(CC32) -fno-builtin -fno-pic -nostdinc -I./include -c boot/cdboot.S -o $(BUILD)/boot/cdbootasm.o + $(LD) -m elf_i386 -nostdlib $(LD_LOWBASE) -n -N -e start -Ttext 0x7C00 \ + -o $(BUILD)/boot/cdboottmp.o $(BUILD)/boot/cdbootasm.o + $(OBJCOPY) -S -O binary -j .text $(BUILD)/boot/cdboottmp.o $@ + ./tools/sign.pl $@ + +$(BUILD)/boot/stage2: boot/stage2.S boot/stage2main.c include/logo.h + @mkdir -p $(BUILD)/boot + $(CC32) $(STAGE2_DEF) -fno-builtin -fno-pic -nostdinc -I./include -c boot/stage2.S -o $(BUILD)/boot/stage2asm.o + $(CC32) $(STAGE2_DEF) -fno-builtin -fno-pic -O -nostdinc -I./include -c boot/stage2main.c -o $(BUILD)/boot/stage2main.o + $(LD) -m elf_i386 -nostdlib $(LD_LOWBASE) -n -N -e stage2start -Ttext 0x7E00 \ + -o $(BUILD)/boot/stage2tmp.o $(BUILD)/boot/stage2asm.o $(BUILD)/boot/stage2main.o + $(OBJCOPY) -S -O binary -j .text -j .rodata -j .data $(BUILD)/boot/stage2tmp.o $(BUILD)/boot/stage2 + ./tools/padstage2.pl $(BUILD)/boot/stage2 $(STAGE2_BYTES) + +# ----------------------------------------------------------------------- +# Kernel binary +# ----------------------------------------------------------------------- +$(BUILD)/kernel/kernel: $(KERNOBJS) $(BUILD)/kernel/initcode_obj $(BUILD)/kernel/entryother_obj $(RAMDISK_OBJ) kernel/kernel.ld + @mkdir -p $(BUILD)/kernel + $(LD) $(LDFLAGS) -T kernel/kernel.ld -o $@ \ + $(BUILD)/kernel/arch/x86_64/entry.o $(KERN_NOENTRY) \ + $(BUILD)/kernel/initcode_obj $(BUILD)/kernel/entryother_obj $(RAMDISK_OBJ) + $(OBJDUMP) -S $@ > $(BUILD)/kernel/kernel.asm + +# The ramdisk root image, and the object wrapping it for the linker. Built from +# the same staged sysroot as the main image, just capped at RAMDISK_BLOCKS -- +# mkfs's content dedup means the whole userland still fits in a few MB. +$(BUILD)/fs-ram.img: $(MKFS) $(BUILD)/sysroot.stamp + @mkdir -p $(BUILD) + @rm -f $@ + $(MKFS) $@ --size $(RAMDISK_BLOCKS) --ninodes $(RAMDISK_NINODES) \ + $(RAMDISK_EXCLUDE_ARGS) --sysroot $(SYSROOT) + +$(BUILD)/kernel/ramdisk_obj: $(BUILD)/fs-ram.img + @mkdir -p $(BUILD)/kernel + $(LD) -r -b binary -m elf_x86_64 -o $@ $< + $(OBJCOPY) \ + --redefine-sym _binary_build_fs_ram_img_start=_binary_ramdisk_start \ + --redefine-sym _binary_build_fs_ram_img_end=_binary_ramdisk_end \ + --redefine-sym _binary_build_fs_ram_img_size=_binary_ramdisk_size \ + $@ + +# AP startup blob +$(BUILD)/kernel/entryother: kernel/arch/x86_64/entryother.S + @mkdir -p $(BUILD)/kernel + $(CC) $(CFLAGS) -fno-pic -nostdinc -I./include -c $< -o $(BUILD)/kernel/entryother.o + $(LD) $(LDFLAGS) $(LD_LOWBASE) -e start -Ttext 0x7000 -o $(BUILD)/kernel/entryothertmp.o $(BUILD)/kernel/entryother.o + $(OBJCOPY) -S -O binary -j .text $(BUILD)/kernel/entryothertmp.o $@ + +# NOTE: ld -r -b binary derives its symbol names from the *path* of the input +# file, so these --redefine-sym pairs must be kept in sync with the build +# directory layout above. Move the file, and the left-hand names change. +$(BUILD)/kernel/entryother_obj: $(BUILD)/kernel/entryother + $(LD) -r -b binary -m elf_x86_64 -o $@ $< + $(OBJCOPY) \ + --redefine-sym _binary_build_kernel_entryother_start=_binary_entryother_start \ + --redefine-sym _binary_build_kernel_entryother_end=_binary_entryother_end \ + --redefine-sym _binary_build_kernel_entryother_size=_binary_entryother_size \ + $@ + +# Init stub (first user-space code, embedded in the kernel image) +$(BUILD)/lib/initcode: lib/initcode.S + @mkdir -p $(BUILD)/lib + $(CC) $(CFLAGS) -fno-pic -nostdinc -I./include -c $< -o $(BUILD)/lib/initcode.o + $(LD) -m elf_x86_64 -nostdlib $(LD_LOWBASE) -N -e start -Ttext 0 -o $(BUILD)/lib/initcodetmp.o $(BUILD)/lib/initcode.o + $(OBJCOPY) -S -O binary $(BUILD)/lib/initcodetmp.o $@ + +$(BUILD)/kernel/initcode_obj: $(BUILD)/lib/initcode + @mkdir -p $(BUILD)/kernel + $(LD) -r -b binary -m elf_x86_64 -o $@ $< + $(OBJCOPY) \ + --redefine-sym _binary_build_lib_initcode_start=_binary_initcode_start \ + --redefine-sym _binary_build_lib_initcode_end=_binary_initcode_end \ + --redefine-sym _binary_build_lib_initcode_size=_binary_initcode_size \ + $@ + +# ----------------------------------------------------------------------- +# vectors.S — generated from perl script +# ----------------------------------------------------------------------- +kernel/arch/x86_64/vectors.S: tools/vectors.pl + perl tools/vectors.pl > $@ + +# ----------------------------------------------------------------------- +# Compile rules for kernel/ +# ----------------------------------------------------------------------- +$(BUILD)/kernel/arch/x86_64/%.o: kernel/arch/x86_64/%.c + @mkdir -p $(BUILD)/kernel/arch/x86_64 + $(CC) $(CFLAGS) -c $< -o $@ + +$(BUILD)/kernel/arch/x86_64/%.o: kernel/arch/x86_64/%.S + @mkdir -p $(BUILD)/kernel/arch/x86_64 + $(CC) $(CFLAGS) -c $< -o $@ + +$(BUILD)/kernel/core/%.o: kernel/core/%.c + @mkdir -p $(BUILD)/kernel/core + $(CC) $(CFLAGS) -c $< -o $@ + +$(BUILD)/kernel/dev/%.o: kernel/dev/%.c + @mkdir -p $(BUILD)/kernel/dev + $(CC) $(CFLAGS) -c $< -o $@ + +# `$(dir $@)` rather than a fixed path: drivers are grouped into one directory +# per device class (gpu/, net/, bus/, usb/), so the output directory varies with +# the target and a hardcoded mkdir only creates the top one. +$(BUILD)/kernel/drivers/%.o: kernel/drivers/%.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -c $< -o $@ + +$(BUILD)/kernel/fs/%.o: kernel/fs/%.c + @mkdir -p $(BUILD)/kernel/fs + $(CC) $(CFLAGS) -c $< -o $@ + +$(BUILD)/kernel/fs/schfs/%.o: kernel/fs/schfs/%.c + @mkdir -p $(BUILD)/kernel/fs/schfs + $(CC) $(CFLAGS) -I./kernel/fs/schfs -c $< -o $@ + +$(BUILD)/kernel/net/%.o: kernel/net/%.c + @mkdir -p $(BUILD)/kernel/net + $(CC) $(CFLAGS) -c $< -o $@ + +$(BUILD)/kernel/proc/%.o: kernel/proc/%.c + @mkdir -p $(BUILD)/kernel/proc + $(CC) $(CFLAGS) -c $< -o $@ + +# sys/ gets an extra -I so syscall.c can do #include "table.inc" +$(BUILD)/kernel/sys/%.o: kernel/sys/%.c + @mkdir -p $(BUILD)/kernel/sys + $(CC) $(CFLAGS_SYS) -c $< -o $@ + +# ----------------------------------------------------------------------- +# First-party userland: lib/ + cmd/ +# ----------------------------------------------------------------------- +$(BUILD)/lib/%.o: lib/%.c + @mkdir -p $(BUILD)/lib + $(CC) $(CFLAGS) -c $< -o $@ + +$(BUILD)/lib/%.o: lib/%.S + @mkdir -p $(BUILD)/lib + $(CC) $(CFLAGS) -c $< -o $@ + +$(BUILD)/cmd/%: cmd/%/main.c $(ULIB) + @mkdir -p $(BUILD)/cmd + $(CC) $(CFLAGS) -c $< -o $(BUILD)/cmd/$*.o + $(LD) $(LDFLAGS) $(LD_LOWBASE) -e _start -Ttext 0x4000 -o $@ $(BUILD)/cmd/$*.o $(ULIB) + $(OBJCOPY) -S $@ + +$(SYSROOT)/bin/%: $(BUILD)/cmd/% | $(SYSROOT)/bin + cp $< $@ + chmod 755 $@ + +$(SYSROOT)/bin: + mkdir -p $@ + +# ----------------------------------------------------------------------- +# Filesystem image +# ----------------------------------------------------------------------- +# ----------------------------------------------------------------------- +# SchFS B-tree torture test (host program). +# +# The B-tree underpins every record type in SchFS, so it is developed and +# tested here -- against a reference model, with simulated crashes -- before +# it is linked into the kernel. Run it after any change to +# kernel/fs/schfs/btree.c. +# ----------------------------------------------------------------------- +schfs-test: $(SCHFS_TEST) + $(SCHFS_TEST) + +# Use ASan/UBSan when the runtime libraries are actually installed; they catch +# exactly the pointer-arithmetic mistakes this code is most exposed to, but not +# every machine has libasan, so fall back rather than failing the build. +SAN := $(shell echo 'int main(void){return 0;}' > /tmp/.santest.c 2>/dev/null && \ + gcc -fsanitize=address,undefined -o /tmp/.santest /tmp/.santest.c \ + >/dev/null 2>&1 && echo -fsanitize=address,undefined) + +SCHFS_SRC = kernel/fs/schfs/btree.c kernel/fs/schfs/btree.h \ + kernel/fs/schfs/space.c kernel/fs/schfs/vol.c \ + kernel/fs/schfs/obj.c kernel/fs/schfs/objw.c \ + kernel/fs/schfs/schfs_int.h include/schfs.h + +# -iquote, not -I: include/ has its own errno.h, stat.h, fcntl.h and types.h, +# and -I would put them ahead of the system ones for a host program that needs +# the real thing. -iquote applies only to "quoted" includes, so btree.h still +# finds schfs.h while still means the C library's. +HOSTCFLAGS = -Wall -Wextra -O1 -g $(SAN) -iquote ./include + +$(SCHFS_TEST): tools/schfs_test.c $(SCHFS_SRC) + @mkdir -p $(BUILD)/tools + @mkdir -p $(BUILD) + $(HOSTCC) $(HOSTCFLAGS) -o $@ tools/schfs_test.c + +# The object layer -- files, directories, and whether deleting things gives the +# space back. Runs against a memory-backed volume, so a full create/write/ +# delete/remount cycle takes milliseconds instead of a rebuild and a boot. +$(SCHFS_OBJT): tools/schfs_objtest.c $(SCHFS_SRC) + @mkdir -p $(BUILD)/tools + @mkdir -p $(BUILD) + $(HOSTCC) $(HOSTCFLAGS) -o $@ tools/schfs_objtest.c + +schfs-objtest: $(SCHFS_OBJT) + $(SCHFS_OBJT) + +# The image writer and checker. Both #include the real filesystem sources, so +# there is exactly one implementation of the on-disk format: a host tool and the +# kernel cannot drift apart because there is nothing to drift from. +$(MKSCHFS): tools/mkschfs.c $(SCHFS_SRC) + @mkdir -p $(BUILD)/tools + @mkdir -p $(BUILD) + $(HOSTCC) $(HOSTCFLAGS) -o $@ tools/mkschfs.c + +$(SCHFS_FSCK): tools/schfs_fsck.c $(SCHFS_SRC) + @mkdir -p $(BUILD)/tools + @mkdir -p $(BUILD) + $(HOSTCC) $(HOSTCFLAGS) -o $@ tools/schfs_fsck.c + +mkschfs: $(MKSCHFS) +schfs-fsck: $(SCHFS_FSCK) + +# End-to-end filesystem test: build an image from a directory tree, read it +# back with schfs_fsck, and diff the result against the original. +# +# The oracle here is the host's own filesystem, which knows nothing about SchFS. +# schfs-test proves the B-tree matches a model written alongside it; this proves +# the *filesystem* matches a tree that exists independently of it, so a writer +# and reader that agree on something wrong are still caught. +schfs-image-test: $(MKSCHFS) $(SCHFS_FSCK) + @sh tools/schfs_roundtrip.sh $(MKSCHFS) $(SCHFS_FSCK) + +# Every SchFS suite. Run this after touching anything under kernel/fs/schfs. +schfs-check: schfs-test schfs-objtest schfs-image-test + +# Crash the kernel on purpose and photograph the result. +# +# The crash screen is the one part of the system you cannot look at by using +# the system, which is exactly why it rots. This makes "does it still render" +# a question with a thirty-second answer. Needs a ramroot build first. +crashshot: + pwsh -File tools/crashshot.ps1 + +# Read the QR code back off a captured crash screen. End-to-end on purpose: it +# reads the pixels that were painted, so payload construction in panic context, +# the encoder, the module scaling and the quiet zone are all covered by whether +# text comes back. Run `make crashshot` first. Needs the same Python packages +# as `qrcheck`. +crashqr: + $(PYTHON) tools/crashqr.py + +$(MKFS): tools/mkfs.c include/fs.h include/stat.h include/param.h + @mkdir -p $(BUILD)/tools + $(HOSTCC) $(HOSTWARN) -I. -o $(MKFS) tools/mkfs.c + +# Stage everything a running system needs into sysroot/, then image it. +# +# ports/ is built via its own Makefile rather than per-port from here, because +# that is where the inter-port ordering lives (mksh and toybox both link +# against musl, whose install prefix is under build/ — so `make clean` wipes it +# and musl must be rebuildable as part of the normal chain, not out-of-band). +# +# On Windows the ports are NOT rebuilt. musl, mksh and toybox are Linux +# userland built by configure scripts and kconfig, and getting those to run +# under Git Bash against a clang cross-target is a separate project from +# building the OS. Their outputs are already staged in sysroot/ and change +# perhaps twice a year, so the cost of not rebuilding them here is close to +# zero -- and it is stated out loud rather than silently skipped, because a +# port that quietly does not rebuild is exactly the kind of thing that wastes +# an afternoon later. +sysroot-install: $(addprefix $(SYSROOT)/bin/, $(CMDS)) +ifdef WINHOST + @echo "ports: skipped (Windows host) -- musl/mksh/toybox are used as already staged in $(SYSROOT)" + @test -f $(SYSROOT)/bin/sh || { echo "ports: $(SYSROOT)/bin/sh is missing and cannot be built here; build ports on a Linux host once" >&2; exit 1; } +else + $(MAKE) -C ports CC=gcc +endif + +# A stamp whose timestamp advances only when the staged tree actually changes. +# +# make cannot depend on "the contents of a directory", and sysroot/ is filled +# by two different builds (cmd/ from here, ports/ recursively), so the images +# below used to depend on the phony sysroot-install -- which meant every image +# was rebuilt on every invocation, whether or not a single byte had moved. +# That cost 100 seconds of a 108-second no-op build. +# +# Path, size and mtime rather than content hashes: reading every staged file +# would undo the point, and a build system that lies about a file whose mtime +# and size both stayed the same has bigger problems. The cmp-then-move keeps +# the stamp's mtime unchanged when the summary is unchanged, which is the +# whole trick -- writing it unconditionally would just move the problem. +$(BUILD)/sysroot.stamp: sysroot-install + @mkdir -p $(BUILD) + @find $(SYSROOT) -type f -printf '%p %s %T@\n' | sort > $@.new + @cmp -s $@.new $@ || mv -f $@.new $@ + @rm -f $@.new + +$(BUILD)/fs.img: $(MKFS) $(BUILD)/sysroot.stamp + @mkdir -p $(BUILD) + @echo "Creating Schunix File System Image..." + @# 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 + @# kernel has already relinked, leaving schunix.img stale. The next test run + @# then boots the previous kernel and the change appears to have done + @# nothing, which has cost several debugging cycles. Say so plainly. + @rm -f $@ || { \ + echo ""; \ + echo " $@ is in use -- a QEMU is still holding it."; \ + echo " Close it, or: pwsh -Command \"Get-Process qemu-system-x86_64 |"; \ + echo " Where-Object { -not \$$_.MainWindowTitle } | Stop-Process -Force\""; \ + echo ""; \ + exit 1; \ + } + $(MKFS) $@ --sysroot $(SYSROOT) + +# ----------------------------------------------------------------------- +# QEMU +# ----------------------------------------------------------------------- +qemu: schunix.img $(BUILD)/schfs.img + $(QEMU) -serial mon:stdio $(QEMU_DISPLAY) -cpu qemu64,+rdtscp \ + -hda schunix.img -hdb $(BUILD)/schfs.img \ + -m 1G -smp 2 -machine pc-i440fx-9.2 + +# The root filesystem. Built from the staged sysroot; the kernel mounts it as +# / in forkret(). +$(BUILD)/schfs.img: $(MKSCHFS) $(BUILD)/sysroot.stamp + @mkdir -p $(BUILD) + @rm -f $@ + ./$(MKSCHFS) $@ --size 8000 --label schunix --sysroot $(SYSROOT) + +# Boot with a SchFS volume attached as the second disk. +# +# Needs the ramdisk-root kernel ("make ramroot" first): with RAMROOT the root +# filesystem comes out of memory and device 1 is free, which is exactly the +# arrangement docs/architecture/schfs.md asks for -- a new-format disk that +# fails to mount cannot stop the system booting. Without RAMROOT, device 1 is +# the live v1 root and the SchFS probe correctly finds nothing there. +# +# Once up: cat /proc/schfs +qemu-schfs: schunix.img $(BUILD)/schfs.img + $(QEMU) -serial mon:stdio $(QEMU_DISPLAY) -cpu qemu64,+rdtscp \ + -hda schunix.img -hdb $(BUILD)/schfs.img \ + -m 1G -smp 2 -machine pc-i440fx-9.2 + +# ----------------------------------------------------------------------- +# Misc +# ----------------------------------------------------------------------- +# schunix.img is deliberately NOT here. It is a real file with real +# prerequisites; listing it as phony made make skip the timestamp check and +# re-run the four dd commands -- including zeroing five megabytes -- on every +# single invocation, including ones where nothing had changed. +# include/logo.h is generated but committed, exactly as include/font.h is: it +# 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. +# Run this by hand after changing the art. +LOGO_SRC = Assets/Schunix Small Logo.png +LOGO_PX = 128 + +logo: + $(PYTHON) tools/mklogo.py "$(LOGO_SRC)" include/logo.h $(LOGO_PX) + +# 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 +# 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 +# the request, and it is the one thing here worth pushing back on: fetching on +# every compilation makes an offline build fail, makes the same source produce +# different images on different days, and puts a third-party web server on the +# critical path of `make`. dist/ exists precisely so a rebuild never needs the +# network -- see docs/layout.md. `make usb-ids` is a deliberate act; the file it +# writes is committed and dated, so what shipped is always knowable. +USB_IDS_URL = http://www.linux-usb.org/usb.ids + +usb-ids: + @echo "==> fetching $(USB_IDS_URL)" + @curl -sfL --max-time 60 -o dist/usb.ids.new "$(USB_IDS_URL)" || \ + { echo " fetch failed; keeping the cached copy"; rm -f dist/usb.ids.new; exit 1; } + @# A truncated or error-page download would otherwise silently replace a + @# good database with rubbish. Check it looks like what it claims to be. + @grep -q "^# Version:" dist/usb.ids.new || \ + { echo " that is not a usb.ids file; keeping the cached copy"; \ + rm -f dist/usb.ids.new; exit 1; } + @mv dist/usb.ids.new dist/usb.ids + @cp dist/usb.ids $(SYSROOT)/usr/share/usb.ids + @grep -m1 "^# Version:" dist/usb.ids + +# Build the kernel's QR encoder on the host and check it. +# +# A QR symbol with a mistyped table entry still looks like a perfectly plausible +# grid of black squares, so the self-checks in qrtest.c cover what can be +# verified mechanically and the PNG covers the rest: point a phone at it. +QRTEST = $(BUILD)/tools/qrtest$(EXE) + +$(QRTEST): tools/qrtest.c kernel/core/qr.c include/qr.h + @mkdir -p $(BUILD)/tools + $(HOSTCC) $(HOSTWARN) -I./include -o $@ tools/qrtest.c + +qrtest: $(QRTEST) + @mkdir -p $(BUILD) + ./$(QRTEST) $(BUILD)/qr.png + +# The check that actually decides whether the encoder works: build a symbol and +# read it back with a real decoder, plus a module-for-module comparison against +# a second encoder. Needs Python packages that are not part of the build, so it +# is not wired into `make` -- install them wherever you like and point +# PYTHONPATH at it: +# +# pip install --target build/pylibs opencv-python-headless numpy segno +# PYTHONPATH=build/pylibs make qrcheck +qrcheck: $(QRTEST) + $(PYTHON) tools/qrcheck.py + +.PHONY: all kernel ramroot cmd ports sysroot-install qemu \ + schfs-test schfs-objtest schfs-image-test schfs-check mkschfs \ + schfs-fsck crashshot qemu-schfs iso qemu-iso clean distclean \ + logo qrtest qrcheck crashqr usb-ids +.PRECIOUS: $(BUILD)/%.o + +# 'clean' removes generated output only. dist/ (upstream tarballs) survives, +# so a rebuild never needs the network. +clean: + rm -rf $(BUILD) schunix.img schunix.iso kernel/arch/x86_64/vectors.S + +distclean: clean + rm -rf dist + +# Header dependencies, from gcc -MD. +# +# This used to be a set of globs including `$(BUILD)/kernel/**/*.d`. make's +# wildcard has no recursive `**`: it behaved as a single `*` and matched +# exactly one level, so build/kernel/core/*.d was picked up while +# build/kernel/arch/x86_64/*.d and build/kernel/fs/schfs/*.d were not. +# Everything under arch/ and schfs/ therefore had NO header dependency +# tracking at all -- editing include/schfs.h or include/mmu.h left stale +# objects that linked without complaint. find actually recurses. +-include $(shell find $(BUILD) -name '*.d' 2>/dev/null) diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..e57492b --- /dev/null +++ b/NOTICE @@ -0,0 +1,145 @@ +Schunix +Copyright 2026 Nexoniarz + +This product includes software developed as part of the Schunix project, +licensed under the Apache License, Version 2.0. See LICENSE. + +================================================================================ +Third-party software +================================================================================ + +Schunix incorporates and redistributes software written by others. Their +licences apply to their code and are NOT superseded by the Schunix licence. +A built Schunix image contains binaries derived from all of the following. + +-------------------------------------------------------------------------------- +xv6-x86_64 / xv6 MIT License +-------------------------------------------------------------------------------- +Copyright (c) 2006-2019 Frans Kaashoek, Robert Morris, Russ Cox, + Massachusetts Institute of Technology CSAIL + +The Schunix kernel is a derivative work of xv6. Substantial portions of +kernel/ -- notably the process, trap, virtual memory, buffer cache and v1 +filesystem code -- descend from it, however heavily rewritten. The MIT licence +requires that this notice be preserved in all copies; see LICENSE.MIT. + +-------------------------------------------------------------------------------- +musl libc 1.2.5 MIT License +-------------------------------------------------------------------------------- +Copyright (c) 2005-2020 Rich Felker and contributors + +Built from ports/musl. Provides the C library every userland program links +against. See the extracted source's COPYRIGHT file for the full contributor +list, which the MIT terms require be carried along with binaries. + +-------------------------------------------------------------------------------- +toybox 0.8.12 Zero-Clause BSD (0BSD) +-------------------------------------------------------------------------------- +Copyright (c) 2006-2024 Rob Landley and contributors + +Built from ports/toybox. Supplies the standard command set in /bin. 0BSD +imposes no attribution requirement at all; this entry is courtesy, not +obligation. + +-------------------------------------------------------------------------------- +mksh R59c MirOS Licence +-------------------------------------------------------------------------------- +Copyright (c) 2002-2023 Thorsten Glaser and contributors +Portions derived from the Public Domain Korn Shell (pdksh) + +Built from ports/mksh. Supplies /bin/sh. The MirOS Licence is permissive and +requires the copyright notice be retained. + +-------------------------------------------------------------------------------- +Intel 8254x device identifiers BSD 3-Clause +-------------------------------------------------------------------------------- +Copyright (c) 2001-2020, Intel Corporation +All rights reserved. + +The PCI device IDs in include/e1000.h are transcribed from FreeBSD's +sys/dev/e1000/e1000_hw.h, which carries the Intel 3-clause BSD licence above +(verified: no advertising clause). Only the identifier constants are used -- +data, not implementation. kernel/drivers/net/e1000/e1000.c is written from +Intel's public manual 317453 and contains no FreeBSD or Intel driver code. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the conditions of the 3-clause BSD +licence are met, including retention of this notice and the disclaimer, and +that neither the name of Intel Corporation nor the names of its contributors +are used to endorse or promote products derived from this software without +specific prior written permission. + +-------------------------------------------------------------------------------- +usb.ids -- USB vendor and product database BSD 3-Clause (dual-licensed) +-------------------------------------------------------------------------------- +Maintained by Stephen J. Gowdy +http://www.linux-usb.org/usb.ids + +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 +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 +2). + +Shipped verbatim as /usr/share/usb.ids. Cached in dist/ and refreshed with +`make usb-ids`, never automatically -- the version and date are in the file's +own header, so what shipped is always knowable. + +-------------------------------------------------------------------------------- +Roboto Apache-2.0 +-------------------------------------------------------------------------------- +Copyright the Roboto Project Authors (https://github.com/googlefonts/roboto) + +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 +obligation beyond this notice. Intended for the desktop, window manager and +compositor. + +-------------------------------------------------------------------------------- +JetBrains Mono SIL OFL 1.1 +-------------------------------------------------------------------------------- +Copyright 2020 The JetBrains Mono Project Authors +(https://github.com/JetBrains/JetBrainsMono) + +Shipped as /usr/share/fonts/JetBrainsMono-Regular.ttf, from ports/JetBrains_Mono +(full licence text at ports/JetBrains_Mono/OFL.txt). Intended for the terminal +and TTY. + +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 +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 +(a pre-rasterised bitmap, for instance) may keep the name. + +-------------------------------------------------------------------------------- +"New File System For XV6" MIT License +-------------------------------------------------------------------------------- +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 +xv6's file system with features Schunix still uses today: + + - the HTree hashed directory index (BKDRHash, HASHRANGE, the primary/overflow + bucket layout), after Daniel Phillips, "A Directory Index for EXT2", + 5th Annual Linux Showcase & Conference, 2001 + - Ext4-style extents (T_EXTENT) + - the inode bitmap + - symbolic links, file permissions, lseek and append + +Licensed under the MIT License, which permits this use and requires that the +copyright notice and permission notice be retained. This entry is that +retention; it was missing until 2026-08-09 and is recorded here regardless of +what happens to the code, because the obligation attaches to every copy already +made. + +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 +ports//patches/. Nothing in ports/ is Schunix code; do not add first-party +work there. See docs/layout.md. + +Licence questions -- what may be copied in, what may never be, and how to check +a NetBSD file's clause before using it -- are worked through in +docs/licensing.md. diff --git a/boot/bootasm.S b/boot/bootasm.S new file mode 100644 index 0000000..10cc78f --- /dev/null +++ b/boot/bootasm.S @@ -0,0 +1,101 @@ +# Stage 1 — the actual MBR boot sector. Hard-limited to 510 bytes (+2-byte +# 0x55AA signature) by the BIOS, so there's no room here for anything but +# "load stage 2 off disk and jump to it". All the VBE/A20/protected-mode/ +# splash/kernel-loading work now lives in stage2.S + stage2main.c, which +# aren't sector-size-constrained. +# +# How many sectors of stage2 to pull in. This, the padding the Makefile gives +# stage2's binary, and the "+(STAGE2_SECTORS+1)" sector math in stage2main.c's +# readseg() all have to agree on where the kernel starts on disk -- so the +# Makefile passes -DSTAGE2_SECTORS and is the single authority. The value below +# is only a fallback for reading this file standalone. +# +# It is 48, not the old 24, because stage2 now carries the boot logo +# (include/logo.h, 8 KiB). The real ceiling is memory rather than this number: +# stage2 loads at 0x7E00 and the multiboot kernel-search buffer starts at +# 0x10000, so stage2 cannot exceed 0x8200 bytes = 65 sectors. +#ifndef STAGE2_SECTORS +#define STAGE2_SECTORS 48 +#endif +#define STAGE2_ADDR 0x7E00 + +.code16 +.global start +start: + cli + xorw %ax, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw $0x7c00, %sp + + # Read STAGE2_SECTORS sectors, starting at disk sector 1 (LBA), into + # memory right after this boot sector (0x7E00). Raw IDE PIO (LBA28) — + # same register convention as stage2main.c's own readsect(), just + # inlined here since we can't call C code yet. Port numbers 0x1F2-0x1F7 + # are all > 0xFF, so they must go through %dx — `out $imm8,%al` only + # encodes an 8-bit port and silently truncates anything larger. + # "You were not booted from a CD." stage2main.c reads this byte to choose + # between ATA and ATAPI when it loads the kernel, and nothing else clears + # it -- so a warm reboot from a disc could otherwise leave the flag set and + # send a perfectly ordinary hard-disk boot looking for an optical drive. + # Placed one byte past the verbose flag; both sit clear of the 256-byte VBE + # mode info block that stage2.S is about to write at 0x30000. + movw $0x3000, %ax + movw %ax, %es + movw $0x101, %di + movb $0, %al + movb %al, %es:(%di) + xorw %ax, %ax + movw %ax, %es + + movw $STAGE2_ADDR, %di # ES:DI destination, ES=0 + movw $1, %si # first LBA sector to read + movb $STAGE2_SECTORS, %bl + +.Lsector: +.Lwait1: + movw $0x1F7, %dx + inb %dx, %al + andb $0xC0, %al + cmpb $0x40, %al + jne .Lwait1 + + movw $0x1F2, %dx + movb $1, %al + outb %al, %dx # sector count = 1 + + incw %dx # 0x1F3 + movw %si, %ax + outb %al, %dx # LBA [7:0] + + incw %dx # 0x1F4 + xorb %al, %al + outb %al, %dx # LBA [15:8] + + incw %dx # 0x1F5 + outb %al, %dx # LBA [23:16] + + incw %dx # 0x1F6 + movb $0xE0, %al + outb %al, %dx # drive 0, LBA mode + + incw %dx # 0x1F7 + movb $0x20, %al + outb %al, %dx # READ SECTORS command + +.Lwait2: + inb %dx, %al # %dx still 0x1F7 + andb $0xC0, %al + cmpb $0x40, %al + jne .Lwait2 + + movw $256, %cx # 256 words = 512 bytes + movw $0x1F0, %dx + rep insw # reads into ES:DI, DI += 512 automatically + + incw %si + decb %bl + jnz .Lsector + + ljmp $0, $STAGE2_ADDR diff --git a/boot/cdboot.S b/boot/cdboot.S new file mode 100644 index 0000000..db3bd3a --- /dev/null +++ b/boot/cdboot.S @@ -0,0 +1,48 @@ +# Stage 1 for optical media -- the El Torito "no emulation" boot sector. +# +# This exists because bootasm.S cannot boot a CD. It loads stage 2 by talking +# straight to the primary IDE controller's ATA registers, and a CD is not an +# ATA disk: it answers to the ATAPI packet interface instead, and under +# El Torito it may not even be the drive at 0x1F0. Rather than teach a +# 512-byte sector two protocols, optical media get their own first stage. +# +# It has almost nothing to do, because El Torito's "load segment / sector +# count" fields do the reading for us: tools/mkiso.sh asks for +# 1 + STAGE2_SECTORS virtual sectors at 0x7C00, so by the time this runs the +# BIOS has already placed stage 2 at 0x7E00 -- exactly where bootasm.S would +# have put it. The only real work is recording *which* medium we came from, +# since stage2main.c has to read the kernel back with the matching protocol. +# +# The flag goes next to the verbose-boot flag, one byte past it, for the same +# reason that one sits where it does: it is clear of the 256-byte VBE mode +# info block at 0x30000 that stage2.S fills in a moment from now. + +#define STAGE2_ADDR 0x7E00 +#define BOOT_MEDIA_FLAG_SEG 0x3000 +#define BOOT_MEDIA_FLAG_OFF 0x101 +#define BOOT_MEDIA_CD 1 + +.code16 +.global start +start: + cli + xorw %ax, %ax + movw %ax, %ds + movw %ax, %ss + movw $0x7c00, %sp + + # "You were booted from a CD." stage2main.c reads this to decide between + # ATA and ATAPI; without it the loader would read the kernel off whatever + # happens to be sitting at 0x1F0, which on a CD boot is usually nothing. + movw $BOOT_MEDIA_FLAG_SEG, %ax + movw %ax, %es + movw $BOOT_MEDIA_FLAG_OFF, %di + movb $BOOT_MEDIA_CD, %al + movb %al, %es:(%di) + + # stage2.S expects zeroed segments and an inherited stack, same as it gets + # from bootasm.S. + xorw %ax, %ax + movw %ax, %es + + ljmp $0, $STAGE2_ADDR diff --git a/boot/stage2.S b/boot/stage2.S new file mode 100644 index 0000000..340d0f4 --- /dev/null +++ b/boot/stage2.S @@ -0,0 +1,129 @@ +# Stage 2 — loaded by stage1 at 0x7E00, still in 16-bit real mode. Does the +# VBE mode setup, A20 line, and real->protected mode switch that used to +# live directly in the boot sector, then hands off to stage2main() (C) to +# draw a splash and load the actual kernel. Not sector-size-constrained — +# only bounded by STAGE2_SECTORS in bootasm.S / the Makefile. +#include "../include/asm.h" +#include "../include/memlayout.h" +#include "../include/mmu.h" + +.code16 +.global stage2start +stage2start: + # Segments are already zeroed by stage1; %sp is inherited too. + + movw $bootmsg, %si + call print16 + + # VBE Setup. Mode info block goes at 0x30000, not 0x9000 — stage2 itself + # is loaded starting at 0x7E00 and, with the boot-menu/progress-bar code, + # is now big enough to reach 0x9000, so writing the VBE block there would + # clobber stage2's own tail end. 0x30000 is clear of stage2 (ends well + # under 0xA000), the multiboot kernel-search buffer (0x10000-0x14000), + # and the kernel's own load address (0x100000). + movw $0x3000, %ax + movw %ax, %es + xorw %di, %di # ES:DI = 3000:0000 = flat 0x30000 + movw $0x0143, %cx + movw $0x4F01, %ax + int $0x10 + + cmpw $0x004F, %ax + jne e820 + movw $0x4143, %bx + movw $0x4F02, %ax + int $0x10 + + # BIOS E820 memory map — the standard firmware interface every serious + # loader (GRUB, Linux's own boot stub, the BSDs) uses to learn the real + # RAM layout instead of guessing. Entry count goes to flat 0x30200, + # 24-byte entries start at 0x30208 (both inside the 0x3000 segment the + # VBE block already claimed; verbose flag sits at +0x100). Capped at 32 + # entries so a pathological BIOS can't run us past the buffer. +e820: + movw $0x3000, %ax + movw %ax, %es + xorl %ebx, %ebx # continuation cookie, 0 = first call + movw $0x208, %di + xorl %ebp, %ebp # entry count +e820loop: + movl $0xE820, %eax + movl $0x534D4150, %edx # 'SMAP' + movl $24, %ecx + int $0x15 + jc e820done # carry = end of map (or unsupported BIOS) + cmpl $0x534D4150, %eax + jne e820done + addw $24, %di + incl %ebp + cmpl $32, %ebp + jae e820done + testl %ebx, %ebx + jnz e820loop +e820done: + movl %ebp, %es:(0x200) + xorw %ax, %ax + movw %ax, %es + +seta20.1: + inb $0x64, %al + testb $0x2, %al + jnz seta20.1 + movb $0xd1, %al + outb %al, $0x64 +seta20.2: + inb $0x64, %al + testb $0x2, %al + jnz seta20.2 + movb $0xdf, %al + outb %al, $0x60 + + lgdt gdtdesc + movl %cr0, %eax + orl $CR0_PE, %eax + movl %eax, %cr0 + + ljmp $(SEG_KCODE<<3), $start32 + +# Print null-terminated string at DS:SI via BIOS teletype (real mode only). +# Clobbers AX, BX, SI. +print16: +.Lp16loop: + lodsb + testb %al, %al + jz .Lp16done + movb $0x0E, %ah + movw $0x0007, %bx + int $0x10 + jmp .Lp16loop +.Lp16done: + ret + +bootmsg: + .asciz "Schunix booting...\r\n" + +.code32 +start32: + movw $(SEG_KDATA<<3), %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + xorw %ax, %ax + movw %ax, %fs + movw %ax, %gs + + movl $0x7c00, %esp + call stage2main + +spin: + jmp spin + +.p2align 2 +gdt: + SEG_NULLASM + SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff) + SEG_ASM(STA_W, 0x0, 0xffffffff) + +gdtdesc: + .word (gdtdesc - gdt - 1) + .long gdt diff --git a/boot/stage2main.c b/boot/stage2main.c new file mode 100644 index 0000000..78966e5 --- /dev/null +++ b/boot/stage2main.c @@ -0,0 +1,878 @@ +#include "../include/types.h" +#include "../include/x86.h" +#include "../include/memlayout.h" +#include "../include/font.h" + +#define SECTSIZE 512 + +// Kernel starts right after stage2 on disk. The Makefile passes +// -DSTAGE2_SECTORS so this, bootasm.S and stage2's padding cannot drift apart; +// the value here is a fallback for reading the file on its own. +#ifndef STAGE2_SECTORS +#define STAGE2_SECTORS 48 +#endif + +// stage2 is loaded at 0x7E00 and must not reach the multiboot kernel-search +// buffer at 0x10000. Nothing checks this at runtime, and the failure it would +// produce -- a kernel image partly overwritten by the loader that loaded it -- +// would be spectacularly hard to read backwards from. +_Static_assert(0x7E00 + STAGE2_SECTORS * 512 <= 0x10000, + "stage2 would overlap the kernel-search buffer at 0x10000"); + +// One palette for the whole system; see include/theme.h. The splash used to +// use the panic screen's deep purple and gold, which meant a healthy boot was +// dressed identically to a crash. +#include "theme.h" +// The boot logo, generated from Assets/ by tools/mklogo.py. Shared verbatim +// with kernel/dev/vga.c so there is one mask, not two. +#include "logo.h" + +// VBE mode info block, written here by stage2.S's VBE call. NOT at 0x9000 +// (the classic single-stage bootloader's choice) — stage2's own code now +// runs from 0x7E00 up to nearly 0x9000 once the boot-menu/progress-bar +// logic is included, so a block at 0x9000 would get partially overwritten +// by stage2's own tail end. 0x30000 is clear of stage2, the multiboot +// kernel-search buffer (0x10000-0x14000), and the kernel's load address +// (0x100000). +#define VBE_INFO_ADDR 0x30000 + +// Fixed low-memory scratch byte, read by kernel/core/main.c's kmain() before +// any other init: 1 if the user picked "verbose" from the boot menu. Placed +// just past the VBE info block (which is at most 256 bytes), NOT at 0x7000 +// — kernel/core/main.c's startothers() already uses 0x7000 for the AP +// (secondary CPU) boot trampoline. That's write-after-read from this flag's +// perspective (verbose is read before startothers() runs), so it wasn't an +// active bug, but reusing a documented-elsewhere address is exactly the +// kind of thing that turns into one later. +#define BOOT_VERBOSE_FLAG_ADDR (VBE_INFO_ADDR + 0x100) + +// Set by boot/cdboot.S when we were booted from optical media. One byte past +// the verbose flag, for the same reason that one sits where it does: clear of +// the 256-byte VBE mode info block at VBE_INFO_ADDR. +#define BOOT_MEDIA_FLAG_ADDR (VBE_INFO_ADDR + 0x101) +#define BOOT_MEDIA_CD 1 + +// E820 memory map, collected by stage2.S in real mode (the same firmware +// interface GRUB and Linux's boot stub use). Count at +0x200, then 24-byte +// entries: {uint64 base; uint64 length; uint32 type; uint32 acpi_ext}. +// The kernel can read the same addresses later; the bootloader uses it to +// report detected RAM like any grown-up loader does. +#define E820_COUNT_ADDR (VBE_INFO_ADDR + 0x200) +#define E820_MAP_ADDR (VBE_INFO_ADDR + 0x208) +#define E820_USABLE 1 + +// NOT include/types.h's uint64: that's `unsigned long`, which is 4 bytes +// in this file's -m32 build and would silently halve the struct. +typedef unsigned long long e820_u64; + +struct e820entry { + e820_u64 base; + e820_u64 length; + uint32 type; + uint32 acpi_ext; +} __attribute__((packed)); + +// Total usable RAM in MB according to the firmware's E820 map. +static uint32 +e820_usable_mb(void) +{ + uint32 count = *(uint32*)E820_COUNT_ADDR; + struct e820entry *e = (struct e820entry*)E820_MAP_ADDR; + e820_u64 total = 0; + if (count > 32) return 0; // garbage count: BIOS didn't fill the map + for (uint32 i = 0; i < count; i++) + if (e[i].type == E820_USABLE) + total += e[i].length; + return (uint32)(total >> 20); +} + +// Minimal unsigned-to-decimal for the memory line; no printf down here. +static char * +utoa10(uint32 v, char *buf) +{ + char tmp[12]; + int n = 0; + do { tmp[n++] = '0' + v % 10; v /= 10; } while (v); + int i = 0; + while (n) buf[i++] = tmp[--n]; + buf[i] = 0; + return buf; +} + +struct mbheader { + uint32 magic; + uint32 flags; + uint32 checksum; + uint32 header_addr; + uint32 load_addr; + uint32 load_end_addr; + uint32 bss_end_addr; + uint32 entry_addr; +}; + +void readseg(uchar*, uint, uint); +static void draw_centered(int y, const char *s, uint32 color); +static void draw_memory_line(int y, uint32 color); + +// Which medium the kernel has to be read back from. cdboot.S sets the flag +// this is loaded from; bootasm.S clears it, and 0 means "an ATA disk, the way +// it has always been". The ATAPI machinery itself is down at the bottom of +// the file next to readsect(), which is the only thing that uses it. +#define CD_SECTSIZE 2048 + +static int g_from_cd; +static int g_atapi_io = 0; // 0 until a drive is found +static int g_atapi_slave = 0; +static uint g_cd_base512 = 0; // where our boot image starts, in 512s +static int atapi_find(void); +static int atapi_boot_base(void); + +// --- Framebuffer state --------------------------------------------------- +// Standalone drawing (not the kernel's vga.c): paging isn't set up yet, so +// the LFB physical address read out of the VBE mode info block is used +// directly, no P2V translation needed. Only handles 32bpp (what QEMU's +// std VGA actually returns for the mode this bootloader requests) — +// anything else just skips all drawing rather than risk drawing garbage. + +static uint8 *g_fb; +static uint32 g_stride; +static int g_width, g_height; +static int g_have_fb; + +static void +fb_init(void) +{ + g_stride = *(ushort*)(VBE_INFO_ADDR + 16); + g_width = *(ushort*)(VBE_INFO_ADDR + 18); + g_height = *(ushort*)(VBE_INFO_ADDR + 20); + uchar bpp = *(uchar*)(VBE_INFO_ADDR + 25); + uint32 fbaddr = *(uint32*)(VBE_INFO_ADDR + 40); + g_fb = (uint8*)fbaddr; + g_have_fb = (bpp == 32 && fbaddr && g_width && g_height); +} + +static void +draw_pixel(int x, int y, uint32 color) +{ + *(uint32*)(g_fb + y * g_stride + x * 4) = color; +} + +// --- Boot logo ------------------------------------------------------------- +// +// include/logo.h is a 4-bit coverage mask generated from Assets/ by +// tools/mklogo.py (`make logo`). It costs 8 KiB, which is most of the reason +// STAGE2_SECTORS went from 24 to 48. +// +// Colour is SCH_FG, not SCH_ACCENT. The source art is a silver gradient and the +// mask preserves its relative values, so compositing coverage straight to +// brightness reproduces that gradient. The accent stays reserved for the single +// rule under the wordmark -- one spot colour, per include/theme.h. +static void +draw_logo(int x0, int y0) +{ + if (!g_have_fb) + return; + for (int dy = 0; dy < LOGO_H; dy++) { + int y = y0 + dy; + if (y < 0 || y >= g_height) + continue; + uint32 *row = (uint32*)(g_fb + y * g_stride); + for (int dx = 0; dx < LOGO_W; dx++) { + int x = x0 + dx; + if (x < 0 || x >= g_width) + continue; + unsigned a = LOGO_INK(dy * LOGO_W + dx); + // Skip empty pixels rather than painting them in the background colour. + // The mask is square but the mark is a circle, so most of it is empty; + // filling that would stamp a visible box onto the splash. + if (a == 0) + continue; + if (a >= 255) { + row[x] = SCH_FG; + continue; + } + // Blend towards SCH_BG per channel. Integer only -- there is no FPU set + // up at this point in boot, and no libgcc to fake one with. + uint32 r = (((SCH_FG >> 16) & 0xFF) * a + ((SCH_BG >> 16) & 0xFF) * (255 - a)) / 255; + uint32 g = (((SCH_FG >> 8) & 0xFF) * a + ((SCH_BG >> 8) & 0xFF) * (255 - a)) / 255; + uint32 b = (((SCH_FG ) & 0xFF) * a + ((SCH_BG ) & 0xFF) * (255 - a)) / 255; + row[x] = (r << 16) | (g << 8) | b; + } + } +} + +static void +fill_rect(int x0, int y0, int w, int h, uint32 color) +{ + // Compute each row's base pointer once instead of re-deriving it (via a + // multiply + add) for every single pixel through draw_pixel() — this is + // the full-screen splash fill, 480,000 pixels at 800x600, done at least + // twice per boot. + for (int y = y0; y < y0 + h; y++) { + uint32 *row = (uint32*)(g_fb + y * g_stride) + x0; + for (int x = 0; x < w; x++) + row[x] = color; + } +} + +static void +draw_char(int x, int y, uchar c, uint32 color, uint32 bg) +{ + if (c > 127) return; + for (int row = 0; row < 16; row++) { + uchar bits = font_data[c][row]; + for (int col = 0; col < 8; col++) + draw_pixel(x + col, y + row, (bits & (0x80 >> col)) ? color : bg); + } +} + +static void +draw_string(int x, int y, const char *s, uint32 color, uint32 bg) +{ + while (*s) { + draw_char(x, y, *s, color, bg); + x += 8; + s++; + } +} + +// Pads with trailing spaces (drawn in bg) so re-drawing a shorter string +// over a longer one doesn't leave stale glyphs behind. +static void +draw_string_padded(int x, int y, const char *s, uint32 color, uint32 bg, int cols) +{ + int n = 0; + while (s[n]) { draw_char(x + n * 8, y, s[n], color, bg); n++; } + while (n < cols) { draw_char(x + n * 8, y, ' ', color, bg); n++; } +} + +// --- Keyboard: raw PS/2 scancode polling, no interrupts, no BIOS calls -- +// (BIOS INT 16h only works in real mode; we're in protected mode by the +// time any of this runs.) Scancode set 1: F8 make code 0x42, arrows are +// extended (0xE0 prefix byte), Enter 0x1C, digits '1'-'3' are 0x02-0x04. + +static int +kbd_haskey(void) +{ + return inb(0x64) & 1; +} + +static int +kbd_readscancode(void) +{ + return inb(0x60); +} + +// Blocking read of one logical key: plain scancodes pass through, extended +// (0xE0-prefixed) scancodes come back OR'd with 0x100 so callers can tell +// "up arrow" (0x148) apart from a plain byte that happens to equal 0x48. +static int +kbd_getkey(void) +{ + int sc; + for (;;) { + while (!kbd_haskey()) + ; + sc = kbd_readscancode(); + // 0xE0 is the extended-key prefix, not a break code, even though it + // also has bit 7 set — must be checked before the break-code test + // below or every arrow/Home/End/etc. press gets silently swallowed. + if (sc == 0xE0) { + while (!kbd_haskey()) + ; + sc = kbd_readscancode(); + if (sc & 0x80) continue; // extended break code: ignore, try again + return 0x100 | sc; + } + if (sc & 0x80) continue; // plain break code: ignore, try again + return sc; + } +} + +// Polls for up to `iterations` busy-loop spins, watching for F8's make +// code. Returns 1 if seen, 0 on timeout. Ignores everything else so a +// stray keypress during the splash doesn't do anything surprising. +static int +wait_for_f8(uint32 iterations) +{ + for (volatile uint32 i = 0; i < iterations; i++) { + if (kbd_haskey()) { + int sc = kbd_readscancode(); + if (sc == 0x42) + return 1; + } + } + return 0; +} + +// --- ATA drive presence (primary channel: master/slave) ------------------ +// Standard "floating bus" trick: select the drive, write a distinguishable +// pattern to two data-path registers, and read it back. A missing drive +// leaves the bus floating and the readback won't match. +// +// Only the primary channel (0x1F0) is checked. QEMU's IDE emulation +// answers the same pattern test "successfully" on the secondary channel +// (0x170) even with nothing attached to it — its floating-bus behavior +// doesn't match real hardware closely enough to tell present from absent — +// so showing it would just be confidently wrong. This project only ever +// configures drives on the primary channel (-hda/-hdb) anyway. + +static int +ata_present(ushort iobase, int slave) +{ + outb(iobase + 6, slave ? 0xB0 : 0xA0); + inb(iobase + 7); inb(iobase + 7); inb(iobase + 7); inb(iobase + 7); + outb(iobase + 2, 0xAA); + outb(iobase + 3, 0x55); + outb(iobase + 2, 0x55); + outb(iobase + 3, 0xAA); + outb(iobase + 2, 0xAA); + outb(iobase + 3, 0x55); + return inb(iobase + 2) == 0xAA && inb(iobase + 3) == 0x55; +} + +// --- Real-time load progress bar ----------------------------------------- + +#define BAR_WIDTH 400 +#define BAR_HEIGHT 18 + +// --- Splash layout ------------------------------------------------------- +// +// Every vertical position on the splash derives from here. It used to be a +// handful of independent offsets from the screen centre -- wordmark at cy-18, +// rule at cy+6, bar at cy+30 -- which was fine while the tallest element was a +// line of text. Adding a 128px mark on top of that stack pushed the group's +// optical centre about 80px above the screen's, so the whole composition read +// as top-heavy with a large void underneath. +// +// Now the group is measured and centred as a unit. The progress bar counts +// towards that height even though it is only on screen during the kernel load: +// if it did not, everything would jump upwards the moment the bar appeared. +#define SPLASH_MARK_GAP 24 // mark to wordmark +#define SPLASH_TEXT_H 16 // one line of the 8x16 font +#define SPLASH_RULE_GAP 8 // wordmark to rule +#define SPLASH_RULE_H 2 +#define SPLASH_BAR_GAP 30 // rule to bar; the bar's label lives in here + +#define SPLASH_GROUP_H (LOGO_H + SPLASH_MARK_GAP + SPLASH_TEXT_H + \ + SPLASH_RULE_GAP + SPLASH_RULE_H + SPLASH_BAR_GAP + BAR_HEIGHT) + +#define SPLASH_MARK_Y ((g_height - SPLASH_GROUP_H) / 2) +#define SPLASH_TEXT_Y (SPLASH_MARK_Y + LOGO_H + SPLASH_MARK_GAP) +#define SPLASH_RULE_Y (SPLASH_TEXT_Y + SPLASH_TEXT_H + SPLASH_RULE_GAP) +#define SPLASH_BAR_Y (SPLASH_RULE_Y + SPLASH_RULE_H + SPLASH_BAR_GAP) + +static uint32 g_load_total, g_load_done; +static int g_progress_active; +static int g_bar_x, g_bar_y; +static int g_last_pct; + +static void +progress_label(const char *label) +{ + draw_string_padded(g_bar_x, g_bar_y - 22, label, SCH_ACCENT, SCH_BG, BAR_WIDTH / 8); +} + +// Border never changes once drawn — separated out so it's only ever drawn +// once per bar instead of being redrawn on every single tick. +static void +progress_border(void) +{ + for (int x = g_bar_x; x < g_bar_x + BAR_WIDTH; x++) { + draw_pixel(x, g_bar_y, SCH_FG); + draw_pixel(x, g_bar_y + BAR_HEIGHT, SCH_FG); + } + for (int y = g_bar_y; y <= g_bar_y + BAR_HEIGHT; y++) { + draw_pixel(g_bar_x, y, SCH_FG); + draw_pixel(g_bar_x + BAR_WIDTH, y, SCH_FG); + } +} + +static void +progress_fill(int pct) +{ + if (pct > 100) pct = 100; + int fillw = (BAR_WIDTH - 4) * pct / 100; + for (int y = g_bar_y + 2; y < g_bar_y + BAR_HEIGHT - 1; y++) + for (int x = g_bar_x + 2; x < g_bar_x + BAR_WIDTH - 2; x++) + draw_pixel(x, y, (x - g_bar_x - 2 < fillw) ? SCH_ACCENT : SCH_BG); +} + +static void +progress_start(const char *label, uint32 total) +{ + if (!g_have_fb) return; + g_bar_x = (g_width - BAR_WIDTH) / 2; + g_bar_y = SPLASH_BAR_Y; + g_load_total = total; + g_load_done = 0; + g_last_pct = -1; + g_progress_active = 1; + progress_label(label); + progress_border(); + progress_fill(0); + g_last_pct = 0; +} + +static void +progress_tick(uint32 n) +{ + if (!g_have_fb || !g_progress_active) return; + g_load_done += n; + // Deliberately all 32-bit. The uint64 cast this used to carry was there to + // stop `done * 100` overflowing, but a 64-bit divide in 32-bit code calls + // libgcc's __udivdi3, which a freestanding bootloader does not link -- it + // only ever built because uint64 was accidentally 32 bits wide here. + // + // Scaling both sides to KiB first keeps the multiply inside 32 bits for any + // image up to 4 GiB, which is comfortably more than a kernel will ever be. + uint32 done_k = g_load_done >> 10; + uint32 total_k = g_load_total >> 10; + uint32 pct = total_k ? (done_k * 100) / total_k : 0; + if (pct > 100) pct = 100; + // A full-bar redraw is a few thousand pixel writes; without this, a + // ~330KB kernel image redraws it ~650 times (once per 512-byte sector) + // instead of at most 100 (once per percentage point) — the single + // biggest chunk of the bootloader's own wall-clock time. + if ((int)pct == g_last_pct) return; + g_last_pct = (int)pct; + progress_fill((int)pct); +} + +// --- Boot menu ------------------------------------------------------- + +static void +reboot_to_firmware(void) +{ + if (g_have_fb) { + fill_rect(0, 0, g_width, g_height, SCH_BG); + draw_string((g_width - 26 * 8) / 2, g_height / 2 - 8, + "Rebooting to firmware...", SCH_ACCENT, SCH_BG); + } + outb(0x64, 0xFE); // pulse the keyboard controller's reset line + for (;;) + ; +} + +static void +show_drive_line(int row, const char *label, int present) +{ + draw_string(g_width / 2 - 160, 340 + row * 20, label, SCH_FG, SCH_BG); + draw_string(g_width / 2 + 20, 340 + row * 20, + present ? "present" : "not present", + present ? SCH_ACCENT : SCH_DIM, SCH_BG); +} + +// Returns 1 for "boot verbose", 0 for "boot normal". Only returns at all +// once the user picks a boot option; "reboot" never returns. +static int +boot_menu(void) +{ + const char *items[] = { + "Boot Schunix", + "Boot Schunix (verbose)", + "Reboot to firmware setup", + }; + int nitems = 3; + int selected = 0; + + int hda = ata_present(0x1F0, 0); + int hdb = ata_present(0x1F0, 1); + + for (;;) { + fill_rect(0, 0, g_width, g_height, SCH_BG); + draw_centered(60, "Schunix Boot Manager", SCH_ACCENT); + draw_memory_line(84, SCH_DIM); + + for (int i = 0; i < nitems; i++) { + uint32 fg = (i == selected) ? SCH_ACCENT : SCH_FG; + draw_string(g_width / 2 - 140, 140 + i * 24, (i == selected) ? "> " : " ", fg, SCH_BG); + draw_string(g_width / 2 - 124, 140 + i * 24, items[i], fg, SCH_BG); + } + + draw_string(g_width / 2 - 160, 300, "Detected drives:", SCH_FG, SCH_BG); + show_drive_line(0, "Primary Master (hda)", hda); + show_drive_line(1, "Primary Slave (hdb)", hdb); + + draw_string(g_width / 2 - 168, g_height - 40, + "Up/Down to choose, Enter to select", SCH_DIM, SCH_BG); + + int key = kbd_getkey(); + if (key == 0x148) selected = (selected + nitems - 1) % nitems; // up + else if (key == 0x150) selected = (selected + 1) % nitems; // down + else if (key == 0x02) selected = 0; // '1' + else if (key == 0x03) selected = 1; // '2' + else if (key == 0x04) { reboot_to_firmware(); } // '3' + else if (key == 0x1C) { // Enter + if (selected == 2) + reboot_to_firmware(); + return selected == 1; + } + } +} + +// Centered one-liner helper; strlen computed here so callers stop +// hand-counting characters (three of them had it wrong at some point). +static void +draw_centered(int y, const char *s, uint32 color) +{ + int n = 0; + while (s[n]) n++; + draw_string((g_width - n * 8) / 2, y, s, color, SCH_BG); +} + +// "Memory: NNNN MB" — assembled by hand, no printf in the bootloader. +static void +draw_memory_line(int y, uint32 color) +{ + char line[32]; + char num[12]; + int i = 0; + const char *pfx = "Memory: "; + while (*pfx) line[i++] = *pfx++; + utoa10(e820_usable_mb(), num); + for (int j = 0; num[j]; j++) line[i++] = num[j]; + const char *sfx = " MB"; + while (*sfx) line[i++] = *sfx++; + line[i] = 0; + draw_centered(y, line, color); +} + +static void +splash(void) +{ + if (!g_have_fb) return; + + fill_rect(0, 0, g_width, g_height, SCH_BG); + + // The product, not the loader. + // + // This used to read "Schunix Boot Manager / version 1.0 / Memory: 1023 MB / + // 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 + // of the component doing the work, its version, and a memory figure nobody + // asked for. No shipping OS names its bootloader on the splash. + // + // What is left is the name, a rule in the accent colour, and the one hint + // that is actually actionable -- moved to the bottom of the screen, where a + // hint belongs, rather than sitting under the title as though it were part + // of the identity. + // The mark, drawn here in the loader rather than by the kernel for a timing + // reason: the kernel does not reach vga_init() until the last few hundred + // milliseconds of a ~2.8s boot, so a kernel-drawn logo appeared for about one + // frame before console_takeover() wiped it. Here it is up for the whole boot. + draw_logo((g_width - LOGO_W) / 2, SPLASH_MARK_Y); + + draw_centered(SPLASH_TEXT_Y, "S C H U N I X", SCH_FG); + + // A 120x2 rule, centred, in the accent -- slightly wider than the 104px + // wordmark so it reads as an underline rather than a strikethrough. Two + // pixels rather than one: a single-pixel line looks like a rendering + // artefact at this size. + fill_rect((g_width - 120) / 2, SPLASH_RULE_Y, 120, SPLASH_RULE_H, SCH_ACCENT); + + draw_centered(g_height - 40, "Press F8 for boot options", SCH_DIM); +} + +void +stage2main(void) +{ + struct mbheader *hdr; + uint32 *x = (uint32*) 0x10000; + uint n; + int verbose = 0; + + fb_init(); + + // Sort out where the kernel is coming from before anything is drawn, so a + // disc we cannot read says so on the splash instead of failing silently + // several seconds later in the middle of the progress bar. + if (*(uchar*)BOOT_MEDIA_FLAG_ADDR == BOOT_MEDIA_CD) { + if (atapi_find()) + g_cd_base512 = atapi_boot_base() * (CD_SECTSIZE / SECTSIZE); + g_from_cd = (g_atapi_io != 0 && g_cd_base512 != 0); + } + + splash(); + + // ~0.6s at QEMU TCG speeds (measured), watching for F8. Shortened from + // ~1s (5000000) — still enough time to react to, but it's flat overhead + // on every single boot whether or not anyone wants the menu. + if (wait_for_f8(3000000)) + verbose = boot_menu(); + + *(uchar*)BOOT_VERBOSE_FLAG_ADDR = verbose; + + if (g_have_fb) { + 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); + } + + // Booted from a disc we then could not read. Falling through would send + // readseg() at the primary ATA channel, which on a CD-only machine is empty + // -- so it would grind through a bounded wait per sector and then jump into + // whatever the uninitialised buffer happened to hold. Stopping with a + // legible reason is the only useful thing left to do. This is drawn after + // the clear above on purpose: an earlier version put it on the splash, + // where it was wiped a moment later and nobody ever saw it. + if (*(uchar*)BOOT_MEDIA_FLAG_ADDR == BOOT_MEDIA_CD && !g_from_cd) { + draw_centered(g_height / 2, "No readable boot disc found.", SCH_ACCENT); + draw_centered(g_height / 2 + 20, "The drive did not answer ATAPI.", SCH_DIM); + for (;;) + asm volatile("hlt"); + } + + if (g_have_fb) + progress_start("Detecting kernel...", 16384); + + // Read 32 sectors (16KB) looking for the multiboot header. + readseg((uchar*)x, 16384, 0); + + for (n = 0; n < 16384/4; n++) { + if (x[n] == 0x1BADB002) { + if ((x[n] + x[n+1] + x[n+2]) == 0) { + hdr = (struct mbheader *) (x + n); + + if (g_have_fb) + progress_start("Loading kernel...", hdr->load_end_addr - hdr->load_addr); + + // Load the actual kernel segments + readseg((uchar*) hdr->load_addr, + hdr->load_end_addr - hdr->load_addr, + (n * 4) - (hdr->header_addr - hdr->load_addr)); + + // Zero out BSS + if (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) + progress_label("Starting Schunix..."); + + // Jump to kernel entry. NOT a normal C call: kernel/arch/x86_64/ + // entry.S's mboot_entry reads its "argument" (the framebuffer + // physical address) out of EAX directly, not off the stack — a + // multiboot-style raw-register handoff, not cdecl. A plain + // `((void(*)(uint32))entry)(fbaddr)` pushes fbaddr on the stack + // per cdecl and leaves EAX as whatever happened to be lying around; + // it only ever "worked" because simpler bootmain.c code coincidentally + // left the right value in EAX as a side effect of its own codegen. + // Adding the boot-menu/progress-bar code changed that codegen and + // broke it silently (kernel received garbage instead of the real + // LFB address). Pin it down explicitly instead of hoping. + { + uint32 fbaddr = *(uint32*)(VBE_INFO_ADDR + 40); + uint32 entry = hdr->entry_addr; + asm volatile("jmp *%0" : : "r"(entry), "a"(fbaddr)); + } + } + } + } +} + +// Bounded, because there might not be a disk there at all. +// +// This used to be `while((inb(0x1F7) & 0xC0) != 0x40);`. On a machine with no +// ATA drive on the primary channel the status register reads 0xFF forever and +// the loader hung on a splash screen with no message and no way to tell what +// had gone wrong -- which is exactly what happened the first time a CD boot +// fell back to this path. A bounded wait turns that into a failed read, and +// stage2main() says so on screen. +void waitdisk(void) { + for (int i = 0; i < 4000000; i++) + if ((inb(0x1F7) & 0xC0) == 0x40) + return; +} + +void readsect_ata(void *dst, uint offset) { + waitdisk(); + outb(0x1F2, 1); + outb(0x1F3, offset); + outb(0x1F4, offset >> 8); + outb(0x1F5, offset >> 16); + outb(0x1F6, (offset >> 24) | 0xE0); + outb(0x1F7, 0x20); + waitdisk(); + insl(0x1F0, dst, SECTSIZE/4); +} + +// --------------------------------------------------------------------------- +// ATAPI -- reading the kernel back off a CD. +// +// An optical drive does not answer the ATA commands above. It speaks the +// packet interface: you hand it a SCSI command descriptor block through the +// data port and it hands back 2048-byte logical blocks. The register file and +// the PIO loop are otherwise the same, which is why this lives here rather +// than forcing the loader back into real mode to use INT 13h -- by the time +// the kernel is read, stage2.S has long since switched to protected mode and +// the BIOS is gone. +// --------------------------------------------------------------------------- + +static void bcopy(void *dst, const void *src, uint n) { + uchar *d = dst; + const uchar *s = src; + while (n--) *d++ = *s++; +} + +// A channel has to be reset before its signature means anything. +// +// ATAPI devices report themselves by leaving 0x14 in LBA-mid and 0xEB in +// LBA-high -- but only until something issues a command, after which those +// registers hold that command's byte count instead. The BIOS has just +// finished reading this very disc in order to load us, so on a CD boot the +// signature is *always* stale by the time we look. Resetting the channel is +// what puts it back. +static void atapi_reset(int io) { + int ctrl = io + 0x206; // 0x1F0 -> 0x3F6, 0x170 -> 0x376 + + outb(ctrl, 0x04); // SRST + for (int i = 0; i < 10000; i++) // hold it well past the required 5us + inb(ctrl); + outb(ctrl, 0x00); + + for (int i = 0; i < 1000000; i++) // bounded: an empty channel reads 0xFF + if (!(inb(io + 7) & 0x80)) // and would otherwise spin forever + break; +} + +static int atapi_find(void) { + static const int bases[2] = { 0x1F0, 0x170 }; + + for (int b = 0; b < 2; b++) { + atapi_reset(bases[b]); + for (int s = 0; s < 2; s++) { + outb(bases[b] + 6, s ? 0xB0 : 0xA0); + // Four throwaway status reads: the standard 400ns settle after a drive + // select, before the register file is meaningful. + inb(bases[b] + 7); inb(bases[b] + 7); + inb(bases[b] + 7); inb(bases[b] + 7); + if (inb(bases[b] + 4) == 0x14 && inb(bases[b] + 5) == 0xEB) { + g_atapi_io = bases[b]; + g_atapi_slave = s; + return 1; + } + } + } + return 0; +} + +// One 2048-byte logical block. Returns 0 on success. +static int atapi_read_block(uint lba, void *dst) { + int io = g_atapi_io; + uchar cdb[12]; + int i; + + outb(io + 6, g_atapi_slave ? 0xB0 : 0xA0); + inb(io + 7); inb(io + 7); inb(io + 7); inb(io + 7); + + outb(io + 1, 0); // features: PIO, no DMA + outb(io + 4, CD_SECTSIZE & 0xFF); // how much we are willing to take + outb(io + 5, CD_SECTSIZE >> 8); + outb(io + 7, 0xA0); // PACKET + + // Wait for the drive to ask for the command packet: BSY clear, DRQ set. + for (i = 0; i < 0x1000000; i++) { + uchar st = inb(io + 7); + if (st & 0x01) return -1; // ERR + if (!(st & 0x80) && (st & 0x08)) break; + } + if (i == 0x1000000) return -1; + + // READ(12). Big-endian LBA and transfer length, because SCSI is. + for (i = 0; i < 12; i++) cdb[i] = 0; + cdb[0] = 0xA8; + cdb[2] = (uchar)(lba >> 24); + cdb[3] = (uchar)(lba >> 16); + cdb[4] = (uchar)(lba >> 8); + cdb[5] = (uchar)lba; + cdb[9] = 1; // one block + outsl(io, cdb, 3); // 12 bytes = 3 dwords + + // Wait for the data itself. + for (i = 0; i < 0x1000000; i++) { + uchar st = inb(io + 7); + if (st & 0x01) return -1; + if (!(st & 0x80) && (st & 0x08)) break; + } + if (i == 0x1000000) return -1; + + insl(io, dst, CD_SECTSIZE / 4); + return 0; +} + +// Where our boot image sits on the disc. +// +// Sector numbers on a CD are absolute, but readseg() counts from the start of +// the boot image -- which on a hard disk is the start of the disk and on a CD +// is wherever the ISO's filesystem happened to leave room. El Torito writes +// that address down, so we read it rather than guess: +// +// LBA 17 Boot Record Volume Descriptor, holding a pointer at offset 0x47 +// catalog validation entry (32 bytes), then the default entry, whose +// "Load RBA" at offset 8 is the boot image's LBA +// +// Returns 0 if the disc does not look like something we booted from. +static int atapi_boot_base(void) { + static uchar buf[CD_SECTSIZE]; + uint catalog, image; + + if (atapi_read_block(17, buf) != 0) + return 0; + if (buf[0] != 0 || buf[1] != 'C' || buf[2] != 'D' || buf[3] != '0' || + buf[4] != '0' || buf[5] != '1') + return 0; + + catalog = (uint)buf[0x47] | ((uint)buf[0x48] << 8) | + ((uint)buf[0x49] << 16) | ((uint)buf[0x4A] << 24); + if (catalog == 0) + return 0; + + if (atapi_read_block(catalog, buf) != 0) + return 0; + if (buf[32] != 0x88) // default entry not marked bootable + return 0; + + image = (uint)buf[40] | ((uint)buf[41] << 8) | + ((uint)buf[42] << 16) | ((uint)buf[43] << 24); + return image; +} + +// A CD block holds four 512-byte sectors, and readseg() asks for them one at +// a time and in order -- so caching the last block turns four reads into one. +// Without it every byte of the kernel would be fetched four times. +static uchar g_cd_cache[CD_SECTSIZE]; +static uint g_cd_cached = 0xFFFFFFFF; + +static void readsect_atapi(void *dst, uint offset) { + uint abs = offset + g_cd_base512; + uint blk = abs / (CD_SECTSIZE / SECTSIZE); + uint sub = abs % (CD_SECTSIZE / SECTSIZE); + + if (blk != g_cd_cached) { + if (atapi_read_block(blk, g_cd_cache) != 0) { + // Nothing useful to do here: there is no console yet and no way back. + // Leaving the buffer alone means the multiboot search simply fails to + // match, which stops with the splash up rather than jumping to garbage. + return; + } + g_cd_cached = blk; + } + bcopy(dst, g_cd_cache + sub * SECTSIZE, SECTSIZE); +} + +void readsect(void *dst, uint offset) { + if (g_from_cd) + readsect_atapi(dst, offset); + else + readsect_ata(dst, offset); + progress_tick(SECTSIZE); +} + +void readseg(uchar* pa, uint count, uint offset) { + uchar* epa = pa + count; + pa -= offset % SECTSIZE; + // Kernel starts right after stage2 (1 boot sector + STAGE2_SECTORS + // stage2 sectors), not immediately after just the boot sector. + offset = (offset / SECTSIZE) + (1 + STAGE2_SECTORS); + for(; pa < epa; pa += SECTSIZE, offset++) + readsect(pa, offset); +} diff --git a/cmd/fbinfo/main.c b/cmd/fbinfo/main.c new file mode 100644 index 0000000..b106441 --- /dev/null +++ b/cmd/fbinfo/main.c @@ -0,0 +1,219 @@ +// fbinfo -- ask /dev/fb0 what it is, and optionally draw on it. +// +// This exists because the framebuffer is the one device whose correctness you +// cannot check by reading kernel source: the numbers have to come back from +// the hardware the bootloader actually programmed. Three places in the kernel +// used to assume the framebuffer lived at 0xfd000000 and was 800x600x32; they +// agreed with QEMU's stdvga by luck, and nothing would have told us when the +// luck ran out. Now `fbinfo` would. +// +// fbinfo print the geometry +// fbinfo fill draw a gradient over the whole screen through mmap +// fbinfo bars draw colour bars through write(), no mmap involved +// +// The two drawing modes take different paths on purpose. If `fill` works and +// `bars` does not, the mapping is right and the device's read/write is wrong; +// if it is the other way round, the reverse. Having both makes a failure say +// which half broke. + +#include "types.h" +#include "user.h" +#include "fcntl.h" +#include "fb.h" + +#define PROT_READ 0x1 +#define PROT_WRITE 0x2 +#define MAP_SHARED 0x01 + +static void +puts(const char *s) +{ + int n = 0; + while (s[n]) n++; + write(1, (void*)s, n); +} + +// Unsigned decimal. No printf in lib/, and pulling one in for six numbers +// would be a worse trade than fourteen lines. +static void +putu(unsigned long v) +{ + char buf[24]; + int i = 0; + + if (v == 0) { + write(1, "0", 1); + return; + } + while (v > 0 && i < (int)sizeof(buf)) { + buf[i++] = (char)('0' + (v % 10)); + v /= 10; + } + while (i > 0) { + i--; + write(1, &buf[i], 1); + } +} + +static void +puthex(unsigned long v) +{ + static const char d[] = "0123456789abcdef"; + char buf[16]; + int i = 0; + + write(1, "0x", 2); + if (v == 0) { + write(1, "0", 1); + return; + } + while (v > 0 && i < (int)sizeof(buf)) { + buf[i++] = d[v & 0xf]; + v >>= 4; + } + while (i > 0) { + i--; + write(1, &buf[i], 1); + } +} + +// Name, then spaces out to a fixed column. Padding inside each string +// literal is what produced "bits_per_pixel32": the longest name happened to +// be exactly as wide as the column, so it got no separator at all and the +// value ran straight into it. +static void +label(const char *name) +{ + int n = 0; + while (name[n]) n++; + write(1, (void*)name, n); + while (n < 16) { write(1, " ", 1); n++; } +} + +static void +field(const char *name, unsigned long v) +{ + label(name); + putu(v); + puts("\n"); +} + +static void +chanline(const char *name, struct fb_bitfield *b) +{ + label(name); + puts("offset "); + putu(b->offset); + puts(", length "); + putu(b->length); + if (b->length == 0) + puts(" (absent)"); + puts("\n"); +} + +int +main(int argc, char *argv[]) +{ + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + int fd; + + fd = open("/dev/fb0", O_RDWR); + if (fd < 0) { + puts("fbinfo: cannot open /dev/fb0\n"); + return 1; + } + + if (ioctl(fd, FBIOGET_VSCREENINFO, &var) < 0) { + puts("fbinfo: FBIOGET_VSCREENINFO failed\n"); + return 1; + } + if (ioctl(fd, FBIOGET_FSCREENINFO, &fix) < 0) { + puts("fbinfo: FBIOGET_FSCREENINFO failed\n"); + return 1; + } + + if (argc < 2) { + label("id"); + puts(fix.id); + puts("\n"); + field("xres", var.xres); + field("yres", var.yres); + field("bits_per_pixel", var.bits_per_pixel); + label("smem_start"); + puthex(fix.smem_start); + puts("\n"); + field("smem_len", fix.smem_len); + field("line_length", fix.line_length); + + // The stride is the number worth staring at. A card is free to pad + // each row, and a program that computes row starts as + // y * xres * bytes_per_pixel instead of y * line_length draws a + // picture that shears progressively down the screen. + if (fix.line_length != var.xres * (var.bits_per_pixel / 8)) { + label("note"); + puts("stride is padded; rows are not xres*bpp/8 apart\n"); + } + + chanline("red", &var.red); + chanline("green", &var.green); + chanline("blue", &var.blue); + chanline("transp", &var.transp); + return 0; + } + + if (argv[1][0] == 'f') { // fill + unsigned char *fb = mmap(0, fix.smem_len, + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (fb == 0 || (long)fb < 0) { + puts("fbinfo: mmap failed\n"); + return 1; + } + unsigned bpp = var.bits_per_pixel / 8; + for (unsigned y = 0; y < var.yres; y++) { + unsigned char *row = fb + (unsigned long)y * fix.line_length; + for (unsigned x = 0; x < var.xres; x++) { + unsigned r = (x * 255) / (var.xres ? var.xres : 1); + unsigned g = (y * 255) / (var.yres ? var.yres : 1); + unsigned long px = ((unsigned long)r << var.red.offset) | + ((unsigned long)g << var.green.offset) | + ((unsigned long)0x80 << var.blue.offset); + unsigned char *p = row + (unsigned long)x * bpp; + for (unsigned b = 0; b < bpp; b++) + p[b] = (unsigned char)(px >> (b * 8)); + } + } + puts("fbinfo: gradient drawn through mmap\n"); + return 0; + } + + if (argv[1][0] == 'b') { // bars + // One scanline at a time through write(). No mapping: this is the + // path that used to be devsw's nullwrite, i.e. a silent no-op. + static unsigned char row[8192]; + unsigned bpp = var.bits_per_pixel / 8; + unsigned len = fix.line_length; + if (len > sizeof(row)) + len = sizeof(row); + + for (unsigned y = 0; y < var.yres; y++) { + unsigned band = (y * 8) / (var.yres ? var.yres : 1); + unsigned long px = + ((unsigned long)((band & 1) ? 255 : 0) << var.red.offset) | + ((unsigned long)((band & 2) ? 255 : 0) << var.green.offset) | + ((unsigned long)((band & 4) ? 255 : 0) << var.blue.offset); + for (unsigned x = 0; x * bpp + bpp <= len; x++) + for (unsigned b = 0; b < bpp; b++) + row[x * bpp + b] = (unsigned char)(px >> (b * 8)); + if (write(fd, row, len) != (int)len) { + puts("fbinfo: short write to /dev/fb0\n"); + return 1; + } + } + puts("fbinfo: colour bars drawn through write()\n"); + return 0; + } + + puts("usage: fbinfo [fill|bars]\n"); + return 1; +} diff --git a/cmd/init/main.c b/cmd/init/main.c new file mode 100644 index 0000000..6d044bb --- /dev/null +++ b/cmd/init/main.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: Apache-2.0 +// Schunix — minimal init (PID 1) + +#include "types.h" +#include "user.h" +#include "fcntl.h" + +static void +xputs(int fd, const char *s) +{ + int n = 0; + while (s[n]) n++; + write(fd, (void *)s, n); +} + +int +main(void) +{ + if (getpid() != 1) + exit(); + + // Open console as fd 0; dup to fd 1 (stdout) and fd 2 (stderr). + if (open("console", O_RDWR) < 0) { + mknod("console", 1, 1); + open("console", O_RDWR); + } + dup(0); + dup(0); + + // --- /dev ------------------------------------------------------------ + // Minor numbers under major 1 follow Linux's mem-major layout where it + // costs nothing (null=2, zero=5, full=7, random=8, urandom=9). + // /dev/hole (was minor 4) is gone: it backed an abandoned experiment and + // nothing has referenced it since. + mkdir("/dev"); + mknod("/dev/console", 1, 1); + mknod("/dev/null", 1, 2); + mknod("/dev/keyboard", 1, 3); + mknod("/dev/zero", 1, 5); + mknod("/dev/full", 1, 7); + mknod("/dev/random", 1, 8); + mknod("/dev/urandom", 1, 9); + mknod("/dev/fb0", 2, 0); + mknod("/dev/mouse", 3, 1); + mknod("/dev/tty", 1, 1); // alias for console — must pass TCGETS ioctl + mknod("/dev/ttyS0", 4, 64); + mknod("/dev/stdin", 1, 1); + mknod("/dev/stdout", 1, 1); + mknod("/dev/stderr", 1, 1); + + // Raw input events, Linux evdev layout (kernel/dev/input.c). /dev/keyboard + // and /dev/mouse above are the old character-and-position interfaces; these + // are the ones with key releases and button transitions, which is what a + // game or a compositor needs and what neither of the others can express. + mkdir("/dev/input"); + mknod("/dev/input/event0", 7, 0); // keyboard + mknod("/dev/input/event1", 7, 1); // mouse + + // --- /proc ----------------------------------------------------------- + // Synthesised status files, major 6 (kernel/dev/procfs.c). These are the + // global ones; per-process /proc// directories need synthetic + // directory support in the filesystem, which does not exist yet. + mkdir("/proc"); + // /proc is a real filesystem now (kernel/fs/procfs.c), not a handful of + // mknod'd nodes: it has to be, because one directory per process cannot be + // created ahead of time. This is what makes `ps` and `top` work. + // + // The mknod'd global files below still happen, and are simply covered by + // the mount. They stay for now so that a failure here degrades to the old + // behaviour instead of losing /proc entirely. + mount("proc", "/proc", "proc", 0, 0); + mknod("/proc/meminfo", 6, 1); + mknod("/proc/uptime", 6, 2); + mknod("/proc/cpuinfo", 6, 3); + mknod("/proc/version", 6, 4); + mknod("/proc/stat", 6, 5); + mknod("/proc/loadavg", 6, 6); + mknod("/proc/mounts", 6, 7); + mknod("/proc/filesystems", 6, 8); + // SchFS volume summary: label, generation, free space, and the root + // directory. Reachable whether or not the volume is mounted into the + // namespace, which is what makes it useful when a mount has gone wrong. + mknod("/proc/schfs", 6, 9); + // Write 'c' here to crash on purpose. The crash screen is otherwise the + // one part of the system that can only be seen by having a bug. + mknod("/proc/sysrq", 6, 10); + mknod("/proc/pci", 6, 11); + mknod("/proc/interrupts", 6, 12); + + mkdir("/sys"); + + xputs(1, "\nSchunix\n"); + xputs(1, "init: ready (pid 1)\n"); + + for (;;) { + int pid = fork(); + if (pid < 0) { + xputs(2, "init: fork failed\n"); + sleep(100); + continue; + } + + if (pid == 0) { + // exec.c auto-enables Linux ABI for musl binaries (entry >= 0x100000). + // Do NOT call enable_linux_abi() here — it corrupts Schunix syscall + // numbers for the exec/exit calls that follow in this child. + // Standardized naming: the shell is always /bin/sh, regardless of + // which implementation backs it (dash, mksh, etc.) — no ksh/mksh/ + // other aliases are looked up here. + static char *argv[] = { "sh", 0 }; + exec("/bin/sh", argv); + xputs(2, "init: no shell found; place sh in /bin\n"); + exit(); + } + + // Reap zombies; the loop restarts the shell when it exits. + int wpid; + while ((wpid = wait()) >= 0 && wpid != pid) + ; + // Brief pause before restarting so we don't spin on a missing shell. + sleep(100); + } + return 0; +} diff --git a/cmd/inputtest/main.c b/cmd/inputtest/main.c new file mode 100644 index 0000000..84a7173 --- /dev/null +++ b/cmd/inputtest/main.c @@ -0,0 +1,124 @@ +// inputtest -- read raw events from /dev/input/eventN. +// +// The point of the raw devices is everything the console cannot say: which +// key was released, whether one is still held, and where the mouse went. None +// of that shows up in a character stream, so none of it can be tested by +// typing into a shell. +// +// inputtest read the keyboard until Esc is released +// inputtest mouse read the mouse until interrupted +// inputtest -n N stop after N events (used by the boot check) +// +// Prints one line per event: type, code and value, decoded where there is a +// name for it. + +#include "types.h" +#include "user.h" +#include "fcntl.h" +#include "input.h" + +static void +puts_(const char *s) +{ + int n = 0; + while (s[n]) n++; + write(1, (void*)s, n); +} + +static void +putn_(int v) +{ + char buf[12]; + int i = 0, neg = 0; + if (v < 0) { neg = 1; v = -v; } + if (v == 0) buf[i++] = '0'; + while (v) { buf[i++] = '0' + (v % 10); v /= 10; } + if (neg) buf[i++] = '-'; + while (i--) write(1, &buf[i], 1); +} + +static const char * +typename_(int t) +{ + switch (t) { + case EV_SYN: return "SYN"; + case EV_KEY: return "KEY"; + case EV_REL: return "REL"; + default: return "?"; + } +} + +static int +streq(const char *a, const char *b) +{ + while (*a && *a == *b) { a++; b++; } + return *a == *b; +} + +int +main(int argc, char **argv) +{ + const char *path = "/dev/input/event0"; + int limit = 0, count = 0, i; + int fd; + struct input_event ev; + + for (i = 1; i < argc; i++) { + if (streq(argv[i], "mouse")) + path = "/dev/input/event1"; + else if (streq(argv[i], "-n") && i + 1 < argc) { + const char *p = argv[++i]; + limit = 0; + while (*p >= '0' && *p <= '9') limit = limit * 10 + (*p++ - '0'); + } + } + + fd = open((char*)path, O_RDONLY); + if (fd < 0) { + puts_("inputtest: cannot open "); + puts_(path); + puts_("\n"); + exit(); + } + puts_("inputtest: reading "); + puts_(path); + puts_("\n"); + + for (;;) { + int n = read(fd, &ev, sizeof(ev)); + + // A short read would mean the device handed back part of a struct, + // which would desynchronise every event after it. Saying so is more + // use than silently carrying on with garbage. + if (n == 0) { puts_("inputtest: end of stream\n"); break; } + if (n < 0) { puts_("inputtest: read error\n"); break; } + if (n != sizeof(ev)) { + puts_("inputtest: SHORT READ -- events are not whole\n"); + break; + } + + puts_(" "); + puts_(typename_(ev.type)); + puts_(" code "); + putn_(ev.code); + puts_(" value "); + putn_(ev.value); + if (ev.type == EV_KEY) + puts_(ev.value ? " (press)" : " (release)"); + puts_("\n"); + + // Esc released ends the keyboard run, so a person can stop it without + // a signal. The boot check uses -n instead. + if (ev.type == EV_KEY && ev.code == KEY_ESC && ev.value == 0) + break; + + if (limit && ++count >= limit) { + puts_("inputtest: event limit reached\n"); + break; + } + } + + close(fd); + puts_("inputtest: done\n"); + exit(); +} diff --git a/cmd/shmtest/main.c b/cmd/shmtest/main.c new file mode 100644 index 0000000..ab0ad99 --- /dev/null +++ b/cmd/shmtest/main.c @@ -0,0 +1,112 @@ +// shmtest -- prove that shared memory is actually shared, and that a +// file-backed mmap returns the file. +// +// Both of these are things you cannot check by reading a return value. shmget +// and shmat returned -ENOSYS until now, and mmap of a file "succeeded" while +// handing back zeroed anonymous pages -- a lie that looks exactly like +// success. The only convincing test is for one process to write and a +// different one to read. +// +// shmtest run every check +// +// Prints one line per check, and a final verdict a script can grep for. + +#include "types.h" +#include "user.h" +#include "fcntl.h" + +#define PROT_READ 0x1 +#define PROT_WRITE 0x2 +#define MAP_PRIVATE 0x02 +#define MAP_SHARED 0x01 +#define IPC_PRIVATE 0 +#define IPC_CREAT 01000 + +static int failures; + +static void +puts_(const char *s) +{ + int n = 0; + while (s[n]) n++; + write(1, (void*)s, n); +} + +static void +check(int ok, const char *what) +{ + puts_(ok ? " [ok] " : " FAIL: "); + puts_(what); + puts_("\n"); + if (!ok) failures++; +} + +int +main(void) +{ + // --- shared memory ---------------------------------------------------- + int id = shmget(IPC_PRIVATE, 8192, IPC_CREAT | 0600); + check(id >= 0, "shmget created a segment"); + if (id < 0) { puts_("shmtest: FAILED\n"); return 1; } + + char *p = shmat(id, 0, 0); + check((long)p > 0, "shmat mapped it"); + if ((long)p <= 0) { puts_("shmtest: FAILED\n"); return 1; } + + // A fresh segment must be zeroed, or it leaks whatever the previous + // tenant left in those pages to whoever gets them next. + int zeroed = 1; + for (int i = 0; i < 8192; i++) + if (p[i] != 0) { zeroed = 0; break; } + check(zeroed, "a new segment reads as zeros"); + + p[0] = 'P'; + p[1] = 0; + + int pid = fork(); + if (pid == 0) { + // The child inherited the attachment through fork. If the pages had + // been copied instead of shared, the parent would never see this. + p[0] = 'C'; + p[100] = 'X'; + exit(); + } + wait(); + + check(p[0] == 'C', "a write by the child is visible in the parent"); + check(p[100] == 'X', "and so is one further into the segment"); + + // --- file-backed mmap -------------------------------------------------- + int fd = open("/tmp/shmtest.dat", O_CREATE | O_RDWR); + check(fd >= 0, "created a file to map"); + if (fd >= 0) { + write(fd, "SCHUNIX-MMAP-OK", 15); + close(fd); + } + + fd = open("/tmp/shmtest.dat", O_RDONLY); + if (fd >= 0) { + char *m = mmap(0, 4096, PROT_READ, MAP_PRIVATE, fd, 0); + int ok = ((long)m > 0) && + m[0]=='S' && m[1]=='C' && m[2]=='H' && m[3]=='U' && + m[8]=='M' && m[13]=='O' && m[14]=='K'; + check(ok, "mmap of a file returns the file, not zeros"); + close(fd); + } else { + check(0, "mmap of a file returns the file, not zeros"); + } + + // MAP_SHARED + PROT_WRITE on a file cannot be honoured without a page + // cache, and is refused rather than quietly downgraded to a private copy. + fd = open("/tmp/shmtest.dat", O_RDWR); + if (fd >= 0) { + void *m = mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + check((long)m < 0, "writable MAP_SHARED on a file is refused, not faked"); + close(fd); + } + + check(shmdt(p) == 0, "shmdt released the attachment"); + + puts_(failures ? "shmtest: FAILED\n" : "shmtest: all checks passed\n"); + return failures ? 1 : 0; +} diff --git a/cmd/socktest/main.c b/cmd/socktest/main.c new file mode 100644 index 0000000..9c73530 --- /dev/null +++ b/cmd/socktest/main.c @@ -0,0 +1,305 @@ +// socktest -- prove that Unix domain sockets carry data between processes. +// +// Every part of a socket is invisible from a return value. bind() returning 0 +// proves nothing; a socket layer that accepts every call and drops every byte +// would pass a test built on return codes alone. So each check here has one +// process write and a *different* process read, and compares the bytes. +// +// socktest run every check +// +// Prints one line per check and a final verdict a script can grep for. + +#include "types.h" +#include "user.h" +#include "socket.h" + +static int failures; + +static void +puts_(const char *s) +{ + int n = 0; + while (s[n]) n++; + write(1, (void*)s, n); +} + +static void +putn_(int v) +{ + char buf[12]; + int i = 0, neg = 0; + if (v < 0) { neg = 1; v = -v; } + if (v == 0) buf[i++] = '0'; + while (v) { buf[i++] = '0' + (v % 10); v /= 10; } + if (neg) buf[i++] = '-'; + while (i--) write(1, &buf[i], 1); +} + +static void +check(int ok, const char *what) +{ + puts_(ok ? " [ok] " : " FAIL: "); + puts_(what); + puts_("\n"); + if (!ok) failures++; +} + +static int +streq(const char *a, const char *b) +{ + while (*a && *a == *b) { a++; b++; } + return *a == *b; +} + +// Fill a sockaddr_un and return the length to pass to bind/connect: the +// family plus the path plus its NUL, which is what musl computes and what the +// kernel side is written to expect. +static int +mkaddr(struct sockaddr_un *sa, const char *path) +{ + int i = 0; + for (i = 0; i < UNIX_PATH_MAX - 1 && path[i]; i++) + sa->sun_path[i] = path[i]; + sa->sun_path[i] = '\0'; + sa->sun_family = AF_UNIX; + return (int)sizeof(sa->sun_family) + i + 1; +} + +// --------------------------------------------------------------------------- +// 1. A round trip over a named socket, between two processes. +// --------------------------------------------------------------------------- +static void +test_roundtrip(void) +{ + struct sockaddr_un sa; + int len = mkaddr(&sa, "/tmp/socktest"); + int srv, pid, cli, n; + char buf[64]; + + puts_("named socket, two processes:\n"); + + srv = socket(AF_UNIX, SOCK_STREAM, 0); + check(srv >= 0, "socket() returns a descriptor"); + if (srv < 0) return; + + check(bind(srv, (struct sockaddr *)&sa, len) == 0, "bind() to /tmp/socktest"); + check(listen(srv, 4) == 0, "listen()"); + + // A second bind to the same name must be refused, or two servers can + // silently steal each other's clients. + { + int dup_ = socket(AF_UNIX, SOCK_STREAM, 0); + check(bind(dup_, (struct sockaddr *)&sa, len) < 0, + "a second bind to the same name is refused"); + close(dup_); + } + + pid = fork(); + if (pid == 0) { + // Child: the client. Connects, sends a question, reads the answer. + int c = socket(AF_UNIX, SOCK_STREAM, 0); + char reply[64]; + int r; + + close(srv); + if (connect(c, (struct sockaddr *)&sa, len) < 0) { + puts_(" FAIL: child connect()\n"); + exit(); + } + write(c, "ping", 4); + + r = read(c, reply, sizeof(reply) - 1); + if (r < 0) r = 0; + reply[r] = '\0'; + if (!streq(reply, "pong")) + puts_(" FAIL: child did not receive pong\n"); + close(c); + exit(); + } + + cli = accept(srv, 0, 0); + check(cli >= 0, "accept() returns a connection"); + if (cli < 0) { close(srv); wait(); return; } + + n = read(cli, buf, sizeof(buf) - 1); + if (n < 0) n = 0; + buf[n] = '\0'; + check(streq(buf, "ping"), "server read the client's bytes"); + + check(write(cli, "pong", 4) == 4, "server replied on the same socket"); + + close(cli); + close(srv); + wait(); +} + +// --------------------------------------------------------------------------- +// 2. Errors that must actually be errors. +// --------------------------------------------------------------------------- +static void +test_errors(void) +{ + struct sockaddr_un sa; + int len = mkaddr(&sa, "/tmp/nobody-listening"); + int s; + + puts_("error paths:\n"); + + s = socket(AF_UNIX, SOCK_STREAM, 0); + check(connect(s, (struct sockaddr *)&sa, len) < 0, + "connect() to a name nobody bound fails"); + close(s); + + check(socket(AF_INET, SOCK_STREAM, 0) < 0, "AF_INET is refused, not faked"); + check(socket(AF_UNIX, SOCK_DGRAM, 0) < 0, "SOCK_DGRAM is refused, not faked"); + + // read/write on a plain file descriptor must not be mistaken for a socket, + // and socket calls on one must be refused. + check(listen(1, 4) < 0, "listen() on a non-socket fd fails"); +} + +// --------------------------------------------------------------------------- +// 3. End-of-file. A reader whose peer closes must be told, not left hanging. +// --------------------------------------------------------------------------- +static void +test_eof(void) +{ + struct sockaddr_un sa; + int len = mkaddr(&sa, "/tmp/socktest-eof"); + int srv, cli, pid, n; + char buf[16]; + + puts_("end of file:\n"); + + srv = socket(AF_UNIX, SOCK_STREAM, 0); + bind(srv, (struct sockaddr *)&sa, len); + listen(srv, 4); + + pid = fork(); + if (pid == 0) { + int c = socket(AF_UNIX, SOCK_STREAM, 0); + close(srv); + connect(c, (struct sockaddr *)&sa, len); + write(c, "x", 1); + close(c); // the peer goes away with the byte still unread + exit(); + } + + cli = accept(srv, 0, 0); + n = read(cli, buf, sizeof(buf)); + check(n == 1, "the byte sent before close() is still delivered"); + + n = read(cli, buf, sizeof(buf)); + check(n == 0, "the next read returns 0 rather than blocking"); + + close(cli); + close(srv); + wait(); +} + +// --------------------------------------------------------------------------- +// 4. socketpair: bidirectional, no name, no listener. +// --------------------------------------------------------------------------- +static void +test_socketpair(void) +{ + int sv[2], n; + char buf[16]; + + puts_("socketpair:\n"); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) { + check(0, "socketpair() succeeds"); + return; + } + check(1, "socketpair() succeeds"); + + write(sv[0], "a", 1); + n = read(sv[1], buf, sizeof(buf)); + check(n == 1 && buf[0] == 'a', "0 -> 1 carries a byte"); + + write(sv[1], "b", 1); + n = read(sv[0], buf, sizeof(buf)); + check(n == 1 && buf[0] == 'b', "1 -> 0 carries a byte, on the same pair"); + + close(sv[0]); + close(sv[1]); +} + +// --------------------------------------------------------------------------- +// 5. A message longer than the socket buffer, so the writer has to block and +// the reader has to drain in more than one go. +// --------------------------------------------------------------------------- +#define BIG 12000 + +static void +test_big(void) +{ + int sv[2], pid, got = 0, ok = 1, i; + static char out[BIG], in[BIG]; + + puts_("a transfer larger than the buffer:\n"); + + for (i = 0; i < BIG; i++) + out[i] = (char)('A' + (i % 26)); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) { + check(0, "socketpair() for the big transfer"); + return; + } + + pid = fork(); + if (pid == 0) { + int sent = 0, r; + close(sv[1]); + while (sent < BIG) { + r = write(sv[0], out + sent, BIG - sent); + if (r <= 0) break; + sent += r; + } + close(sv[0]); + exit(); + } + + close(sv[0]); + while (got < BIG) { + int r = read(sv[1], in + got, BIG - got); + if (r <= 0) break; + got += r; + } + close(sv[1]); + wait(); + + check(got == BIG, "every byte arrived"); + if (got != BIG) { + puts_(" got "); + putn_(got); + puts_(" of "); + putn_(BIG); + puts_("\n"); + } + for (i = 0; i < got; i++) + if (in[i] != out[i]) { ok = 0; break; } + check(ok, "and in the right order"); +} + +int +main(void) +{ + puts_("socktest: unix domain sockets\n"); + + test_roundtrip(); + test_errors(); + test_eof(); + test_socketpair(); + test_big(); + + if (failures == 0) + puts_("socktest: ALL CHECKS PASSED\n"); + else { + puts_("socktest: "); + putn_(failures); + puts_(" CHECK(S) FAILED\n"); + } + exit(); +} diff --git a/docs/architecture/kernel-history.md b/docs/architecture/kernel-history.md new file mode 100644 index 0000000..cb3d4b4 --- /dev/null +++ b/docs/architecture/kernel-history.md @@ -0,0 +1,666 @@ +# Kernel history — what broke, and what the fix actually was + +Not a design document. This is the record of bugs that were expensive to find +and whose causes are not visible from the code that fixed them, plus the few +subsystem write-ups (bootloader, boot speed, naming) that have nowhere better +to live. + +It is worth keeping because every entry here is a thing that looked like a +different problem than it was. + +> **Where the old design plan went.** Sections 1-6 of this file used to hold a +> "Segregated Kernel" design: a Ring 0 Alpha / Ring 0 Beta split with driver +> modules isolated by CR3 switching, from an `IDEA.txt` that no longer exists. +> None of it was ever implemented, and it is superseded by +> [schapi.md](schapi.md) — a macOS-shaped system answers driver isolation with +> userspace drivers and a personality boundary, not a bespoke in-kernel ring +> split. It also referenced a Zig toolchain that is now clang/LLVM. Removed +> rather than left to be mistaken for a plan. + +--- + +## 1. Fixed: boot didn't reliably reach a working shell + +Investigated 2026-07-05, before phase 1 started (predates this design, not +caused by it). Originally manifested as `ksh` (mksh) crashing on every +launch, apparently inside musl's mallocng allocator (`get_meta`, +`src/malloc/mallocng/meta.h`, deliberately executing `hlt` on detecting +"corrupted" heap metadata — a `trap 13` GPF at a fixed rip). It wasn't a +musl bug. Six real kernel bugs were found and fixed across three +investigation passes, and mksh boots and runs cleanly with all of them in +place — the calloc assertion was a symptom of real memory/pointer-handling +bugs downstream in the kernel, not anything musl or mallocng did wrong. + +Fixed: +- `copyuvm()` (`kernel/arch/x86_64/vm.c`, used by `fork()`) never copied + `mmap()`-backed `proc->vma[]` regions into the child — only `[0, sz)`. + Fixed via new `copy_vma_range()`, called from `fork()` (`kernel/proc/proc.c`). +- `kmem.freelist` (`kernel/core/kalloc.c`) could get corrupted by a wild + write elsewhere and would silently hand back a bad pointer, panicking far + from the actual cause. Added a canary check (`check_run()`) at the top of + both `kalloc()`/`kfree()` so corruption panics immediately at the point + it's touched, with a clear message. +- No TLB invalidation existed anywhere except the full `lcr3` reload on + context switch — `mappages()`/`vm_unmap_range()` never called `invlpg`. + Fixed by adding `invlpg()` (`include/x86.h`) to both functions. +- **`MSR_STAR` was misconfigured** (`syscallinit()`, `kernel/arch/x86_64/vm.c`): + `SYSRETQ` computes the returned `cs`/`ss` as `STAR[63:48]+16`/`+8`, which + requires the *compat* 32-bit code selector (`SEG_UCODE32`) in that field — + the kernel was putting the real 64-bit `USER_CS` there instead. Every + `sysretq` silently loaded an invalid `cs` (`0x3b`, pointing at the TSS + descriptor)/`ss` pair; QEMU's TCG doesn't validate segment descriptors on + `SYSRET`, so this went unnoticed until a hardware interrupt forced a + strictly-validated `IRETQ` with that bogus `cs` still loaded, which + correctly `#GP`'d. +- `sys_mmap`'s non-`MAP_FIXED` path (`kernel/sys/sys_mem.c`) assigned a fixed + 8MB virtual-address window per `vma[]` slot regardless of the requested + length. A single allocation over 8MB (e.g. `realloc()` growth past that + size) mapped straight into a neighboring live mapping and hit + `mappages()`'s `panic("remap")`. Replaced with a real bump allocator + (`proc->mmap_next`, `include/proc.h`), so every mapping gets its own + disjoint, exactly-sized range regardless of size. +- **`uva2ka()`** (`kernel/arch/x86_64/vm.c`) returned only the page-aligned + base address of a user pointer's page, silently dropping the in-page byte + offset. Direct callers (`sys_ioctl`'s `TIOCGPGRP`/`TCGETS`, `sys_getcwd`, + signal masks, `times()`, `sysinfo()`, ...) read/wrote near the wrong + address whenever the pointer wasn't page-aligned — i.e. almost always. + Fixed at the source so every caller benefits. +- **`fetchint`/`fetchaddr`/`fetchstr`/`argptr`** (`kernel/sys/syscall.c`) + rejected any address `>= proc->sz`, wrongly assuming every valid user + pointer lives in the heap. Stack addresses and `mmap()`'d buffers (used + constantly by real programs, e.g. path-resolution buffers) live above + `proc->sz` and were being rejected outright. Fixed to rely solely on + `uva2ka()`'s page-table validation. + +Bringing in toybox (see "Coreutils" below) surfaced four more, all fixed: +- Linux syscall 58 (`vfork`) wasn't in the syscall-ABI translation table at + all (`kernel/sys/linux_abi.c`) — every external command spawn from a + program that prefers `vfork()` over `fork()` failed outright. Mapped to + the existing `fork()` (a fully correct, if slightly slower, substitute). +- `sys_stat`/`fstat`/`fstatat` (`kernel/sys/sys_fs.c`) filled in Schunix's + 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 + tools like `ls` couldn't tell files from directories, or executables from + non-executables. Added `struct linux_stat` + `stati_linux()`, gated on + Linux-ABI mode (`proc->syscall_map`). +- `sys_open`/`sys_openat` required `omode == O_RDONLY` *exactly* to open a + directory, but `opendir()`-style calls legitimately OR in `O_DIRECTORY`/ + `O_CLOEXEC` alongside it. Fixed to check just the access-mode bits + (`O_ACCMODE`, added to `include/fcntl.h`). +- `sys_getdents64` read one `struct dirent` (16 bytes) at a time — a full + `bmap()`+`bread()` per slot. Directories here are hash-indexed (see + `tree_search()`/`tree_expand()` below), so a directory with a few dozen + real entries can have a size in the hundreds of KB, nearly all empty + slots — this made listing such a directory look hung (it wasn't a + deadlock, just thousands of redundant single-slot disk reads). Rewrote it + to read a full block at a time and resolve each entry's type via + `iget(inum)` (exported from `fs.c`, it was `static`) instead of + re-searching the whole directory by name with `dirlookup()` for every + entry. That rewrite's first version introduced a **new** self-deadlock: + the "." entry's inode number equals the directory's own, and `iget()` + correctly hands back the *same, already-locked* `struct inode*` — calling + `ilock()` on it again sleeps forever on a lock the process already holds. + Fixed by special-casing `xde->inum == ip->inum` (we already know it's a + directory, no need to re-lock at all). + +A synthetic stress test (interleaved malloc/free, realloc growth crossing +`MMAP_THRESHOLD`, calloc, large allocations) runs to completion with zero +crashes, and mksh now boots straight to an interactive prompt, runs external +programs, pipes, and `ls`/`mkdir`/`grep` without issue. + +## 2. Naming standardization + +Schunix standardizes on exactly one name per role, regardless of the +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/init`. `cmd/init/main.c`'s exec loop only ever tries `/bin/sh` — no +ksh/mksh/dash/zsh/other-name fallbacks. dash was tried first +(BSD-licensed, minimal) while the boot crash above was still open, then +replaced with mksh once the underlying kernel bugs were fixed and dash's +lack of interactive features (history, completion, line editing) made it +feel unusably bare for day-to-day use; the dash port's source tree was left in +place rather than deleted, in case it's useful again (e.g. as a `/bin/sh` +POSIX-strict target distinct from an interactive login shell). + +## 3. Coreutils + +`ports/toybox/` (0BSD-licensed, https://landley.net/toybox/) provides `ls`, +`cat`, `cp`, `mv`, `rm`, `mkdir`, `grep`, `sed`, `find`, `chmod`, `date`, +`sort`, and more — see the `APPLETS` list in `ports/toybox/Makefile`. It builds +as a single multicall binary; `tools/mkfs.c` doesn't understand symlinks or +hardlink dedup, so `ports/toybox/Makefile`'s `install` target copies the built +binary once per applet name into `sysroot/bin/` rather than symlinking +(costs disk space per applet — currently ~44MB total — instead of one +shared inode, but needed no mkfs changes). + +## 4. Two-stage bootloader + PSOGM splash + +`boot/` used to be a single BIOS boot sector doing everything (VBE mode +set, A20, GDT, protected-mode switch, multiboot kernel scan/load) — silent, +and packed to within 4 bytes of the hard 510-byte MBR limit, so there was +no room to add so much as a print statement. + +Split into two stages, the standard way real bootloaders solve this: + +- **Stage 1** (`boot/bootasm.S`, still the literal MBR sector, still + ≤510 bytes) does exactly one thing: raw IDE PIO (LBA28) reads + `STAGE2_SECTORS` (16) sectors starting at disk sector 1 into memory at + `0x7E00`, then jumps there. Nothing else fits, nothing else is needed. + (Caught a real bug writing this: `outb $0x1F7,%al`-style immediates + silently truncate to 8 bits — ports 0x1F2-0x1F7 are all > 0xFF and need + the `%dx` register form, or you're hitting the wrong I/O port entirely.) +- **Stage 2** (`boot/stage2.S` + `boot/stage2main.c`, loaded at `0x7E00`, + occupies disk sectors 1-16) does everything stage 1 used to skip straight + to, plus a boot banner (BIOS teletype, real mode, before the VBE mode + switch — note this only reaches the video device, not serial, so it + won't show up in a `-serial file:...`-captured log), a splash screen, a + real-time loading bar, and an F8 boot menu (all described below). Not + size-constrained the same way as stage 1 — `tools/padstage2.pl` zero-pads + it out to a fixed `STAGE2_SECTORS*512` (8192) bytes so the kernel's + on-disk starting sector stays predictable regardless of stage2's actual + 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. + +The kernel now starts at disk sector 17 instead of 1 (`schunix.img`'s `dd +... seek=17` in the root `Makefile`, and the equivalent `+(1+STAGE2_SECTORS)` +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 +all). `boot/bootmain.c` no longer exists; its logic was split between +`stage2.S` (real-mode/protected-mode setup) and `stage2main.c` (splash + +the unchanged multiboot-header-scan-and-load logic). + +The VBE mode info block itself lives at `0x30000`, not the classic +single-stage bootloader's `0x9000` — stage2's own code now runs from +`0x7E00` up to nearly `0x9000` once the boot-menu/progress-bar logic is +included, and a block at `0x9000` gets partially overwritten by stage2's +own tail end (found this the hard way: the kernel's `LFB:` cprintf started +reporting a different wrong value on every boot, because it was reading +whatever stage2 code/data now happened to occupy that address). +`kernel/dev/vga.c`'s `vga_init()` has to agree on `0x30000` too, since it +independently re-reads mode fields from the same block. + +Splash/progress bar/boot menu rendering is a small standalone pixel +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 +pointer) reusing the kernel's own font data (`include/font.h`) directly. +It fills the framebuffer with PSOGM's purple (matching +`kernel/core/console.c`'s panic screen) and draws "SCHUNIX" centered, then: + +- **Real-time loading bar**: `readsect()` (in `stage2main.c`, not the + kernel) calls `progress_tick()` after every 512-byte disk read, updating + an actual pixel-filled bar against the real total byte count — first a + small one while scanning for the multiboot header, then a second, + properly-sized one once the header's found and the true kernel size is + known, labeled "Loading kernel...". Not simulated/timed — it reflects + real bytes read off disk. +- **F8 boot menu**: `wait_for_f8()` busy-polls the keyboard controller + (`inb(0x64)`/`inb(0x60)`, raw scancodes — real-mode BIOS keyboard calls + aren't available once we're in protected mode) for about a second after + the splash appears. F8 (scancode `0x42`) drops into `boot_menu()`: three + options (boot normal, boot verbose, reboot to firmware setup) navigated + with up/down arrows and Enter, plus a "detected drives" panel from + `ata_present()` — a standard floating-bus presence check (select the + drive, write a pattern to two registers, read it back) on the primary + IDE channel's master/slave (the only channel this project ever actually + puts drives on; QEMU's IDE emulation answers the same test + "successfully" on the unpopulated secondary channel too, so that channel + isn't shown — it'd just be confidently wrong). "Reboot to firmware + setup" pulses the keyboard controller's reset line + (`outb(0x64, 0xFE)`, same technique as `kernel/sys/sys_proc.c`'s + `sys_reboot()`); a real bootloader can't jump into BIOS/UEFI setup + 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. +- **Verbose boot**: picking "Boot Schunix (verbose)" writes a flag byte to + `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()` + reads it into a global `boot_verbose` as its very first action and, if + set, prints a line after every subsystem init call + (`uartearlyinit`, `kinit1`, ..., `sinit`) — real per-step boot logging, + not a canned message. + +Two bugs worth remembering if this code gets touched again: + +- **Keyboard extended-scancode handling**: `0xE0` (the prefix byte for + arrow keys and friends) also has bit 7 set, the same bit used to detect + key-*release* ("break") codes. A naive "skip anything with bit 7 set, + then check for 0xE0" loop skips the 0xE0 byte itself before ever testing + for it, so extended keys silently never register. The 0xE0 check has to + come before the break-code check, not after. +- **The kernel entry call is not a real C function call.** Both the + original single-stage `bootmain()` and the new `stage2main()` do + `((void(*)(uint32))entry)(fbaddr)` — normal cdecl, which pushes `fbaddr` + on the stack. But `kernel/arch/x86_64/entry.S`'s `mboot_entry` reads its + framebuffer argument out of **EAX** (a multiboot-style raw-register + handoff, then `mov %eax,%ebp` / `mov %ebp,%ebx` / `mov %rbx,%rdi` carries + it through the 32→64-bit transition into `kmain()`'s first argument). + The cdecl call never puts anything in EAX — it "worked" for years purely + because simple bootmain.c code happened, as a side effect of its own + codegen, to leave the right value sitting in EAX right up until the + `call` instruction. Adding the splash/menu/progress-bar code changed + that codegen and broke it silently: the kernel booted fine and reported + a plausible-looking but wrong `LFB:` address (garbage left over in EAX + from unrelated prior code, different on every boot). Fixed by pinning + the argument down explicitly with `asm volatile("jmp *%0" : : "r"(entry), + "a"(fbaddr))` instead of hoping the compiler's register allocation + cooperates. If this code moves around again, re-verify with a screendump + taken *immediately* before the jump compared against the kernel's own + `LFB:` log line — they silently diverging is exactly this bug. + +## 5. `*at()` syscalls ignored/rejected real dirfds + +`ls -l`/`ls -lR` (and, by the same code path, `find`/`du`/anything using +toybox's `lib/dirtree.c`) would hang on `ls -l` and either hang or silently +misbehave on recursive listings. Root cause: `kernel/sys/sys_fs.c`'s +`*at()` syscalls (`openat`, `fstatat`, `unlinkat`, `renameat`, `linkat`, +`symlinkat`, `mkdirat`, `mknodat`, `readlinkat`, `faccessat`) only handled +two cases for their `dirfd` argument — `AT_FDCWD` (resolve relative to +`proc->cwd`) or an absolute path (resolve from root, ignoring `dirfd` +entirely). A **real** dirfd with a **relative** path — e.g. +`fstatat(open("/bin", O_RDONLY), "ls", &st, ...)`, the standard, efficient +way any directory-tree walker avoids rebuilding full path strings for every +entry — was either rejected outright (`fstatat`, `unlinkat`, ...) or +silently ignored in favor of `proc->cwd` (`openat`, which never checked at +all — worse than rejecting, since it can silently resolve the *wrong* +file if cwd happens to contain a same-named entry). + +Fixed by adding a real dirfd-relative path resolver: `kernel/fs/fs.c`'s +`namex()` was refactored into `namex_from(struct inode *start, ...)`, +parameterizing what used to be a hardcoded `idup(proc->cwd)`, with two new +exported entry points, `nameifrom()`/`nameiparentfrom()`. `sys_fs.c` gained +`at_dir(dirfd)` (resolves `AT_FDCWD` or a real fd to a starting inode) and +`at_namei()`/`at_nameiparent()` built on top of it, plus a `createat()` +(parameterizing `create()`'s hardcoded `nameiparent()` call the same way). +Every `*at()` syscall now uses these instead of its own inline +absolute-path/`AT_FDCWD`-only check. + +**Known follow-on issue, not yet root-caused**: heavy `ls`/`ls -lR` use +across many commands in one long-running shell session can eventually make +a *later*, unrelated directory hang (reproduced with `ls -lR /var` after +~10 prior commands in the same session; the identical command succeeds +immediately on a fresh boot). Not an inode-table or file-table exhaustion +— both `iget()` and `filealloc()` fail cleanly (panic / return 0 +respectively) when full, and neither fired. Smells like a lock or +reference-count leak somewhere in the *at() paths above, or in toybox's +own fd handling, that only manifests after enough accumulated opens/closes. +Next step: instrument `itable`/`ftable` occupancy counts and watch them +across a long `ls`-heavy session to see what's actually climbing. + +## 6. Boot speed + +Two cheap, real wins in `boot/stage2main.c`, no functional changes: + +- `progress_tick()` (called once per 512-byte disk sector) used to trigger + a full progress-bar redraw — border plus fill, a few thousand pixel + writes — on *every* sector. For the ~330KB kernel image that's ~650 full + redraws (the multiboot-header-scan phase adds another ~32) for a bar + that only has 101 visually distinct states (0-100%). Split into + `progress_border()` (drawn once, in `progress_start()`, since the border + never changes) and `progress_fill()`, and `progress_tick()` now skips the + redraw entirely unless the percentage actually changed. This was the + single biggest chunk of the bootloader's own wall-clock time. +- `fill_rect()` (the full-screen splash fill, 480,000 pixels at 800x600, + run at least twice per boot) used to call `draw_pixel()` per pixel, which + recomputes `g_fb + y*stride + x*4` from scratch every time. Now computes + each row's base pointer once and indexes into it. +- The F8 boot-menu wait was shortened from ~1s (`5000000` busy-loop + iterations) to ~0.6s (`3000000`) — flat overhead on every boot whether + or not the menu is wanted, so it's the most direct lever available + without giving up the feature entirely. + +## 7. `*at()` syscalls, real signal delivery, and mksh job control (in progress) + +`ls -l`/`ls -la` hanging outright turned out to be the same root cause +described in section 11 above (dirfd-relative path resolution) — fixed +and verified extensively (plain `ls`, `ls -l`, `ls -la`, `ls -lR`, piped +output, all confirmed working repeatedly). + +A *second*, deeper issue was found investigating a follow-up report +(`cd` with no `HOME` set, then `cd var`, then `ls` hanging): mksh's +interactive job control (`ports/mksh (mksh R59c source): jobs.c`) blocks in +`sigsuspend()` waiting for `SIGCHLD`, expecting its own handler +(`j_sigchld()`) to run, reap the child via `waitpid(-1, &status, WNOHANG)`, +and update its internal job-state tracking. This kernel had **no real +signal delivery at all** — `sys_rt_sigaction()` was a no-op stub, so no +handler was ever invoked for anything, and `sigsuspend()` just slept out +one tick and returned `-EINTR` unconditionally. mksh's wait loop had no +way to ever learn the child had exited, hanging forever. + +Real signal delivery was implemented from scratch: +- `struct proc` (`include/proc.h`) gained `sig_handler[32]`/ + `sig_restorer[32]` (populated by `sys_rt_sigaction()`, + `kernel/sys/sys_sig.c`), `saved_sigtf` (stashed pre-signal trapframe), + and `in_signal` (re-entrancy guard). `allocproc()` zeroes these for a + freshly claimed ptable slot (they weren't before — a reused slot + silently inherited a previous, unrelated process's handler addresses, + which crashed the *next* process to occupy that slot the moment + anything tried to delivver a signal to it). `fork()` copies handler/ + restorer/mask from parent to child (POSIX semantics) but not pending + signals. +- `kernel/proc/proc.c`'s `exit()` sets `SIGCHLD` pending on the parent. +- `kernel/sys/syscall.c`'s `syscall()` calls `deliver_signals(tf)` in its + tail, right before returning to user mode: if there's a pending, + unblocked signal with a registered handler, it redirects the trapframe + to jump to the handler (`rdi`=signal number per SysV ABI, `rip`=handler) + instead of resuming the interrupted code, having first stashed the + original trapframe in `proc->saved_sigtf`. +- The return address is **not** `sig_restorer[sig]` — checked, `SA_RESTORER` + is not defined anywhere in this musl build, so `sigaction()` never fills + in a restorer; it's always 0, and pushing 0 as a return address crashes + with `rip=0` the instant the handler function returns. Instead, + `deliver_signals()` injects a tiny 7-byte trampoline (`mov eax,15; + syscall` — `rt_sigreturn`) directly onto the user's own stack, below the + current `rsp` (clear of the SysV red zone), and points the return + address at that — the standard technique for when the C library doesn't + supply its own restorer. +- `sys_rt_sigreturn()` restores `*proc->tf` from `proc->saved_sigtf`, + clearing `in_signal`. + +**A real bug found and fixed along the way**: the first version of +`sys_rt_sigaction()` translated the user's `struct sigaction` pointer +*once* via `uva2ka()` and then did a bulk `memset`+copy across the whole +~152-byte structure. `uva2ka()` only guarantees the *page containing that +address* is mapped, not everything up to some further offset — when the +user's pointer landed close enough to a page boundary, the write ran past +the mapped page into whatever physical page happened to be next in kernel +address space (P2V is a flat offset, so "next page" there has nothing to +do with the user's actual next page), corrupting unrelated kernel memory. +This crashed every freshly `exec`'d `/bin/sh` almost immediately, since +mksh calls `sigaction()` during its own startup. Fixed by only touching +the two individual 8-byte fields actually needed (`sa_handler` at offset +0, `sa_restorer` at offset 144), each through its own `uva2ka()` call. + +`sys_waitpid()`/`sys_wait4()` (`kernel/sys/sys_proc.c`) were also rewritten +on top of a new `waitpid(pid, status, options)` in `kernel/proc/proc.c` +(refactored from the old any-child-only, always-blocking `wait()`, which +is now just `waitpid(-1, 0, 0)`): a specific `pid` (not just "any child"), +`WNOHANG` (return 0 immediately instead of blocking), and — importantly — +a genuinely optional status pointer. The old code ran a NULL status +pointer through `argptr()`, which rejects NULL/unmapped addresses outright +(page 0 is deliberately unmapped) — but `waitpid(pid, NULL, WNOHANG)` is +completely standard, and is exactly what mksh's job control does. + +**Status: signal delivery mechanically works** — verified directly (a +debug build logged the handler being invoked with the correct trapframe +and `sys_rt_sigreturn()` restoring cleanly, no crash, repeatable). **mksh's +job control still doesn't reliably progress afterward**, including for +plain non-piped foreground commands, not just the original piped-into-head +case. Root cause not yet isolated. Leading suspects, in order of +likelihood: +- `sys_setpgid()`/`sys_getpgid()` are no-op stubs (`kernel/sys/sys_proc.c`) + — `j_sigchld()` (`ports/mksh (mksh R59c source): jobs.c:1344-1348`) has an early-out + keyed on `j->ppid == procpid`, which may never resolve the way mksh + expects without real process-group tracking. +- `getrusage(RUSAGE_CHILDREN, ...)` — called at the top of `j_sigchld()` — + isn't verified to behave sanely under this kernel's implementation + (`kernel/sys/sys_proc.c`'s `sys_getrusage()` only fills in `ru_utime` + from the *calling* process's own tick count, not accumulated child + time; `RUSAGE_CHILDREN` isn't distinguished from `RUSAGE_SELF` at all). +- Possibly something in how `j_sigchld()` matches a reaped `pid` against + its own `job_list` (`ports/mksh (mksh R59c source): jobs.c:1372-1385`) silently fails + to find the job for reasons not yet traced. + +This was left here deliberately rather than continuing to iterate blind: +SIGCHLD delivery is left **enabled** (`kernel/proc/proc.c`'s `exit()`) +since disabling it guarantees zero chance of mksh's wait loop ever exiting, +whereas leaving it on at least gives the cases that don't hit the +still-unknown remaining gap a chance to work. Next session should start +by instrumenting `j_sigchld()`'s own control flow (or strace-equivalent +logging in the kernel around `sys_setpgid`/`sys_getrusage`/`sys_waitpid` +calls specifically while reproducing `cd; cd var; ls` or even simpler +`ls -l /bin` followed by a second command) rather than re-deriving the +signal-delivery mechanism, which is now confirmed solid. + +--- + +## 8. Two ABI assumptions that only GCC was keeping true + +Found when the build moved from GCC-in-WSL to clang-on-Windows. Neither is a +clang bug; both are places where the code relied on GCC doing something it +never promised, and both had been latent for years. + +### `%fs:0` was being used as scratch — it is the TCB self-pointer + +`syscall_entry` (`kernel/arch/x86_64/trapasm.S`) stashed `%rax` at `%fs:(0)` +while it fetched `proc` to find the kernel stack. The comment called it a +"per-CPU scratch slot". It is not: the x86-64 TLS ABI reserves the word *at* +the thread pointer to hold the thread pointer, and a compiler may read it to +materialise the TP before applying a variable's offset. + +GCC compiles `__thread` access to a direct `%fs:-8` segment reference and never +reads that word, so the clobber was invisible. clang at `-O0` emits +`movq %fs:0, %rax; addq $-8, %rax; (%rax)` — reading back the syscall number +this code had just stored. The first process's first syscall is +`exec` (7), so `proc` resolved to address `7 - 8 = -1` and the kernel +page-faulted recursively until the stack was gone. + +Fixed by moving the scratch to `%fs:(8)`. Positive offsets are safe: the TLS +block lives at negative offsets and `seginit` places the thread pointer 2048 +bytes into a 4096-byte page. + +**How it was found** is the part worth copying next time. Three rounds of +`cprintf` narrowed it to "the word is right at `mpmain`, wrong by the first +trap" and no further — the instrumentation perturbed the timing enough to move +the symptom. A hardware watchpoint through QEMU's gdb stub named the +instruction on the first run: + +``` +qemu ... -S -gdb tcp::26000 +gdb -batch -x tcp.gdb # hbreak mpmain; watch *(unsigned long*)kernel_fs_base +``` + +`seginit` also now writes the self-pointer, which it never did. That is ABI +-correct regardless and costs one store per CPU. + +### `_start` read incoming registers with `register ... asm("rdi")` + +`lib/glue.c` captured `argc`/`argv` from `%rdi`/`%rsi` using GCC local register +variables. Both compilers only guarantee that binding for inline-asm operands; +using it to pick up an incoming argument is undefined. clang ignored it and +read two uninitialised stack slots: + +```asm +movl -0x4(%rbp), %eax # should have been %edi +movq -0x10(%rbp), %rax # should have been %rsi +``` + +Every program still ran. `init`, `shmtest` and `socktest` take no arguments and +passed their entire suites; the only symptom in the whole system was +`inputtest -n 6` ignoring its limit. Moved to `lib/start.S`, where reading +incoming registers is expressible and correct — `exec` passes argc/argv in the +SysV argument registers already, so `_start` calls `main` without touching +them. + +--- + +## 9. The boot looked like a hobby OS, and two things were why + +Not a bug — a design problem, fixed by looking at a screenshot instead of the +code. + +**The display was the kernel log.** Boot printed `pci: 6 devices` and +`vga: display controller 1234:1111, aperture fd000000 (16 MB)` to the screen +the user is looking at. That single fact is most of what separates a hobby +project from a product; every shipping system puts that behind a flag. + +`cons_serial_only` already existed for panic, so the fix was to start it *set*. +Everything still goes out the UART — which is where `tools/bootcheck.ps1` reads +it from, so all five suites kept passing untouched — and `console_takeover()` +clears it on the first `exec()`, the moment userspace genuinely starts. +`vga_init` no longer clears the screen, so the splash survives the whole of +boot rather than being wiped a few hundred milliseconds in. + +**There were three unrelated designs.** The splash was deep purple with gold +text, deliberately matching the *panic* screen. The console was cream with +near-black text. So a healthy boot was dressed as a crash, then abruptly +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 +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 +/ 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 +belongs. No shipping OS names its bootloader on the splash. + +### Three latent bugs it flushed out + +Retheming meant `stage2main.c` included `types.h` properly for the first time, +and the 32-bit build stopped compiling: + +- `_Static_assert(sizeof(uint64) == 8)` fired. `uint64` was `unsigned long`, + which is **4 bytes** in the `-m32` loader — the file even carried a local + `e820_u64` workaround with a comment saying so. Now conditioned on + `__SIZEOF_LONG__` rather than on the platform, which covers LP64, LLP64 *and* + ILP32 correctly. +- `x86.h`'s `stosq` and `xchg` use `rep stosq` and `xchgq`, which do not exist + in 32-bit mode. They only ever compiled because `uint64` was silently + narrowed. Now behind `#ifdef __x86_64__`. +- The progress bar computed `(uint64)done * 100 / total`, a 64-bit divide that + needs libgcc's `__udivdi3` — which a freestanding loader does not link. Now + scaled to KiB and done in 32 bits. + +All three had been sitting in a bootloader that worked fine, waiting for +someone to make `uint64` mean what it says. + +--- + +## 10. A full-screen program typed the whole session into the shell + +Keys reached `/dev/input/event0` **and** the tty line discipline at the same +time. That is correct for two consumers of one keyboard and completely wrong +for a full-screen program: while it had the display, the shell behind it was +quietly accumulating every keystroke, and the first Enter afterwards ran +whatever had piled up. Arrow keys arrived as CP437 glyphs on the console for +good measure. + +The fix is the standard one and it is a *primitive*, not a patch: an exclusive +grab, `EVIOCGRAB`, with Linux's ioctl number. While a device is grabbed its +events still flow to `/dev/input/eventN` but both keyboard drivers withhold the +decoded character from the console. + +Three details that matter more than the feature: + +- **The grab is released by the devsw `close` hook**, not by the program. A + program that grabs the keyboard and then crashes would otherwise leave the + console permanently deaf, with no way to type the command that fixes it. +- **Modifier state is still tracked while grabbed** (`kbdgetc` keeps updating + shift/caps and only skips the character). Otherwise releasing the grab would + hand the line discipline a stuck Shift. +- **The USB path updates `prev[]` before returning**, or the next report would + look like every held key had just been pressed again. + +It is also exactly what Schcom will need, which is why it lives in the input +layer rather than in any one client. + +### The near-miss worth remembering + +The first attempt appeared to work: the harness passed, every assertion green. +It had not worked at all — the ioctl call was never inserted into the client +source, because a scripted string replacement silently failed to match. The +`grep` that should have caught it printed three hits (a comment, a `#define`, +and the *release* call) and was read as confirmation without counting what +they were. + +What actually caught it was reading the transcript rather than the verdict: +four bare `#` prompts after quitting, which is precisely the symptom the change +was supposed to remove. `input_grab()` now announces itself, so "did the grab +happen" is never again a thing anyone has to infer. + +--- + +## 11. `ps` and `top`, and why they never worked + +/proc was a set of character devices: init ran `mknod("/proc/uptime", 6, 2)` and +friends, so every file was a real inode on the root filesystem with a +major/minor behind it. That is fine for a fixed list and cannot work at all for +the thing /proc is mostly for -- one directory per process. You cannot mknod a +directory for a process that does not exist yet and will be gone in a minute. +`ps` calls `dirtree_flagread("/proc")`, got a listing with no numbers in it, and +reported nothing. It was never a `ps` problem. + +So /proc is now a real filesystem behind the same `struct fs_ops` vtable SchFS +uses (`kernel/fs/procfs.c`, `PROCFS_DEV`), mounted by init with +`mount("proc", "/proc", "proc", ...)`. Nothing is stored: directory listings +are generated from the process table when asked, file contents when read. + +Three things worth keeping in mind: + +- **The split is deliberate.** `kernel/fs/procfs.c` owns the *namespace* (what + exists); `kernel/dev/procfs.c` keeps the *generators* (what the global files + say). They change for different reasons, so `proc_gen_global()` is the only + thing that crosses between them. +- **procfs never touches ptable.** `proc_snapshot()` copies what is needed out + from under the lock, so a process that exits between the readdir that listed + it and the open that reads it produces a stale line rather than a + use-after-free. +- **Sizes are reported as zero**, exactly as Linux does. A synthetic file has + no length until it is generated, and generating every one on every `stat()` + to fill in a number almost nothing reads would be absurd. + +### What the suite caught + +Marking every procfs inode read-only broke `echo s > /proc/sysrq`, and three +USB checks failed on it within a minute of the change -- they drive the disk +through sysrq. /proc is read-only *except* sysrq, which is the one deliberate +write target, and the code now says so in one place. + +### Still not right + +`ps -o comm` prints `[init]` rather than `init`. That field comes from +`/proc//exe`, which Linux makes a **symlink** and toybox `readlink()`s; +ours is a regular file, so the readlink fails and toybox brackets the name as +it would for a kernel thread. Default `ps` and `top` output are unaffected. +Fixing it needs symlink support in procfs, which belongs with the rest of the +VFS work rather than as a one-off. + +--- + +## 12. A test program crashed at random, and had been typing its own launch command + +Symptom: a full-screen framebuffer program, launched with arguments, worked +four times and then died with + + pid 9 : trap 14 err 4 on cpu 0 rip 0x2269be addr 0x18--kill proc + +`err 4` is a user-mode read of a non-present page and `addr 0x18` is a null +pointer at offset 24. `llvm-nm` put `rip` inside the routine that opens the +program's overlay view, which dereferences a pointer the program only fills in +once a level is loaded -- at offset 0x18 on x86-64, because the three 64-bit +words of a base struct sit in front of it. So the program had been asked to open +that view before there was anything to show. + +**The technique is the transferable part:** the fault address alone said +"null pointer plus 24", which is nearly useless; `llvm-nm` on the faulting `rip` +turned it into a function name, and the offset then identified the exact field. +Reach for that before adding printfs to a program you did not write. + +The cause was ours, and it was visible in the log the whole time: every run +printed a burst of garbage bytes *before* the grab was taken, and the amount +differed each run. + +**`/dev/input/eventN` had no notion of being opened.** Events were queued from +boot onwards whether or not anything was listening, into one 256-entry ring +with one read cursor. When the program opened the device it inherited the entire +backlog -- including the keystrokes of the command line that had launched it, +which the shell had already consumed -- and replayed them as input. Whether that +crashed depended on which keys happened to be sitting there, which is exactly +the "sometimes" in the report. + +Fixed by giving `struct devsw` an `open` hook to match `close`, and having +`/dev/input`: + +- drop the backlog on open (`r = w`) -- a reader starts from *now*; +- only queue events while `opens > 0`, which is what Linux does: an evdev + device with no clients does not accumulate. + +Linux gets both for free by giving every open its own client queue. One shared +ring plus "start from now" is the same answer for a single reader, which is the +only case that exists today; per-client queues become necessary the moment +Schcom and a client both want the keyboard. + +### Also fixed + +`cd` into a file reported "Operation not permitted". It was right to fail, but +`sys_chdir` returned a bare `-1`, so the shell printed whatever errno happened +to be lying around. It returns `-ENOTDIR` now, and `-ENOENT`/`-EFAULT` on the +other two failure paths -- "Not a directory" sends you to the right place, +"Operation not permitted" sends you looking at permissions. diff --git a/docs/architecture/schapi.md b/docs/architecture/schapi.md new file mode 100644 index 0000000..28c2541 --- /dev/null +++ b/docs/architecture/schapi.md @@ -0,0 +1,239 @@ +# SchAPI, and Schunix as a system + +Status: **direction agreed, not yet implemented.** Nothing in this document +changes what is being built this week; it changes what everything is being +built *towards*. See §7 for what actually happens now. + +--- + +## 1. The decision + +Schunix 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 +sit on it, designed together. + +The model is NeXTSTEP/macOS, not Linux. Specifically: + +- A kernel that provides mechanism, with **more than one personality** on top. +- **POSIX/Unix is a personality, not the identity.** It stays, completely and + seriously, because it is how you get software. It is not the thing programs + are expected to be written against. +- **SchAPI** is the native interface: higher-level, object-shaped, designed for + the GUI and services rather than retrofitted onto 1970s process semantics. + +Two systems are being borrowed from, and they are *different* systems. It is +worth being precise about which, because they disagree: + +| Borrowed | From | Why | +|---|---|---| +| Layered architecture, personalities, native API over a Unix substrate | macOS / NeXTSTEP | It is the only mainstream design that got a modern API onto a Unix base without abandoning either | +| Permanent backward compatibility | **Windows** | macOS is emphatically *not* this — Apple dropped 32-bit apps, Carbon, kexts and OpenGL, each time on a deadline | + +That mix is coherent, but it is a mix. Taking the architecture from Apple and +the compatibility policy from Microsoft is a deliberate choice, and the rest of +this document is mostly about making that choice survivable — because +compatibility-forever is the single most expensive promise an OS can make, and +Windows pays for it every day. + +--- + +## 2. The one mechanism that makes the promise affordable + +**The stable interface is a library, not the syscall table.** + +This is the whole trick, and it is what lets macOS keep decade-old binaries +running while freely renumbering its syscalls. On macOS, nothing may issue a +syscall directly; you link `libSystem`. Apple therefore owes compatibility only +at the library boundary, and the kernel stays editable forever. + +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 +there, with a `2` or a `64` suffixed to the name of its replacement. + +So, for Schunix: + +``` + ┌──────────────────────────────────────────────┐ + │ applications, SchWM, SchDE │ + ├──────────────────────────────────────────────┤ + │ SchAPI │ POSIX / Linux personality│ ← THE STABLE BOUNDARY + ├──────────────────┴───────────────────────────┤ + │ libschunix — the only thing that may syscall│ + ├──────────────────────────────────────────────┤ + │ syscall table — PRIVATE, unstable, renumberable + ├──────────────────────────────────────────────┤ + │ kernel │ + └──────────────────────────────────────────────┘ +``` + +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 + any release. Only `libschunix` may. +2. `libschunix` exports versioned symbols. An entry point's behaviour never + changes; a changed behaviour is a new version of the symbol. +3. The kernel may renumber, merge, split or delete syscalls at will, provided + `libschunix` still presents the same surface. + +This *reconciles* with the existing decision to adopt Linux syscall numbering +(`docs/roadmap.md`, and the reason musl/toybox/mksh work at all). Linux +numbering does not go away — it becomes the **Linux personality's** entry path, +which is exactly what it already is in practice. It is a compatibility surface +that happens to be entered via `syscall`, and it is frozen because *Linux* +froze it, not because we did. + +--- + +## 3. Stability tiers + +"Nothing can ever be removed" is only affordable if you are precise about what +"anything" covers. Windows' real problem was never the documented API — it was +that undocumented behaviour became load-bearing, and then it was too late. + +Every public interface carries exactly one tier: + +| Tier | Promise | May change | +|---|---|---| +| `stable` | Forever, from the release that introduced it | Never. Additions only. | +| `provisional` | Until the next release | Freely | +| `internal` | None | Freely, without notice | + +**Everything in Schunix 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 +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 +was a documented no-op until last week and a `struct file` whose `O_NONBLOCK` +handling had never been exercised. + +Nothing becomes `stable` by being old. It becomes `stable` by someone deciding +it is right and writing that down. + +--- + +## 4. `compat/` — what it actually means + +The instinct is right: old interfaces should not litter the current tree. But +moving *source* into a folder does not reduce the *runtime* cost, and the +runtime cost is the one that hurts. + +The rule that keeps compatibility cheap: + +> **A compatibility entry point must be implementable as a translation into the +> current API. If it cannot be, that is a defect in the current API — fix the +> current API before freezing it.** + +So `compat/` holds shims, not parallel implementations. A shim: + +- lives in `compat//`, +- is written in terms of today's API and nothing else, +- is never called by new code, +- carries its own tests, which are the only thing that proves the promise is + still being kept. + +When a shim *cannot* be expressed as a translation, that is the alarm. It means +the new API lost information the old one carried, and it is far cheaper to +notice that before 1.0 than to maintain two real implementations forever. That +is precisely the trap Win32 fell into. + +--- + +## 5. Taking from the BSDs + +`src-trunk/` is a NetBSD checkout, and a FreeBSD one is being added alongside +it. Both are reference material and parts bins; neither is built and neither +may ever end up in an image. + +**Two trees is not redundancy.** They are worth having together for three +reasons that a single tree cannot give: + +- Where an RFC is ambiguous — and TCP's are, constantly — two independent + implementations agreeing is far stronger evidence than one implementation + asserting. +- Where one is licence-encumbered, the other may not be. NetBSD's + `tcp_input.c` carries a WIDE Project advertising clause that Berkeley's + rescission does not cover; FreeBSD's equivalent may well be 2-clause. See + [../licensing.md](../licensing.md) §3. +- They have opposite biases, and knowing which you are reading matters: + +| | FreeBSD | NetBSD | +|---|---|---| +| Stack quality | The better stack in absolute terms — faster, more complete, more actively developed | Solid, conservative, less featureful | +| Extractability | Welded to FreeBSD: `epoch(9)`, `uma`, `netisr`, VIMAGE/vnet, `if_t`, a rich locking vocabulary | Portability *is* the project's identity; assumes far less of its host kernel | +| Use it as | The reference you check yourself against | The code you actually lift | + +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 +USB stack means porting the device framework first. Networking is the same +shape. Read FreeBSD, lift NetBSD, write Schunix. + +### Licensing — read this before copying anything + +NetBSD is not uniformly licensed: 2-clause, UC 3-clause and a minority of +4-clause-with-advertising files all appear, and only the first two are +comfortable. The per-template rules, the measured counts, and the one-line +check to run before copying a file are in [../licensing.md](../licensing.md) +§3. Do not copy from `src-trunk/` without reading it. + +### What is actually worth taking + +Ranked by value, not by size: + +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 + mature, clean, readable, 2-clause-heavy implementation of exactly that. +2. **`sys/kern/subr_pool.c` — the pool/slab allocator.** Schunix has `kalloc` + and a page at a time. Every subsystem written since has invented its own + fixed-size table to work around that. +3. **`autoconf` — the driver framework** (`config(1)`, `cfdriver`/`cfattach`, + `device_t`). This is the grown-up version of what `kernel/drivers/registry.c` + and `kernel/dev/irq.c` are hand-rolling. Adopt the *model*; do not try to + port the code wholesale. +4. `sys/kern/subr_*` generally — rbtree, workqueue, condvar, kmem. + +Low value: `lib/libc` (musl already fills that role), `sys/dev/usb` (we have a +working xHCI stack written from the spec). + +**Take designs before code.** Every file copied is a file to be understood, +relicensed-in-notice, and maintained forever under the §3 promise. + +--- + +## 6. What SchAPI is, concretely + +Not yet designed. What is decided about it: + +- 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 designed *with* Schcom in mind, because a compositor and its clients + are the first real users and their needs (IPC, shared buffers, event streams, + object lifetimes) are what will shape it. +- The IPC primitive comes first. Everything in a NeXT-shaped system rests on + it, and unix domain sockets — already built and working — are the substrate, + not the interface. + +What is explicitly *not* decided: whether it is object-oriented in the Objective-C +sense, what language it is expressed in, and whether it takes Mach's port model +or something smaller. Those need their own document, written when Schcom has +told us what it actually needs. + +--- + +## 7. What changes now + +Almost nothing, on purpose. The ordering does not change: + +- **The native Windows build must boot first.** The clang-built kernel + currently reaches `sinit` and dies on the first trap. A direction is worth + nothing while the tree does not run. +- Then the roadmap continues as written: network, GPU, fonts, Schcom. + +What this document changes *today* is only this: + +1. `src-trunk/` is reference material, excluded from every build and image. +2. New interfaces are marked `provisional` from now on, so that §3 has + something to work with at 1.0. +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. +4. `libschunix` is created when there is a second personality to justify it. + Until then, the *rule* stands even though the library does not exist yet: + no new first-party program issues raw syscalls. diff --git a/docs/architecture/schfs.md b/docs/architecture/schfs.md new file mode 100644 index 0000000..e0dc7e0 --- /dev/null +++ b/docs/architecture/schfs.md @@ -0,0 +1,403 @@ +# SchFS — design + +**Status: phases 1 and 2 are done.** The copy-on-write B-tree, the volume layer, +the object layer, a working image writer and a checker all exist, and the kernel +mounts a SchFS volume read-only at boot. Phase 3 (writes and transaction groups) +is next. See §8 for exactly what is built and how to run its tests. + +Supersedes the on-disk format described in `include/fs.h`. Keeps the name SchFS; +the on-disk magic changes so v1 images are detected and rejected rather than +silently misread. + +The brief was "the best aspects of BeFS, ZFS and btrfs." Those three disagree +with each other in places, so this document says explicitly what is taken from +each and what is deliberately left behind. + +## 1. What each one is actually good at + +**ZFS — never be inconsistent.** Copy-on-write: no block that is part of the +live tree is ever overwritten. An update writes new blocks, then atomically +flips a single root pointer. A crash therefore lands on either the old tree or +the new one — never a half-written mix. Consequence: **no fsck**, ever. Paired +with end-to-end checksums where a block's checksum is stored in its *parent* +pointer, not in the block itself, which makes the whole tree self-validating and +catches misdirected writes and bit rot that a self-stored checksum cannot. + +**btrfs — one data structure, reused everywhere.** btrfs has essentially one +engine: a copy-on-write B-tree. Inodes, directory entries, extent maps, free +space, and snapshots are all just different key types in that same tree. For a +small team this is the single most important idea in the whole design: you write +and debug *one* tricky data structure, then get five subsystems from it. Also +takes extents with **reference counts**, which is what makes snapshots and +reflink copies fall out almost for free. + +**BeFS — the part that feels like a database, at a size one person can build.** +BeFS is a 64-bit journaled filesystem whose distinguishing feature is B+tree +**indexes over file attributes**, with a query interface on top. That is the +"SQL-like" capability, and unlike WinFS it actually shipped. Critically, BeFS is +also the right *scale* model: a small team, a readable codebase, and a book +(Giampaolo, *Practical File System Design*, free online) that describes it +end to end. + +## 2. What is deliberately not taken + +- **No ZFS storage pools / RAID-Z / vdevs.** Multi-disk redundancy is a large + subsystem that solves a problem Schunix does not have yet. +- **No btrfs-style rebalancing or online format conversion.** Enormous + 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 — + the useful part of "database filesystem" is the *index*, not the language. + WinFS spent 2003-2006 and a large team on the other interpretation and + shipped nothing. +- **No deduplication.** ZFS's dedup is famous for needing more RAM than anyone + expects. Extent refcounts give reflink/snapshot benefits without it. + +## 3. On-disk shape + +``` ++--------------------+ block 0 boot block (untouched by the FS) ++--------------------+ blocks 1..N uberblock array (128 slots, rotated) ++--------------------+ +| CoW B-tree | one tree, many key types: +| | (ino, INODE, 0) -> inode record +| | (ino, DIRENT, hash) -> directory entry +| | (ino, EXTENT, offset) -> extent mapping +| | (ino, ATTR, nameid) -> extended attribute +| | (idx, INDEX, key) -> attribute index entry ++--------------------+ +| free space | extent-based, tracked as tree keys, not a bitmap ++--------------------+ +``` + +**Uberblock array (from ZFS).** 128 slots written round-robin, each carrying a +transaction number and a checksum. Mount scans all slots and takes the +highest-numbered one that validates. This is what makes crash recovery +"pick the newest good root" instead of "replay a journal." + +**Everything is one B-tree (from btrfs).** Keyed by +`(objectid, type, offset)`, 24 bytes. Adding a feature usually means adding a +key type, not a new on-disk structure. + +**Checksums live in the parent (from ZFS).** Each internal node stores, for +every child pointer, that child's CRC32c. A block that is read is verified +against the pointer that led to it. v1 already chose CRC32c and already has +checksum fields in `dinode` and `superblock` — same algorithm, better placement. + +### Widths — every v1 limit that has to die + +| v1 | limit | v2 | +|---|---|---| +| `dirent.inum` is `ushort` | 65,535 files, total | `uint64` object ids | +| `dinode.size` is `uint` | 4 GB max file | `uint64` | +| `uint` block numbers, BSIZE 1024 | 4 TB volume | `uint64` blocks, 4096-byte | +| `DIRSIZ` 14 | 14-char filenames | variable, up to 255 | +| fixed hash table per dir | every dir ≥113 KB, capped at 119 KB | B+tree, pay per entry | +| `addrs[NDIRECT+3]` | block-at-a-time | extents with refcounts | + +Block size moves 1024 → 4096 to match modern media and make extents worthwhile. + +## 4. What already exists and gets reused + +Not starting from zero: + +- **`struct schfs_extent`** is already defined in `include/fs.h` and unused. + The extent concept is already sketched; v2 gives it refcounts and 64-bit + fields. +- **CRC32c checksum fields** already exist in `dinode` and `superblock`, and + mkfs already computes them. Same algorithm, relocated into parent pointers. +- **`kernel/fs/log.c`** is a working transaction log with `begin_op`/`end_op` + call sites throughout the FS. Under CoW the log is not needed for consistency, + but `begin_op`/`end_op` are exactly the right places to bracket a transaction + group, so the *call sites* survive even though the implementation is replaced. +- **The buffer cache** (`bio.c`) is format-agnostic and needs no change beyond + the block-size constant. + +## 5. Phasing + +Each phase leaves a bootable system. Do not start phase 2 before phase 1 is +solid — the B-tree is the load-bearing piece and everything else assumes it. + +**Phase 1 — the B-tree, in userland first.** Write the CoW B-tree as a plain C +library with a block-device abstraction, and test it on a *host* file with a +fuzz/torture harness (random insert/delete/lookup, simulated crash at every +write point, verify the tree always mounts). This is the one component where a +subtle bug is unfixable later, and testing it in the kernel is far harder. It is +also portable straight into `tools/mkfs`. + +**Phase 2 — read-only mount. DONE.** New magic, uberblock scan, tree walk, inode +and dirent key types. `tools/mkschfs` writes images; the kernel only reads them. +The system boots from a ramdisk root (see `docs/layout.md` and the ramdisk work) +so a broken disk cannot stop you from booting. + +Went further than planned in two places, both cheaply: data blocks carry +checksums too (a `CSUM` key type, as btrfs does — without it "end-to-end +checksums" would cover only metadata, which is the part least likely to rot), +and extents landed early because reserving a file's blocks in one go was +simpler than not doing it. + +Not yet done: SchFS files are not reachable through `open(2)`. The mount is +observable through `/proc/schfs` and through the kernel API in `schfs_int.h`, +but wiring it into `namei`/`readi` means the VFS work that phase 3 needs anyway. + +**Phase 3 — writes, transaction groups. DONE.** Every `schfs_k*` call that +changes anything is one transaction group, committed by writing a new uberblock +before it returns. The full write API — create, link, unlink, rename, write at +an arbitrary offset, truncate — lives in `objw.c` and is exercised by +`tools/schfs_objtest.c`. + +Two things went differently from the plan above, both for reasons worth +recording. + +*Free space is not tracked as tree keys.* Allocating from a free map that lives +in the tree mutates the tree, which allocates, which changes the map; btrfs +resolves that with a fixpoint loop and ZFS with log-structured space maps. SchFS +sidesteps it: the committed tree already says exactly which blocks are live, so +the map is **derived** by walking the tree once at mount and held only in RAM. +It cannot disagree with the filesystem, because it is computed from it, and a +crash raises no question at all. The cost is mount time proportional to metadata +size, and a ceiling on volume size set by how much bitmap fits in memory. If +mount time ever hurts, the map can be cached on disk purely as a hint, +validated against the generation and discarded on a mismatch — an addition, not +a format change. See `kernel/fs/schfs/space.c`. + +*Data blocks needed a generation stamp too.* The B-tree already rewrites its own +nodes in place within a group, since a block that no committed root can reach is +nobody's fallback. Data blocks had no such marker, so every hundred-byte write +copied a whole 4 KB block and split an extent record around it. `schfs_extent` +gained a 64-bit `gen`, and the same rule now applies to file data. + +**Phase 3½ — reachable through `open(2)`. DONE.** SchFS is a mounted filesystem: + +``` +mkdir /mnt +mount -t schfs /dev/hdb /mnt +ls /mnt ; echo hi > /mnt/tmp/w ; cat /mnt/tmp/w ; mkdir /mnt/tmp/d +``` + +The VFS grew a real dispatch layer rather than a set of `if (dev == SCHFS_DEV)` +checks. `struct fs_ops` (include/file.h) is one table per filesystem, chosen by +`iget()` from the device number and hung off the inode; v1's implementations +keep their bodies and are simply named `v1_*`. Adding a third filesystem is a +new table and nothing else. `kernel/fs/schfs/vfs.c` is SchFS's, and it is pure +translation — object ids in, inodes out — because all the filesystem logic +already lives below it. + +Three things had to change on the way, none of them SchFS's fault: + +- `struct inode.inum` and `.size` were 32-bit, capping objects at 2³² and files + at 4 GiB on a filesystem that promises far more. Both are `uint64` now, as are + `readi`/`writei` offsets and `struct file.off`. +- `struct dirent` carries a 16-bit inum and a 14-byte name, so it cannot + represent a SchFS entry at all. `getdents64` is now an fs_op: each filesystem + emits the record stream itself, and `f->off` is whatever position it needs to + resume. v1 walks its hash buckets; SchFS walks a key range and synthesises + "." and "..", which it does not store. +- Mounting is a substitution made during path resolution (`mount_add` / + `mount_cross` in `fs.c`). Nothing on either disk records it. The reverse + direction matters as much as the forward one: `..` at a mounted root has to + leave the mount, and the filesystem underneath has no idea it is mounted + anywhere. + +Three long-standing bugs surfaced the moment real commands ran against it, all +in the shared VFS rather than in SchFS: + +- `include/fcntl.h` used xv6's open flags while every program in the userland + sends Linux's. `O_APPEND` (0x400) landed on `O_TRUNC`, so `cmd >> file` + *truncated* it; `O_TRUNC` (0x200) landed on `O_CREATE`, so `cmd > file` left + whatever was past the new end in place. Nothing about either pointed at a + header. +- `sys_openat` silently dropped `O_TRUNC` and `O_APPEND` while `sys_open` + honoured both, so the same redirection behaved differently depending on which + entry point libc happened to call. +- `rmdir` had no Linux syscall number, so every Linux-ABI program got ENOSYS. + +**Phase 4 — extents with refcounts.** Enables reflink copies and snapshots +nearly for free. + +**Phase 5 — attribute index and query.** See below. + +## 6. The "SQL" part, honestly + +What you want from "works like SQL" is: *ask a question about a lot of files and +get an answer fast, without walking every directory*. That is an **index**, not +a query language. BeFS's design: + +- Files carry typed attributes (`string`, `int`, `time`, …). +- An attribute can be *indexed*: a dedicated B+tree keyed by attribute value, + mapping value → object ids. +- A query is a predicate over indexed attributes, evaluated by intersecting + index ranges. + +In SchFS this is just another key type — `(idx, INDEX, key)` — in the tree +that already exists. That is the whole reason to build phases 1-4 the btrfs way: +the "database filesystem" feature becomes a few hundred lines on top of +machinery already written and debugged, rather than a separate engine. + +A concrete `query()` syscall and a `find`-like tool come after that, and are +small by comparison. + +## 7. Honest cost + +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 +later phase compounds on it. + +This is the largest single piece of work in Schunix. It is also entirely +ordinary filesystem engineering with excellent published references +(Giampaolo for BeFS; the btrfs design papers; the ZFS uberblock/checksum-in- +parent scheme) — there is no research risk here, only volume. + +**Do this before the installer.** The installer's entire job is to create and +populate this format. Building it against v1 means building it twice. + +## 7½. Limits + +Three different things get called "the limit", and they are worth keeping apart: +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 +what you actually hit. + +### The format + +| | limit | where it comes from | +|---|---|---| +| Volume | **64 ZiB** (2⁶⁴ × 4 KiB blocks) | `uint64` block numbers | +| File | **16 EiB** (2⁶⁴ bytes) | `schfs_inode.size` | +| Files per volume | **1.8 × 10¹⁹** | `uint64` object ids | +| Hard links per file | **4.3 × 10⁹** | `uint32 nlink` | +| Filename | **255 bytes** | `SCHFS_NAME_MAX` | +| Entries per directory | no fixed limit | one tree key per name hash | +| Extent | **64 ZiB** in one record | `uint64 nblocks` | +| Tree depth | **8 levels** | `SCHFS_MAX_LEVEL` | +| Block size | **4096 bytes**, fixed | `SCHFS_BLKSIZE`; a mismatch is refused at mount | +| Transaction groups | **1.8 × 10¹⁹** | `uint64` generation, never reused | + +Directory *depth* is unbounded on disk; path resolution is what limits it. + +### This implementation + +| | limit | where it comes from | +|---|---|---| +| Volume, mounted | **64 GiB** | the in-RAM allocation bitmap: `SCHFS_SPACE_PAGES` (512) pages × 32768 blocks | +| Volume, via the buffer cache | **4 TiB** | `bio.c` addresses blocks with a `uint`, and one SchFS block spans four of them | +| RAM per mount | **8 KiB per GiB** of volume | two bitmaps, one bit per block each | +| Inline value in a leaf | **1016 bytes** | `SCHFS_MAX_INLINE` = a quarter of a node | +| Colliding names in one directory | ~**60**, sharing a hash | the packed list for one hash must fit in one inline value | +| Directory entries at 8-byte names | ~**42** per key, unlimited keys | as above | +| Records per leaf / children per node | **127 / 84** | 4 KiB minus a 32-byte header | +| Mount time | one pass over the metadata | the allocation map is derived, not stored | + +The 64 GiB mount ceiling is the one that bites first, and it is one constant: +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 +`struct schfs_vol`, which the kernel holds as static storage. + +### The rest of Schunix + +These are VFS and driver limits rather than SchFS ones: + +- `MAXPATH` caps a path at **128 bytes**. +- `NMOUNT` allows **8** mounts. +- The IDE driver is 28-bit LBA: **128 GiB** per disk. +- A single `read`/`write` call is capped at **4 GiB** (`n` is a `uint`); the + file itself is not. + +The two that used to be here — a 16-bit inode number in `struct dirent` and a +32-bit `inum`/`size` in `struct inode` — are gone. `getdents64` is a per- +filesystem operation now, so SchFS emits its own records with 64-bit inode +numbers and names up to 255 bytes, and the inode carries 64-bit numbers and +sizes throughout. + +## 8. What exists now + +``` +include/schfs.h on-disk format + compile-time layout assertions +kernel/fs/schfs/btree.{c,h} the copy-on-write B-tree and its cursor +kernel/fs/schfs/schfs_int.h volume + object layer interface +kernel/fs/schfs/space.c allocation bitmap, derived from the tree at mount +kernel/fs/schfs/vol.c uberblock ring: open, format, commit +kernel/fs/schfs/obj.c read side: inodes, dirents, extents, path lookup +kernel/fs/schfs/objw.c write side: create, link, unlink, rename, write +kernel/fs/schfs/kmount.c kernel: block device, mount, transaction bracket +kernel/fs/schfs/vfs.c the fs_ops table: SchFS behind open/read/write +tools/mkschfs.c build an image from a directory tree +tools/schfs_fsck.c verify, list, extract +tools/schfs_test.c B-tree torture harness +tools/schfs_objtest.c object layer: files, directories, space accounting +tools/schfs_roundtrip.sh end-to-end filesystem test +tools/mutate.sh mutation-tests the suites themselves +tools/bootcheck.ps1 boots under QEMU and drives the shell +``` + +Everything except `kmount.c` is compiled *both* into the kernel and into the +host tools, so the writer and the reader cannot drift apart: there is one +implementation of the format and nothing to disagree with. + +### Running the tests + +``` +make schfs-check all three suites +make schfs-test B-tree only +make schfs-objtest object layer only +make schfs-image-test round-trip only +``` + +`make schfs-check` after touching anything under `kernel/fs/schfs`. + +The round-trip's oracle is the host's own filesystem: an image is built from a +directory tree, extracted with a separate program, and `diff -r`'d against the +original. It also asserts hard-link counts (which `diff` cannot see), checks +that rebuilding produces byte-identical output, and runs the whole thing a +second time with the name hash cut to 6 bits so the packed-dirent collision path +— which a 64-bit hash would never reach — is actually exercised. + +`schfs_objtest` runs against a memory-backed volume, so a full +create/write/delete/remount cycle takes milliseconds. Its most important check +is the least glamorous: after deleting everything, free space must be back to +exactly what it was on an empty volume. Every other test in the suite still +passes on a filesystem that leaks a block on every delete. + +`tools/mutate.sh` injects six deliberate bugs and fails if any of them goes +undetected. It is how the suites are kept honest; see the note in §9. + +### Verifying on real hardware + +``` +make ramroot root from RAM, so device 1 is free +make build/schfs.img +make qemu-schfs then, at the shell: cat /proc/schfs +``` + +`.\run.ps1 -SchFS` does the same on Windows, and `tools\bootcheck.ps1 -SchFS` +does it unattended and asserts on the transcript. + +## 9. Things learned the hard way + +Recorded because each one cost real time and none is obvious from the code. + +- **The root's object id must be reserved.** `next_objectid` started at + `SCHFS_FIRST_OBJECTID`, which *is* the root's id, so the first directory + created silently became the root. It then contained itself, and every tree + walk recursed until the stack ran out. `schfs_fsck --check` now detects + directory loops explicitly rather than crashing. +- **Cursor buffers alias.** A range callback gets a pointer into the cursor's + block buffer, and almost every readdir caller immediately looks the entry up, + which overwrites it. Directory iteration copies each entry out before calling + back. Extracting a tree with directories reparented under their own children + is what this looks like when it goes wrong. +- **A 4096-byte block does not fit on a 4096-byte kernel stack.** The cursor + exists precisely to avoid one block buffer per tree level, but + `schfs_vol_open` still kept a whole uberblock as a local and blew the stack on + the first boot. The kstack canary caught it cleanly. +- **Extents only merge if you allocate the run first.** Writing an extent record + allocates blocks for its own copy-on-write path, so allocating data one block + at a time guarantees the blocks are never adjacent and every block needs its + own extent. `schfs_file_reserve` claims the whole run up front; an 822 KB + binary is one extent instead of 201. +- **Freed blocks are reusable during a build.** Copy-on-write forbids reusing a + released block because the previously committed tree still points at it — but + a build has committed nothing. Recycling them cut the test image from 3596 + blocks to 374. +- **Reproducibility dies from atime.** mkschfs reads every source file, which + updates its atime, so copying atime into the image made two builds of the same + tree differ. All three timestamps come from mtime. diff --git a/docs/drivers.md b/docs/drivers.md new file mode 100644 index 0000000..a120c61 --- /dev/null +++ b/docs/drivers.md @@ -0,0 +1,130 @@ +# Drivers + +How hardware gets found, claimed and used, and where drivers that are not part +of the build will attach. + +--- + +## 1. The device model + +There is one list of everything attached, whatever bus found it: +`include/device.h` and `kernel/dev/device.c`, readable at `/proc/devices`. + +``` +name bus class driver device +kbd0 platform input ps2kbd PS/2 keyboard +mouse0 platform input ps2mouse PS/2 mouse +uart0 platform other uart8250 16550 serial port +ide0 platform storage ide ATA disk controller +vga0 pci display vga display controller +``` + +Before this there were two registries in `kernel/drivers/registry.c` — an array +of PCI drivers and an array of USB drivers — with nothing that knew about both. +That is sufficient for *binding* and useless for the three things wanted next. + +**Enumeration.** "What is in this machine, and what claimed it" had no answer +covering a USB disk and a PCI display at once. A device manager is exactly that +question. + +**Classes.** A compositor should ask for *the display* and not care whether that +is the VBE framebuffer or virtio-gpu. Without a class every consumer hardcodes a +driver, and adding the second driver means editing the consumers — which is how +a framebuffer address ended up hardcoded in three places here once already. + +**A boundary for drivers that are not compiled in.** They have to attach +somewhere that is not an array fixed at link time. + +Two vocabularies are kept deliberately separate: a device's **bus** is +provenance (`platform`, `pci`, `usb`), its **class** is capability +(`display`, `input`, `storage`, `net`, `bus`). A USB disk and a SATA disk are +both `storage` despite sharing no numbering at all. Where a driver claims a +device, the driver's opinion wins over the descriptor's: `struct usb_driver` has +a `devclass` field separate from the USB interface class, because the descriptor +says what the device *claims* to be and the driver knows what it *made* of it. + +It is a flat list with a bus tag, **not** a device tree. Nothing yet needs to +walk a hierarchy, and a tree nobody traverses is just a harder list. Hot-unplug +would need more; the `in_use` flag is the hook. + +Platform devices are registered in one place +(`platform_register_devices()` in `registry.c`) rather than inside each driver's +init, for the same reason the driver arrays are written out by hand: a list you +can read beats a list assembled by side effects. + +--- + +## 2. Where this is going: a hybrid model + +The intended shape is the NeXTSTEP/macOS one rather than Linux's — a device is +an object with a class and an ops vtable, and consumers talk to the class. + +Two things often get bundled together as "loadable drivers" and they are +separable: + +| | | +|---|---| +| **Loadable modules** | A stable driver ABI, drivers as files loaded at runtime (`.sys`, `.kext`). A linker/loader job on top of the model above. | +| **Drivers out of kernel** | Drivers as user-space processes (macOS DriverKit, which is why kexts are being retired). An IPC and memory-mapping job; the `AF_UNIX` and shared-memory work it needs already exists. | + +The second is more in the spirit of the SchAPI direction and is slower and +larger. Neither is built yet. What exists is the attachment point they both +need. + +--- + +## 3. Linux drivers + +**Decided 2026-08-08.** Linux drivers are not shipped with Schunix and never +will be. The user may install one on their own machine, through a device +manager or equivalent, and Schunix will load it. + +The licensing reasoning matters and is worth stating exactly, because it is +easy to get wrong in both directions: + +- **Distribution is what triggers the GPL.** Shipping a GPL-2.0-only driver in + an Apache-2.0 image is what cannot be done — see [licensing.md](licensing.md) + §2. A user obtaining a driver themselves and loading it on their own machine + is their act, not ours, and is not a distribution by us. +- **Implementing a loader is not copying.** Writing support for a module format + and a driver ABI from published documentation produces our own work. It is a + clean-room implementation, and it stays one only if it is written from + documentation rather than transcribed from Linux source. Reading Linux to + understand *hardware* is fine; translating its code is not, whatever the + identifiers say. + +So the rule for this subsystem is the same as everywhere else in the tree: the +loader is ours and Apache-2.0, what it loads is the user's business, and nothing +GPL ever enters an image we build. `RAMDISK_EXCLUDE` and `NOTPORTS` are the +existing mechanisms for keeping that true mechanically rather than by intention. + +--- + +## 4. Adding a driver today + +1. Write `kernel/drivers///.c` exporting a + `struct pci_driver` or `struct usb_driver`. One directory per driver, so a + driver that grows a register header, a second source file or a firmware blob + has somewhere to put it: + + kernel/drivers/ + registry.c + gpu/vga/ gpu/virtio_gpu/ + net/e1000/ + bus/xhci/ + usb/core/ usb/hid/ usb/storage/ usb/hub/ + +2. Declare it in `kernel/drivers/registry.c` and add it to the array. +3. Add the object to `KERN_DRIVERS` in the `Makefile`. + +Registration in the device model is automatic — `pci_bind()` and +`usb_bind_all()` publish whatever they claim, so a driver cannot forget to. Set +`devclass` on a USB driver, or the device lands in `other`. + +The best source for a new driver is the **specification**, not another kernel: +xHCI, AHCI, virtio, NVMe and the Intel datasheets are public documents with no +licence on what you write from them. `kernel/drivers/bus/xhci/xhci.c` came from the spec, and so did +`net/e1000/` and `gpu/virtio_gpu/`. Where a *table* of constants is genuinely +faster to transcribe than to retype from a PDF -- device IDs, register offsets -- +taking it from a BSD tree is fine after the licence check, and goes in `NOTICE`. +That is data; the logic stays ours. diff --git a/docs/layout.md b/docs/layout.md new file mode 100644 index 0000000..6b39196 --- /dev/null +++ b/docs/layout.md @@ -0,0 +1,175 @@ +# Repository layout + +One rule holds the whole thing together: + +> **A directory contains either hand-written source or generated output. Never both.** + +Everything generated lives under `build/`. Delete `build/` and you lose nothing +that can't be rebuilt (except upstream tarballs, which live in `dist/` and are +deliberately kept out of `clean`). + +``` +schunix/ +├─ boot/ Stage 1 MBR + stage 2 loader (splash, F8 menu, kernel load) +├─ kernel/ The kernel, by subsystem: arch/ core/ dev/ fs/ proc/ sys/ +├─ include/ Headers shared by kernel, userland, and tools/mkfs +├─ lib/ First-party userland runtime: _start glue, syscall stubs, +│ the initcode blob embedded in the kernel, user.ld +├─ cmd/ First-party programs — one directory per program: +│ cmd//main.c → sysroot/bin/ +├─ ports/ Third-party software — one directory per port. +│ Contains ONLY a Makefile and optional patches/. +├─ projects/ Things that run ON Schunix rather than things that ARE it: +│ the compositor, window manager, desktop, and installer. +│ Not part of the kernel build. See projects/README.md. +├─ tools/ Host-side helpers, SOURCE ONLY: mkfs.c, the SchFS test +│ suites, sign.pl, vectors.pl, and the PowerShell harnesses. +│ Their binaries build into build/tools/ -- this directory +│ used to hold both, which is the one rule this layout has. +│ tools/loc.ps1 counts how much of the tree is first-party. +├─ sysroot/ Staging for the disk image. etc/ is hand-maintained; +│ bin/ lib/ sbin/ are populated by `make sysroot-install`. +├─ dist/ Upstream tarball cache. Survives `make clean`. +├─ Refrence/ A FreeBSD checkout (Refrence/freebsd-src), kept as reference +│ material and a parts bin. Never built, never in an image. +│ Read it when a specification is ambiguous; copy from it only +│ after the per-file licence check in docs/licensing.md. +│ A full clone is 2.1 GB and a previous NetBSD one was deleted +│ for that reason. Only sys/dev, sys/net and sys/netinet have +│ ever been read, so a sparse checkout is ~100 MB: +│ git clone --filter=blob:none --sparse Refrence/freebsd-src +│ git -C Refrence/freebsd-src sparse-checkout set │ sys/dev sys/net sys/netinet +├─ src-trunk/ A NetBSD checkout, kept as reference material and a parts +│ bin. NOT built, NOT installed, and it must never reach an +│ image. Copying from it is governed by the per-file licence +│ check in docs/architecture/schapi.md §5 — NetBSD is not +│ uniformly licensed. +├─ docs/ Design docs +└─ build/ ALL generated output (see below) +``` + +## build/ + +``` +build/ +├─ boot/ bootblock, stage2 +├─ kernel/ object files, the linked kernel, kernel.asm +├─ lib/ libc glue objects, initcode blob +├─ cmd/ linked first-party programs +├─ fs.img the filesystem image +└─ ports// + ├─ src/ extracted upstream tarball + ├─ obj/ out-of-tree build directory + └─ prefix/ install prefix (musl's headers and libs land here) +``` + +## Adding your own program + +```sh +mkdir cmd/hello +$EDITOR cmd/hello/main.c # include "types.h", "user.h", ... +``` + +Then add `hello` to `CMDS` in the root `Makefile`. It gets linked against +`lib/` and installed to `sysroot/bin/hello` by `make sysroot-install`. + +## Adding a third-party port + +```sh +mkdir ports/foo +$EDITOR ports/foo/Makefile # start with `include ../mk/port.mk` +``` + +`port.mk` derives everything from the directory name — it gives you `$(SRCDIR)`, +`$(BUILDDIR)`, `$(PREFIX)`, `$(DISTDIR)`, `$(SYSROOT)`, and `$(MUSL)` (the +musl install prefix that every port links against). Follow the pattern in +`ports/mksh/Makefile`: fetch tarball to `$(DISTDIR)`, extract to `$(SRCDIR)`, +build into `$(BUILDDIR)`, install into `$(SYSROOT)`. `clean` removes +`$(PORTDIR)` and nothing else. + +`ports/Makefile` picks up the new directory automatically. If it links against +musl, add `foo: musl` there so ordering is right. + +Local modifications to upstream go in `ports/foo/patches/*.patch` and are +applied after extraction — never by editing files under `build/`, which are +wiped on every clean. + +## Ramdisk root + +```sh +make # normal: root on the IDE disk (build/fs.img as hdb) +make ramroot # root from a SCHFS image linked into the kernel +``` + +`make ramroot` builds `build/fs-ram.img` (default 6000 blocks, override with +`RAMDISK_BLOCKS=`) and links it into the kernel, so the system boots to a shell +with **no data disk attached at all**. That is what makes destructive work on +the real disk survivable — reformatting it, or bringing up a new on-disk format +— and it is the first piece of the installer. + +Use `make ramroot`, not `make RAMROOT=1`: the flag changes `CFLAGS`, which make +cannot see, so objects compiled for one setting would be silently reused for +the other and `ROOTDEV` would point at the wrong device. The target drops the +compiled objects first. Switching back is the same — plain `make` after a +`ramroot` build reuses stale objects, so run `rm -rf build/kernel build/lib +build/cmd` first (or just `make clean`). + +The image costs boot time: stage2 loads the kernel by PIO one sector at a time, +so a 6 MB ramroot kernel is visibly slower to start than the 350 KB default. + +**What may go in it is a licensing question, not only a size one.** The image is +linked into the kernel binary, so anything in `sysroot/` when it is built becomes +part of a distributable artifact. A file staged there under a licence that +cannot be combined with Apache-2.0 does not merely ride along — it makes the +kernel itself undistributable. `RAMDISK_EXCLUDE` in the Makefile is the list of +paths kept out, and enforcing it in the build rather than relying on someone +remembering to unstage something first is deliberate. It has been needed once +already: a 33 MB test payload landed in `sysroot/` and both overflowed the image +and would have gone into the kernel binary. + +Three knobs, all in the Makefile, none of them `FSSIZE`: + +| | | +|---|---| +| `RAMDISK_BLOCKS` | image size, 6000 (× 1 KiB `BSIZE`) | +| `RAMDISK_NINODES` | inode table size, 2000 | +| `RAMDISK_EXCLUDE` | sysroot-relative paths to omit, with their subtrees | + +`RAMDISK_NINODES` is worth knowing about because the inode table is +*preallocated*: mkfs's default of 12000 inodes cost 1501 of the 6000 blocks — a +quarter of the image — to describe about 260 files. At 2000 it costs 251, and +metadata overall fell from 1596 blocks to 345. + +If `mkfs` reports the image is full, read its message: it now prints the +metadata breakdown and names the right knob for whichever image overflowed. It +used to say only "increase FSSIZE in param.h", which is a constant that has +nothing to do with the ramdisk root and sends you to the wrong file. + +## Two things that will bite you + +**`ld -r -b binary` derives symbol names from the input file's path.** The +kernel embeds two blobs this way (`initcode`, `entryother`), and the root +Makefile has `--redefine-sym` lines mapping e.g. +`_binary_build_lib_initcode_start` → `_binary_initcode_start`. Move either +blob's build location and those symbol names change; update the Makefile to +match or the kernel fails to link. + +**`STAGE2_SECTORS` now lives in exactly one place: the root `Makefile`.** It used +to be written out by hand in five — `boot/bootasm.S`, `boot/stage2main.c`'s +`readseg()`, the `dd ... seek=` offset, and twice more inside `tools/mkiso.sh` +(its stage2 size assertion and `-boot-load-size`). This note used to warn you to +keep three of them in step and did not know about the other two. + +Raising it from 24 to 48 for the boot logo demonstrated the problem: the `dd +seek=25` offset stayed behind, so the kernel was written directly over stage2's +own tail. Now the Makefile passes `-DSTAGE2_SECTORS` to both boot sources, +derives the padding budget and the `seek=` offset from the same variable, and +exports it to `mkiso.sh`. The `#define`s that remain in the two boot sources are +`#ifndef`-guarded fallbacks so those files still read sensibly alone; the +Makefile always wins. + +Two things still fail the build rather than silently misbooting, and should stay +that way: `tools/padstage2.pl` errors if stage2 overflows its budget instead of +truncating it, and `boot/stage2main.c` static-asserts that stage2 cannot reach +the multiboot kernel-search buffer at `0x10000` — which puts the hard ceiling at +65 sectors, since stage2 loads at `0x7E00`. diff --git a/docs/licensing.md b/docs/licensing.md new file mode 100644 index 0000000..b3a4df4 --- /dev/null +++ b/docs/licensing.md @@ -0,0 +1,241 @@ +# Licensing + +The one page to check before copying anyone else's code into Schunix. + +Referenced from `LICENSE`, `LICENSE.MIT` and `NOTICE`, all three of which +pointed here long before this file existed. + +--- + +## 1. Schunix is Apache-2.0 + +Copyright Nexoniarz. See `LICENSE`. + +Apache-2.0 was chosen over MIT/BSD for one reason that actually matters at OS +scale: it contains an **express patent grant** and a patent-retaliation clause. +MIT and BSD are silent on patents, which means a contributor can hand you code +and later assert a patent over it. For a kernel that is intended to accept +outside contributions, that silence is the expensive kind. + +What that grant means in practice: Apache-2.0 §2 gives everyone a perpetual, +worldwide, irrevocable licence to reproduce, modify, sublicense and distribute +Schunix. Any additional restriction stated elsewhere — in a README, a website, +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 +(a bespoke proprietary licence, or something like BUSL-1.1 with a conversion +date), not a wording change, and it means giving up the Apache grant. + +--- + +## 2. What can be copied in + +| Licence | Verdict | Obligation | +|---|---|---| +| Public domain, 0BSD, CC0 | **Yes** | None | +| MIT, ISC | **Yes** | Keep the notice | +| BSD 2-clause | **Yes** | Keep the notice | +| BSD 3-clause | **Yes** | Keep the notice; no endorsement claims | +| BSD **4-clause** (advertising) | **Avoid** — see §3 | Notice *and* an acknowledgement in advertising materials | +| Apache-2.0 | **Yes** | Keep NOTICE contents | +| MPL-2.0 | Case by case | File-level copyleft; keep those files separate | +| **GPL-2.0-only** | **No** | — | +| **GPL-3.0 / LGPL-3.0** | **No** for linked code | — | + +**Every "yes" above requires an entry in `NOTICE`.** That file is the project's +attribution record and the thing that makes the permissive licences actually +satisfied rather than merely tolerated. + +### Why GPL-2.0-only is a hard no + +Apache-2.0 imposes conditions GPLv2 treats as "further restrictions" under its +§6 — principally the patent-retaliation term. The FSF and the ASF agree on +this: **Apache-2.0 code and GPL-2.0-only code cannot be combined into one +distributable work.** It is not a matter of taste or of how carefully the files +are kept apart in the tree; it is that the combined binary cannot satisfy both +licences at once. + +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 +Schunix does not. + +**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 +specification rather than ported. + +--- + +## 3. NetBSD in particular + +`src-trunk/` is a NetBSD checkout kept as reference material and a parts bin +(see [architecture/schapi.md](architecture/schapi.md) §5). NetBSD is **not +uniformly licensed**, and the difference matters per file: + +| Template | Status | +|---|---| +| 2-clause BSD — modern NetBSD Foundation files | **Fine** | +| 3-clause, "Regents of the University of California" | **Fine.** Berkeley formally rescinded the advertising clause in 1999 | +| 4-clause with the advertising clause, **non-UC** copyright holder | **Avoid.** Berkeley's rescission covers Berkeley's copyright, not other people's | + +The last row is real, not hypothetical. Measured on this checkout: + +``` +sys/kern 26 of 220 files carry the advertising clause +sys/dev 500 of 3565 +lib/libc 101 of 1575 +sys/net 5 of 180 ← the TCP/IP stack is nearly clean +``` + +4-clause is still permissive and still redistributable; the burden is an +advertising obligation that accumulates quietly and is tedious to honour +properly. Prefer a 2-clause or UC-Regents file. If a 4-clause file is genuinely +the right answer, it goes into `NOTICE` with the full clause quoted. + +Check before copying, not after: + +```sh +grep -l "All advertising materials" +``` + +### And check *whose* clause it is + +A file can carry several licence blocks from several copyright holders. Finding +the advertising clause is only half the check — Berkeley's rescission covers +Berkeley's copyright and nobody else's, so the question is always *whose* +clause you found. + +Measured on `src-trunk`, the networking tree: + +``` +sys/net 106 files, 5 with the advertising clause +sys/netinet 121 files, 25 " " " +sys/netinet6 51 files, 5 " " " +``` + +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`, +`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. + +**But `tcp_input.c` and `tcp_output.c` are not.** Their advertising clause +belongs to the **WIDE Project** (the KAME IPv6 people), whose copyright sits at +the top of the file; the UC block is a separate licence further down. Berkeley +never spoke for WIDE, so the rescission does not reach it. The two most +valuable files in the stack are the two encumbered ones. + +That is not fatal — 4-clause is still permissive — but it is exactly the case +where a **second BSD tree earns its disk space**: FreeBSD's TCP has been +through a relicensing effort NetBSD's has not, so the same file there may well +be 2-clause. Check it the same way before assuming either: + +```sh +grep -n "Copyright" | head # who claims it +grep -n -B6 "All advertising" # whose clause is it +``` + +### FreeBSD's TCP is clean where NetBSD's is not + +Checked, 2026-08-08, exactly that way. Against FreeBSD `main`: +`sys/netinet/tcp_input.c` contains **no advertising clause at all**. Its +copyright holders are the UC Regents, Swinburne University, Lawrence Stewart, +the FreeBSD Foundation and Juniper Networks -- all BSD-2 or BSD-3. + +So if BSD networking code is taken, it must come from **FreeBSD, not NetBSD**, +and the specific reason is TCP. This reverses the earlier assumption in +`docs/roadmap.md` that NetBSD was the intended starting point; NetBSD remains +the better-written reference to *read*, but FreeBSD is the one that can be +copied from. + + +### The third option: lwIP + +Before porting either BSD stack, weigh **lwIP** against both. Verified +2026-08-08 from its `COPYING`: 3-clause BSD, Swedish Institute of Computer +Science, **no advertising clause anywhere in the file**. Compatible, one NOTICE +entry, done. + +The licence is the smaller half of the argument. The larger half is that +FreeBSD's `sys/netinet` is not a library -- `tcp_input.c` alone is 122 KB and +reaches into mbufs, `epoch(9)`, netisr, VNET, `uma(9)`, sockbufs, inpcb hash +tables and FreeBSD's locking. Taking it means porting FreeBSD's kernel +infrastructure first and finding the TCP somewhere underneath, which is the same +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 +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 +brings ARP, IPv4, ICMP, UDP, TCP, DHCP and DNS. + +### Fonts + +Chosen 2026-08-09, both licences checked at source rather than assumed: + +| Font | Where | Licence | +|---|---|---| +| Roboto | desktop, window manager, compositor | **Apache-2.0** | +| JetBrains Mono | terminal, TTY | **SIL OFL 1.1** | + +Roboto is the same licence as Schunix, so it is the easy case: a NOTICE entry +and nothing else. + +OFL is permissive and bundling is precisely what it is for, with two conditions +worth knowing before anyone subsets or converts a font: + +- **The font stays under OFL** even inside an Apache-2.0 system. It does not + infect anything else; it just cannot be relicensed. +- **It may not be sold on its own.** Shipping it as part of an OS is fine. +- **Reserved Font Names.** JetBrains Mono declares *none* -- its copyright line + names no reserved name -- so a modified version may keep the name. Most OFL + fonts do reserve theirs, and then a derivative must be renamed. + Pre-rasterising a font into bitmaps at build time **is** a modification, so + this is not a theoretical point for this project. + +--- + +## 4. Things that are deliberately not shipped + +Some code is fine to *build and run locally* and impossible to *distribute* +with Schunix. Keeping the distinction sharp is what stops it eroding: + +- **`Refrence/`** — a FreeBSD checkout (`Refrence/freebsd-src`), kept as + reference material and a parts bin. Never built, never in an image. The + directory name is spelled as it is on disk; renaming it is a one-line change + if it ever grates. +- **`src-trunk/`** — a NetBSD checkout, same rules. Currently absent; it was + deleted for disk space and can be re-fetched sparsely if needed. +- **`dist/`** — upstream tarballs and other downloaded blobs. Cached so a + rebuild never needs the network; not part of any image, and not all of it is + redistributable. + +The mechanisms that keep this from eroding, since good intentions have already +failed once here: + +- `NOTPORTS` in `ports/Makefile` — a port that lives in the tree but is never + built by `make`. +- `RAMDISK_EXCLUDE` in the root `Makefile` — paths kept out of the ramdisk root. + This one matters more than it looks: the ramdisk image is linked *into the + kernel binary*, so anything sitting in `sysroot/` when that image is built + becomes part of a distributable artifact. A GPL-2.0 or non-redistributable + file staged there does not merely ride along, it makes the kernel itself + undistributable. + +A previous acceptance test — a ported 1993 shooter, GPL-2.0 engine on +non-redistributable shareware data — was carried under exactly these rules and +has since been removed. It is worth recording *why* it was safe: it was never in +`PORTS`, and its 33 MB of data was excluded from the ramdisk. It is equally +worth recording that the safety depended on two separate opt-outs staying +correct, which is a lot of standing risk for a test that had stopped finding +bugs. See `docs/roadmap.md` Phase 7. + +--- + +## 5. Specifications are not code + +A published specification carries no copyright over an independent +implementation of it. The xHCI, USB, PCI, fbdev and ELF specifications were all +read and implemented directly, which is why those drivers have no licence +entanglement at all despite equivalents existing in both Linux and BSD. + +When a subsystem is small enough to write from the spec, that is usually the +cheapest option in the long run — not because copying is hard, but because a +copied file is a file to be understood, attributed and maintained forever. diff --git a/docs/roadmap.md b/docs/roadmap.md new file mode 100644 index 0000000..c29fa10 --- /dev/null +++ b/docs/roadmap.md @@ -0,0 +1,481 @@ +# Roadmap + +Written 2026-08-04, from the plan: USB, GPU, fonts, networking and sockets, +then a compositor (Schcom), a window manager (SchWM) and a desktop (SchDE), +plus an installer and a `.sip` package format. + +This file records two things that are easy to lose: the *order* the work has +to happen in, and the decisions that constrain it. + +**Superseded in direction, not in order.** Schunix is now aimed at being a +*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 +personality, and a native API (**SchAPI**) above it. See +[architecture/schapi.md](architecture/schapi.md). That decision changes what +the phases below are building towards; it does not reorder them, and it does +not start until the tree builds and boots natively again. + +That assumption about §1 has since been revised. NetBSD's TCP/IP stack was the +intended starting point; the per-file licence check found that NetBSD's +`tcp_input.c` and `tcp_output.c` carry the WIDE Project's 4-clause advertising +clause, which Berkeley's rescission does not reach. FreeBSD's equivalent is +clean, and lwIP is cleaner still and a far smaller port. See Phase 2 below and +docs/licensing.md §3. + +--- + +## 1. Where drivers can come from + +**BSD: yes. Linux: no.** This is not a preference, it is a licence +incompatibility, and it decides the whole driver strategy. + +The reasoning — Apache-2.0's patent terms counting as "further restrictions" +under GPLv2 §6, which is why the two cannot be combined and redistributed — is +in [licensing.md](licensing.md), along with the per-licence table and the +NetBSD-specific rules. Read it before copying anything. The short version: +BSD-2 and BSD-3 code can be used directly with a `NOTICE` entry; GPL-2.0-only +code can never be, at any distance. + +There is a third source that is better than either: **the specifications**. +xHCI, AHCI, virtio, NVMe, the Intel e1000 and i915 datasheets are all public +documents with no licence attached to what you write from them. That is where +`kernel/drivers/xhci.c` came from. + +One caveat about "port it from BSD" as a plan, learned by looking: FreeBSD's +`sys/dev/usb` is roughly 100k lines welded to newbus, devclass, `bus_dma`, +callouts, taskqueues and FreeBSD's locking. Porting it means porting +FreeBSD's device framework first and finding the USB stack somewhere +underneath. NetBSD's is more portable and the same argument applies with a +smaller multiplier. **BSD is far more valuable as the reference you check +yourself against than as the code you paste.** Read it when the spec is +ambiguous — which it is, often — and write your own. + +Reading Linux for *understanding* is fine and normal. Translating a Linux +driver function-by-function is not; the result is a derivative work whatever +the variable names say. + +--- + +## 2. Ordering, and why it is not the order it was asked in + +The requested order was USB → GPU → fonts → network → GUI → installer. That +is a reasonable order by *interest*. By dependency it wants one change: + +**Shared driver infrastructure comes before all of it.** USB, any GPU beyond +the VBE framebuffer, and any NIC all need the same three things, none of +which existed: + +- a way to register an interrupt handler at runtime (`kernel/dev/irq.c`) +- physically contiguous memory for rings and descriptors + (`kernel/core/dma.c`) +- PCI capability walking and MSI (`kernel/dev/pci.c`) + +That work is done. It was the first step of USB, not a detour from it. + +The other honest note: **USB is the item that does least for the GUI.** Under +QEMU there is already a PS/2 keyboard and mouse, so USB buys real hardware +support — which matters, but not for getting Schcom on screen. Sockets and +raw input events are what actually block the compositor. USB is being done +first because it was asked for first; the ordering below reflects that with +the dependencies fixed. + +--- + +## 3. The plan + +### Phase 1 — USB *(done, bar the boot path)* + +- [x] Shared infrastructure: IRQ registration, DMA arena, PCI capabilities +- [x] xHCI: reset, DCBAA, command ring, event ring, scratchpad +- [x] Port enumeration, Enable Slot, Address Device, control transfers +- [x] Device descriptors read from real devices (USB2 and USB3 paths) +- [x] Configuration and interface descriptor parsing, `SET_CONFIGURATION` +- [x] Interrupt endpoints, driven from the IRQ handler +- [x] HID boot protocol: keyboard and mouse into the existing input paths +- [x] Bulk endpoints, bulk-only transport, SCSI, a block device at + `USBDISK_DEV` — a superblock reads back through `bread()` +- [x] Hubs — route strings, hub slot contexts, per-port reset and power. A + mouse behind a hub enumerates a tier deep, which is what proves it +- [ ] Making a USB disk mountable and bootable (needs the root device to be + selectable rather than compiled in) + +### Phase 2 — Sockets, raw input, and networking + +Do sockets **before** the network stack. **Unix domain sockets are what Schcom +needs** — clients and compositor have to pass messages and share buffers, and +a pipe cannot carry an shm handle. Unix sockets are also far simpler than +TCP/IP, so they are the right thing to build the socket layer's shape around. + +- [x] `socket`/`bind`/`listen`/`accept`/`connect`/`send`/`recv` syscalls, at + their real Linux numbers — they were `NO_LINUX` stubs, so a musl program + calling `socket()` never even reached the stub +- [x] `AF_UNIX` SOCK_STREAM, `socketpair`, `shutdown`; names live in a table + rather than the filesystem (see the comment at the top of + `kernel/net/unix.c` for what that costs) +- [x] Raw input events — `/dev/input/event0` and `event1`, Linux evdev layout, + fed by the PS/2 keyboard and mouse and by USB HID. The console keeps its + own path; both consumers see every key +- [ ] `SCM_RIGHTS` for passing descriptors. Possibly unnecessary: an shm id is + an integer and travels fine over a stream socket, so this waits until + something actually needs to pass an open file +- [x] e1000 driver — `kernel/drivers/net/e1000.c`, from Intel's public manual + 317453. MAC from EEPROM, transmit and receive rings, link detection. + Run with `-netdev user,id=n0 -device e1000,netdev=n0`. + **Verified to carry real traffic**: `echo n > /proc/sysrq` sends a + hand-built ARP request and receives the gateway's reply, which exercises + the descriptor formats, the DD handshake, the tail bookkeeping, the DMA + addresses and the MAC filter in one exchange. That check came before any + protocol stack on purpose -- a stack on an unproven driver fails in ways + indistinguishable from its own bugs +- [ ] ARP, IPv4, ICMP, UDP, then TCP. **Not written from scratch** -- decided + 2026-08-08. Writing TCP is the one part of this where doing it yourself is + a bad trade: it is not the packet format that is hard, it is congestion + control, retransmission, window management and twenty years of accumulated + corner cases that only appear against a real peer. + **Preferred base: lwIP** (BSD-3, no advertising clause, verified). It was + written for exactly this situation -- a small OS with a raw Ethernet + driver -- and its port layer is a handful of files. + **If BSD instead: FreeBSD, not NetBSD.** NetBSD's `tcp_input.c` carries + the WIDE Project's 4-clause advertising clause; FreeBSD's has none. But + FreeBSD's `sys/netinet` is not a library -- it reaches into mbufs, + epoch(9), netisr, VNET and uma(9), so taking it means porting FreeBSD's + kernel infrastructure first. See docs/licensing.md §3. +- [ ] `AF_INET` on top of the same socket layer + +### Phase 3 — GPU + +"Basic GPU driver" has a right answer and a wrong one. The wrong one is +starting with Intel or AMD hardware: modern GPU drivers are enormous and most +of the size is mode setting, power management and a command submission model +that only pays off once there is something to submit. + +- [x] **virtio-gpu**, 2D. `kernel/drivers/virtio_gpu.c`, written from the OASIS + specification. Full path: GET_DISPLAY_INFO, RESOURCE_CREATE_2D, + RESOURCE_ATTACH_BACKING, SET_SCANOUT, TRANSFER_TO_HOST_2D, + RESOURCE_FLUSH. Bound as the display class ahead of the VBE framebuffer. + Run with `-vga std -device virtio-gpu-pci`; keep `-vga std`, because the + bootloader's splash goes through VBE and there is no virtio path that + early +- [ ] A `/dev/dri`-style device with mode setting, so resolution stops being + whatever the bootloader asked VBE for +- [ ] Double buffering and vblank — Schcom needs both to not tear +- [ ] Only then: real hardware, and only 2D/blit acceleration + +### Phase 4 — Fonts + +This is a bigger job than it sounds and it should be sized honestly. A TTF/OTF +rasteriser needs: `cmap`/`glyf`/`loca`/`head`/`hmtx` table parsing, quadratic +béziers for TrueType outlines and *cubic* ones for OpenType/CFF, a scanline +rasteriser with anti-aliasing, and a glyph cache. + +The bigger structural problem is that the console assumes a fixed 8×16 cell +grid throughout — `vga_putc`, the cursor, the ANSI erase operations. Variable +width text is not a font change, it is a text-rendering layer. + +- [x] **The text layer** — `include/text.h` + `kernel/dev/text.c`. Glyph + metrics, a `struct surface` target so a compositor can draw off-screen, + 8-bit coverage with real blending, UTF-8, and `font_ops` so a rasteriser + plugs in as a second provider. This was the actual blocker: the font was + never the problem, the character-cell grid was. +- [ ] Port the console onto it and delete the cell grid +- [x] A TrueType rasteriser — `kernel/dev/ttf.c`, glyf outlines, composite + glyphs, cmap format 4, anti-aliased scanline fill. Host harness at + `tools/ttftest.c` +- [x] A glyph cache — direct-mapped over ASCII into a 48 KB pool +- [ ] Load a font from disk and point the console at it, deleting the cell grid +- [ ] CFF/Type 2 charstrings, so OTF fonts work too (a separate `font_ops` + provider; a bytecode interpreter, not an extension of the glyf path) +- [ ] A rasteriser. `stb_truetype.h` is public domain and therefore usable + as-is if wanted; writing one is also reasonable and more interesting +- [ ] **The typefaces, decided 2026-08-09.** Both verified, not assumed: + **Roboto** for the desktop, window manager and compositor -- + **Apache-2.0**, the same licence as Schunix, so it needs nothing beyond a + NOTICE entry. + **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 + still called JetBrains Mono. That matters more than it sounds: + pre-rasterising a font into bitmaps at build time is a modification, and + an RFN would have forbidden keeping the name on the result. + OFL's one real constraint is that the font may not be sold on its own and + must stay under OFL; bundling it in an Apache-2.0 system is exactly the + case it is written for. +- [ ] Text layout (advance widths, kerning) as a library in `lib/` +- [ ] The console keeps its fixed grid; proportional text belongs to the GUI + +**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 +the same one that governs drivers (§1): a font file is redistributed inside +every Schunix image, so its licence attaches to the image. + +Safe choices, in rough order of usefulness: + +- **CC0 / public domain** — best case, nothing to comply with. +- **MIT / BSD / Apache-2.0 fonts** — fine, needs a `NOTICE` entry. +- **SIL OFL** — usable but has a real string attached: a modified font must + be renamed, and OFL fonts cannot be sold on their own. Workable, but read + it before committing one. + +Whatever is chosen, the licence goes in `NOTICE` **before** the file is +committed, not after. + +### Phase 5 — The GUI, as separate projects + +See `projects/README.md`. Schcom, SchWM and SchDE live outside the kernel +tree on purpose. + +- [ ] **Schcom** — the compositor. Owns the framebuffer, composites client + buffers, routes input. Needs: unix sockets, shm (done), raw input + events, and a GPU driver with double buffering. +- [ ] **SchWM** — window management on top of Schcom's protocol +- [ ] **SchDE** — panel, launcher, settings + +Raw input is the missing kernel piece nobody thinks of until it bites: +keyboard events currently only arrive through the tty line discipline, cooked +and line-buffered and delivered to one foreground process. A compositor needs +key-down/key-up with modifiers and no line discipline at all — an evdev-style +`/dev/input`. + +### Phase 6 — Installer and `.sip` + +`.sip` (Schunix 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 +whole filesystem, be applied to a partition of any size, and hold several +images that share their common files. + +The pieces for this mostly exist already. `tools/mkschfs.c` does content +dedup with an `(st_dev, st_ino)` fast path; SchFS's B-tree is content +addressed. A sensible `.sip` is: a header, a file index (path, metadata, +content hash), and a blob store keyed by hash, with compression per blob. + +- [ ] `.sip` format specification, written down before any code +- [ ] `tools/mksip` — capture a directory tree into a `.sip` +- [ ] Kernel or userspace apply path +- [ ] An installation environment that boots from the ISO, partitions, + applies the `.sip`, and installs the bootloader + +--- + +### Phase 7 — The full-stack acceptance test *(served its purpose; removed)* + +For a while this phase was a ported copy of a well-known 1993 shooter, kept as +an acceptance test rather than a feature. The reasoning was sound and is worth +keeping even though the test is gone: a large program that somebody else wrote, +which exercises `/dev/fb0`, `/dev/input/event0`, `mmap`, the ELF loader, +`gettimeofday` and a fixed-rate tic loop *simultaneously* and notices when any +of them lie, is a much harsher test than anything written in-house — because it +was not written against our bugs. + +It found real ones, all of which are fixed and covered by narrower tests now: + +- `fcntl(F_SETFL, O_NONBLOCK)` was a documented no-op, so the first read blocked + forever and looked exactly like a hung renderer. +- `/dev/input/eventN` replayed its backlog to each new opener, handing a program + the keystrokes that had launched it as input. +- Without `EVIOCGRAB`, a full-screen program and the shell behind it both read + the same keystrokes. + +It was removed once it stopped finding anything: the port was ~100k lines of +third-party source under licences that can never ship in an Apache-2.0 image, +and carrying it had a standing cost — 33 MB of non-redistributable data staged +into `sysroot/`, which is linked into the kernel binary for a ramdisk-root +build. That combination is a licensing accident waiting to happen, for a test +that was passing every time. + +**What replaced it:** `tools/bootcheck.ps1` with its `-Sock`, `-Evdev` and `-Ps` +modes, plus `tools/splashshot.ps1` for the boot path. These are narrower and do +not prove the whole stack composes, which is the honest cost of the removal. + +**The lesson worth keeping** is the shape of the test, not the program: the next +full-stack test should be something large that we did not write, driven to a +real pixel-level assertion rather than a log line. `tools/splashshot.ps1`'s +colour counting exists because a log-only harness once passed on a blank screen. + +### Phase 8 — The system layer: `schinit`, firmware, and a crash channel + +Three ideas parked here rather than started, because each one is a project and +the phases above are the agreed order. Recorded so they are not re-derived from +scratch later. + +**`schinit`, a launchd-shaped init.** The point of copying launchd rather than +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 +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. +Schunix 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 +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` +must be able to enumerate processes, or the supervisor is unobservable. + +**A crash screen you can work in, and a QR code channel out of it.** PSOGM +(`kernel/core/panic.c`) currently renders and stops. The idea is two staged +things, and the staging matters: + +- *An interactive mode — "a small OS inside the crash".* This is the right + framing and it is worth stating precisely, because it decides the design. At + panic time the kernel is the only thing running, which is exactly why it can + offer what a live system cannot: walk the stack, read another process's + memory, dump page tables, inspect the process table — with no scheduler and no + locking to respect, because nothing else can race you. + + What makes it a *system* rather than a print statement is that it keeps the + base machine's drivers. Concretely, the ones that work with interrupts off: + the VGA/framebuffer (`vga_draw_pixel` is a plain memory write), the PS/2 + keyboard (pollable via port 0x60/0x64), and the serial port. Those three are + a complete console. Everything else — IDE, USB, the timer, anything that + sleeps or takes a sleeplock — is off limits, because the lock it needs may be + precisely the one held by the CPU that just died. + + So the shape is a **polled event loop over preallocated state**: no `kalloc`, + no `sleep`/`wakeup`, no `acquire` on anything a live path might hold, one + static command buffer, and a driver set restricted to the three above. That + restriction is not a limitation to work around later; it is the invariant that + makes the mode trustworthy when everything else is not. Anything that wants + more should be answered by rebooting into a recovery environment instead. + + A useful precedent to read but not copy: DDB (NetBSD/FreeBSD's in-kernel + debugger) is exactly this, and its hard-won rule is the same one — a debugger + that can deadlock is worse than no debugger. +- *A QR code.* **Done.** `kernel/core/qr.c` (byte mode, EC level L, versions + 1–6, no allocation) and a card on the right of the crash screen. A panic + report is worth nothing if it cannot leave a machine whose network stack is + dead, and a phone camera is an out-of-band channel needing no driver on our + side. Deliberately *not* a URL: it encodes the report itself and reaches + nothing. + + It ended up unconditional rather than behind Enter, which is better — it + costs nothing to always draw, and requiring a keypress would mean the one + case where input is least trustworthy is also the case where the report is + hardest to retrieve. Verified end-to-end by `make crashshot && make crashqr`, + which decodes the symbol out of the captured framebuffer. + +**UEFI.** Not a feature so much as the point at which the current bootloader +stops being extendable: it is 16-bit real mode, INT 10h VBE, and PIO ATA, none +of which exist on a UEFI-only machine. The realistic shape is a *second* +loader — an EFI application that gets the framebuffer from GOP, the memory map +from `GetMemoryMap()`, loads the kernel off a FAT ESP, and enters at the same +place `boot/stage2main.c` does — rather than a port of the existing one. Worth +noting that the splash work just done survives that transition: it is a mask, a +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 +memory (see `docs/layout.md`). + +### SchFS beyond Schunix + +Three ideas parked 2026-08-08, in the order they should happen. + +**An on-disk format version, and an upgrade path.** This one is not optional and +gets harder every day it is postponed: the moment an image exists that someone +cares about, changing the layout means being able to read the old one. The +superblock already carries a version field and a CRC32c; what is missing is a +*policy* — a documented rule for what a version bump means, a refusal to mount +something newer than the driver understands (rather than misreading it), and an +explicit upgrade step. Cheap now, expensive later, and it blocks the other two: +a second implementation is only meaningful against a format that is pinned. + +**A Linux implementation.** The realistic first form is **FUSE**, not a kernel +module — it needs no GPL entanglement (`libfuse` is LGPL and used across a +process boundary), it can reuse the read/write logic already in `tools/mkschfs` +and `tools/schfs_fsck` rather than being written twice, and it turns "does our +filesystem work" into something testable with `fsx` and `xfstests`, which is a +far harsher examination than anything in this tree. A Linux *kernel* module is a +different project and carries the licence problem that +[licensing.md](licensing.md) describes. + +**The missing features.** Worth listing honestly before adding any: no journal +replay across an unclean shutdown beyond what CoW gives for free, no snapshots +(despite the B-tree being copy-on-write, which is most of the work), no extended +attributes, no sparse-file support, and no online `fsck`. Snapshots are the one +where the existing design already pays for most of the cost. + +--- + +## 3b. Known broken + +Two things that are wrong *now*, both reported 2026-08-08 and both diagnosed +rather than merely observed. Neither blocks the GUI work, which is why they are +here and not in a phase. + +### ~~SMP is broken~~ *(fixed 2026-08-08)* + +**SMP works.** One, two and four processors all boot; every CPU reports in with +`cpu%d: starting`, and `/proc/cpuinfo` lists them all. `smp_start_aps` in +`kernel/core/main.c` is 1. + +Five distinct bugs, each hidden behind the one before it, and all invisible +under QEMU because it publishes only one processor in the legacy MP table. +VMware published the real count, which is why the triple fault only ever +appeared there. + +| | | +|---|---| +| CPU enumeration | `mpinit()` read the 1994 MP table. `kernel/arch/x86_64/acpi.c` now reads the ACPI MADT. | +| triple fault | `entry64high` had **no AP branch** — every AP took the BSP's stack and ran `kmain()` twice. Now tests `EBX == 1`. | +| `panic("acquire")` | `seginit()` called `kalloc()` before `%fs` existed; kalloc locks, locking reads `cpu`. BSP now preallocates each AP's page. | +| `panic("sched locks")` | `kernel_fs_base` was **one global** read by `trapasm.S` on every entry, so all CPUs shared one per-CPU block. Now `%gs:0`. | +| null `proc` in `sleep()` | `cpu`/`proc` were `__thread` — per *thread*, so the compiler cached the thread pointer across `sched()`, but `%fs` is per *CPU*. Now `mycpu()`/`myproc()`. | +| `#GP` in `syscall_entry` | The new per-CPU slots landed on `%fs:(8)`, the syscall scratch word — the same memory as `%gs:8`. Moved to +16 and +24. | + +The `__thread` one is the lesson worth keeping: **`__thread` is wrong for +per-CPU kernel data.** It means per thread, and the compiler is entitled to +cache the thread pointer across calls on that basis. A kernel thread changes CPU +at every `sched()`, so the assumption is false for exactly the variables that +most need to be right. `include/proc.h` carries the disassembly that proves it. + +Per-CPU block layout, shared with assembly and not to be reordered: + + +0 self-pointer x86-64 TLS ABI (%fs:0) + +8 syscall scratch trapasm.S parks %rsp here + +16 struct cpu * + +24 struct proc * + +### ~~The kernel demands 224 MB of RAM~~ *(fixed 2026-08-08)* + +`kernel/arch/x86_64/e820.c` reads the firmware's memory map and sets `phystop` +from it. **The floor went from 224 MB to 32 MB**, and the kernel now sees all +the memory a machine actually has: 512 MB in gives `MemTotal: 524160 kB`, where +before it reported 224 MB whatever was installed. + +Three details worth keeping: + +- It takes the end of the usable region **containing the kernel**, not the + highest usable address anywhere. A memory map has reserved holes in it, and + `freerange()` walks straight from the end of the kernel image to `phystop` + handing out every page between — so the global maximum would put firmware + tables on the free list, failing later and elsewhere and looking like anything + but a memory map problem. +- 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. +- 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`. + +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. + +### The kernel demanded 224 MB of RAM + +**Symptom as reported:** the OS needs ~256 MB, which is absurd next to Windows 98 +or an early Linux. + +**Diagnosis:** it is one constant. `PHYSTOP` in `include/memlayout.h` is +`0xE000000` — 224 MB — inherited unchanged from xv6, and `main()` hands +`P2V(PHYSTOP)` straight to `kinit1()`/`dma_init()`. The kernel therefore +*assumes* that much physical memory exists and walks off the end of RAM if it +does not. Measured 2026-08-08: boots at 224M and above, triple faults at 192M +and below. Nothing is actually being *used* — the requirement is entirely +fictional. + +**The fix is already half-built.** `boot/stage2.S` collects a full E820 memory +map in real mode and leaves it at `VBE_INFO_ADDR + 0x200` (count) and `+ 0x208` +(24-byte entries); `boot/stage2main.c` already parses it to print detected RAM. +**The kernel never reads it.** So: have `main()` take the top of the highest +usable E820 region instead of the constant, clamp it to what the direct map +covers, and keep `PHYSTOP` only as a fallback for the case where the firmware +returned nothing. That should drop the floor to something in the tens of +megabytes and is a contained change. + +--- + +## 4. Kept out of scope on purpose + +- Anything that needs pushing or publishing. This work stays local. diff --git a/include/asm.h b/include/asm.h new file mode 100644 index 0000000..68210d7 --- /dev/null +++ b/include/asm.h @@ -0,0 +1,21 @@ +// +// assembler macros to create x86 segments +// + +#define SEG_NULLASM \ + .word 0, 0; \ + .byte 0, 0, 0, 0 + +// The 0xC0 means the limit is in 4096-byte units +// and (for executable segments) 32-bit mode. +#define SEG_ASM(type,base,lim) \ + .word (((lim) >> 12) & 0xffff), ((base) & 0xffff); \ + .byte (((base) >> 16) & 0xff), (0x90 | (type)), \ + (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff) + +#define STA_X 0x8 // Executable segment +#define STA_E 0x4 // Expand down (non-executable segments) +#define STA_C 0x4 // Conforming code segment (executable only) +#define STA_W 0x2 // Writeable (non-executable segments) +#define STA_R 0x2 // Readable (executable segments) +#define STA_A 0x1 // Accessed diff --git a/include/buf.h b/include/buf.h new file mode 100644 index 0000000..3266495 --- /dev/null +++ b/include/buf.h @@ -0,0 +1,14 @@ +struct buf { + int flags; + uint dev; + uint blockno; + struct sleeplock lock; + uint refcnt; + struct buf *prev; // LRU cache list + struct buf *next; + struct buf *qnext; // disk queue + uchar data[BSIZE]; +}; +#define B_VALID 0x2 // buffer has been read from disk +#define B_DIRTY 0x4 // buffer needs to be written to disk + diff --git a/include/config_sinit.h b/include/config_sinit.h new file mode 100644 index 0000000..4f16fac --- /dev/null +++ b/include/config_sinit.h @@ -0,0 +1,3 @@ +static char *const rcinitcmd[] = { "/bin/sh", NULL }; +static char *const rcrebootcmd[] = { "/bin/halt", "-rb", NULL }; +static char *const rcpoweroffcmd[] = { "/bin/halt", "-po", NULL }; diff --git a/include/date.h b/include/date.h new file mode 100644 index 0000000..18e12e0 --- /dev/null +++ b/include/date.h @@ -0,0 +1,15 @@ +#pragma once + +struct rtcdate { + uint second; + uint minute; + uint hour; + uint day; + uint month; + uint year; +}; + +struct timeval { + long tv_sec; + long tv_usec; +}; diff --git a/include/defs.h b/include/defs.h new file mode 100644 index 0000000..11bde89 --- /dev/null +++ b/include/defs.h @@ -0,0 +1,466 @@ +#pragma once + +struct buf; +struct context; +struct file; +struct inode; +struct pipe; +struct proc; +struct rtcdate; +struct spinlock; +struct sleeplock; +struct stat; +struct superblock; +struct trapframe; +struct dirent; + +// entryother.S / syscall.S +void syscall_entry(void); +void ignore_sysret(void); + +// bio.c +void binit(void); +struct buf* bread(uint, uint); +void brelse(struct buf*); +void bwrite(struct buf*); + +// console.c +struct termios; +void consoleinit(void); +extern int tty_fg_pgrp; +// The terminal's line-discipline settings. TCGETS/TCSETS in sys_fs.c are the +// only callers; the console honours ICANON, ECHO, ECHOE, ECHONL, ISIG, +// ICRNL, INLCR, IGNCR, ISTRIP and VMIN. +void cons_get_termios(struct termios *); +void cons_set_termios(const struct termios *); +void cprintf(char*, ...); +void consoleintr(int(*)(void)); +void panic(char*) __attribute__((noreturn)); + +// exec.c +int exec(char*, char**); + +// file.c +struct file* filealloc(void); +int fdalloc(struct file*); +void fileclose(struct file*); +struct file* filedup(struct file*); +void fileinit(void); +int fileread(struct file*, char*, int n); +int file_poll(struct file*, int events); +int filestat(struct file*, struct stat*); +int filewrite(struct file*, char*, int n); + +// fs.c +void fsinit(int); +int dirlink(struct inode*, char*, uint64); +struct inode* dirlookup(struct inode*, char*, uint*); +// Remove the entry `name` at the cookie dirlookup returned in *poff. +int dirunlink(struct inode*, char*, uint); +// 1 if the directory holds no real entries, 0 if it does, -1 on error. +int dirempty(struct inode*); +// Fill `out` with getdents64 records starting at *poff, which is an opaque +// position the filesystem advances. Returns bytes written, 0 at end of +// directory. The inode must be locked. +int getdents(struct inode*, char *out, int cap, uint64 *poff); +// Mount table: a substitution applied during path resolution. Nothing on disk +// records a mount, so unmounting is forgetting. +void mountinit(void); +int mount_add(uint dev, uint64 inum, uint fsdev, uint64 root); +int mount_del_by_root(uint fsdev, uint64 root); +struct inode* ialloc(uint, short); +struct inode* iget(uint, uint64); +struct inode* idup(struct inode*); +void iinit(void); +void ilock(struct inode*); +void iput(struct inode*); +void iunlock(struct inode*); +void iunlockput(struct inode*); +void iupdate(struct inode*); +int namecmp(const char*, const char*); +struct inode* namei(char*); +struct inode* nameiparent(char*, char*); +struct inode* nameifrom(struct inode*, char*); +struct inode* nameiparentfrom(struct inode*, char*, char*); +int readi(struct inode*, int, uint64, uint64, uint); +void stati(struct inode*, struct stat*); +int writei(struct inode*, int, uint64, uint64, uint); +void itrunc(struct inode*); +void itrunc_to(struct inode*, uint64); +unsigned int BKDRHash(char * str); +uint tree_expand(struct inode *ip, uint off); +void tree_search(struct inode* dp, char* name, uint* poff, struct dirent* de,uint add); +void build_dir_tree(struct inode* dp,uint64 pinum); +struct inode* divesymlink(struct inode *); +void readsb(int dev, struct superblock *sb); + +// pci.c -- bus enumeration. Drivers that need to *find* their hardware use +// these; drivers for things that have lived at a fixed address since 1984 +// (the PIC, the PIT, the legacy IDE ports) do not. +struct pci_dev; +struct pci_driver; +void pci_init(void); +uint32 pci_read32(uint8, uint8, uint8, uint8); +uint16 pci_read16(uint8, uint8, uint8, uint8); +uint8 pci_read8(uint8, uint8, uint8, uint8); +void pci_write32(uint8, uint8, uint8, uint8, uint32); +void pci_enable(struct pci_dev *, uint16 bits); +uint8 pci_find_cap(struct pci_dev *, uint8 id); +int pci_msi_enable(struct pci_dev *, int vector, int cpu); +int pci_count(void); +struct pci_dev *pci_get(int); +struct pci_dev *pci_find_class(uint8 class, uint8 subclass); +struct pci_dev *pci_find_id(uint16 vendor, uint16 device); +void pci_bind(const struct pci_driver *); +int pci_info(char *buf, int cap); + +// drivers/registry.c -- the one list of every driver in the kernel. +void pci_bind_all(void); + +// xhci.c — `echo u > /proc/sysrq` +void xhci_dump(void); + +// ide.c +void ideinit(void); +void ideintr(void); +void iderw(struct buf*); +// For probes, not for reads: iderw() panics on an absent drive, so anything +// that is guessing whether a disk exists has to ask here first. +int ide_disk_present(int dev); + +// fs/schfs/kmount.c -- SchFS. +// +// Objects are named by 64-bit object id, not by a path: resolution is the +// caller's business, so these compose with a VFS rather than assuming one. +// Every schfs_k* that changes anything is one transaction and is durable by the +// time it returns. +struct schfs_inode; +void schfs_kmount(uint dev); +int schfs_kmounted(void); +uint64 schfs_klookup(const char *path); +int schfs_kstat(uint64 ino, struct schfs_inode *out); +long schfs_kread(uint64 ino, uint64 off, void *buf, unsigned n); +int schfs_kreaddir(uint64 dir, + int (*fn)(uint64, unsigned short, const char *, + unsigned, void *), + void *arg); +int schfs_kinfo(char *buf, int cap); + +int schfs_kcreate(uint64 dir, const char *name, unsigned namelen, + unsigned short type, uint mode, + unsigned short major, unsigned short minor, uint64 *out); +long schfs_kwrite(uint64 ino, uint64 off, const void *buf, + unsigned n); +int schfs_ktruncate(uint64 ino, uint64 size); +int schfs_kunlink(uint64 dir, const char *name, unsigned namelen); +int schfs_klink(uint64 dir, const char *name, unsigned namelen, + uint64 ino); +int schfs_krename(uint64 olddir, const char *oldname, + unsigned oldlen, uint64 newdir, const char *newname, + unsigned newlen); +int schfs_ksetattr(uint64 ino, const struct schfs_inode *in); +int schfs_ksync(void); + +// Pieces the VFS layer (fs/schfs/vfs.c) needs, where a directory entry and the +// object it names are separate operations. The VFS keeps the link count. +uint64 schfs_klookup_at(uint64 dir, const char *name, unsigned len); +int schfs_kdirempty(uint64 dir); +int schfs_kalloc_object(unsigned short type, uint mode, + uint64 *out); +int schfs_kdiradd(uint64 dir, const char *name, unsigned len, + uint64 ino, unsigned short type); +int schfs_kdirdel(uint64 dir, const char *name, unsigned len); +int schfs_kfree(uint64 ino); +uint64 schfs_kroot(void); + +// ramdisk.c +uint uptime(void); + +// procfs.c +int procread(struct inode*, uint, char*, int); +int procwrite(struct inode*, uint, char*, int); +// Shared with the /proc filesystem (kernel/fs/procfs.c): one owns the +// namespace, the other the content. +int proc_gen_global(int id, char *buf, int cap); +int proc_write_sysrq(int user_src, uint64 src, uint n); +void procfs_mount(void); + +// input.c -- raw evdev event devices +void inputinit(void); +int inputread(struct inode*, uint, char*, int); +int inputwrite(struct inode*, uint, char*, int); +int inputready(struct inode*); +void inputclose(struct inode*); +void inputopen(struct inode*); +int input_ioctl(struct inode*, int request, addr_t arg); +int input_grab(int dev, int on); +int input_is_grabbed(int dev); +void input_report(int dev, int type, int code, int value); +void input_sync(int dev); +int input_ready(int dev); +void input_ps2_scancode(int raw, int e0); +void input_key(int hid_usage, int down); +int input_hid_keycode(int hid_usage); +void input_mouse(int dx, int dy, int buttons); + +void ramdiskinit(void); +void ramdiskrw(struct buf*); +int ramdisk_present(void); + +// usb_storage.c +void usb_storage_rw(struct buf*); +int usb_storage_present(void); +void usb_storage_dump(void); // `echo s > /proc/sysrq` + +// ioapic.c +void ioapicenable(int irq, int cpu); +void ioapicroute(int irq, int cpu, int level_low); +void ioapicmask(int irq); +extern uchar ioapicid; +void ioapicinit(void); + +// dma.c — see include/dma.h for the full contract +void dma_init(void*, void*); +void *dma_alloc(uint64 size, uint64 align); +void dma_free(void*, uint64 size); +addr_t dma_phys(const void*); +uint64 dma_free_bytes(void); +uint64 dma_total_bytes(void); + +// kalloc.c +char* kalloc(void); +uint64 kalloc_free_bytes(void); +void kfree(char*); +void kinit1(void*, void*); +void kinit2(void); + +// kbd.c +void kbdintr(void); + +// mouse.c +void mouseinit(void); +void mouseintr(void); +void mouse_inject(int dx, int dy, int buttons); +int get_mouse_x(void); +int get_mouse_y(void); +uint8 get_mouse_buttons(void); + +// lapic.c +void cmostime(struct rtcdate *r); + +// time.c -- wall-clock time, from the RTC read once at boot plus uptime. +void time_init(void); +void wallclock(uint64 *sec, uint64 *usec); +extern uint64 boot_epoch; +int cpunum(void); +extern volatile uint* lapic; +void lapiceoi(void); +void lapicinit(void); +void lapicstartap(uchar, uint); +void microdelay(int); + +// log.c +void initlog(int dev); +void log_write(struct buf*); +void begin_op(); +void end_op(); + +// mp.c +extern int ismp; +void mpinit(void); + +// pipe.c +int pipealloc(struct file**, struct file**); +void pipeclose(struct pipe*, int); +int piperead(struct pipe*, char*, int); +int pipewrite(struct pipe*, char*, int); + +// net/unix.c +struct socket; +void sockinit(void); +struct socket* socknew(int domain, int type); +void sockclose(struct socket*); +void sockdup(struct socket*); +int sockread(struct socket*, char*, int); +int sockwrite(struct socket*, char*, int); +int sockbind(struct socket*, const char *path); +int socklisten(struct socket*, int backlog); +struct socket* sockaccept(struct socket*); +int sockconnect(struct socket*, const char *path); +int sockreadable(struct socket*); +int sock_hup(struct socket*); +int sock_shutdown(struct socket*, int how); +int sockpair(struct socket **a, struct socket **b); +const char* sockname(struct socket*); + +// proc.c +void exit(int status); +int fork(void); +int growproc(int64); +int kill(int); +int sigsend_pgrp(int pgid, int sig); +int proc_pgid(int pid); +int proc_setpgid(int pid, int pgid); +int proc_setsid(void); +int sigsend(int pid, int sig); +int proc_exists(int); +int proc_num(void); +struct procinfo; +int proc_snapshot(int idx, struct procinfo *out); +int proc_snapshot_pid(int pid, struct procinfo *out); +void pinit(void); +void procdump(void); +void scheduler(void) __attribute__((noreturn)); +void sched(void); +void sleep(void*, struct spinlock*); +int wait(void); +int waitpid(int, int*, int); +void wakeup(void*); +void yield(void); +void sinit(void); +void kstack_check_canary(const char *where); + +// swtch.S +void swtch(struct context**, struct context*); + +// spinlock.c +void acquire(struct spinlock*); +void getcallerpcs(void*, addr_t*); +void getstackpcs(addr_t*, addr_t*); +int holding(struct spinlock*); +void initlock(struct spinlock*, char*); +void release(struct spinlock*); +void pushcli(void); +void popcli(void); + +// sleeplock.c +void acquiresleep(struct sleeplock*); +void releasesleep(struct sleeplock*); +int holdingsleep(struct sleeplock*); +void initsleeplock(struct sleeplock*, char*); + +// string.c +int memcmp(const void*, const void*, uint64); +void* memmove(void*, const void*, uint64); +void* memset(void*, int, uint64); +char* safestrcpy(char*, const char*, int); +int strlen(const char*); +int strnlen(const char*, int); +int strncmp(const char*, const char*, uint64); +char* strncpy(char*, const char*, int); + +// syscall.c +void syscall(struct trapframe *); +void syscallinit(void); +void deliver_signals(struct trapframe *); +int argint(int, int*); +int argptr(int, char**, int); +int argstr(int, char**); +int argaddr(int, addr_t*); +int fetchaddr(addr_t, addr_t*); +int fetchstr(addr_t, char**); +int fetchint(addr_t, int*); + +// trap.c +void idtinit(void); +extern uint ticks; +void tvinit(void); +extern struct spinlock tickslock; + +// uart.c +void uartearlyinit(void); +void uartinit(void); +void uartintr(void); +void uartputc(int); + +// vga.c +void vga_init(uint64); +void vga_draw_pixel(int, int, uint32); +void vga_draw_char(int, int, uchar, uint32); +void vga_puts(int, int, char*, uint32); +void vga_putc(int, uint32); +void vga_clear(uint32); +void vga_screen_reset(void); +void vga_set_bg(uint32); +// Crash-screen primitives: the panic handler lays itself out rather than +// printing. See kernel/core/panic.c. +int vga_ready(void); +void vga_dims(int *w, int *h); +int vga_char_w(void); +int vga_char_h(void); +// Framebuffer geometry. vga.c reads the VBE mode info, so it is the only +// thing that knows where the framebuffer is; nobody else may assume. +uint64 vga_fb_phys(void); +uint64 vga_fb_size(void); +uint32 vga_fb_stride(void); +uint32 vga_fb_bpp(void); +volatile uchar *vga_fb_ptr(void); + +// fb.c -- /dev/fb0, major 2. +void fbclose(struct inode*); +// Called from sys_mmap: a mapping of /dev/fb0 is a licence to draw with no +// further syscalls, so it is the last the kernel hears about it. +void fb_mapped(void); +int fbread(struct inode*, uint, char*, int); +int fbwrite(struct inode*, uint, char*, int); +int fb_ioctl(int request, addr_t arg); +// drivers/net/e1000 -- raw Ethernet. No protocol stack above it yet, so these +// are the whole interface: queue a frame, take a frame, and the MAC. +int e1000_transmit(const void *frame, int len); +int e1000_receive(void *out, int cap); +const unsigned char *e1000_mac(void); +void e1000_selftest(void); + +// registry.c +void platform_register_devices(void); + +void e820_init(void); +int acpi_init(void); +void vga_fill_rect(int x, int y, int w, int h, uint32); +void vga_fill_circle(int cx, int cy, int r, uint32); +void vga_text_at(int, int, const char*, uint32); +void vga_draw_logo(int x, int y, uint32 color, uint32 bg); +void vga_logo_centered(int cy, uint32 color, uint32 bg); +// Cursor addressing and erasing, for the console's ANSI escape parser. +int vga_cols(void); +int vga_rows(void); +void vga_cursor_get(int *col, int *row); +void vga_cursor_set(int col, int row); +void vga_erase_display(int mode); +void vga_erase_line(int mode); + +// console.c / panic.c +void cons_panic_mode(void); +extern int cons_serial_only; +void console_takeover(void); + +// vm.c +void seginit(void); +void kvmalloc(void); +pml4e_t* setupkvm(void); +char* uva2ka(pml4e_t*, char*); +addr_t allocuvm(pml4e_t*, uint64, uint64); +addr_t deallocuvm(pml4e_t*, uint64, uint64); +void freevm(pml4e_t*); +void inituvm(pml4e_t*, char*, uint64); +int loaduvm(pml4e_t*, char*, struct inode*, uint64, uint64); +pml4e_t* copyuvm(pml4e_t*, uint64); +void switchuvm(struct proc*); +void switchkvm(void); +int pipe_poll(struct pipe*, int readable, int writable); +int console_input_ready(void); +int copyin(pml4e_t*, addr_t, void*, uint64); +int copyout(pml4e_t*, addr_t, void*, uint64); +void vm_unmap_range(pml4e_t*, uint64, uint64); +// Unmap without freeing: for pages this process does not own — device memory +// and shared segments. vm_unmap_range() would hand them to kfree. +void vm_unmap_norelease(pml4e_t*, uint64, uint64); +// Shared memory (sys_mem.c). shm_ref/shm_detach maintain the attachment +// count that decides when a segment's pages go back. +void shm_ref(int id); +void shm_detach(int id); +void proc_release_shared(struct proc *); +int copy_vma_range(pml4e_t *dstpgdir, pml4e_t *srcpgdir, uint64 va, uint64 length, int is_fb); +void clearpteu(pml4e_t *pgdir, char *uva); + +#define NELEM(x) (sizeof(x)/sizeof((x)[0])) diff --git a/include/device.h b/include/device.h new file mode 100644 index 0000000..8827dfe --- /dev/null +++ b/include/device.h @@ -0,0 +1,89 @@ +#pragma once + +// The device model: one list of everything attached, whatever bus found it. +// +// Before this there were two registries in kernel/drivers/registry.c -- one +// array of PCI drivers, one of USB drivers -- and nothing that knew about both. +// That is fine for binding drivers to hardware, which is all it was for, and +// useless for the three things wanted next: +// +// *Enumeration.* "What is in this machine, and what claimed it" had no +// answer that covered a USB disk and a PCI display at once. A device manager +// is exactly that question, so it needs exactly this list. +// +// *Classes.* A compositor should ask for "the display" and not care whether +// that is the VBE framebuffer or virtio-gpu. Without a class, every consumer +// hardcodes a driver, and adding the second driver means editing the +// consumers -- which is how a framebuffer address ends up hardcoded in three +// places, as it once was here. +// +// *A boundary for drivers that are not compiled in.* Drivers the user +// installs (see docs/drivers.md) have to attach somewhere that is not "an +// array in registry.c", because that array is fixed at link time. +// +// The shape is deliberately the one NeXTSTEP/macOS uses rather than Linux's: +// a device is an object with a class and an ops vtable, and consumers talk to +// the class. It is *not* a device tree -- there is no parent/child nesting +// here, only a flat list with a bus tag, because nothing yet needs to walk a +// hierarchy and a tree that nobody traverses is just a harder list. + +#define DEV_NAMELEN 24 + +// Which bus found it. This is provenance, not capability -- what the device +// *does* is its class. +enum dev_bus { + DEVBUS_PLATFORM = 0, // found by looking, not by enumerating: PS/2, VBE + DEVBUS_PCI, + DEVBUS_USB, + DEVBUS_NBUS +}; + +// What it is. A consumer asks for a class and gets whatever is bound. +enum dev_class { + DEVCLASS_OTHER = 0, + DEVCLASS_DISPLAY, + DEVCLASS_INPUT, + DEVCLASS_STORAGE, + DEVCLASS_NET, + DEVCLASS_BUS, // a controller that finds more devices (xHCI, hubs) + DEVCLASS_NCLASS +}; + +struct device { + char name[DEV_NAMELEN]; // "vga0", "xhci0" -- unique, human-readable + char desc[48]; // free text for the enumerator + enum dev_bus bus; + enum dev_class class; + + // Where it came from, for the enumerator to print. Zero when not applicable. + uint16 vendor, product; + uint8 b, s, f; // PCI bus/slot/func + + const char *driver; // whatever claimed it, or 0 for unclaimed + void *ops; // class-specific vtable; see display.h + void *priv; // the driver's own state + + int in_use; +}; + +#define NDEVICE 32 + +// Register a device. Returns it, or 0 if the table is full. The name is made +// unique by appending an index, so a caller passes "vga" and gets "vga0". +struct device *device_add(const char *base, enum dev_bus bus, + enum dev_class class, const char *driver); + +// Set the human-readable description. Bounded copy into the fixed field, so +// callers do not each need to know how long it is. +void device_set_desc(struct device *, const char *); + +// Walk. Returns 0 past the end; index is dense over registered devices. +struct device *device_at(int i); +int device_count(void); + +// First device of a class with a bound driver, or 0. This is how a consumer +// finds "the display" without naming a driver. +struct device *device_find_class(enum dev_class class); + +const char *dev_bus_name(enum dev_bus); +const char *dev_class_name(enum dev_class); diff --git a/include/display.h b/include/display.h new file mode 100644 index 0000000..b695d0f --- /dev/null +++ b/include/display.h @@ -0,0 +1,56 @@ +#pragma once + +// The display class: what a consumer talks to instead of a driver. +// +// A compositor should ask for "the display" and get whatever is bound -- +// today the VBE framebuffer, later virtio-gpu. Without this, every consumer +// names a driver, and adding the second display driver means editing all of +// them. That is not hypothetical here: the framebuffer's physical address was +// once hardcoded in three separate places. +// +// Found with device_find_class(DEVCLASS_DISPLAY); see include/device.h. + +struct device; + +struct display_mode { + int width, height; + int bpp; + uint32 stride; // bytes per row of the *visible* framebuffer +}; + +struct display_ops { + void (*mode)(struct device *, struct display_mode *); + + // The buffer to draw into, and its stride. Returns 0 if double buffering is + // unavailable, in which case the caller should draw directly and accept + // tearing rather than not drawing at all. + // + // Allocated on first call, never at boot: it is around two megabytes at + // 800x600, and a machine whose compositor never starts should not pay that. + void *(*acquire)(struct device *, uint32 *stride_out); + + // Copy a rectangle of the back buffer to the display. Coordinates are in + // pixels; the whole screen is (0, 0, width, height). + void (*present)(struct device *, int x, int y, int w, int h); + + // Block until the display is between frames. Optional -- a driver that + // cannot tell leaves this null, and present() then simply tears less than + // drawing directly would. + void (*wait_vblank)(struct device *); +}; + +// The bound display, or 0. Convenience over device_find_class(). +struct device *display_get(void); + +// Wrappers that do nothing gracefully when there is no display or the driver +// left an op null, so callers are not each written around a maybe-null vtable. +int display_mode(struct display_mode *out); +void *display_acquire(uint32 *stride_out); +void display_present(int x, int y, int w, int h); +void display_wait_vblank(void); + +// Drive the whole path once and draw a test pattern. `echo d > /proc/sysrq`. +void display_selftest(void); + +// Draw a text specimen through the display class. `echo t > /proc/sysrq`. +void text_selftest(void); diff --git a/include/dma.h b/include/dma.h new file mode 100644 index 0000000..1a40de9 --- /dev/null +++ b/include/dma.h @@ -0,0 +1,43 @@ +#pragma once + +// Physically contiguous memory for devices that read and write it themselves. +// +// kalloc() hands out 4 KB pages from a free list, in whatever order they were +// released. That is exactly what a page table wants and exactly what a device +// cannot use: an xHCI command ring, a NIC's descriptor array or a virtio +// queue is a single physically contiguous object that the hardware walks +// without any idea that paging exists. Two kalloc'd pages are adjacent in the +// kernel's address space only by luck. +// +// So DMA memory comes from an arena carved out of the top of physical memory +// before kalloc ever sees it, and is handed out contiguous and aligned. +// +// On x86 this memory needs no special cacheability. The PCI bus is cache +// coherent: a device's write invalidates the corresponding cache line, and a +// CPU write is snooped out of the store buffer before the device sees stale +// data. Architectures without that guarantee need explicit cache maintenance +// around every descriptor access, and porting this file is where that would +// go. What is *not* free even here is ordering -- the compiler and the CPU +// will happily reorder stores to a ring, so a driver still needs a barrier +// between filling a descriptor and telling the device about it. + +#define DMA_ARENA_BYTES (4*1024*1024) + +void dma_init(void *vstart, void *vend); + +// Zeroed, physically contiguous, at least `align`-aligned (align must be a +// power of two). Returns a kernel virtual address, or 0. +void *dma_alloc(uint64 size, uint64 align); + +// `size` must be the size the allocation was made with, as in Linux's +// dma_free_coherent(). Tracking it here would mean a second table whose only +// job is to remember something the caller already knows. +void dma_free(void *p, uint64 size); + +// The address to give the device. Kernel memory is direct-mapped, so this is +// just V2P -- but drivers should say what they mean, because on a machine +// with an IOMMU these stop being the same number. +addr_t dma_phys(const void *p); + +uint64 dma_free_bytes(void); +uint64 dma_total_bytes(void); diff --git a/include/e1000.h b/include/e1000.h new file mode 100644 index 0000000..12f63ee --- /dev/null +++ b/include/e1000.h @@ -0,0 +1,165 @@ +#pragma once + +// Intel 8254x gigabit Ethernet — the register and descriptor layout. +// +// From Intel's public "PCI/PCI-X Family of Gigabit Ethernet Controllers +// Software Developer's Manual" (317453). A public document with no licence on +// what you write from it, which is why this is written rather than ported: see +// docs/licensing.md and docs/roadmap.md §1. +// +// QEMU's `-device e1000` is an 82540EM and implements enough of the manual to +// be worth targeting; it is also what the default `-net nic` gives you. + +#define E1000_VENDOR 0x8086 + +// The 8254x family: PCI/PCI-X gigabit controllers that share the register map, +// descriptor format and EEPROM interface this driver implements. +// +// The device IDs are transcribed from FreeBSD's `sys/dev/e1000/e1000_hw.h` +// (Copyright (c) 2001-2020, Intel Corporation, BSD 3-clause -- verified to +// carry no advertising clause; see docs/licensing.md and NOTICE). They are +// data, not logic: the driver below is still written from Intel's manual +// 317453, and nothing of FreeBSD's implementation is used. +// +// This matters more than it looks. The driver bound exactly one device -- the +// 82540EM QEMU emulates -- which is fine for a virtual machine and useless on +// the sort of second-hand hardware a system like this actually gets run on. +// These are the cards in every desktop and server of that generation. +// +// Deliberately *not* included: the PCIe 8257x parts (82571-82574) and anything +// newer. They present a similar register map but differ in NVM access and +// initialisation, and claiming a device this driver has not been shown to +// initialise is worse than not claiming it -- the card binds, reports a MAC of +// nonsense, and nothing works for reasons that look nothing like the cause. +#define E1000_DEV_82540EM 0x100E +#define E1000_DEV_82540EM_LOM 0x1015 +#define E1000_DEV_82540EP_LOM 0x1016 +#define E1000_DEV_82540EP 0x1017 +#define E1000_DEV_82540EP_LP 0x101E +#define E1000_DEV_82541EI 0x1013 +#define E1000_DEV_82541EI_MOBILE 0x1018 +#define E1000_DEV_82541ER_LOM 0x1014 +#define E1000_DEV_82541ER 0x1078 +#define E1000_DEV_82541GI 0x1076 +#define E1000_DEV_82541GI_MOBILE 0x1077 +#define E1000_DEV_82541GI_LF 0x107C +#define E1000_DEV_82544EI_FIBER 0x1009 +#define E1000_DEV_82544GC_COPPER 0x100C +#define E1000_DEV_82544GC_LOM 0x100D +#define E1000_DEV_82545EM_COPPER 0x100F +#define E1000_DEV_82545EM_FIBER 0x1011 +#define E1000_DEV_82545GM_COPPER 0x1026 +#define E1000_DEV_82545GM_FIBER 0x1027 +#define E1000_DEV_82545GM_SERDES 0x1028 +#define E1000_DEV_82546EB_COPPER 0x1010 +#define E1000_DEV_82546EB_FIBER 0x1012 +#define E1000_DEV_82546EB_QUAD 0x101D +#define E1000_DEV_82546GB_COPPER 0x1079 +#define E1000_DEV_82546GB_FIBER 0x107A +#define E1000_DEV_82546GB_SERDES 0x107B +#define E1000_DEV_82547EI 0x1019 + +// --- registers, byte offsets into BAR 0 ------------------------------------ + +#define E1000_CTRL 0x0000 // device control +#define E1000_STATUS 0x0008 // device status +#define E1000_EERD 0x0014 // EEPROM read +#define E1000_ICR 0x00C0 // interrupt cause read +#define E1000_IMS 0x00D0 // interrupt mask set +#define E1000_IMC 0x00D8 // interrupt mask clear + +#define E1000_RCTL 0x0100 // receive control +#define E1000_TCTL 0x0400 // transmit control +#define E1000_TIPG 0x0410 // transmit inter-packet gap + +#define E1000_RDBAL 0x2800 // receive descriptor base, low +#define E1000_RDBAH 0x2804 // receive descriptor base, high +#define E1000_RDLEN 0x2808 // receive descriptor length, in bytes +#define E1000_RDH 0x2810 // receive descriptor head +#define E1000_RDT 0x2818 // receive descriptor tail + +#define E1000_TDBAL 0x3800 +#define E1000_TDBAH 0x3804 +#define E1000_TDLEN 0x3808 +#define E1000_TDH 0x3810 +#define E1000_TDT 0x3818 + +#define E1000_MTA 0x5200 // multicast table array, 128 entries +#define E1000_RAL 0x5400 // receive address low (the MAC filter) +#define E1000_RAH 0x5404 // receive address high + +// CTRL +#define E1000_CTRL_RST (1 << 26) +#define E1000_CTRL_ASDE (1 << 5) // auto-speed detection +#define E1000_CTRL_SLU (1 << 6) // set link up + +// STATUS +#define E1000_STATUS_LU (1 << 1) // link up + +// EERD +#define E1000_EERD_START (1 << 0) +#define E1000_EERD_DONE (1 << 4) +#define E1000_EERD_ADDR_SHIFT 8 +#define E1000_EERD_DATA_SHIFT 16 + +// RCTL +#define E1000_RCTL_EN (1 << 1) // receiver enable +#define E1000_RCTL_SBP (1 << 2) // store bad packets +#define E1000_RCTL_UPE (1 << 3) // unicast promiscuous +#define E1000_RCTL_MPE (1 << 4) // multicast promiscuous +#define E1000_RCTL_LBM_NONE (0 << 6) +#define E1000_RCTL_BAM (1 << 15) // accept broadcast +#define E1000_RCTL_SZ_2048 (0 << 16) // buffer size, with BSEX clear +#define E1000_RCTL_SECRC (1 << 26) // strip the Ethernet CRC + +// TCTL +#define E1000_TCTL_EN (1 << 1) +#define E1000_TCTL_PSP (1 << 3) // pad short packets +#define E1000_TCTL_CT_SHIFT 4 // collision threshold +#define E1000_TCTL_COLD_SHIFT 12 // collision distance + +// Transmit descriptor command bits +#define E1000_TXD_CMD_EOP (1 << 0) // end of packet +#define E1000_TXD_CMD_IFCS (1 << 1) // insert FCS/CRC +#define E1000_TXD_CMD_RS (1 << 3) // report status +#define E1000_TXD_STAT_DD (1 << 0) // descriptor done + +// Receive descriptor status bits +#define E1000_RXD_STAT_DD (1 << 0) +#define E1000_RXD_STAT_EOP (1 << 1) + +// Interrupt causes worth unmasking. +#define E1000_ICR_TXDW (1 << 0) // transmit descriptor written back +#define E1000_ICR_LSC (1 << 2) // link status change +#define E1000_ICR_RXDMT0 (1 << 4) // receive descriptor minimum threshold +#define E1000_ICR_RXT0 (1 << 7) // receiver timer + +// --- descriptors ----------------------------------------------------------- +// +// Both are 16 bytes and the hardware reads them by physical address, so the +// rings must be physically contiguous and 16-byte aligned. + +struct e1000_tx_desc { + uint64 addr; + uint16 length; + uint8 cso; // checksum offset + uint8 cmd; + uint8 status; + uint8 css; // checksum start + uint16 special; +} __attribute__((packed)); + +struct e1000_rx_desc { + uint64 addr; + uint16 length; + uint16 checksum; + uint8 status; + uint8 errors; + uint16 special; +} __attribute__((packed)); + +// Ring sizes. The manual requires the descriptor ring length to be a multiple +// of 128 bytes, i.e. a multiple of 8 descriptors. +#define E1000_NTX 16 +#define E1000_NRX 16 +#define E1000_BUFSZ 2048 diff --git a/include/elf.h b/include/elf.h new file mode 100644 index 0000000..a457d78 --- /dev/null +++ b/include/elf.h @@ -0,0 +1,35 @@ +#define ELF_MAGIC 0x464C457FU + +struct elfhdr { + uint32 magic; + uchar elf[12]; + uint16 type; + uint16 machine; + uint32 version; + uint64 entry; + uint64 phoff; + uint64 shoff; + uint32 flags; + uint16 ehsize; + uint16 phentsize; + uint16 phnum; + uint16 shentsize; + uint16 shnum; + uint16 shstrndx; +}; + +struct proghdr { + uint32 type; + uint32 flags; + uint64 off; + uint64 vaddr; + uint64 paddr; + uint64 filesz; + uint64 memsz; + uint64 align; +}; + +#define ELF_PROG_LOAD 1 +#define ELF_PROG_FLAG_EXEC 1 +#define ELF_PROG_FLAG_WRITE 2 +#define ELF_PROG_FLAG_READ 4 \ No newline at end of file diff --git a/include/errno.h b/include/errno.h new file mode 100644 index 0000000..ea518e6 --- /dev/null +++ b/include/errno.h @@ -0,0 +1,60 @@ +// Error numbers, matching the Linux x86_64 ABI values so that musl-linked +// programs interpret syscall failures correctly. Kernel code returns these +// negated (e.g. `return -ENOSYS;`), exactly like Linux does internally. +#ifndef SCHUNIX_ERRNO_H +#define SCHUNIX_ERRNO_H + +#define EPERM 1 // Operation not permitted +#define ENOENT 2 // No such file or directory +#define ESRCH 3 // No such process +#define EINTR 4 // Interrupted system call +#define EIO 5 // I/O error +#define ENXIO 6 // No such device or address +#define E2BIG 7 // Argument list too long +#define ENOEXEC 8 // Exec format error +#define EBADF 9 // Bad file descriptor +#define ECHILD 10 // No child processes +#define EAGAIN 11 // Try again +#define ENOMEM 12 // Out of memory +#define EACCES 13 // Permission denied +#define EFAULT 14 // Bad address +#define EBUSY 16 // Device or resource busy +#define EEXIST 17 // File exists +#define EXDEV 18 // Cross-device link +#define ENODEV 19 // No such device +#define ENOTDIR 20 // Not a directory +#define EISDIR 21 // Is a directory +#define EINVAL 22 // Invalid argument +#define ENFILE 23 // File table overflow +#define EMFILE 24 // Too many open files +#define ENOTTY 25 // Not a typewriter +#define EFBIG 27 // File too large +#define ENOSPC 28 // No space left on device +#define ESPIPE 29 // Illegal seek +#define EROFS 30 // Read-only file system +#define EMLINK 31 // Too many links +#define EPIPE 32 // Broken pipe +#define ERANGE 34 // Math result not representable +#define ENAMETOOLONG 36 // File name too long +#define ENOSYS 38 // Function not implemented +#define ENOTEMPTY 39 // Directory not empty +#define ELOOP 40 // Too many symbolic links encountered + +// Sockets. Same Linux x86_64 values, so strerror() in a musl-linked program +// prints the message the programmer expected rather than a neighbouring one. +#define ENOTSOCK 88 // Socket operation on non-socket +#define EDESTADDRREQ 89 // Destination address required +#define EMSGSIZE 90 // Message too long +#define EPROTOTYPE 91 // Protocol wrong type for socket +#define ENOPROTOOPT 92 // Protocol not available +#define EPROTONOSUPPORT 93 // Protocol not supported +#define EOPNOTSUPP 95 // Operation not supported on transport endpoint +#define EAFNOSUPPORT 97 // Address family not supported by protocol +#define EADDRINUSE 98 // Address already in use +#define EADDRNOTAVAIL 99 // Cannot assign requested address +#define ECONNRESET 104 // Connection reset by peer +#define EISCONN 106 // Transport endpoint is already connected +#define ENOTCONN 107 // Transport endpoint is not connected +#define ECONNREFUSED 111 // Connection refused + +#endif // SCHUNIX_ERRNO_H diff --git a/include/fb.h b/include/fb.h new file mode 100644 index 0000000..2a0300d --- /dev/null +++ b/include/fb.h @@ -0,0 +1,95 @@ +#pragma once + +// Framebuffer device ABI -- /dev/fb0. +// +// These are Linux's fbdev request numbers and structure layouts, not ours. +// Schunix invented this device, so nothing forced the choice; matching Linux +// 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 +// FBIOGET_VSCREENINFO. Inventing a private struct would have meant patching +// each one we ever port, and -- worse -- a Linux-ABI binary calling +// FBIOGET_VSCREENINFO would have gotten a *differently shaped* answer to a +// request it thought it understood, which is the failure mode that made +// `>>` truncate back when include/fcntl.h held xv6's open flags instead of +// Linux's. Same lesson, applied before it bites rather than after. +// +// Plain C types throughout (no types.h) so userspace can include this +// directly. Both sides are LP64. + +#define FBIOGET_VSCREENINFO 0x4600 +#define FBIOPUT_VSCREENINFO 0x4601 +#define FBIOGET_FSCREENINFO 0x4602 +#define FBIOBLANK 0x4611 + +// fb_fix_screeninfo.type +#define FB_TYPE_PACKED_PIXELS 0 + +// fb_fix_screeninfo.visual +#define FB_VISUAL_TRUECOLOR 2 + +// fb_var_screeninfo.activate +#define FB_ACTIVATE_NOW 0 + +// One colour channel's position within a pixel. `offset` is the bit position +// of the channel's least significant bit; `length` is how many bits it gets. +// A length of 0 means the channel does not exist -- which is how an opaque +// framebuffer reports `transp`. +struct fb_bitfield { + unsigned int offset; + unsigned int length; + unsigned int msb_right; // != 0 means bit 0 is the MSB; never here +}; + +struct fb_var_screeninfo { + unsigned int xres; // visible resolution + unsigned int yres; + unsigned int xres_virtual; // virtual resolution; == visible, no panning + unsigned int yres_virtual; + unsigned int xoffset; // offset of visible area within virtual + unsigned int yoffset; + unsigned int bits_per_pixel; + unsigned int grayscale; // 0 == colour + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; + unsigned int nonstd; // 0 == standard pixel format + unsigned int activate; + unsigned int height; // physical size in mm; 0 == unknown, and + unsigned int width; // VBE does not tell us, so it stays 0 + unsigned int accel_flags; + // Timings. The mode is whatever the bootloader's VBE call established and + // we cannot change it, so these are all reported as zero rather than + // invented. + unsigned int pixclock; + unsigned int left_margin; + unsigned int right_margin; + unsigned int upper_margin; + unsigned int lower_margin; + unsigned int hsync_len; + unsigned int vsync_len; + unsigned int sync; + unsigned int vmode; + unsigned int rotate; + unsigned int colorspace; + unsigned int reserved[4]; +}; + +struct fb_fix_screeninfo { + char id[16]; // "schunixfb" + unsigned long smem_start; // physical address of the framebuffer + unsigned int smem_len; // its length in bytes + unsigned int type; + unsigned int type_aux; + unsigned int visual; + unsigned short xpanstep; // 0 == panning unsupported + unsigned short ypanstep; + unsigned short ywrapstep; + unsigned int line_length; // bytes per scanline (the VBE stride, which + // is NOT always xres * bytes_per_pixel) + unsigned long mmio_start; // no separate register aperture + unsigned int mmio_len; + unsigned int accel; // no acceleration + unsigned short capabilities; + unsigned short reserved[2]; +}; diff --git a/include/fcntl.h b/include/fcntl.h new file mode 100644 index 0000000..45b98b1 --- /dev/null +++ b/include/fcntl.h @@ -0,0 +1,43 @@ +#pragma once + +// open(2) flags. +// +// These are the *Linux x86-64* values, and they have to be: every program in +// 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 +// results that looked like filesystem corruption rather than like a mistake -- +// Linux O_APPEND (0x400) landed on Schunix's O_TRUNC, so `cmd >> file` +// 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. +// Neither failure pointed anywhere near a header. +// +// Do not tidy these into a neat sequence. They are an external interface. + +#define O_RDONLY 0x000000 +#define O_WRONLY 0x000001 +#define O_RDWR 0x000002 +#define O_ACCMODE 0x000003 + +#define O_CREATE 0x000040 /* Linux O_CREAT (0100) */ +#define O_CREAT O_CREATE /* the spelling every program uses */ +#define O_EXCL 0x000080 /* Linux O_EXCL (0200) */ +#define O_NOCTTY 0x000100 /* Linux O_NOCTTY (0400) */ +#define O_TRUNC 0x000200 /* Linux O_TRUNC (01000) */ +#define O_APPEND 0x000400 /* Linux O_APPEND (02000) */ +#define O_NONBLOCK 0x000800 /* Linux O_NONBLOCK (04000); no-op here */ +#define O_DIRECTORY 0x010000 /* Linux O_DIRECTORY (0200000) */ +#define O_NOFOLLOW 0x020000 /* Linux O_NOFOLLOW (0400000) */ +#define O_CLOEXEC 0x080000 /* Linux O_CLOEXEC (02000000) */ + +// Schunix-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. +#define O_EXTENT 0x8000000 /* sparse-extent hint */ + +#define F_DUPFD 0 +#define F_GETFD 1 +#define F_SETFD 2 +#define F_GETFL 3 +#define F_SETFL 4 +#define F_DUPFD_CLOEXEC 1030 // Linux value + +#define FD_CLOEXEC 1 diff --git a/include/file.h b/include/file.h new file mode 100644 index 0000000..4f4f17e --- /dev/null +++ b/include/file.h @@ -0,0 +1,132 @@ +struct file { + enum { FD_NONE, FD_PIPE, FD_INODE, FD_SOCKET } type; + int ref; // reference count + char readable; + char writable; + // O_NONBLOCK. A property of the open file description, not of the + // descriptor, which is why it lives here and not in myproc()->ofile_flags -- + // dup() shares it and F_SETFL on either fd changes it for both, exactly as + // POSIX says. + char nonblock; + struct pipe *pipe; + struct inode *ip; + struct socket *sock; + uint64 off; +}; + +// --------------------------------------------------------------------------- +// Filesystem operations +// +// One table per filesystem, chosen by iget() from the device number and hung +// off the inode. Everything above this line -- the syscall layer, exec, the +// page cache -- calls the wrappers in fs.c and never learns which filesystem it +// is talking to. +// +// A vtable rather than a chain of `if (dev == SCHFS_DEV)` because there are two +// filesystems today and there will be more: the whole point of the exercise is +// that adding one is a new table, not another branch in fifteen functions. +// +// Every hook takes an inode that is already locked, except ialloc (which has no +// inode yet) and iload (which is what makes one valid in the first place). +// --------------------------------------------------------------------------- + +struct stat; + +struct fs_ops { + const char *name; + + // Fill in the type/size/link fields of a freshly iget()'d inode. + void (*iload)(struct inode *); + // Write those fields back to disk. + void (*istore)(struct inode *); + // The last link is gone and nobody has it open: release the object. + void (*ifree)(struct inode *); + + int (*read)(struct inode *, int user_dst, uint64 dst, uint64 off, uint n); + int (*write)(struct inode *, int user_src, uint64 src, uint64 off, uint n); + // Set the length. Growing is allowed only where the filesystem can represent + // the gap; v1 cannot and ignores it. + void (*truncate)(struct inode *, uint64 newsize); + + // Directory operations. `poff` is an opaque cookie identifying where the + // entry lives, meaningful only to the same filesystem's dirunlink. + struct inode *(*dirlookup)(struct inode *dp, char *name, uint *poff); + int (*dirlink)(struct inode *dp, char *name, uint64 inum); + int (*dirunlink)(struct inode *dp, char *name, uint off); + int (*dirempty)(struct inode *dp); + + // Create an object with no name yet. The caller sets nlink and calls + // dirlink; until it does, the object is unreachable. + struct inode *(*ialloc)(uint dev, short type); + + // Read directory entries into a getdents64-shaped stream. `off` is an opaque + // position that starts at 0 and is echoed back; returns bytes written, 0 at + // the end of the directory, or negative on error. + int (*getdents)(struct inode *dp, char *out, int cap, uint64 *off); +}; + +// In-memory inode. +// +// `inum` and `size` are 64-bit because the filesystem underneath may be: SchFS +// object ids and file sizes are both uint64 on disk, and a 32-bit copy here +// would silently truncate them into a different file. The v1 filesystem uses a +// small fraction of the range and is unaffected. +struct inode { + uint dev; + uint64 inum; + int ref; + struct sleeplock lock; + int valid; + const struct fs_ops *ops; // chosen by iget from dev; never null once held + + short type; + short major; + short minor; + short nlink; + uint64 size; + + uint rwmode; + uint supermode; + uint showmode; + uint atime; + uint mtime; + uint ctime; + uint addrs[NDIRECT+3]; +}; +#define I_VALID 0x2 + +// Device number that means "the mounted SchFS volume". Real disks are 0 and 1, +// and this is deliberately far from them so a stray value never looks like a +// SchFS inode. +#define SCHFS_DEV 64 + +// Device number that means "the synthetic /proc". Like SCHFS_DEV, it is +// deliberately nowhere near a real disk's 0 or 1. +#define PROCFS_DEV 65 + +// table mapping major device number to +// device functions +struct devsw { + int (*read)(struct inode*, uint, char*, int); + int (*write)(struct inode*, uint, char*, int); + // Optional. Returns 0 when a read would block, which is the only thing + // fileread needs to know to honour O_NONBLOCK without every device driver + // growing a flags argument. A device that omits this is treated as always + // ready, which is the right answer for a disk and for /dev/zero. + int (*ready)(struct inode*); + // Optional. The last descriptor for this open file is going away. A device + // that hands a program exclusive-feeling control of the hardware needs this + // to put the hardware back -- /dev/fb0 uses it to give the text console its + // screen back when whatever was drawing on it exits. + void (*close)(struct inode*); + // Optional. A descriptor has just been opened on this device. /dev/input + // uses it to discard events that arrived while nobody was listening -- see + // inputopen(). + void (*open)(struct inode*); +}; + +extern struct devsw devsw[]; + +#define CONSOLE 1 +// Major number of /dev/input/eventN. The minor is the device index. +#define INPUT_MAJOR 7 diff --git a/include/font.h b/include/font.h new file mode 100644 index 0000000..2a2b021 --- /dev/null +++ b/include/font.h @@ -0,0 +1,4627 @@ +/* Schunix OS System Font - 8x16, 256 glyphs. + * + * 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. + * + * IGNORE THE PER-GLYPH COMMENTS BELOW FROM 128 UP. They label index N with + * Unicode codepoint N -- so 0xE9 is annotated 'e-acute' when the bitmap it + * sits above is unmistakably a theta. Whatever generated this file assumed + * Latin-1 and was wrong; the bitmaps are the truth, and console.c maps + * Unicode onto them through a table rather than by trusting an index. + * + * This was declared [128][16] until 2026-08-04, so the compiler discarded + * every glyph from 128 up -- 128 of them, already drawn and sitting in this + * file -- with nothing but a wall of "excess elements in array initializer" + * warnings to say so. + */ +unsigned char font_data[256][16] = { + + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x81, /* 10000001 */ + 0xa5, /* 10100101 */ + 0x81, /* 10000001 */ + 0x81, /* 10000001 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0x81, /* 10000001 */ + 0x81, /* 10000001 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 2 0x02 '^B' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xdb, /* 11011011 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 3 0x03 '^C' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 6 0x06 '^F' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 11 0x0b '^K' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x0e, /* 00001110 */ + 0x1a, /* 00011010 */ + 0x32, /* 00110010 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 12 0x0c '^L' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 13 0x0d '^M' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 14 0x0e '^N' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe7, /* 11100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 15 0x0f '^O' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 16 0x10 '^P' */ + 0x00, /* 00000000 */ + 0x80, /* 10000000 */ + 0xc0, /* 11000000 */ + 0xe0, /* 11100000 */ + 0xf0, /* 11110000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x00, /* 00000000 */ + 0x02, /* 00000010 */ + 0x06, /* 00000110 */ + 0x0e, /* 00001110 */ + 0x1e, /* 00011110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x1e, /* 00011110 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 19 0x13 '^S' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 24 0x18 '^X' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x28, /* 00101000 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x86, /* 10000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc2, /* 11000010 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0x86, /* 10000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0xff, /* 11111111 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x02, /* 00000010 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x38, /* 00111000 */ + 0x78, /* 01111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x1c, /* 00011100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 60 0x3c '<' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xdc, /* 11011100 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc2, /* 11000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xde, /* 11011110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x66, /* 01100110 */ + 0x3a, /* 00111010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe6, /* 11100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xee, /* 11101110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xfe, /* 11111110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xde, /* 11011110 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 82 0x52 'R' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x5a, /* 01011010 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0xee, /* 11101110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x86, /* 10000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc2, /* 11000010 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x80, /* 10000000 */ + 0xc0, /* 11000000 */ + 0xe0, /* 11100000 */ + 0x70, /* 01110000 */ + 0x38, /* 00111000 */ + 0x1c, /* 00011100 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 96 0x60 '`' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x36, /* 00110110 */ + 0x32, /* 00110010 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 104 0x68 'h' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x6c, /* 01101100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 107 0x6b 'k' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0xfc, /* 11111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x36, /* 00110110 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 124 0x7c '|' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 126 0x7e '~' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '€' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc2, /* 11000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 129 0x81 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '‚' */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 131 0x83 'ƒ' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '„' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '…' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '†' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '‡' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 136 0x88 'ˆ' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '‰' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 138 0x8a 'Š' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '‹' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 140 0x8c 'Œ' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 142 0x8e 'Ž' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '‘' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x6e, /* 01101110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '’' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3e, /* 00111110 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '“' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '”' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '•' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '–' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '—' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '˜' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 153 0x99 '™' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a 'š' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '›' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 156 0x9c 'œ' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x64, /* 01100100 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xe6, /* 11100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 158 0x9e 'ž' */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xf8, /* 11111000 */ + 0xc4, /* 11000100 */ + 0xcc, /* 11001100 */ + 0xde, /* 11011110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 159 0x9f 'Ÿ' */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 ' ' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '¡' */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '¢' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '£' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '¤' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '¥' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xfe, /* 11111110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '¦' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '§' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '¨' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '©' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa 'ª' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '«' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0xe0, /* 11100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xdc, /* 11011100 */ + 0x86, /* 10000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 172 0xac '¬' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0xe0, /* 11100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xce, /* 11001110 */ + 0x9a, /* 10011010 */ + 0x3f, /* 00111111 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 173 0xad '­' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '®' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x36, /* 00110110 */ + 0x6c, /* 01101100 */ + 0xd8, /* 11011000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '¯' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xd8, /* 11011000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x6c, /* 01101100 */ + 0xd8, /* 11011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '°' */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + + /* 177 0xb1 '±' */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + + /* 178 0xb2 '²' */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + + /* 179 0xb3 '³' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 180 0xb4 '´' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 181 0xb5 'µ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 182 0xb6 '¶' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 183 0xb7 '·' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 184 0xb8 '¸' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 185 0xb9 '¹' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 186 0xba 'º' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 187 0xbb '»' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 188 0xbc '¼' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd '½' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe '¾' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf '¿' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 192 0xc0 'À' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 'Á' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 'Â' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 195 0xc3 'Ã' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 196 0xc4 'Ä' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 'Å' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 198 0xc6 'Æ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 199 0xc7 'Ç' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 200 0xc8 'È' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 'É' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 202 0xca 'Ê' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb 'Ë' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 204 0xcc 'Ì' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 205 0xcd 'Í' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce 'Î' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 207 0xcf 'Ï' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 'Ð' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 'Ñ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 210 0xd2 'Ò' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 211 0xd3 'Ó' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 'Ô' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 'Õ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 214 0xd6 'Ö' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 215 0xd7 '×' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 216 0xd8 'Ø' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 217 0xd9 'Ù' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda 'Ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 219 0xdb 'Û' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 220 0xdc 'Ü' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 221 0xdd 'Ý' */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + + /* 222 0xde 'Þ' */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + + /* 223 0xdf 'ß' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 'à' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 'á' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 'â' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 'ã' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 'ä' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 'å' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 'æ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 231 0xe7 'ç' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 'è' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 233 0xe9 'é' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 234 0xea 'ê' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xee, /* 11101110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 235 0xeb 'ë' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x3e, /* 00111110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 236 0xec 'ì' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed 'í' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x03, /* 00000011 */ + 0x06, /* 00000110 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xf3, /* 11110011 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 238 0xee 'î' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 239 0xef 'ï' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 'ð' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 'ñ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 'ò' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 'ó' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 'ô' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 245 0xf5 'õ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 246 0xf6 'ö' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 '÷' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 'ø' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 'ù' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa 'ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb 'û' */ + 0x00, /* 00000000 */ + 0x0f, /* 00001111 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xec, /* 11101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3c, /* 00111100 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 252 0xfc 'ü' */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd 'ý' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe 'þ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff 'ÿ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + +}; diff --git a/include/fs.h b/include/fs.h new file mode 100644 index 0000000..29bad86 --- /dev/null +++ b/include/fs.h @@ -0,0 +1,203 @@ +// SCHFS - On-disk file system format. +// Both the kernel and user programs use this header file. +// +// Changes from original: +// - struct dinode gains atime, mtime, ctime (timestamps) and checksum +// (CRC32c). Padding reduced from 44 to 28 bytes; struct stays 128 bytes. +// - struct superblock gains checksum field. +// - struct fsv1_extent added for T_EXTENT inode block mapping. +// - OVERFLOW_DIR_START / OVERFLOW_DIR_END replace the bare "113 * BSIZE" +// magic numbers used in fs.c and mkfs.c. + +#ifndef FS_H +#define FS_H + +#define ROOTINO 1 // root i-number +#define BSIZE 1024 // block size + +// Permission mode bits (rwmode field) +#define RW 3 // 11 read+write +#define W_ 1 // 01 write-only +#define R_ 2 // 10 read-only +#define NONE 0 // 00 no access + +// --------------------------------------------------------------------------- +// Superblock +// --------------------------------------------------------------------------- +// Disk layout: +// [ boot | super | log | inode-bitmap | inode-blocks | block-bitmap | data ] + +struct superblock { + uint magic; // Must be FSMAGIC + uint size; // Size of file system image (blocks) + uint nblocks; // Number of data blocks + uint ninodes; // Number of inodes + uint nlog; // Number of log blocks + uint logstart; // Block number of first log block + uint inodestart; // Block number of first inode block + uint bmapstart; // Block number of first free-block bitmap block + uint ibmapstart; // Block number of first inode-bitmap block + uint freeinodes; // Count of free inodes + uint freeblocks; // Count of free blocks + uint checksum; // CRC32c of this struct (field zeroed during computation) +}; + +extern struct superblock sb; + +#define FSMAGIC 0x10203040 + +// --------------------------------------------------------------------------- +// Block / inode geometry +// --------------------------------------------------------------------------- + +#define NDIRECT 12 +#define NINDIRECT (BSIZE / sizeof(uint)) + +// Maximum file size in blocks: direct + 1x + 2x + 3x indirect +#define MAXFILE (NDIRECT \ ++ NINDIRECT \ ++ (NINDIRECT * NINDIRECT) \ ++ (NINDIRECT * NINDIRECT * NINDIRECT)) + +// --------------------------------------------------------------------------- +// Extent descriptor (T_EXTENT inodes only) +// +// Up to MAX_INLINE_EXTENTS are packed into ip->addrs[0..NDIRECT-1]. +// addrs[] = NDIRECT uints = 12*4 = 48 bytes +// each fsv1_extent = 12 bytes → 48/12 = 4 inline extents +// (addrs[NDIRECT], [NDIRECT+1], [NDIRECT+2] remain as indirect pointers) +// +// For files needing more extents, addrs[NDIRECT] points to an indirect block +// of BSIZE/sizeof(struct fsv1_extent) = 85 additional extents. +// --------------------------------------------------------------------------- + +// Renamed from "schfs_extent". The new format in include/schfs.h has its own, +// completely different, struct of that name -- 64-bit fields and a refcount -- +// and any file including both headers hit a redefinition error. Two structs +// with one name and two layouts is a trap worth removing rather than working +// around; this one belongs to the v1 format and dies with it. +struct fsv1_extent { + uint start_block; // logical block number in the file (first of run) + uint start_blkaddr; // physical disk block address + uint len; // number of contiguous blocks in this run +}; + +// Inline extents packed into addrs[0 .. NDIRECT-1] only. +#define MAX_INLINE_EXTENTS (NDIRECT * sizeof(uint) / sizeof(struct fsv1_extent)) + +// --------------------------------------------------------------------------- +// On-disk inode (exactly 128 bytes; IPB = 8 inodes per 1024-byte block) +// +// Byte layout: +// 0 short type 2 +// 2 short major 2 +// 4 short minor 2 +// 6 short nlink 2 +// 8 uint size 4 +// 12 uint rwmode 4 +// 16 uint supermode 4 +// 20 uint addrs[15] 60 T_EXTENT: packed fsv1_extent[4] in [0..11], rest normal +// 80 uint showmode 4 +// 84 uint atime 4 ← last access time (Unix seconds) +// 88 uint mtime 4 ← last modification time +// 92 uint ctime 4 ← last metadata-change time +// 96 uint checksum 4 ← CRC32c (zeroed during computation) +// 100 uchar pad[28] 28 ← was 44; reduced by 16 for the 4 new fields +// 128 bytes total +// --------------------------------------------------------------------------- + +struct dinode { + short type; // file type + short major; // major device number (T_DEVICE only) + short minor; // minor device number (T_DEVICE only) + short nlink; // hard-link count + uint size; // file size in bytes + uint rwmode; // read/write permission flags + uint supermode; // superuser-only flag + uint addrs[NDIRECT + 3]; // block addresses / packed extent entries + uint showmode; // visibility flag + uint atime; // last access time (seconds since epoch) + uint mtime; // last modification time + uint ctime; // last metadata-change time + uint checksum; // CRC32c of this dinode (field = 0 when hashing) + uchar pad[28]; // reserved padding (struct = 128 bytes) +}; + +// Inodes per block +#define IPB (BSIZE / sizeof(struct dinode)) + +// Block containing inode i +#define IBLOCK(i, sb) ((i) / IPB + (sb).inodestart) + +// Bitmap bits per block +#define BPB (BSIZE * 8) + +// Block of free-block bitmap containing bit for block b +#define BBLOCK(b, sb) ((b) / BPB + (sb).bmapstart) + +// Block of inode bitmap containing bit for inode i +#define IBBLOCK(i, sb) ((i) / BPB + (sb).ibmapstart) + +// --------------------------------------------------------------------------- +// Directory entry +// --------------------------------------------------------------------------- + +// 30, not 14. +// +// 14 was xv6's, and the v1 filesystem truncated to it *silently*: a file called +// JetBrainsMono-Regular.ttf was stored as "JetBrainsMono-", could not be opened +// by its real name, and would have collided outright with +// JetBrainsMono-Bold.ttf. Any two files sharing a 14-character prefix mapped to +// one entry. That is data loss, not a display limit. +// +// The value is chosen so that `struct dirent` is exactly 32 bytes, because the +// directory HTree below is laid out in *bytes* and a bucket must stay 256 bytes +// (see DIRENT_BUCKET_BYTES). Going from 16-byte to 32-byte entries therefore +// halves the slots per bucket from 16 to 8 and changes no offset anywhere else +// -- HASHRANGE, the overflow region and MAXFSIZE all keep their values. The +// cost is more overflow use in heavily collided directories, which is a far +// better trade than silently mangling names. +// +// It is still not POSIX's 255. Getting there means reshaping the directory +// format, which wants the on-disk version policy SchFS is getting first. +#define DIRSIZ 30 + +struct dirent { + ushort inum; + char name[DIRSIZ]; +}; + +// --------------------------------------------------------------------------- +// Directory HTree constants +// +// BKDRHash(name) returns a value in [16, 16 + HASHRANGE). +// Each bucket is 256 bytes: 8 dirent slots of 32 bytes. It was 16 slots of 16 +// until DIRSIZ grew; the byte size is what the layout depends on, so it is the +// thing held constant. +// +// With HASHRANGE=443: +// max primary end byte = (16 + 443) * 256 = 117 504 (~114.75 blocks) +// OVERFLOW_DIR_START = 113 * BSIZE = 115 712 +// OVERFLOW_DIR_END = 115 * BSIZE = 117 760 +// MAXFSIZE = 119 * BSIZE = 121 856 +// --------------------------------------------------------------------------- + +#define DIRENT_NUM 7168 +#define FIRST_LAYER_NODE_NUM 112 +#define OVERFLOW_BLOCK (FIRST_LAYER_NODE_NUM + 1) +#define NUM_DIRENT_PER_BLOCK (BSIZE / sizeof(struct dirent)) +#define SECOND_LAYER_NODE_NUM NUM_DIRENT_PER_BLOCK +#define HASHRANGE 443 + +// One hash bucket, in bytes. Every offset in the HTree is derived from this, so +// it must not change when DIRSIZ does -- see the note on DIRSIZ. +#define DIRENT_BUCKET_BYTES 256 +#define DIRENT_PER_BUCKET (DIRENT_BUCKET_BYTES / sizeof(struct dirent)) +#define MAXFSIZE (119 * BSIZE) + +// Overflow bucket: shared between fs.c and mkfs.c. +// These replace the bare "113 * BSIZE" / "115 * BSIZE" literals. +#define OVERFLOW_DIR_START (113 * BSIZE) +#define OVERFLOW_DIR_END (115 * BSIZE) + +#endif // FS_H diff --git a/include/input.h b/include/input.h new file mode 100644 index 0000000..2842de6 --- /dev/null +++ b/include/input.h @@ -0,0 +1,93 @@ +#pragma once + +#include "types.h" + +// Raw input events -- Linux's evdev interface. +// +// The console gives characters. That is the right thing for a shell and the +// wrong thing for everything else: a character stream has no key *releases*, +// no way to tell left shift from right, no notion of a key being held, and no +// mouse at all. A game holding W to walk forward, or a compositor deciding +// which window a click landed in, needs the events underneath the characters. +// +// The layout is Linux's, deliberately. It is what every program that reads input +// already speaks -- SDL, X, libinput, every game engine -- so a program that +// runs on Linux reads input here without a porting layer. It costs nothing to +// match: the struct is four fields. +// +// Nodes are /dev/input/event0 (keyboard) and /dev/input/event1 (mouse). + +struct input_timeval { + int64 tv_sec; + int64 tv_usec; +}; + +struct input_event { + struct input_timeval time; + uint16 type; + uint16 code; + int32 value; +}; + +// Event types. +#define EV_SYN 0x00 +#define EV_KEY 0x01 +#define EV_REL 0x02 +#define EV_ABS 0x03 +#define EV_MSC 0x04 + +#define SYN_REPORT 0 + +// Relative axes. +#define REL_X 0x00 +#define REL_Y 0x01 +#define REL_WHEEL 0x08 + +// Buttons live in the EV_KEY code space alongside keys, which is why the +// keyboard's codes stop well below 0x100. +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 + +// Key codes worth naming. The rest are the AT scancode-set-1 numbers, which +// Linux's keycodes were derived from and still match for everything below +// 0x54 -- that is not a coincidence and it is why the PS/2 path needs no +// translation table for unprefixed bytes. +#define KEY_RESERVED 0 +#define KEY_ESC 1 +#define KEY_ENTER 28 +#define KEY_LEFTCTRL 29 +#define KEY_LEFTSHIFT 42 +#define KEY_RIGHTSHIFT 54 +#define KEY_LEFTALT 56 +#define KEY_SPACE 57 +#define KEY_RIGHTCTRL 97 +#define KEY_RIGHTALT 100 +#define KEY_HOME 102 +#define KEY_UP 103 +#define KEY_PAGEUP 104 +#define KEY_LEFT 105 +#define KEY_RIGHT 106 +#define KEY_END 107 +#define KEY_DOWN 108 +#define KEY_PAGEDOWN 109 +#define KEY_INSERT 110 +#define KEY_DELETE 111 +#define KEY_LEFTMETA 125 +#define KEY_RIGHTMETA 126 + +#define KEY_MAX 255 + +// EVIOCGRAB -- take/release exclusive access to a device. +// +// 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 +// 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. +#define EVIOCGRAB 0x40044590 + +// Which device an event came from. Both are minor numbers under the input +// major, and both are the index into the driver's array. +#define INPUT_KBD 0 +#define INPUT_MOUSE 1 +#define NINPUTDEV 2 diff --git a/include/irq.h b/include/irq.h new file mode 100644 index 0000000..c4285b2 --- /dev/null +++ b/include/irq.h @@ -0,0 +1,43 @@ +#pragma once + +// Hardware interrupt registration. +// +// Until this existed, trap() was a switch statement listing every interrupt +// the kernel knew about, and adding a device meant editing the trap handler. +// That is fine while the devices are the four the PC has always had at fixed +// pins; it stops being fine the moment a device's IRQ is whatever the BIOS +// decided to put in its PCI config space this boot. A driver cannot write +// `case T_IRQ0 + IRQ_XHCI:` because there is no such constant -- it only +// learns its line at probe time. +// +// So: a line has a chain of handlers, a driver adds itself to one at probe +// time, and enabling the line is a consequence of registering rather than a +// separate call somebody can forget. +// +// Chains matter more than they look. PCI interrupt pins are *shared*: four +// INTx lines are routed to a handful of IOAPIC inputs, so two unrelated +// devices routinely land on the same one. A handler must therefore check +// whether its own device actually raised the interrupt and do nothing if it +// did not. + +#define NIRQ 24 // IOAPIC redirection entries on a PC +#define NCHAIN 4 // handlers that may share one line + +typedef void (*irq_handler_t)(void *arg); + +// Returns 0, or -1 if the line is out of range, reserved, or full. +// Registering enables the line; the last unregister masks it again. +// +// `level_low` selects PCI's signalling (level-triggered, active low) rather +// than ISA's (edge-triggered, active high). Getting this wrong does not fail +// cleanly: an edge-configured level interrupt fires once and then wedges, +// because the device keeps the line asserted and no further edge ever comes. +int irq_register(int irq, irq_handler_t fn, void *arg, const char *name, + int level_low); +void irq_unregister(int irq, irq_handler_t fn, void *arg); + +// Called from trap() with the IOAPIC pin number, not the vector. +void irq_dispatch(int irq); + +void irq_init(void); +int irq_info(char *buf, int cap); // /proc/interrupts diff --git a/include/kbd.h b/include/kbd.h new file mode 100644 index 0000000..babbd6e --- /dev/null +++ b/include/kbd.h @@ -0,0 +1,112 @@ +// PC keyboard interface constants + +#define KBSTATP 0x64 // kbd controller status port(I) +#define KBS_DIB 0x01 // kbd data in buffer +#define KBDATAP 0x60 // kbd data port(I) + +#define NO 0 + +#define SHIFT (1<<0) +#define CTL (1<<1) +#define ALT (1<<2) + +#define CAPSLOCK (1<<3) +#define NUMLOCK (1<<4) +#define SCROLLLOCK (1<<5) + +#define E0ESC (1<<6) + +// Special keycodes +#define KEY_HOME 0xE0 +#define KEY_END 0xE1 +#define KEY_UP 0xE2 +#define KEY_DN 0xE3 +#define KEY_LF 0xE4 +#define KEY_RT 0xE5 +#define KEY_PGUP 0xE6 +#define KEY_PGDN 0xE7 +#define KEY_INS 0xE8 +#define KEY_DEL 0xE9 + +// C('A') == Control-A +#define C(x) (x - '@') + +static uchar shiftcode[256] = +{ + [0x1D] CTL, + [0x2A] SHIFT, + [0x36] SHIFT, + [0x38] ALT, + [0x9D] CTL, + [0xB8] ALT +}; + +static uchar togglecode[256] = +{ + [0x3A] CAPSLOCK, + [0x45] NUMLOCK, + [0x46] SCROLLLOCK +}; + +static uchar normalmap[256] = +{ + NO, 0x1B, '1', '2', '3', '4', '5', '6', // 0x00 + '7', '8', '9', '0', '-', '=', '\b', '\t', + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', // 0x10 + 'o', 'p', '[', ']', '\n', NO, 'a', 's', + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', // 0x20 + '\'', '`', NO, '\\', 'z', 'x', 'c', 'v', + 'b', 'n', 'm', ',', '.', '/', NO, '*', // 0x30 + NO, ' ', NO, NO, NO, NO, NO, NO, + NO, NO, NO, NO, NO, NO, NO, '7', // 0x40 + '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', NO, NO, NO, NO, // 0x50 + [0x9C] '\n', // KP_Enter + [0xB5] '/', // KP_Div + [0xC8] KEY_UP, [0xD0] KEY_DN, + [0xC9] KEY_PGUP, [0xD1] KEY_PGDN, + [0xCB] KEY_LF, [0xCD] KEY_RT, + [0x97] KEY_HOME, [0xCF] KEY_END, + [0xD2] KEY_INS, [0xD3] KEY_DEL +}; + +static uchar shiftmap[256] = +{ + NO, 033, '!', '@', '#', '$', '%', '^', // 0x00 + '&', '*', '(', ')', '_', '+', '\b', '\t', + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', // 0x10 + 'O', 'P', '{', '}', '\n', NO, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', // 0x20 + '"', '~', NO, '|', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', NO, '*', // 0x30 + NO, ' ', NO, NO, NO, NO, NO, NO, + NO, NO, NO, NO, NO, NO, NO, '7', // 0x40 + '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', NO, NO, NO, NO, // 0x50 + [0x9C] '\n', // KP_Enter + [0xB5] '/', // KP_Div + [0xC8] KEY_UP, [0xD0] KEY_DN, + [0xC9] KEY_PGUP, [0xD1] KEY_PGDN, + [0xCB] KEY_LF, [0xCD] KEY_RT, + [0x97] KEY_HOME, [0xCF] KEY_END, + [0xD2] KEY_INS, [0xD3] KEY_DEL +}; + +static uchar ctlmap[256] = +{ + NO, NO, NO, NO, NO, NO, NO, NO, + NO, NO, NO, NO, NO, NO, NO, NO, + C('Q'), C('W'), C('E'), C('R'), C('T'), C('Y'), C('U'), C('I'), + C('O'), C('P'), NO, NO, '\r', NO, C('A'), C('S'), + C('D'), C('F'), C('G'), C('H'), C('J'), C('K'), C('L'), NO, + NO, NO, NO, C('\\'), C('Z'), C('X'), C('C'), C('V'), + C('B'), C('N'), C('M'), NO, NO, C('/'), NO, NO, + [0x9C] '\r', // KP_Enter + [0xB5] C('/'), // KP_Div + [0xC8] KEY_UP, [0xD0] KEY_DN, + [0xC9] KEY_PGUP, [0xD1] KEY_PGDN, + [0xCB] KEY_LF, [0xCD] KEY_RT, + [0x97] KEY_HOME, [0xCF] KEY_END, + [0xD2] KEY_INS, [0xD3] KEY_DEL +}; + diff --git a/include/logo.h b/include/logo.h new file mode 100644 index 0000000..390199e --- /dev/null +++ b/include/logo.h @@ -0,0 +1,534 @@ +#pragma once + +// GENERATED by tools/mklogo.py -- do not edit. Run `make logo`. +// source: Assets/Schunix Small Logo.png +// +// 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 +// include/theme.h and can change without regenerating anything. +// +// Two pixels per byte, high nibble first. Included by boot/stage2main.c +// as well as kernel/dev/vga.c, and stage2 must fit below the 0x10000 +// kernel-search buffer -- hence 4 bits rather than 8. + +#define LOGO_W 128 +#define LOGO_H 128 + +// Ink at linear pixel index i, 0..255. +#define LOGO_INK(i) ((unsigned char)((((i) & 1) ? (logo_mask[(i) >> 1] & 0xF) \ + : (logo_mask[(i) >> 1] >> 4)) * 17)) + +static const unsigned char logo_mask[LOGO_W * LOGO_H / 2] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x56,0x79,0xaa,0xbb, + 0xbb,0xaa,0x98,0x75,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x47,0x9b,0xbb,0xbb,0xbb,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcb,0xbb,0xb9,0x74,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x47,0x9a,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xba,0x75,0x20,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x15,0x8a,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0xbb,0xb9,0x51,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x37,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0xaa,0x84,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x01,0x58,0x99,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0xaa,0xaa,0x96,0x10,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x01,0x69,0x99,0x99,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0xaa,0xaa,0xaa,0xa7,0x10,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x58,0x99,0x99,0x99,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0xba,0x87,0x76,0x66, + 0x66,0x67,0x89,0xab,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0xaa,0xaa,0xaa,0xaa,0xa6,0x10, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x48,0x88,0x99,0x99,0x99,0x99,0xaa,0xaa,0xaa,0xa9,0x65,0x31,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x13,0x57,0x9b,0xbb,0xbb,0xba,0xaa,0xaa,0xaa,0xaa,0xaa,0x95, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37, + 0x88,0x88,0x99,0x99,0x99,0x99,0xaa,0xa9,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0xab,0xba,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x93,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x88, + 0x88,0x88,0x99,0x99,0x99,0x99,0x95,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x6a,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x99,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x78,0x88, + 0x88,0x88,0x99,0x99,0x99,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x99,0x99,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x57,0x78,0x88, + 0x88,0x88,0x99,0x98,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0xaa,0xaa,0xaa,0xaa, + 0x99,0x99,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x77,0x78,0x88, + 0x88,0x88,0x98,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xaa,0xaa,0xaa, + 0x99,0x99,0x99,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x77,0x77,0x78,0x88, + 0x88,0x88,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xaa,0xaa, + 0x99,0x99,0x99,0x99,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x77,0x77,0x78,0x88, + 0x88,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0xaa, + 0x99,0x99,0x99,0x99,0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x77,0x77,0x77,0x78,0x88, + 0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x49, + 0x99,0x99,0x99,0x99,0x99,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x57,0x77,0x77,0x77,0x78,0x86, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, + 0x79,0x99,0x99,0x99,0x99,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x67,0x77,0x77,0x77,0x77,0x30, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x04,0x99,0x99,0x99,0x99,0x99,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x67,0x77,0x77,0x77,0x61,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x28,0x99,0x99,0x99,0x99,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x66,0x67,0x77,0x77,0x76,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x79,0x99,0x99,0x99,0x98,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x66,0x67,0x77,0x77,0x50,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x06,0x99,0x99,0x99,0x98,0x85,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x66,0x66,0x67,0x77,0x74,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x59,0x99,0x99,0x98,0x88,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x26,0x66,0x66,0x67,0x77,0x30,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x04,0x99,0x99,0x98,0x88,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x56,0x66,0x66,0x67,0x73,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x49,0x99,0x98,0x88,0x88,0x10,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x66,0x66,0x66,0x67,0x30,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x05,0x99,0x98,0x88,0x88,0x70,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x66,0x66,0x66,0x64,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x59,0x98,0x88,0x88,0x86,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x02,0x56,0x66,0x66,0x66,0x50,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x06,0x98,0x88,0x88,0x88,0x30,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x05,0x56,0x66,0x66,0x65,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x88,0x88,0x88,0x71,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x45,0x56,0x66,0x66,0x61,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x88,0x88,0x88,0x86,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x02,0x55,0x56,0x66,0x66,0x20,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x88,0x88,0x88,0x88,0x30,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x05,0x55,0x56,0x66,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x88,0x88,0x88,0x70,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x35,0x55,0x56,0x66,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x88,0x88,0x88,0x84,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x55,0x55,0x56,0x66,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x88,0x88,0x88,0x87,0x10,0x00,0x00,0x00, + 0x00,0x00,0x00,0x03,0x55,0x55,0x56,0x64,0x00,0x00,0x00,0x00,0x05,0xaa,0xaa,0xa9, + 0x99,0x98,0x88,0x88,0x77,0x77,0x66,0x66,0x65,0x55,0x55,0x30,0x00,0x00,0x00,0x00, + 0x00,0x00,0x35,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x29,0x98,0x10,0x00,0x00,0x68,0x88,0x88,0x88,0x50,0x00,0x00,0x00, + 0x00,0x00,0x00,0x15,0x55,0x55,0x56,0x50,0x00,0x00,0x00,0x00,0x5e,0xee,0xdd,0xdc, + 0xcc,0xcb,0xbb,0xaa,0xaa,0x99,0x98,0x88,0x77,0x77,0x66,0x63,0x00,0x00,0x00,0x00, + 0x00,0x03,0x77,0x77,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x02,0xbc,0xcc,0xb1,0x00,0x00,0x18,0x88,0x88,0x88,0x81,0x00,0x00,0x00, + 0x00,0x00,0x00,0x35,0x55,0x55,0x56,0x30,0x00,0x00,0x00,0x06,0xee,0xed,0xdd,0xdc, + 0xcc,0xbb,0xba,0xaa,0xa9,0x99,0x88,0x88,0x77,0x76,0x66,0x66,0x10,0x00,0x00,0x00, + 0x00,0x07,0x77,0x77,0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x3b,0xcc,0xcc,0xd8,0x00,0x00,0x04,0x88,0x88,0x88,0x85,0x00,0x00,0x00, + 0x00,0x00,0x01,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x6e,0xee,0xdd,0xdd,0xcc, + 0xcb,0xbb,0xba,0xaa,0x99,0x98,0x88,0x87,0x77,0x66,0x66,0x66,0x10,0x00,0x00,0x00, + 0x00,0x07,0x77,0x77,0x78,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x03,0xbc,0xcc,0xcc,0xd8,0x00,0x00,0x00,0x88,0x88,0x88,0x87,0x10,0x00,0x00, + 0x00,0x00,0x03,0x55,0x55,0x55,0x53,0x00,0x00,0x00,0x05,0xee,0xee,0xdd,0xdc,0xcc, + 0xbb,0xbb,0xaa,0xa9,0x99,0x98,0x88,0x77,0x76,0x66,0x66,0x66,0x10,0x00,0x00,0x00, + 0x00,0x07,0x77,0x77,0x78,0x85,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x2b,0xcc,0xcc,0xcd,0xd8,0x00,0x00,0x00,0x48,0x88,0x88,0x87,0x40,0x00,0x00, + 0x00,0x00,0x04,0x55,0x55,0x55,0x50,0x00,0x00,0x00,0x6e,0xee,0xed,0xdd,0xcc,0xcc, + 0xbb,0xba,0xaa,0x99,0x99,0x88,0x87,0x77,0x76,0x66,0x66,0x62,0x00,0x00,0x00,0x00, + 0x00,0x02,0x77,0x77,0x88,0x88,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0xbc,0xcc,0xcc,0xdd,0xa1,0x00,0x00,0x00,0x07,0x88,0x88,0x87,0x70,0x00,0x00, + 0x00,0x00,0x25,0x55,0x55,0x55,0x20,0x00,0x00,0x06,0xfe,0xee,0xdd,0xdc,0xa7,0x77, + 0x77,0x66,0x66,0x65,0x55,0x55,0x54,0x44,0x44,0x33,0x44,0x20,0x00,0x00,0x00,0x00, + 0x00,0x00,0x27,0x78,0x88,0x88,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x3b,0xcc,0xcc,0xcd,0xda,0x00,0x00,0x00,0x00,0x04,0x88,0x88,0x87,0x73,0x00,0x00, + 0x00,0x00,0x45,0x55,0x55,0x55,0x00,0x00,0x00,0x5e,0xee,0xed,0xdd,0xc9,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x03,0x78,0x88,0x88,0x88,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02, + 0xbc,0xcc,0xcc,0xdd,0xb1,0x00,0x00,0x00,0x00,0x00,0x88,0x88,0x87,0x76,0x00,0x00, + 0x00,0x01,0x45,0x55,0x55,0x53,0x00,0x00,0x05,0xee,0xee,0xdd,0xdd,0x80,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x28,0x88,0x88,0x88,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3b, + 0xcc,0xcc,0xcd,0xda,0x10,0x00,0x00,0x00,0x00,0x00,0x58,0x88,0x87,0x77,0x10,0x00, + 0x00,0x02,0x45,0x55,0x55,0x51,0x00,0x00,0x5e,0xee,0xed,0xdd,0xd8,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x02,0x88,0x88,0x88,0x99,0x60,0x00,0x00,0x00,0x00,0x00,0x03,0xbc, + 0xcc,0xcc,0xcd,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x88,0x87,0x77,0x40,0x00, + 0x00,0x04,0x45,0x55,0x55,0x50,0x00,0x04,0xee,0xee,0xed,0xdd,0x90,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x38,0x88,0x88,0x99,0x96,0x00,0x00,0x00,0x00,0x00,0x2b,0xcc, + 0xcc,0xcc,0xdb,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x88,0x87,0x77,0x70,0x00, + 0x00,0x14,0x45,0x55,0x55,0x20,0x00,0x08,0xee,0xee,0xdd,0xd8,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x88,0x89,0x99,0x99,0x60,0x00,0x00,0x00,0x02,0xbc,0xcc, + 0xcc,0xcd,0xa1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x88,0x87,0x77,0x71,0x00, + 0x00,0x24,0x45,0x55,0x55,0x00,0x00,0x08,0xee,0xed,0xdd,0xc8,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x38,0x99,0x99,0x9a,0xa7,0x00,0x00,0x00,0x2b,0xcc,0xcc, + 0xcc,0xda,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x88,0x87,0x77,0x73,0x00, + 0x00,0x34,0x45,0x55,0x54,0x00,0x00,0x05,0xee,0xdd,0xdc,0xcc,0x80,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x03,0x99,0x99,0xaa,0xaa,0x70,0x00,0x02,0xbb,0xcc,0xcc, + 0xcd,0xb1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x87,0x77,0x75,0x00, + 0x00,0x44,0x45,0x55,0x52,0x00,0x00,0x00,0x5d,0xdd,0xdc,0xcc,0xb7,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x39,0x99,0xaa,0xaa,0xa7,0x00,0x2b,0xbc,0xcc,0xcc, + 0xda,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x87,0x77,0x77,0x00, + 0x01,0x44,0x45,0x55,0x51,0x00,0x00,0x00,0x05,0xdd,0xcc,0xcb,0xbb,0x70,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x9a,0xaa,0xaa,0xab,0x82,0xbb,0xcc,0xcc,0xcc, + 0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x87,0x77,0x77,0x10, + 0x02,0x44,0x45,0x55,0x50,0x00,0x00,0x00,0x00,0x5c,0xcc,0xbb,0xbb,0xa7,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3a,0xaa,0xaa,0xbb,0xbb,0xbc,0xcc,0xcc,0xcb, + 0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x87,0x77,0x77,0x30, + 0x03,0x44,0x45,0x55,0x40,0x00,0x00,0x00,0x00,0x05,0xcc,0xbb,0xba,0xaa,0x75,0x55, + 0x55,0x44,0x44,0x43,0x33,0x33,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xaa,0xab,0xbb,0xbb,0xcc,0xcc,0xcc,0xa1, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x87,0x77,0x77,0x50, + 0x04,0x44,0x45,0x55,0x30,0x00,0x00,0x00,0x00,0x00,0x5b,0xbb,0xaa,0xaa,0x99,0x98, + 0x88,0x77,0x77,0x66,0x66,0x66,0x66,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4a,0xbb,0xbb,0xbc,0xcc,0xcc,0xca,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x87,0x77,0x77,0x60, + 0x04,0x44,0x45,0x55,0x20,0x00,0x00,0x00,0x00,0x00,0x04,0xba,0xaa,0xa9,0x99,0x88, + 0x87,0x77,0x76,0x66,0x66,0x66,0x66,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xbb,0xbb,0xcc,0xcc,0xcc,0xb1,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x87,0x77,0x77,0x70, + 0x14,0x44,0x45,0x55,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x4a,0xaa,0x99,0x98,0x88, + 0x77,0x77,0x66,0x66,0x66,0x66,0x66,0x66,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6b,0xbb,0xcc,0xcc,0xcc,0x10,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x87,0x77,0x77,0x71, + 0x14,0x44,0x45,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xa9,0x99,0x88,0x88, + 0x77,0x76,0x66,0x66,0x66,0x66,0x66,0x67,0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xab,0xbc,0xcc,0xcc,0xcd,0x90,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x77,0x77,0x72, + 0x24,0x44,0x45,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x39,0x98,0x88,0x87, + 0x77,0x66,0x66,0x66,0x66,0x66,0x66,0x77,0x77,0x60,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3a,0xbb,0xcc,0xcc,0xcc,0xdd,0xd9,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x77,0x77,0x77,0x73, + 0x24,0x44,0x45,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x76,0x66,0x65, + 0x55,0x55,0x44,0x55,0x55,0x56,0x67,0x77,0x77,0x76,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xbb,0xbc,0xcc,0xcc,0xcd,0xdd,0xdd,0xa0, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0x77,0x77,0x74, + 0x34,0x44,0x45,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x02,0x67,0x77,0x77,0x77,0x60,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2a,0xbb,0xcc,0xcc,0xcc,0xdd,0xdd,0xde,0xea, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x57,0x77,0x77,0x74, + 0x34,0x44,0x45,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x77,0x77,0x77,0x76,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xab,0xbc,0xcc,0xcc,0xa5,0xcd,0xdd,0xee,0xee, + 0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x77,0x77,0x75, + 0x34,0x44,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x77,0x77,0x77,0x77,0x60,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x3b,0xbb,0xbc,0xcc,0xca,0x00,0x4d,0xdd,0xee,0xee, + 0xe9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x77,0x77,0x75, + 0x44,0x44,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x77,0x77,0x78,0x86,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x02,0xab,0xbb,0xcc,0xcc,0xb1,0x00,0x05,0xde,0xee,0xee, + 0xdd,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x77,0x77,0x76, + 0x44,0x44,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x77,0x77,0x88,0x88,0x10,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x3a,0xbb,0xbc,0xcc,0xca,0x10,0x00,0x00,0x4d,0xee,0xed, + 0xdd,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x77,0x77,0x76, + 0x44,0x44,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x77,0x88,0x88,0x10,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0xbb,0xbb,0xcc,0xcc,0xa0,0x00,0x00,0x00,0x05,0xee,0xdd, + 0xdd,0xdd,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x77,0x77,0x76, + 0x44,0x44,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x78,0x88,0x88,0x10,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x2a,0xbb,0xbc,0xcc,0xca,0x10,0x00,0x00,0x00,0x00,0x5d,0xdd, + 0xdd,0xdd,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x77,0x77,0x76, + 0x44,0x44,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x88,0x88,0x88,0x10,0x00,0x00,0x00, + 0x00,0x00,0x00,0x02,0xab,0xbb,0xcc,0xcc,0xa1,0x00,0x00,0x00,0x00,0x00,0x05,0xdd, + 0xdd,0xdd,0xcc,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x77,0x77,0x76, + 0x44,0x44,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x88,0x88,0x88,0x10,0x00,0x00,0x00, + 0x00,0x00,0x00,0x2a,0xbb,0xbb,0xcc,0xca,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5d, + 0xdd,0xdc,0xcc,0xc8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x77,0x77,0x76, + 0x34,0x44,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x88,0x88,0x88,0x10,0x00,0x00,0x00, + 0x00,0x00,0x02,0xab,0xbb,0xbc,0xcc,0xa1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05, + 0xdd,0xcc,0xcc,0xcc,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x77,0x77,0x76, + 0x34,0x44,0x45,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x88,0x88,0x10,0x00,0x00,0x00, + 0x00,0x00,0x2a,0xbb,0xbb,0xcc,0xca,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x5c,0xcc,0xcc,0xcc,0xc8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x77,0x77,0x75, + 0x34,0x44,0x45,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x88,0x88,0x10,0x00,0x00,0x00, + 0x00,0x02,0xab,0xbb,0xbc,0xcc,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x05,0xcc,0xcc,0xcc,0xbb,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x57,0x77,0x77,0x75, + 0x24,0x44,0x45,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x88,0x88,0x10,0x00,0x00,0x00, + 0x00,0x0a,0xbb,0xbb,0xcc,0xca,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x5c,0xcc,0xcb,0xbb,0xb6,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0x77,0x77,0x74, + 0x24,0x44,0x45,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x88,0x89,0x10,0x00,0x00,0x00, + 0x00,0x0b,0xbb,0xbc,0xcc,0xa1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x05,0xcc,0xbb,0xbb,0xb7,0x00,0x00,0x00,0x00,0x00,0x00,0x77,0x77,0x77,0x73, + 0x14,0x44,0x45,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x88,0x99,0x10,0x00,0x00,0x00, + 0x00,0x1b,0xbb,0xbc,0xca,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x4b,0xbb,0xbb,0xb7,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x77,0x77,0x72, + 0x14,0x44,0x45,0x55,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x89,0x99,0x10,0x00,0x00,0x00, + 0x00,0x1b,0xbb,0xcc,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x09,0xbb,0xbb,0xb7,0x00,0x00,0x00,0x00,0x00,0x01,0x87,0x77,0x77,0x71, + 0x04,0x44,0x45,0x55,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x99,0x99,0x10,0x00,0x00,0x00, + 0x00,0x1b,0xbc,0xcc,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x09,0xbb,0xbb,0xa7,0x00,0x00,0x00,0x00,0x00,0x02,0x87,0x77,0x77,0x70, + 0x04,0x44,0x45,0x55,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x99,0x99,0x10,0x00,0x00,0x00, + 0x00,0x1b,0xcc,0xcc,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x09,0xbb,0xbb,0xa7,0x00,0x00,0x00,0x00,0x00,0x04,0x87,0x77,0x77,0x70, + 0x03,0x44,0x45,0x55,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x89,0x99,0x99,0x10,0x00,0x00,0x00, + 0x00,0x1c,0xcc,0xcc,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x09,0xbb,0xba,0xa7,0x00,0x00,0x00,0x00,0x00,0x06,0x87,0x77,0x77,0x50, + 0x02,0x44,0x45,0x55,0x50,0x00,0x00,0x00,0x05,0x65,0x20,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x99,0x99,0x9a,0x10,0x00,0x00,0x00, + 0x00,0x1c,0xcc,0xcc,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x08,0xbb,0xaa,0xa7,0x00,0x00,0x00,0x00,0x00,0x07,0x87,0x77,0x77,0x30, + 0x01,0x44,0x45,0x55,0x51,0x00,0x00,0x00,0x66,0x66,0x62,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x99,0x99,0xaa,0x10,0x00,0x00,0x00, + 0x00,0x1c,0xcc,0xcd,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x08,0xba,0xaa,0xa7,0x00,0x00,0x00,0x00,0x00,0x18,0x87,0x77,0x77,0x20, + 0x00,0x44,0x45,0x55,0x52,0x00,0x00,0x03,0x66,0x66,0x66,0x20,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x99,0x99,0xaa,0x10,0x00,0x00,0x00, + 0x00,0x1c,0xcc,0xdd,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x00,0x00,0x48,0x87,0x77,0x77,0x00, + 0x00,0x34,0x45,0x55,0x54,0x00,0x00,0x03,0x66,0x66,0x66,0x62,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x69,0x99,0x9a,0xaa,0x20,0x00,0x00,0x00, + 0x00,0x1c,0xcc,0xdd,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x00,0x00,0x68,0x87,0x77,0x76,0x00, + 0x00,0x24,0x45,0x55,0x55,0x00,0x00,0x03,0x66,0x66,0x66,0x66,0x20,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x99,0x99,0xaa,0xaa,0x10,0x00,0x00,0x00, + 0x00,0x1c,0xcd,0xdd,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x00,0x01,0x88,0x87,0x77,0x74,0x00, + 0x00,0x14,0x45,0x55,0x55,0x20,0x00,0x00,0x46,0x66,0x66,0x66,0x72,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x69,0x99,0x9a,0xaa,0xa3,0x00,0x00,0x00,0x00, + 0x00,0x1c,0xdd,0xdd,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x00,0x04,0x88,0x87,0x77,0x72,0x00, + 0x00,0x04,0x45,0x55,0x55,0x40,0x00,0x00,0x04,0x66,0x66,0x67,0x77,0x20,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x99,0x99,0xaa,0xaa,0x30,0x00,0x00,0x00,0x00, + 0x00,0x1d,0xdd,0xdd,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x00,0x07,0x88,0x87,0x77,0x70,0x00, + 0x00,0x03,0x45,0x55,0x55,0x51,0x00,0x00,0x00,0x46,0x66,0x77,0x77,0x73,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x69,0x99,0x9a,0xaa,0xa4,0x00,0x00,0x00,0x00,0x00, + 0x00,0x1d,0xdd,0xdd,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x00,0x18,0x88,0x87,0x77,0x50,0x00, + 0x00,0x01,0x45,0x55,0x55,0x53,0x00,0x00,0x00,0x04,0x66,0x77,0x77,0x77,0x32,0x22, + 0x22,0x22,0x22,0x22,0x22,0x26,0x99,0x99,0x9a,0xaa,0x30,0x00,0x00,0x00,0x00,0x00, + 0x00,0x1d,0xdd,0xde,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x00,0x48,0x88,0x87,0x77,0x20,0x00, + 0x00,0x00,0x45,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x47,0x77,0x77,0x77,0x77,0x77, + 0x88,0x88,0x88,0x88,0x88,0x99,0x99,0x99,0xaa,0xa3,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x1d,0xdd,0xee,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x00,0x78,0x88,0x87,0x76,0x00,0x00, + 0x00,0x00,0x25,0x55,0x55,0x55,0x20,0x00,0x00,0x00,0x05,0x77,0x77,0x77,0x77,0x78, + 0x88,0x88,0x88,0x88,0x88,0x99,0x99,0x9a,0xaa,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x1d,0xde,0xee,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x03,0x88,0x88,0x87,0x73,0x00,0x00, + 0x00,0x00,0x04,0x55,0x55,0x55,0x50,0x00,0x00,0x00,0x00,0x47,0x77,0x77,0x77,0x78, + 0x88,0x88,0x88,0x88,0x89,0x99,0x99,0xaa,0xa3,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x1d,0xee,0xee,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x07,0x88,0x88,0x87,0x70,0x00,0x00, + 0x00,0x00,0x03,0x55,0x55,0x55,0x52,0x00,0x00,0x00,0x00,0x05,0x77,0x77,0x77,0x88, + 0x88,0x88,0x88,0x88,0x99,0x99,0x9a,0xaa,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x1e,0xee,0xee,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x38,0x88,0x88,0x87,0x50,0x00,0x00, + 0x00,0x00,0x01,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x00,0x57,0x77,0x78,0x88, + 0x88,0x88,0x88,0x89,0x99,0x99,0xaa,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x0b,0xee,0xee,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x05,0xaa,0xaa,0xa4,0x00,0x00,0x00,0x78,0x88,0x88,0x87,0x20,0x00,0x00, + 0x00,0x00,0x00,0x45,0x55,0x55,0x56,0x20,0x00,0x00,0x00,0x00,0x05,0x77,0x88,0x88, + 0x88,0x88,0x88,0x99,0x99,0x99,0xaa,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xae,0xec,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x5a,0xaa,0x30,0x00,0x00,0x04,0x88,0x88,0x88,0x86,0x00,0x00,0x00, + 0x00,0x00,0x00,0x15,0x55,0x55,0x56,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x01,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x88,0x88,0x88,0x82,0x00,0x00,0x00, + 0x00,0x00,0x00,0x04,0x55,0x55,0x56,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x88,0x88,0x88,0x60,0x00,0x00,0x00, + 0x00,0x00,0x00,0x01,0x55,0x55,0x56,0x66,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x88,0x88,0x88,0x10,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x35,0x55,0x56,0x66,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x88,0x88,0x88,0x85,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x05,0x55,0x56,0x66,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x88,0x88,0x88,0x71,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x02,0x55,0x56,0x66,0x66,0x20,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x88,0x88,0x88,0x40,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x45,0x56,0x66,0x66,0x60,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x88,0x88,0x88,0x87,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x15,0x56,0x66,0x66,0x65,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x88,0x88,0x88,0x81,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x03,0x56,0x66,0x66,0x66,0x40,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x05,0x98,0x88,0x88,0x88,0x40,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x66,0x66,0x66,0x63,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x49,0x98,0x88,0x88,0x87,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x66,0x66,0x66,0x67,0x30,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x99,0x98,0x88,0x88,0x71,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x66,0x66,0x66,0x67,0x72,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x39,0x99,0x98,0x88,0x88,0x20,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x66,0x66,0x67,0x77,0x20,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x03,0x99,0x99,0x98,0x88,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x66,0x66,0x67,0x77,0x73,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x49,0x99,0x99,0x98,0x88,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x66,0x67,0x77,0x77,0x40,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x04,0x99,0x99,0x99,0x98,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x66,0x67,0x77,0x77,0x75,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x69,0x99,0x99,0x99,0x98,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x67,0x77,0x77,0x77,0x60,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x17,0x99,0x99,0x99,0x99,0x97,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x67,0x77,0x77,0x77,0x77,0x20, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x99,0x99,0x99,0x99,0x99,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x57,0x77,0x77,0x77,0x78,0x85, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x59,0x99,0x99,0x99,0x99,0x97,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x77,0x77,0x77,0x78,0x88, + 0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28, + 0x99,0x99,0x99,0x99,0x99,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x57,0x77,0x77,0x78,0x88, + 0x88,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0xaa, + 0x99,0x99,0x99,0x99,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x77,0x77,0x78,0x88, + 0x88,0x88,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x9a,0xaa, + 0x99,0x99,0x99,0x99,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x77,0x78,0x88, + 0x88,0x88,0x98,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x9a,0xaa,0xaa, + 0x99,0x99,0x99,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x67,0x78,0x88, + 0x88,0x88,0x99,0x98,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x9a,0xaa,0xaa,0xaa, + 0x99,0x99,0x98,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x78,0x88, + 0x88,0x88,0x99,0x99,0x98,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x9a,0xaa,0xaa,0xaa,0xaa, + 0x99,0x99,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x88, + 0x88,0x88,0x99,0x99,0x99,0x99,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x99,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48, + 0x88,0x88,0x99,0x99,0x99,0x99,0xaa,0xa7,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x8b,0xba,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, + 0x58,0x88,0x99,0x99,0x99,0x99,0xaa,0xaa,0xaa,0x97,0x53,0x10,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x35,0x8a,0xbb,0xbb,0xba,0xaa,0xaa,0xaa,0xaa,0xaa,0xa7, + 0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x68,0x99,0x99,0x99,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0x98,0x76,0x54,0x44, + 0x44,0x45,0x67,0x8a,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0xaa,0xaa,0xaa,0xaa,0xa8,0x20, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x02,0x79,0x99,0x99,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0xaa,0xaa,0xaa,0xa8,0x30,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x02,0x69,0x99,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0xaa,0xaa,0xa7,0x30,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x01,0x58,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0xaa,0x95,0x10,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x36,0x9a,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0x73,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x68,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0x96,0x30,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x68,0xab,0xbb,0xbb,0xbb,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0x96,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x34,0x67,0x89,0xab,0xbb, + 0xbb,0xba,0x98,0x76,0x53,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; diff --git a/include/memlayout.h b/include/memlayout.h new file mode 100644 index 0000000..96340aa --- /dev/null +++ b/include/memlayout.h @@ -0,0 +1,49 @@ +#pragma once + +// Memory layout + +#define EXTMEM 0x100000 // Start of extended memory +// Top of usable physical memory. A *variable*, read from the firmware's E820 +// map at boot -- see kernel/arch/x86_64/e820.c. It used to be the constant +// below, which was not a limit on what the kernel used but an assertion that +// exactly 224 MB existed: less and the allocator walked off the end of RAM, +// more and it was invisible. +// +// The macro spelling is kept so that the twenty-odd call sites read the same as +// they always did. It must not be used before e820_init(), which runs first +// thing in main() for that reason. +#ifndef __ASSEMBLER__ +extern uint64 phystop; +#define PHYSTOP phystop +#endif + +// What to assume when the firmware gives us nothing usable: the old constant, +// so that path behaves exactly as the kernel always did. +#define PHYSTOP_FALLBACK 0xE000000ULL + +// kvmalloc() maps physical 0-4 GB as four 1 GB pages and marks the top one +// uncached, because that is where PCI BARs and the framebuffer sit. 3 GB is +// therefore the most that can be treated as RAM. +#define PHYSTOP_MAX 0xC0000000ULL + +// Below this the kernel image, its page tables and the DMA arena do not fit. +#define PHYSTOP_MIN (24ULL * 1024 * 1024) + +// Key addresses for address space layout +#define KERNBASE 0xFFFF800000000000 // First kernel virtual address +#define KERNLINK (KERNBASE+EXTMEM) // Address where kernel is linked + +#ifndef __ASSEMBLER__ +static inline addr_t v2p(void *a) { + return ((addr_t)(a)) - ((addr_t)KERNBASE); +} +static inline void *p2v(addr_t a) { + return (void *)((a) + ((addr_t)KERNBASE)); +} +#endif + +#define V2P(a) (((addr_t) (a)) - KERNBASE) +#define P2V(a) (((void *) (a)) + KERNBASE) + +#define V2P_WO(x) ((x) - KERNBASE) // same as V2P, but without casts +#define P2V_WO(x) ((x) + KERNBASE) // same as P2V, but without casts diff --git a/include/mmu.h b/include/mmu.h new file mode 100644 index 0000000..d79e294 --- /dev/null +++ b/include/mmu.h @@ -0,0 +1,130 @@ +#pragma once + +// Eflags register +#define FL_CF 0x00000001 // Carry Flag +#define FL_PF 0x00000004 // Parity Flag +#define FL_AF 0x00000010 // Auxiliary carry Flag +#define FL_ZF 0x00000040 // Zero Flag +#define FL_SF 0x00000080 // Sign Flag +#define FL_TF 0x00000100 // Trap Flag +#define FL_IF 0x00000200 // Interrupt Enable +#define FL_DF 0x00000400 // Direction Flag +#define FL_OF 0x00000800 // Overflow Flag +#define FL_IOPL_MASK 0x00003000 // I/O Privilege Level bitmask +#define FL_NT 0x00004000 // Nested Task +#define FL_RF 0x00010000 // Resume Flag +#define FL_VM 0x00020000 // Virtual 8086 mode +#define FL_AC 0x00040000 // Alignment Check +#define FL_VIF 0x00080000 // Virtual Interrupt Flag +#define FL_VIP 0x00100000 // Virtual Interrupt Pending +#define FL_ID 0x00200000 // ID flag + +// Control Register flags +#define CR0_PE 0x00000001 // Protection Enable +#define CR0_MP 0x00000002 // Monitor coProcessor +#define CR0_EM 0x00000004 // Emulation +#define CR0_TS 0x00000008 // Task Switched +#define CR0_ET 0x00000010 // Extension Type +#define CR0_NE 0x00000020 // Numeric Errror +#define CR0_WP 0x00010000 // Write Protect +#define CR0_AM 0x00040000 // Alignment Mask +#define CR0_NW 0x20000000 // Not Writethrough +#define CR0_CD 0x40000000 // Cache Disable +#define CR0_PG 0x80000000 // Paging + +#define CR4_PSE 0x00000010 // Page size extension +#define CR4_PAE 0x00000020 // Physical address extensions +#define CR4_OSXFSR 0x00000200 // OS supports FXSAVE and FXRSTOR +#define CR4_OSXMMEXCPT 0x00000400 // OS supports SSE exceptions + +// Model specific registers +#define MSR_EFER 0xC0000080 // Extended Feature Enable Register +#define MSR_STAR 0xC0000081 // Legacy Mode SYSCALL Target +#define MSR_LSTAR 0xC0000082 // Long Mode SYSCALL Target +#define MSR_CSTAR 0xC0000083 // Compatibility Mode SYSCALL Target +#define MSR_SFMASK 0xC0000084 // SYSCALL Flag Mask + +// Segment selectors +#define SEG_KCODE 1 +#define SEG_KDATA 2 +#define SEG_UCODE32 3 +#define SEG_UDATA 4 +#define SEG_UCODE 5 +#define SEG_KCPU 6 +#define SEG_TSS 7 // TSS takes 2 slots in 64-bit GDT + +#define NSEGS 9 + +#define DPL_USER 0x3 + +#define USER_CS ((SEG_UCODE<<3)|DPL_USER) +#define USER_DS ((SEG_UDATA<<3)|DPL_USER) +#define KERNEL_CS (SEG_KCODE<<3) + +#ifndef __ASSEMBLER__ +// Segment Descriptor +struct segdesc { + uint32 lim_15_0 : 16; // Low bits of segment limit + uint32 base_15_0 : 16; // Low bits of segment base address + uint32 base_23_16 : 8; // Middle bits of segment base address + uint32 type : 4; // Segment type + uint32 s : 1; // 0 = system, 1 = application + uint32 dpl : 2; // Descriptor Privilege Level + uint32 p : 1; // Present + uint32 lim_19_16 : 4; // High bits of segment limit + uint32 avl : 1; // Available for software use + uint32 l : 1; // 1 = 64-bit segment (Long mode) + uint32 db : 1; // 0 = 16-bit, 1 = 32-bit + uint32 g : 1; // Granularity + uint32 base_31_24 : 8; // High bits of segment base address +}; + +// 64-bit System Segment Descriptor (e.g., TSS) +struct desclong { + struct segdesc sd; + uint32 base_63_32; // High bits of 64-bit base address + uint32 res; // Reserved +}; + +#define SEG(type, base, lim, dpl) (struct segdesc) \ +{ ((lim) >> 12) & 0xffff, (uint32)(base) & 0xffff, \ + ((uint32)(base) >> 16) & 0xff, type, 1, dpl, 1, \ + (uint32)(lim) >> 28, 0, 1, 0, 1, (uint32)(base) >> 24 } + +#endif + +// Application segment type bits +#define STA_X 0x8 // Executable segment +#define STA_W 0x2 // Writeable (non-executable) +#define STA_R 0x2 // Readable (executable) + +// System segment type bits +#define STS_T64A 0x9 // Available 64-bit TSS +#define STS_T64B 0xB // Busy 64-bit TSS +#define STS_IG64 0xE // 64-bit Interrupt Gate +#define STS_TG64 0xF // 64-bit Trap Gate + +// Page table structure: 4 levels +#define PMX(va) (((addr_t)(va) >> 39) & 0x1FF) +#define PDPX(va) (((addr_t)(va) >> 30) & 0x1FF) +#define PDX(va) (((addr_t)(va) >> 21) & 0x1FF) +#define PTX(va) (((addr_t)(va) >> 12) & 0x1FF) + +#define PGSIZE 4096 +#define PXMASK 0x1FF + +#define PGROUNDUP(sz) (((sz)+((addr_t)PGSIZE-1)) & ~((addr_t)(PGSIZE-1))) +#define PGROUNDDOWN(a) (((a)) & ~((addr_t)(PGSIZE-1))) + +// Page table/directory entry flags +#define PTE_P 0x001 // Present +#define PTE_W 0x002 // Writeable +#define PTE_U 0x004 // User +#define PTE_PWT 0x008 // Write-Through +#define PTE_PCD 0x010 // Cache-Disable +#define PTE_A 0x020 // Accessed +#define PTE_D 0x040 // Dirty +#define PTE_PS 0x080 // Page Size (Huge Page) + +#define PTE_ADDR(pte) ((addr_t)(pte) & 0x000FFFFFFFFFF000ull) +#define PTE_FLAGS(pte) ((addr_t)(pte) & 0xFFF) diff --git a/include/mp.h b/include/mp.h new file mode 100644 index 0000000..dea5705 --- /dev/null +++ b/include/mp.h @@ -0,0 +1,54 @@ +// See MultiProcessor Specification Version 1.[14] + +struct mp { // floating pointer + uchar signature[4]; // "_MP_" + uint32 physaddr; // 32-bit phys addr of MP config table + uchar length; // 1 + uchar specrev; // [14] + uchar checksum; // all bytes must add up to 0 + uchar type; // MP system config type + uchar imcrp; + uchar reserved[3]; +}; + +struct mpconf { // configuration table header + uchar signature[4]; // "PCMP" + ushort length; // total table length + uchar version; // [14] + uchar checksum; // all bytes must add up to 0 + uchar product[20]; // product id + uint32 oemtable_p; // OEM table pointer + ushort oemlength; // OEM table length + ushort entry; // entry count + uint32 lapicaddr_p; // address of local APIC + ushort xlength; // extended table length + uchar xchecksum; // extended table checksum + uchar reserved; +}; + +struct mpproc { // processor table entry + uchar type; // entry type (0) + uchar apicid; // local APIC id + uchar version; // local APIC verison + uchar flags; // CPU flags + #define MPBOOT 0x02 // This proc is the bootstrap processor. + uchar signature[4]; // CPU signature + uint feature; // feature flags from CPUID instruction + uchar reserved[8]; +}; + +struct mpioapic { // I/O APIC table entry + uchar type; // entry type (2) + uchar apicno; // I/O APIC id + uchar version; // I/O APIC version + uchar flags; // I/O APIC flags + uint32 addr_p; // I/O APIC address +}; + +// Table entry types +#define MPPROC 0x00 // One per processor +#define MPBUS 0x01 // One per bus +#define MPIOAPIC 0x02 // One per I/O APIC +#define MPIOINTR 0x03 // One per bus interrupt source +#define MPLINTR 0x04 // One per system interrupt source + diff --git a/include/param.h b/include/param.h new file mode 100644 index 0000000..7412dfe --- /dev/null +++ b/include/param.h @@ -0,0 +1,28 @@ +#pragma once + +#define NPROC 128 // maximum number of processes +#define KSTACKSIZE 4096 // size of per-process kernel stack (increased for x64) +#define KSTACK_CANARY 0xDEADC0DEDEADC0DEULL // sentinel at kstack[0], see kstack_check_canary() +#define NCPU 16 // maximum number of CPUs +#define NOFILE 128 // open files per process +#define NFILE 512 // open files per system +#define NINODE 200 // maximum number of active i-nodes +#define NDEV 10 // maximum major device number +#define RAMDISK_DEV 2 // memory-backed block device (kernel/dev/ramdisk.c) +#define USBDISK_DEV 3 // USB mass storage (kernel/drivers/usb_storage.c) + +// Device the root filesystem is mounted from. Building with RAMROOT=1 defines +// RAMDISK_ROOT and boots from the SCHFS image linked into the kernel instead +// of the IDE disk, leaving the physical disk free to be reformatted from a +// running system. See kernel/dev/ramdisk.c. +#ifdef RAMDISK_ROOT +#define ROOTDEV RAMDISK_DEV +#else +#define ROOTDEV 1 // device number of file system root disk +#endif +#define MAXARG 32 // max exec arguments +#define MAXPATH 128 // max path +#define MAXOPBLOCKS 30 // max # of blocks any FS op writes +#define LOGSIZE (MAXOPBLOCKS*3) // max data blocks in on-disk log +#define NBUF (MAXOPBLOCKS*3) // size of disk block cache +#define FSSIZE 150000 // size of file system in blocks diff --git a/include/pci.h b/include/pci.h new file mode 100644 index 0000000..7c5eb15 --- /dev/null +++ b/include/pci.h @@ -0,0 +1,110 @@ +#pragma once + +// PCI bus enumeration and driver binding. +// +// Until this existed, every driver in Schunix found its hardware by knowing +// 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 +// devices that predate PCI and for nothing else. A NIC, an AHCI controller, +// a virtio device or a real GPU has no fixed address at all -- you find it by +// asking the bus what is plugged into it, which is what this does. + +// --------------------------------------------------------------------------- +// Config space +// --------------------------------------------------------------------------- + +#define PCI_CONFIG_ADDR 0xCF8 +#define PCI_CONFIG_DATA 0xCFC + +#define PCI_VENDOR_ID 0x00 +#define PCI_DEVICE_ID 0x02 +#define PCI_COMMAND 0x04 +#define PCI_STATUS 0x06 +#define PCI_REVISION 0x08 +#define PCI_PROG_IF 0x09 +#define PCI_SUBCLASS 0x0A +#define PCI_CLASS 0x0B +#define PCI_HEADER_TYPE 0x0E +#define PCI_BAR0 0x10 +#define PCI_SECONDARY_BUS 0x19 +#define PCI_INTERRUPT_LINE 0x3C +#define PCI_INTERRUPT_PIN 0x3D + +// PCI_COMMAND bits a driver usually wants set before touching its device. +#define PCI_CMD_IO 0x0001 +#define PCI_CMD_MEMORY 0x0002 +#define PCI_CMD_BUS_MASTER 0x0004 + +// Base classes worth naming. The full list is long and mostly irrelevant here. +#define PCI_CLASS_STORAGE 0x01 +#define PCI_CLASS_NETWORK 0x02 +#define PCI_CLASS_DISPLAY 0x03 +#define PCI_CLASS_MULTIMEDIA 0x04 +#define PCI_CLASS_BRIDGE 0x06 +#define PCI_CLASS_SERIAL_BUS 0x0C + +#define PCI_STATUS_CAPLIST 0x0010 // device has a capability list +#define PCI_CAP_PTR 0x34 // offset of the first capability + +#define PCI_CAP_MSI 0x05 +#define PCI_CAP_MSIX 0x11 +#define PCI_CAP_VENDOR 0x09 // virtio's configuration lives here +#define PCI_CAP_PCIE 0x10 + +#define PCI_ANY 0xFFFF // wildcard in a match table + +#define NPCI 64 // devices we will remember + +struct pci_bar { + uint64 base; // already masked; 0 means "no BAR here" + uint64 size; // determined by write-ones-and-read-back + int is_io; // I/O port range rather than memory + int is_64; // consumed the following BAR slot too + int prefetch; +}; + +struct pci_dev { + uint8 bus, slot, func; + uint16 vendor, device; + uint8 class, subclass, prog_if, revision; + uint8 irq; // interrupt line, 0xFF when unrouted + uint8 header_type; + struct pci_bar bar[6]; + const char *driver; // name of whatever claimed it, or 0 +}; + +// One row of a driver's match table. Terminate the table with a row whose +// vendor is 0. +struct pci_match { + uint16 vendor, device; // PCI_ANY to ignore + uint8 class, subclass; // used only when vendor is PCI_ANY +}; + +// Declared here rather than defs.h because both take a struct pci_dev, which +// only this header defines. See kernel/dev/device.c for the model they feed. +// device.h is included rather than forward-declaring `enum dev_class`, which +// is a compiler extension and warns. +#include "device.h" + +enum dev_class pci_class_of(const struct pci_dev *); +void pci_describe(const struct pci_dev *, char *out, int cap); + +struct pci_driver { + const char *name; + // Base for the device's name in /proc/devices, if the driver's own name + // makes a bad one. `e1000` plus an index reads as "e10000"; a NIC wants to + // be `eth0`. Optional -- null means use `name`. + const char *devname; + const struct pci_match *match; + // Class-specific vtable, published on the device when this driver claims + // it -- struct display_ops for a display, and so on. Optional; a driver + // with nothing to offer a consumer leaves it null. + // + // It lives on the driver rather than being set inside probe() because + // pci_bind() registers the device *after* probe returns, so a driver has + // nothing to attach it to at the point it would want to. + const void *ops; + // Return 0 to claim the device. A driver that returns non-zero leaves it + // unclaimed for anything else that matches. + int (*probe)(struct pci_dev *); +}; diff --git a/include/posix.h b/include/posix.h new file mode 100644 index 0000000..87757c4 --- /dev/null +++ b/include/posix.h @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: Apache-2.0 +// Schunix — POSIX-compatibility types used by kernel syscall handlers. +#pragma once +#include "types.h" +#include "date.h" + +struct iovec { + void *iov_base; + uint64 iov_len; +}; + +// Linux's IOV_MAX. readv/writev used to cap iovcnt at 16 -- which is legal, +// since POSIX only requires 16 -- and returned EINVAL above it. But programs +// are written against the platform they run on, and on Linux that limit is +// 1024: toybox's `yes` builds a 256-entry iovec and writev()s it in a loop, +// so `yes | head -2` failed with "Invalid argument" before producing a single +// byte. Nothing here costs per-entry memory; the count is just a loop bound. +#define UIO_MAXIOV 1024 + +// Simplified termios (matches Linux x86_64 layout enough for basic use). +struct termios { + uint32 c_iflag; + uint32 c_oflag; + uint32 c_cflag; + uint32 c_lflag; + uint8 c_line; + uint8 c_cc[19]; + uint32 c_ispeed; + uint32 c_ospeed; +}; + +// Terminal flags, with Linux's values. The kernel honours the ones marked +// below; the rest are accepted and stored so a program that sets them and +// reads them back sees what it wrote, which is what cfmakeraw() and every +// line-editing library actually check. +// +// c_iflag +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 // honoured: strip the eighth bit +#define INLCR 0000100 // honoured: NL -> CR on input +#define IGNCR 0000200 // honoured: drop CR +#define ICRNL 0000400 // honoured: CR -> NL on input +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 +#define IUTF8 0040000 + +// c_oflag +#define OPOST 0000001 // honoured: enable output processing +#define OLCUC 0000002 +#define ONLCR 0000004 // honoured: NL -> CR NL on output +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 + +// c_cflag +#define CS8 0000060 +#define CREAD 0000200 +#define HUPCL 0002000 +#define CLOCAL 0004000 + +// c_lflag +#define ISIG 0000001 // honoured: INTR/QUIT/SUSP generate signals +#define ICANON 0000002 // honoured: line-at-a-time with editing +#define ECHO 0000010 // honoured +#define ECHOE 0000020 // honoured: ERASE rubs the character out +#define ECHOK 0000040 +#define ECHONL 0000100 // honoured: echo NL even with ECHO off +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define IEXTEN 0100000 + +// c_cc indices (Linux order). VMIN/VTIME share slots with VEOF/VEOL, which is +// why they are only meaningful in the mode the other pair is not. +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +struct winsize { + uint16 ws_row; + uint16 ws_col; + uint16 ws_xpixel; + uint16 ws_ypixel; +}; + +struct rlimit { + uint64 rlim_cur; + uint64 rlim_max; +}; + +// Linux ioctl codes we handle. +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCSCTTY 0x540E +#define TIOCGSERIAL 0x541E +#define FIONREAD 0x541B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D + +// arch_prctl commands +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 + +// clone flags (subset) +#define CLONE_VM 0x00000100 +#define CLONE_THREAD 0x00010000 +#define CLONE_SIGHAND 0x00000800 + +// futex ops +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_WAIT_PRIVATE 128 +#define FUTEX_WAKE_PRIVATE 129 + +// Resource limit codes (POSIX) +#define RLIMIT_AS 9 +#define RLIMIT_STACK 3 +#define RLIMIT_NOFILE 7 + +// clock IDs +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 + +struct timespec { + long tv_sec; + long tv_nsec; +}; + +struct itimerval { + struct timeval it_interval; + struct timeval it_value; +}; + +struct rusage { + struct timeval ru_utime; + struct timeval ru_stime; + long ru_maxrss; + long ru_ixrss; + long ru_idrss; + long ru_isrss; + long ru_minflt; + long ru_majflt; + long ru_nswap; + long ru_inblock; + long ru_oublock; + long ru_msgsnd; + long ru_msgrcv; + long ru_nsignals; + long ru_nvcsw; + long ru_nivcsw; +}; + +struct tms { + long tms_utime; + long tms_stime; + long tms_cutime; + long tms_cstime; +}; + +struct sysinfo { + long uptime; + uint64 loads[3]; + uint64 totalram; + uint64 freeram; + uint64 sharedram; + uint64 bufferram; + uint64 totalswap; + uint64 freeswap; + uint16 procs; + uint16 pad; + uint32 pad2; + uint64 totalhigh; + uint64 freehigh; + uint32 mem_unit; + char _f[8]; +}; + +struct statfs { + int64 f_type; + int64 f_bsize; + int64 f_blocks; + int64 f_bfree; + int64 f_bavail; + int64 f_files; + int64 f_ffree; + int64 f_fsid[2]; + int64 f_namelen; + int64 f_frsize; + int64 f_flags; + int64 f_spare[4]; +}; + +// at-syscall dirfd sentinel +#define AT_FDCWD (-100) +#define AT_REMOVEDIR 0x200 +#define AT_SYMLINK_NOFOLLOW 0x100 +#define AT_EMPTY_PATH 0x1000 +#define AT_NO_AUTOMOUNT 0x800 + +// prctl options +#define PR_SET_NAME 15 +#define PR_GET_NAME 16 +#define PR_SET_DUMPABLE 4 +#define PR_GET_DUMPABLE 3 + +// signal numbers (Linux x86_64 values), used by kill dispatch and +// default-action classification in sigsend() +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGABRT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +// Job-control and the remaining standard signals. A shell needs the TSTP/ +// TTIN/TTOU trio to implement ^Z and background-job terminal access at all; +// they were simply absent, so any reference to them failed to compile. +#define SIGTRAP 5 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPWR 30 +#define SIGSYS 31 + +// getrusage who +#define RUSAGE_SELF 0 +#define RUSAGE_CHILDREN (-1) + +// fallocate mode +#define FALLOC_FL_KEEP_SIZE 1 + +// poll(2) event bits (Linux values) +#define POLLIN 0x001 +#define POLLPRI 0x002 +#define POLLOUT 0x004 +#define POLLERR 0x008 +#define POLLHUP 0x010 +#define POLLNVAL 0x020 + +struct pollfd { + int fd; + short events; + short revents; +}; diff --git a/include/proc.h b/include/proc.h new file mode 100644 index 0000000..773b3a5 --- /dev/null +++ b/include/proc.h @@ -0,0 +1,240 @@ +#pragma once + +#include "types.h" +#include "traps.h" + +#define NVMA 64 + +struct vma { + uint64 addr; + uint64 length; + int used; + // The pages under this mapping are not ours to free on unmap: either they + // are device memory (the framebuffer) or they belong to something with a + // longer life than this process (a shared memory segment). This was + // `is_fb`, which was the only such case until shared memory existed -- + // and freeing another process's shared pages on exit is exactly the kind + // of bug that shows up somewhere else entirely, hours later. + int no_free; + int shmid; // shared segment this came from, or -1 +}; + +// Per-CPU state +struct cpu { + uchar id; + uchar apicid; // Local APIC ID + struct context *scheduler; // swtch() here to enter scheduler + volatile uint64 started; // Has the CPU started? + int ncli; // Depth of pushcli nesting. + int intena; // Were interrupts enabled before pushcli? + void *local; // CPU-local storage (GS base) +}; + +extern struct cpu cpus[NCPU]; +extern int ncpu; // processors present +extern int ncpu_online; // processors actually running + +// --- per-CPU variables ------------------------------------------------------ +// +// These were `__thread struct cpu *cpu` and `__thread struct proc *proc`, and +// that was wrong in a way that only appears once a second processor runs. +// +// `__thread` means *per thread*, and the compiler is entitled to assume a +// thread's pointer never changes: it reads %fs:0 once and keeps the value in a +// register or spilled on the stack across calls. clang did exactly that in +// sleep(): +// +// movq %fs:0x0, %rax # read the thread pointer +// movq %rax, -0x18(%rbp) # spill it +// callq sched # <-- the CPU can change here +// movq -0x18(%rbp), %rax # reload the OLD pointer +// movq (%rax,%rcx), %rax # proc, from the previous CPU's block +// movq $0x0, 0x40(%rax) # NULL, because that CPU set proc = 0 +// +// But %fs here is *per CPU*, not per thread, and a kernel thread changes CPU at +// every sched(). So the assumption is false for exactly the variables that +// most need to be right, and the failure is a null dereference deep in the +// scheduler on a machine with more than one core. +// +// The fix is to read the value at each use, with no cached base: an explicit +// %gs-relative access that the compiler cannot hoist across a call. `volatile` +// is what forbids that, and the memory clobber on the setters keeps stores in +// order with the rest of the scheduler's bookkeeping. +// +// Layout of the per-CPU block, whose base is in both FS_BASE and GS_BASE, set +// by seginit() in kernel/arch/x86_64/vm.c: +// +// +0 self-pointer required by the x86-64 TLS ABI (%fs:0) +// +8 syscall scratch trapasm.S parks %rsp here across the stack switch +// +16 struct cpu * +// +24 struct proc * +// +// Offset 8 is NOT free. syscall_entry uses %fs:(8) as its scratch slot, and +// because seginit() sets GS base and FS base to the same address, %fs:8 and +// %gs:8 are the same memory. Putting `cpu` there made every syscall overwrite +// it with %rsp -- a #GP in syscall_entry itself, several layers below anything +// that could report it. +// +// trapasm.S reads %gs:24 for proc on the way out to user mode, so these three +// offsets are shared with assembly and must not be reordered. +#define PERCPU_SELF 0 +#define PERCPU_SCRATCH 8 +#define PERCPU_CPU 16 +#define PERCPU_PROC 24 + +static inline struct cpu * +cpu_get(void) +{ + struct cpu *c; + asm volatile("movq %%gs:16, %0" : "=r" (c)); + return c; +} + +static inline void +cpu_set(struct cpu *c) +{ + asm volatile("movq %0, %%gs:16" :: "r" (c) : "memory"); +} + +static inline struct proc * +proc_get(void) +{ + struct proc *p; + asm volatile("movq %%gs:24, %0" : "=r" (p)); + return p; +} + +static inline void +proc_set(struct proc *p) +{ + asm volatile("movq %0, %%gs:24" :: "r" (p) : "memory"); +} + +// Named mycpu()/myproc(), as xv6-riscv does, and *not* spelled `cpu`/`proc`. +// A macro by those names would also rewrite every `struct cpu` and +// `struct proc`, because macros have no namespace and tags do -- which is +// exactly why the variables could carry those names in the first place. +#define mycpu() cpu_get() +#define myproc() proc_get() + +// Saved registers for kernel context switches (x86_64 ABI) +struct context { + uint64 r15; + uint64 r14; + uint64 r13; + uint64 r12; + uint64 rbx; + uint64 rbp; + uint64 rip; +}; + +enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; + +// Per-process state +// A copy of the interesting fields of one process, taken under ptable.lock. +// procfs reads these rather than struct proc, so nothing outside proc.c needs +// the lock or the layout. +struct procinfo { + int pid, ppid, pgid, sid; + uint uid; + int state; // enum procstate + uint64 sz; + int killed; + char name[16]; + char exe[64]; // full path, for /proc//exe +}; + +struct proc { + uint64 sz; // Size of process memory (bytes) [+0x00] + pml4e_t* pgdir; // Page table (PML4 on x86_64) [+0x08] + char *kstack; // Bottom of kernel stack [+0x10] + uint64 fs_base; // User TLS base (IA32_FS_BASE MSR) [+0x18] ← trapasm.S depends on this offset + enum procstate state; // Process state [+0x20] + int pid; // [+0x24] + struct proc *parent; // [+0x28] + struct trapframe *tf; // [+0x30] + struct context *context; // [+0x38] + void *chan; // [+0x40] + int killed; // [+0x48] + int _pad; // [+0x4c] + struct file *ofile[NOFILE]; // Open files [+0x50] + struct inode *cwd; // follows + char name[16]; // + // The path exec() was given. `name` is only the last component and only 15 + // characters of it, which is what /proc//stat wants; this is the whole + // path, reported by /proc//exe. + // + // Note it is exposed as a regular *file*, not the symlink Linux uses, so + // `cat /proc/1/exe` works but readlink() does not. That is why `ps -o comm` + // still prints "[init]": toybox readlink()s exe and brackets the name when + // that fails. Default ps and top output is unaffected. Fixing it properly + // means symlink support in procfs, which is worth doing with the rest of the + // VFS work rather than on its own. + char exe[64]; + uint64 signal_mask; + uint64 pending_signals; + int alarm_ticks; + char ofile_flags[NOFILE]; + + // Real signal delivery (added for SIGCHLD — see kernel/sys/syscall.c's + // deliver_signals() and kernel/proc/proc.c's exit()). sig_handler[sig]/ + // sig_restorer[sig] come straight from the user's struct sigaction + // (sys_rt_sigaction); 0 means no handler installed. saved_sigtf stashes + // the pre-signal trapframe so sys_rt_sigreturn() can restore it; in_signal + // prevents re-entering a handler while one is already running (we don't + // support nested signal delivery). + uint64 sig_handler[32]; + uint64 sig_restorer[32]; + struct trapframe saved_sigtf; + int in_signal; + + // rt_sigsuspend() support: the pre-suspend mask to restore once the + // handler that woke us finishes (sigsuspend swaps the mask atomically + // for the duration of the wait -- POSIX). sigsusp_active is set while a + // restore is owed; sys_rt_sigreturn() performs it. + uint64 sigsusp_oldmask; + int sigsusp_active; + + struct vma vma[NVMA]; // VMA tracking for mmap + uint64 mmap_next; // next free mmap VA (bump allocator, see sys_mmap) + + // ABI translation (Linux compat syscall number map) + int *syscall_map; + int map_size; + + // Current working directory path; maintained by sys_chdir / sys_fchdir. + char cwd_path[256]; + + // --- POSIX process identity ------------------------------------------- + // Appended at the end of the struct deliberately: trapasm.S hard-codes the + // offsets of the fields at the top (see the _Static_assert on fs_base in + // kernel/proc/proc.c), so nothing may be inserted above them. + + // Exit status, already encoded the way wait(2) reports it -- see + // W_EXITCODE() below. Read by waitpid() before the slot is recycled. + int xstate; + + // Signal that killed us, if any. Set by sigsend() alongside ->killed so the + // eventual exit() can report *which* signal, instead of a blanket SIGKILL. + int killsig; + + // Process group and session. Job control is defined entirely in terms of + // these: a shell puts each pipeline in its own process group and signals the + // group, not individual pids. Without them a shell's wait loop cannot work, + // which is why mksh's job control never made progress. + int pgid; + int sid; + + // Real/effective/saved user and group ids. Nothing enforces permissions with + // them yet (the on-disk format has no owner field until SchFS), but they + // are tracked honestly so getuid()/setuid() stop lying to userland. + uint uid, euid, suid; + uint gid, egid, sgid; +}; +#define FD_CLOEXEC 1 + +// wait(2) status encoding, as understood by musl's WIFEXITED/WEXITSTATUS/ +// WIFSIGNALED/WTERMSIG macros: +// normal exit -> (code & 0xff) << 8 +// killed by signal -> sig & 0x7f +#define W_EXITCODE(code, sig) ((((code) & 0xff) << 8) | ((sig) & 0x7f)) \ No newline at end of file diff --git a/include/qr.h b/include/qr.h new file mode 100644 index 0000000..1c7b762 --- /dev/null +++ b/include/qr.h @@ -0,0 +1,42 @@ +#pragma once + +// A QR encoder, for getting a crash report off a machine whose network stack is +// dead. +// +// A panic report is worth nothing if it cannot leave the machine, and at panic +// time there is no network, no filesystem write that can be trusted, and often +// no second machine on the desk. A phone camera is a working out-of-band +// channel that needs no drivers on our side at all. See docs/roadmap.md Phase 8. +// +// Deliberately small, in three ways: +// +// - Byte mode only. The report is arbitrary bytes; alphanumeric mode would +// pack tighter but only for a restricted character set. +// - Error correction level L only. The screen is a clean, evenly lit, +// high-contrast source -- the failure mode QR's stronger levels protect +// against (dirt, print damage, curved packaging) does not apply. +// - Versions 1 to 6 only. Version 7 is where QR starts requiring an extra +// 18-bit version-information block in two more places on the symbol, and +// version 10 is where the character count field grows and the alignment +// pattern grid becomes 2-dimensional. Stopping at 6 avoids both, and +// 134 bytes is a large crash report. +// +// If a payload ever needs more than 134 bytes, the honest fix is to shorten the +// report -- not to reach for version 10 and its two extra tables. + +#define QR_MAX_VERSION 6 +#define QR_MAX_SIZE (17 + 4 * QR_MAX_VERSION) // 41 modules per side +#define QR_MAX_BYTES 134 + +struct qr { + int size; // modules per side; 0 if unencoded + unsigned char mod[QR_MAX_SIZE][QR_MAX_SIZE]; // 1 = dark + unsigned char fn[QR_MAX_SIZE][QR_MAX_SIZE]; // 1 = function pattern +}; + +// Encode len bytes into q. Picks the smallest version that fits. +// Returns 0, or -1 if len > QR_MAX_BYTES. +int qr_encode(struct qr *q, const unsigned char *data, int len); + +// Largest payload, in bytes, for a given version (1..QR_MAX_VERSION). +int qr_capacity(int version); diff --git a/include/schfs.h b/include/schfs.h new file mode 100644 index 0000000..ffe44d7 --- /dev/null +++ b/include/schfs.h @@ -0,0 +1,246 @@ +// SchFS — on-disk format. +// +// Design rationale lives in docs/architecture/schfs.md. In short: copy-on-write +// with the checksum of a block stored in the pointer that leads to it (ZFS), +// one B-tree reused for every kind of record (btrfs), and attribute indexes as +// just another record type (BeFS). +// +// This header is shared by the kernel and by host tools (tools/mkfs, +// tools/schfs_test), so it must stay free of kernel-only types. + +#ifndef SCHFS_H +#define SCHFS_H + +#include + +#define SCHFS_MAGIC 0x53636846u // "SchF" +#define SCHFS_NODE_MAGIC 0x536e6f64u // "Snod" + +// 4096 to match modern media and make extents worth having. The old format +// used 1024, which is also why its directories were so wasteful. +#define SCHFS_BLKSIZE 4096 + +// Deepest tree we will walk without recursing. 8 levels of a ~84-way internal +// node is far more than any plausible volume needs. +#define SCHFS_MAX_LEVEL 8 + +// --------------------------------------------------------------------------- +// Keys +// +// Every record in the filesystem is addressed by one 24-byte key, sorted by +// (objectid, type, offset). This is the whole reason there is only one tree: +// inodes, directory entries, extent maps and indexes are just different `type` +// values in the same keyspace. +// --------------------------------------------------------------------------- + +#define SCHFS_KEY_INODE 1 // (ino, INODE, 0) -> struct schfs_inode +#define SCHFS_KEY_DIRENT 2 // (dirino,DIRENT, namehash) -> packed dirent list +#define SCHFS_KEY_EXTENT 3 // (ino, EXTENT, fileblk) -> struct schfs_extent +#define SCHFS_KEY_ATTR 4 // (ino, ATTR, namehash) -> attribute value +#define SCHFS_KEY_INDEX 5 // (idxid, INDEX, valuehash) -> objectid +#define SCHFS_KEY_CSUM 6 // (CSUM, CSUM, diskblk) -> uint32 CRC32c + +// Data-block checksums live under one reserved object id, exactly as btrfs +// keeps a checksum tree. Tree nodes carry their checksum in their parent +// pointer, but file *data* blocks have no parent to hold it — without these +// records "end-to-end checksums" would only cover metadata, which is the part +// least likely to rot. +#define SCHFS_CSUM_OBJECTID 1ULL + +// Object ids below this are reserved; the root directory is the first real one. +#define SCHFS_FIRST_OBJECTID 16ULL +#define SCHFS_ROOT_OBJECTID 16ULL + +struct schfs_key { + uint64_t objectid; + uint64_t offset; + uint8_t type; + uint8_t pad[7]; +}; /* 24 bytes */ + +// --------------------------------------------------------------------------- +// Node header — identical for internal nodes and leaves. +// +// `blocknr` is a self-pointer: a block that was written to the wrong place +// still checksums correctly, so the only way to catch a misdirected write is +// for the block to say where it thinks it lives. +// --------------------------------------------------------------------------- + +struct schfs_node_hdr { + uint32_t magic; // SCHFS_NODE_MAGIC + uint32_t crc; // CRC32c of the whole block, this field zeroed + uint64_t blocknr; // where this block believes it lives + uint64_t generation; // transaction that wrote it + uint16_t level; // 0 = leaf, >0 = internal + uint16_t nritems; + uint32_t pad; +}; /* 32 bytes */ + +// Internal node entry: a key and the child it leads to, plus that child's +// checksum and generation. Storing the checksum *here* rather than in the +// child is what makes the tree self-validating. +struct schfs_kptr { + struct schfs_key key; + uint64_t blocknr; + uint64_t generation; + uint32_t crc; + uint32_t pad; +}; /* 48 bytes */ + +// Leaf entry. Items grow forward from the end of the header; their data grows +// backward from the end of the block, exactly like btrfs. `offset` is measured +// from the start of the block. +struct schfs_item { + struct schfs_key key; + uint32_t offset; + uint32_t size; +}; /* 32 bytes */ + +#define SCHFS_NODE_SPACE (SCHFS_BLKSIZE - (int)sizeof(struct schfs_node_hdr)) +#define SCHFS_MAX_KPTR (SCHFS_NODE_SPACE / (int)sizeof(struct schfs_kptr)) +#define SCHFS_MAX_ITEMS (SCHFS_NODE_SPACE / (int)sizeof(struct schfs_item)) + +// Largest value that can live inline in a leaf. Anything bigger becomes an +// extent record pointing at data blocks. +#define SCHFS_MAX_INLINE (SCHFS_NODE_SPACE / 4) + +// --------------------------------------------------------------------------- +// Uberblock +// +// A ring of these is written round-robin. Mounting means reading them all and +// taking the highest generation that checksums — that is the entire crash +// recovery story, in place of a journal replay. +// --------------------------------------------------------------------------- + +#define SCHFS_UBER_COUNT 128 +#define SCHFS_UBER_START 1 // block 0 stays free for a boot sector + +// First block available for the tree and for file data: everything below is +// the boot block and the uberblock ring. +#define SCHFS_FIRST_BLOCK (SCHFS_UBER_START + SCHFS_UBER_COUNT) + +#define SCHFS_VERSION 1 +#define SCHFS_LABEL_MAX 32 + +struct schfs_uberblock { + uint32_t magic; // SCHFS_MAGIC + uint32_t crc; // CRC32c of this struct, this field zeroed + uint32_t version; // SCHFS_VERSION + uint32_t blocksize; // SCHFS_BLKSIZE; a reader must refuse a mismatch + uint64_t generation; // transaction number; highest valid one wins + uint64_t root; // block number of the tree root + uint32_t root_crc; // checksum of that root block + uint32_t pad0; + uint64_t root_generation; + uint64_t total_blocks; + // Informational only. Which blocks are actually free is derived from the + // tree at mount rather than stored, so this is what the volume believed at + // commit time — useful for df before anything is mounted, never trusted. + uint64_t free_blocks; + uint64_t reserved0; + uint64_t next_objectid; + uint64_t root_objectid; // normally SCHFS_ROOT_OBJECTID + uint8_t uuid[16]; + char label[SCHFS_LABEL_MAX]; + uint8_t pad[SCHFS_BLKSIZE - 136]; +}; + +// --------------------------------------------------------------------------- +// Records +// --------------------------------------------------------------------------- + +#define SCHFS_T_FILE 1 +#define SCHFS_T_DIR 2 +#define SCHFS_T_DEV 3 +#define SCHFS_T_SYMLINK 4 + +struct schfs_inode { + uint64_t size; + uint64_t blocks; + uint64_t atime, mtime, ctime; + // Containing directory. Meaningful for directories only, where it is what + // ".." resolves to — neither "." nor ".." is stored on disk, so a directory + // costs nothing until it has real entries. For files with several hard + // links "parent" is simply the first directory that linked them and must + // not be trusted. + uint64_t parent; + uint32_t mode; // real POSIX mode bits, at last + uint32_t uid, gid; + uint32_t nlink; + uint16_t type; // SCHFS_T_* + uint16_t rdev_major, rdev_minor; + uint16_t pad; + uint32_t flags; // SCHFS_I_* — none defined yet + uint32_t gen; // transaction that last changed this inode; + // what an incremental send/snapshot diff needs +}; + +// An extent maps a run of file blocks onto a run of disk blocks. refs is what +// makes snapshots and reflink copies nearly free: sharing a range is a refcount +// bump rather than a data copy. +struct schfs_extent { + uint64_t disk_block; + uint64_t nblocks; + // Transaction group that allocated this run. A run stamped with the group + // currently being built cannot be reached from any committed root, so its + // blocks may be overwritten in place — which is what stops a program that + // writes a hundred bytes at a time from copying a whole 4 KB block, and + // then a whole tree path, on every call. + // + // A full 64 bits, matching the tree's generation counter, because a 32-bit + // one would wrap after four billion commits and a wrapped comparison says + // "same group" about a block belonging to a committed tree — the one + // mistake this field exists to prevent. Only ever trusted together with + // refs == 1; a shared run belongs to somebody else as well. + uint64_t gen; + uint32_t refs; + uint32_t pad; +}; + +// Directory entry payload. The key's offset field holds the name hash, so a +// lookup is one tree descent rather than a directory scan. +// +// Two names in one directory can hash the same, and the key would then be +// identical — the second insert would silently replace the first. So the value +// is a *packed list*: one schfs_dirent_rec plus its name bytes, repeated. A +// 64-bit hash makes lists longer than one vanishingly rare, but "vanishingly +// rare" is not "impossible", and a filesystem that loses a file under a hash +// collision is not one to build on. +struct schfs_dirent_rec { + uint64_t objectid; + uint16_t type; + uint16_t namelen; + uint32_t pad; + /* name bytes follow, namelen of them, not NUL-terminated */ +}; + +#define SCHFS_NAME_MAX 255 + +// Step from one packed dirent to the next. Records are 8-byte aligned so the +// uint64 objectid of the next one is naturally aligned. +#define SCHFS_DIRENT_LEN(namelen) \ + ((unsigned)((sizeof(struct schfs_dirent_rec) + (namelen) + 7) & ~7u)) + +// --------------------------------------------------------------------------- +// Compile-time layout checks. +// +// Every one of these is a number that ends up baked into images on disk. A +// silent change to any of them — adding a field, changing a type, a compiler +// padding a struct differently — makes every existing image unreadable in a way +// that looks like corruption rather than like a mistake. Failing the build is +// enormously cheaper than debugging that. +// --------------------------------------------------------------------------- + +#define SCHFS_ASSERT_SIZE(t, n) \ + typedef char schfs_sizecheck_##t[(sizeof(struct t) == (n)) ? 1 : -1] + +SCHFS_ASSERT_SIZE(schfs_key, 24); +SCHFS_ASSERT_SIZE(schfs_node_hdr, 32); +SCHFS_ASSERT_SIZE(schfs_kptr, 48); +SCHFS_ASSERT_SIZE(schfs_item, 32); +SCHFS_ASSERT_SIZE(schfs_uberblock, SCHFS_BLKSIZE); +SCHFS_ASSERT_SIZE(schfs_inode, 80); +SCHFS_ASSERT_SIZE(schfs_extent, 32); +SCHFS_ASSERT_SIZE(schfs_dirent_rec, 16); + +#endif /* SCHFS_H */ diff --git a/include/sleeplock.h b/include/sleeplock.h new file mode 100644 index 0000000..e389e34 --- /dev/null +++ b/include/sleeplock.h @@ -0,0 +1,9 @@ +// Long-term locks for processes +struct sleeplock { + uint locked; // Is the lock held? + struct spinlock lk; // spinlock protecting this sleep lock + + // For debugging: + char *name; // Name of lock. + int pid; // Process holding lock +}; diff --git a/include/socket.h b/include/socket.h new file mode 100644 index 0000000..9d1f581 --- /dev/null +++ b/include/socket.h @@ -0,0 +1,81 @@ +#pragma once + +#include "types.h" + +// Unix domain sockets. +// +// These exist for Schcom. A compositor and its clients have to exchange +// messages, and a pipe cannot do it: a pipe is one-directional, has no +// notion of a connection, and gives no way for a server to be *found* by a +// client that starts later. A socket with a name in the filesystem is +// exactly the missing piece. +// +// AF_INET is deliberately absent. The socket layer is being built around the +// local case first because that is the one the GUI needs and the one whose +// semantics are simplest; a network stack plugs in underneath the same +// syscalls later rather than reshaping them. + +#define AF_UNIX 1 +#define AF_LOCAL 1 +#define AF_INET 2 // recognised so it can be refused honestly + +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 + +#define UNIX_PATH_MAX 108 + +#define SHUT_RD 0 +#define SHUT_WR 1 +#define SHUT_RDWR 2 + +struct sockaddr_un { + uint16 sun_family; + char sun_path[UNIX_PATH_MAX]; +}; + +// The generic form syscalls take. Same shape as Linux's, so a musl-linked +// program's struct lines up byte for byte. +struct sockaddr { + uint16 sa_family; + char sa_data[UNIX_PATH_MAX]; +}; + +#ifdef _KERNEL_SOCKET_INTERNALS + +#define NSOCK 32 // sockets in the system +#define SOCKBUF 4096 // receive buffer per connected socket +#define NBACKLOG 8 + +enum sockstate { + SS_FREE = 0, + SS_UNBOUND, + SS_BOUND, + SS_LISTENING, + SS_CONNECTED, +}; + +// Every field here is protected by the socket table's single lock in +// kernel/net/unix.c -- there is deliberately no per-socket lock; see the +// comment at the top of that file for why. +struct socket { + int ref; + int type; + int state; + + char name[UNIX_PATH_MAX]; // the bound path, for a listener + + // A connected socket's peer. Writing to a socket appends to the *peer's* + // buffer, which is what makes one buffer per socket enough for a + // bidirectional connection. + struct socket *peer; + int peer_closed; + + char data[SOCKBUF]; + uint nread, nwrite; + + // Connections waiting to be accepted, on a listener. + struct socket *queue[NBACKLOG]; + int nqueue; +}; + +#endif diff --git a/include/spinlock.h b/include/spinlock.h new file mode 100644 index 0000000..1392bbc --- /dev/null +++ b/include/spinlock.h @@ -0,0 +1,9 @@ +// Mutual exclusion lock. +struct spinlock { + uint64 locked; // Is the lock held? + // For debugging: + char *name; // Name of lock. + struct cpu *cpu; // The cpu holding the lock. + addr_t pcs[10]; // The call stack (an array of program counters) + // that locked the lock. +}; diff --git a/include/stat.h b/include/stat.h new file mode 100644 index 0000000..9152d0c --- /dev/null +++ b/include/stat.h @@ -0,0 +1,24 @@ +#pragma once +#include "types.h" + +#define T_DIR 1 // Directory +#define T_FILE 2 // File +#define T_DEV 3 // Device +#define T_SYMLINK 4 // Divesymlink +#define T_EXTENT 5 // bmap & itrunc + +struct stat { + int32 type; // File type (T_DIR, T_FILE, or T_DEV) + int32 dev; // File system's disk device ID + uint64 ino; // Inode number + int32 nlink; // Number of hard links to file + uint32 pad; // Padding for 64-bit alignment + uint64 size; // Size of file in bytes + uint rwmode; // Permissions + uint supermode; // Mode + uint showmode; // Visiblity + uint atime; // Last access time + uint mtime; // Last modification time + uint ctime; // Last metadata-change time + uint addrs[12+3]; // Block Addresses +}; diff --git a/include/syscall.h b/include/syscall.h new file mode 100644 index 0000000..7d29ceb --- /dev/null +++ b/include/syscall.h @@ -0,0 +1,49 @@ +#pragma once + +// Syscall numbers and definition macros — all derived from +// kernel/sys/table.inc, which is the single source of truth. +// +// Do NOT add SYS_* constants by hand, and do NOT add anything to +// kernel/sys/linux_abi.c: add one SYSCALL() line to table.inc and write the +// body with SYSCALL_DEFINE(). The constant, the dispatch slot and the Linux +// ABI mapping are all generated from that one line. + +#define NSYSCALLS 512 + +// Scratch slot for syscalls with no Linux equivalent. Every such entry lands +// on this one index of the translation map, which is never dispatched (Linux +// x86_64 numbers currently top out around 450). Using a real index rather +// than a negative sentinel keeps the generated map a plain designated +// initialiser instead of needing a second macro. +#define NO_LINUX 511 + +#ifdef __ASSEMBLER__ +// In .S files GCC passes through the C preprocessor but the assembler +// sees the output, so emit .set directives instead of an enum. +#define SYSCALL(nr, lnr, name) .set SYS_##name, nr +#define SYSCALL_ALIAS(lnr, name) +#include "../kernel/sys/table.inc" +#undef SYSCALL +#undef SYSCALL_ALIAS +#else +// In C files generate a proper enum so constants work in switch/designators. +enum syscall_nr { + _SYS_RESERVED = 0, +#define SYSCALL(nr, lnr, name) SYS_##name = (nr), +#define SYSCALL_ALIAS(lnr, name) +#include "../kernel/sys/table.inc" +#undef SYSCALL +#undef SYSCALL_ALIAS +}; + +// Every syscall body is written as: +// +// SYSCALL_DEFINE(getpid) +// { +// return myproc()->pid; +// } +// +// so the signature lives in exactly one place and every implementation is +// findable with a single grep. +#define SYSCALL_DEFINE(name) addr_t sys_##name(void) +#endif diff --git a/include/text.h b/include/text.h new file mode 100644 index 0000000..c9f7c5b --- /dev/null +++ b/include/text.h @@ -0,0 +1,86 @@ +#pragma once + +// Text rendering. +// +// The console draws text by indexing `font_data[256][16]` and stepping the +// cursor eight pixels. That is a *character cell grid*, and it is the thing in +// the way -- not the font. A grid cannot do variable-width glyphs, cannot +// position text anywhere except on a multiple of eight, cannot anti-alias, and +// cannot represent a codepoint above 255. Swapping the bitmap for a nicer +// bitmap changes none of that. +// +// So this is a layer, not a font. Three things it fixes: +// +// *Glyphs have metrics.* A glyph knows its own size, its bearing and how far +// to advance afterwards. That is what variable-width text is; everything else +// follows from it. +// +// *It draws into a surface, not into the screen.* A compositor draws into an +// off-screen buffer and presents it. Rendering that writes straight to the +// VGA aperture is unusable to it, which is why this takes a target. +// +// *The font is behind an interface.* The bitmap font is one implementation. +// A TrueType rasteriser is another, and arrives without any caller changing: +// glyphs carry 8-bit coverage, so an anti-aliased outline renderer already +// has somewhere to put its output. + +struct font; + +// Somewhere to draw. Deliberately not a `struct device` or a framebuffer: the +// same code has to work on the virtio-gpu back buffer, on a window's own +// buffer, and on the VGA aperture, and none of those know about each other. +struct surface { + void *pixels; // 32-bit 0x00RRGGBB, the format everything here uses + uint32 stride; // bytes per row, not pixels -- they differ on real hardware + int width, height; +}; + +// One rendered glyph. `cov` is 8-bit coverage, not a bitmap: 0 is background, +// 255 is solid, and everything between is an anti-aliased edge. A bitmap font +// fills it with 0 and 255 only, and costs nothing for the generality. +struct glyph { + const unsigned char *cov; // w*h bytes, row-major + int w, h; // size of the coverage bitmap + int bearing_x, bearing_y; // offset from the pen to the top-left of `cov` + int advance; // how far the pen moves afterwards +}; + +struct font_ops { + // Fill `out` for `cp`. Returns 0, or -1 if the font has no such glyph -- + // callers substitute rather than failing, because a missing glyph must not + // stop a line of text. + int (*glyph)(struct font *, uint32 cp, struct glyph *out); + int (*height)(struct font *); // line height + int (*baseline)(struct font *); // pen offset from the top of the line +}; + +struct font { + const struct font_ops *ops; + void *priv; +}; + +// The built-in bitmap font, as a font provider. Always available, needs no +// allocation, and is what the console falls back to before any filesystem +// exists to load a real typeface from. +struct font *font_builtin(void); + +// Draw one UTF-8 string. Returns the x advance. +// +// `x, y` is the pen position on the *baseline*, which is how every text API +// that is not a terminal works -- glyphs of different heights then sit on a +// common line instead of being top-aligned. +int text_draw(struct surface *, struct font *, int x, int y, + const char *utf8, uint32 color); + +// Width the same string would occupy, without drawing it. Needed before you +// draw, for centring and for laying out anything at all. +int text_measure(struct font *, const char *utf8); + +// One glyph, for callers doing their own layout. +int text_draw_glyph(struct surface *, struct font *, int x, int y, + uint32 cp, uint32 color); + +// Decode one UTF-8 sequence. Returns the codepoint and advances *p. +// Malformed input yields U+FFFD and consumes one byte, so a decoder loop +// always terminates. +uint32 utf8_next(const char **p); diff --git a/include/theme.h b/include/theme.h new file mode 100644 index 0000000..5ea0c3f --- /dev/null +++ b/include/theme.h @@ -0,0 +1,57 @@ +#pragma once + +// Schunix visual identity — one palette, shared by everything that draws. +// +// This header exists because there were three unrelated designs and the seams +// showed. The bootloader splash was deep purple with gold text, deliberately +// matching the *panic* screen; the kernel console was cream with near-black +// text; the panic screen was the purple both were copying. So a normal boot +// looked like a crash, then abruptly became an amber terminal, and none of the +// three looked like the same product. +// +// The rule now: **normal states are calm and dark; only failure is loud.** +// Boot, console and shell share SCH_BG/SCH_FG. The panic screen keeps the +// full-bleed purple entirely to itself, which is what makes it mean something. +// +// Included by boot/stage2main.c (freestanding, pre-kernel), kernel/dev/vga.c, +// kernel/core/console.c and kernel/core/panic.c. Plain #defines only — no +// types, no code — because stage2 is compiled 32-bit against a different +// world than the kernel. +// +// Colours are 0xRRGGBB. vga_draw_pixel packs them for whatever depth the +// framebuffer actually is. + +// --- the product --------------------------------------------------------- +// Near-black with a slight blue cast rather than pure #000: pure black on an +// LCD reads as "the machine is off", and every serious platform sits a few +// points above it. +#define SCH_BG 0x0C0E13 +#define SCH_FG 0xE6E8EC // primary text +#define SCH_DIM 0x707784 // secondary text, hints, version strings +#define SCH_ACCENT 0x7C5CFF // the one accent: violet, keeping the + // project's purple lineage without the + // eye-searing chroma of the old splash +#define SCH_ACCENT_DIM 0x2A2440 // unused track behind a progress bar +#define SCH_OK 0x4ADE80 // reserved: success states +#define SCH_WARN 0xFBBF24 // reserved: warnings that are not panics + +// --- failure ------------------------------------------------------------- +// PSOGM. Deliberately unlike anything above, because its whole job is to be +// unmistakable. See kernel/core/panic.c. +// +// These are the values panic.c actually renders. It used to carry a second, +// different set of PSOGM_* defines of its own, so the two disagreed about what +// the crash screen looked like and this header was quietly fiction. There was +// also a PSOGM_TITLE in gold here, left over from a splash design that no +// longer exists -- the screen is one background and two weights of text, on +// purpose, because a crash screen with an accent colour is a crash screen +// someone was enjoying designing. +#define PSOGM_BG 0x4B1D9A // the purple +#define PSOGM_FG 0xFFFFFF // the face, the headline, the values +#define PSOGM_DIM 0xC3AEEC // labels and the closing lines + +// The one exception to "two weights of text": the QR card has to be a light +// panel with dark modules, because that is what a scanner needs. It reads as a +// label stuck onto the screen, which is roughly what it is. +#define PSOGM_CARD 0xFFFFFF +#define PSOGM_INK 0x000000 diff --git a/include/traps.h b/include/traps.h new file mode 100644 index 0000000..b8f2756 --- /dev/null +++ b/include/traps.h @@ -0,0 +1,69 @@ +#pragma once + +// x86 trap and interrupt constants. + +// Processor-defined exceptions: +#define T_DIVIDE 0 // divide error +#define T_DEBUG 1 // debug exception +#define T_NMI 2 // non-maskable interrupt +#define T_BRKPT 3 // breakpoint +#define T_OFLOW 4 // overflow +#define T_BOUND 5 // bounds check +#define T_ILLOP 6 // illegal opcode +#define T_DEVICE 7 // device not available +#define T_DBLFLT 8 // double fault +#define T_TSS 10 // invalid task switch segment +#define T_SEGNP 11 // segment not present +#define T_STACK 12 // stack exception +#define T_GPFLT 13 // general protection fault +#define T_PGFLT 14 // page fault +#define T_FPERR 16 // floating point error +#define T_ALIGN 17 // aligment check +#define T_MCHK 18 // machine check +#define T_SIMDERR 19 // SIMD floating point error + +// IRQ offsets +#define T_IRQ0 32 // IRQ 0 corresponds to int T_IRQ + +#define IRQ_TIMER 0 +#define IRQ_KBD 1 +#define IRQ_COM1 4 +#define IRQ_MOUSE 12 +#define IRQ_IDE 14 +#define IRQ_ERROR 19 +#define IRQ_SPURIOUS 31 + +// System call interrupt number for legacy int 0x40 or 0x80 if used +// although syscall/sysret is preferred for x64 +#define T_SYSCALL 0x40 + +#ifndef __ASSEMBLER__ +struct trapframe { + // Registers saved by trapasm.S + uint64 rax; + uint64 rbx; + uint64 rcx; + uint64 rdx; + uint64 rbp; + uint64 rsi; + uint64 rdi; + uint64 r8; + uint64 r9; + uint64 r10; + uint64 r11; + uint64 r12; + uint64 r13; + uint64 r14; + uint64 r15; + + uint64 trapno; + + // Error code and info saved by hardware + uint64 err; + uint64 rip; + uint64 cs; + uint64 rflags; + uint64 rsp; + uint64 ss; +}; +#endif diff --git a/include/ttf.h b/include/ttf.h new file mode 100644 index 0000000..d840e9c --- /dev/null +++ b/include/ttf.h @@ -0,0 +1,49 @@ +#pragma once + +// TrueType outlines, as a font provider for include/text.h. +// +// Scope, and why it is this and not "TTF and OTF": +// +// .ttf and .otf are both sfnt containers -- the same table directory, the same +// cmap, the same hmtx. What differs is how outlines are stored. TrueType puts +// quadratic B-spline contours in a `glyf` table; OpenType/PostScript puts cubic +// béziers in a `CFF ` table encoded as Type 2 charstrings, which is a +// stack-based interpreted format and a separate project. +// +// Checked before writing any of it: JetBrains Mono and Roboto -- the two fonts +// this system is going to use -- both ship `glyf` and neither ships `CFF `. So +// CFF support would buy nothing today, and the honest thing is to implement the +// format the fonts actually use and say so, rather than half-implement two. +// +// Everything here is from Apple's TrueType Reference Manual and the OpenType +// specification, both public documents. + +struct ttf { + const unsigned char *data; + uint32 len; + + uint32 glyf, glyf_len; + uint32 loca, loca_len; + uint32 cmap4; // offset of the format 4 subtable, 0 if none + uint32 hmtx; + int num_glyphs; + int num_hmetrics; + int units_per_em; + int long_loca; // indexToLocFormat: 0 = 16-bit offsets, 1 = 32 + int ascent, descent; + + // Rasterisation target size, in pixels per em. Set by ttf_open. + int px; +}; + +// Parse a font already in memory. Returns 0, or -1 if it is not a TrueType +// font this can read. `data` must outlive the struct -- nothing is copied. +int ttf_open(struct ttf *, const void *data, uint32 len, int pixels_per_em); + +// Rasterise one codepoint into `cov`. Returns 0, or -1 if the font has no such +// glyph or it will not fit. Exposed because the host harness uses it directly. +int ttf_render(struct ttf *, uint32 cp, struct glyph *out, unsigned char *cov, + int covcap, int *ox, int *oy); + +// A font provider over it, for text.h. The struct must outlive the font. +struct font *ttf_font(struct ttf *); diff --git a/include/types.h b/include/types.h new file mode 100644 index 0000000..5dec6bb --- /dev/null +++ b/include/types.h @@ -0,0 +1,79 @@ +#pragma once + +typedef unsigned int uint; +typedef unsigned short ushort; +typedef unsigned char uchar; + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; + +typedef signed char int8; +typedef signed short int16; +typedef signed int int32; + +// uint64 has to be 64 bits everywhere this header is used, and `unsigned long` +// is not that everywhere. Linux and the x86_64-elf kernel target are LP64, so +// long is 64-bit; Windows is LLP64, where long is 32-bit and only long long is +// 64-bit. +// +// This matters far more than a portability nicety. The host tools -- mkfs, +// mkschfs, the SchFS suites -- include this header *and* the on-disk structure +// definitions in fs.h and schfs.h. Building them on Windows with a 32-bit +// uint64 does not fail: it quietly produces images whose inode numbers, sizes +// and block pointers are half the width the kernel reads back, which shows up +// as a corrupt filesystem long after the tool that wrote it has exited. +// +// Spelled as long/long long rather than 's uint64_t so the `%l` +// format specifiers used throughout the kernel stay correct and untouched. +// Conditioned on the actual width of `long` rather than on the platform, +// because there are three cases and only one of them is about Windows: +// x86_64-elf / Linux LP64 -> long is 64-bit +// Windows LLP64 -> long is 32-bit, long long is 64 +// i386-elf (boot/) ILP32 -> long is 32-bit, and stage2main.c includes +// this header too +#if defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8 +typedef unsigned long uint64; +typedef signed long int64; +#else +typedef unsigned long long uint64; +typedef signed long long int64; +#endif + +// Belt and braces: if the above is ever wrong on some new host, say so at +// compile time rather than in a filesystem image. +_Static_assert(sizeof(uint64) == 8, "uint64 must be 64 bits"); +_Static_assert(sizeof(int64) == 8, "int64 must be 64 bits"); + +typedef uint64 uintptr_t; +typedef int64 intptr_t; +typedef int64 ptrdiff_t; + +typedef uint64 addr_t; +typedef uint64 size_t; +typedef int64 ssize_t; + +#ifndef MKFS +#ifndef _SIGSET_T +#define _SIGSET_T +typedef uint64 sigset_t; +#endif +#endif + +typedef addr_t pte_t; +typedef addr_t pde_t; +typedef addr_t pdpe_t; +typedef addr_t pml4e_t; + +struct mouse_data { + int x; + int y; + uint8 buttons; +}; + +#ifndef NULL +#define NULL ((void*)0) +#endif + +#define TRUE 1 +#define FALSE 0 \ No newline at end of file diff --git a/include/uaccess.h b/include/uaccess.h new file mode 100644 index 0000000..eb172e2 --- /dev/null +++ b/include/uaccess.h @@ -0,0 +1,49 @@ +// User-memory access API, modeled on Linux's . +// +// Rules for kernel code touching user pointers: +// +// 1. Never dereference a user-supplied address without validating it +// first. A syscall argument can point anywhere, including at kernel +// memory or at nothing at all. +// +// 2. Never assume a user buffer is physically contiguous. uva2ka() only +// translates ONE page; the direct-map alias it returns runs into an +// unrelated physical page at the next 4K boundary. Any multi-byte +// access through it must stay within a single page. +// +// These helpers encapsulate both rules. Because Schunix (like old x86 +// without SMAP) keeps the user page table active in kernel mode, a raw +// user virtual address is directly dereferenceable once the whole range +// 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. +#ifndef SCHUNIX_UACCESS_H +#define SCHUNIX_UACCESS_H + +#include "types.h" + +// Nonzero if [uaddr, uaddr+size) is entirely mapped, user-accessible +// memory in the current process. size == 0 is always ok. +int access_ok(addr_t uaddr, uint64 size); + +// Validate the whole range and return it as a directly usable pointer +// (the raw user VA). 0 on bad/NULL address. +void *user_ptr(addr_t uaddr, uint64 size); + +// Copy between kernel and user memory, page by page. +// Return 0 on success, -EFAULT on any unmapped page. +int copy_from_user(void *dst, addr_t uaddr, uint64 n); +int copy_to_user(addr_t uaddr, const void *src, uint64 n); + +// Fixed-size scalar variants, in the spirit of Linux's get_user/put_user. +#define get_user(x, uaddr) copy_from_user(&(x), (addr_t)(uaddr), sizeof(x)) +#define put_user(x, uaddr) copy_to_user((addr_t)(uaddr), &(x), sizeof(x)) + +// Longest string fetchstr()/strlen_user() will scan before giving up. +#define USER_STR_MAX 32768 + +// Length of the NUL-terminated string at uaddr (excluding the NUL), +// validating every page it spans. -EFAULT if it runs off mapped memory +// or exceeds USER_STR_MAX. +long strlen_user(addr_t uaddr); + +#endif // SCHUNIX_UACCESS_H diff --git a/include/usb.h b/include/usb.h new file mode 100644 index 0000000..a01ac65 --- /dev/null +++ b/include/usb.h @@ -0,0 +1,270 @@ +#pragma once + +#include "device.h" + +// USB, the parts that are the same whatever host controller you have. +// +// Everything here comes from the USB 2.0 specification chapter 9, which every +// USB device implements regardless of speed, class or vendor. That is what +// makes enumeration possible at all: before you know anything about a device +// you can still ask it what it is, because the question is standardised. + +// bmRequestType +#define USB_DIR_OUT 0x00 +#define USB_DIR_IN 0x80 +#define USB_TYPE_STANDARD 0x00 +#define USB_TYPE_CLASS 0x20 +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 // a hub's downstream port + +// bRequest, standard requests +#define USB_REQ_GET_STATUS 0 +#define USB_REQ_CLEAR_FEATURE 1 +#define USB_REQ_SET_FEATURE 3 +#define USB_REQ_SET_ADDRESS 5 +#define USB_REQ_GET_DESCRIPTOR 6 +#define USB_REQ_SET_DESCRIPTOR 7 +#define USB_REQ_GET_CONFIG 8 +#define USB_REQ_SET_CONFIG 9 +#define USB_REQ_GET_INTERFACE 10 +#define USB_REQ_SET_INTERFACE 11 + +// Descriptor types (the high byte of wValue in a GET_DESCRIPTOR) +#define USB_DT_DEVICE 1 +#define USB_DT_CONFIG 2 +#define USB_DT_STRING 3 +#define USB_DT_INTERFACE 4 +#define USB_DT_ENDPOINT 5 + +// Class codes we care about +#define USB_CLASS_HID 0x03 +#define USB_CLASS_MASS_STORAGE 0x08 +#define USB_CLASS_HUB 0x09 + +// HID subclass/protocol. Boot protocol is the one a BIOS uses, and the reason +// a USB keyboard works before any operating system has loaded: the report +// layout is fixed, so it can be read without parsing a report descriptor. +#define USB_HID_SUBCLASS_BOOT 0x01 +#define USB_HID_PROTO_KEYBOARD 0x01 +#define USB_HID_PROTO_MOUSE 0x02 + +// Bus speeds. +// +// These are xHCI's numbering, used as the common currency rather than +// translated at the boundary. That is a deliberate choice: there is one host +// controller, the values have to reach a slot context eventually, and a +// second enum whose only job is to be converted into this one would be +// ceremony. If a second controller ever appears, this is the thing to +// revisit -- but a class driver still has no business including xhci.h. +#define USB_SPEED_FULL 1 // 12 Mb/s +#define USB_SPEED_LOW 2 // 1.5 Mb/s +#define USB_SPEED_HIGH 3 // 480 Mb/s +#define USB_SPEED_SUPER 4 // 5 Gb/s + +// An eight-byte SETUP packet, the header of every control transfer. +struct usb_setup { + uint8 bmRequestType; + uint8 bRequest; + uint16 wValue; + uint16 wIndex; + uint16 wLength; +} __attribute__((packed)); + +struct usb_device_desc { + uint8 bLength; + uint8 bDescriptorType; + uint16 bcdUSB; + uint8 bDeviceClass; + uint8 bDeviceSubClass; + uint8 bDeviceProtocol; + uint8 bMaxPacketSize0; + uint16 idVendor; + uint16 idProduct; + uint16 bcdDevice; + uint8 iManufacturer; + uint8 iProduct; + uint8 iSerialNumber; + uint8 bNumConfigurations; +} __attribute__((packed)); + +struct usb_config_desc { + uint8 bLength; + uint8 bDescriptorType; + uint16 wTotalLength; + uint8 bNumInterfaces; + uint8 bConfigurationValue; + uint8 iConfiguration; + uint8 bmAttributes; + uint8 bMaxPower; +} __attribute__((packed)); + +struct usb_interface_desc { + uint8 bLength; + uint8 bDescriptorType; + uint8 bInterfaceNumber; + uint8 bAlternateSetting; + uint8 bNumEndpoints; + uint8 bInterfaceClass; + uint8 bInterfaceSubClass; + uint8 bInterfaceProtocol; + uint8 iInterface; +} __attribute__((packed)); + +struct usb_endpoint_desc { + uint8 bLength; + uint8 bDescriptorType; + uint8 bEndpointAddress; // bit 7: 1 = IN + uint8 bmAttributes; // bits 1:0: 0 ctrl, 1 iso, 2 bulk, 3 interrupt + uint16 wMaxPacketSize; + uint8 bInterval; +} __attribute__((packed)); + +#define USB_EP_XFERTYPE(a) ((a) & 0x03) +#define USB_EP_BULK 2 +#define USB_EP_INTERRUPT 3 +#define USB_EP_IS_IN(a) (((a) & 0x80) != 0) +#define USB_EP_NUM(a) ((a) & 0x0F) + +// Mass storage: SCSI transparent command set over bulk-only transport. +#define USB_MSC_SUBCLASS_SCSI 0x06 +#define USB_MSC_PROTO_BOT 0x50 + +// --------------------------------------------------------------------------- +// Hubs +// +// A hub is a USB device like any other, and everything it does is done by +// sending it ordinary control requests. There is no separate bus protocol: +// "reset port 3" is a SET_FEATURE addressed to the hub. +// --------------------------------------------------------------------------- + +#define USB_DT_HUB 0x29 + +// Port features, the wValue of SET_FEATURE / CLEAR_FEATURE on a port. +#define PORT_FEAT_ENABLE 1 +#define PORT_FEAT_RESET 4 +#define PORT_FEAT_POWER 8 +#define PORT_FEAT_C_CONNECTION 16 +#define PORT_FEAT_C_ENABLE 17 +#define PORT_FEAT_C_RESET 20 + +// wPortStatus, the first half of a port's GET_STATUS reply. +#define PORTSTAT_CONNECTION (1 << 0) +#define PORTSTAT_ENABLE (1 << 1) +#define PORTSTAT_RESET (1 << 4) +#define PORTSTAT_POWER (1 << 8) +#define PORTSTAT_LOWSPEED (1 << 9) +#define PORTSTAT_HIGHSPEED (1 << 10) + +struct usb_hub_desc { + uint8 bDescLength; + uint8 bDescriptorType; + uint8 bNbrPorts; + uint16 wHubCharacteristics; + uint8 bPwrOn2PwrGood; // in 2 ms units + uint8 bHubContrCurrent; +} __attribute__((packed)); + +// Bits 1:0 of wHubCharacteristics: 00 ganged power, 01 per-port. +#define HUB_CHAR_TT_MASK 0x0060 + +// HID class requests, on the interface rather than the device. +#define USB_HID_SET_IDLE 0x0A +#define USB_HID_SET_PROTOCOL 0x0B +#define USB_HID_PROTOCOL_BOOT 0 + +// --------------------------------------------------------------------------- +// The interface between the USB core and a host controller +// +// One host controller exists (xHCI) and one probably always will, but the +// core has no business knowing about TRBs and slot IDs, and the controller +// has no business knowing what a HID report is. This is where the line goes. +// --------------------------------------------------------------------------- + +struct usb_dev; + +struct usb_hc_ops { + // A control transfer on endpoint 0. `buf`, if any, must be DMA memory. + int (*control)(struct usb_dev *, struct usb_setup *, void *buf, int len); + // Make an endpoint usable. Returns 0, or -1 if the controller refused. + int (*open_ep)(struct usb_dev *, const struct usb_endpoint_desc *); + // Queue one IN transfer. Completion arrives via dev->complete. + int (*queue_in)(struct usb_dev *, int ep_addr, void *buf, int len); + // One bulk transfer, synchronously. Sleeps, so process context only. + // Returns bytes transferred, or -1. + int (*bulk)(struct usb_dev *, int ep_addr, void *buf, int len); + + // Bring up a device found on a downstream port of `hub`. The controller + // works out the route string from the hub's own position. + void (*attach)(struct usb_dev *hub, int hub_port, int speed); + + // Tell the controller this device is a hub with `nports` ports. It has to + // know: a hub is scheduled differently from anything else, and devices + // behind it are addressed relative to it. + int (*set_hub)(struct usb_dev *, int nports, int mtt); +}; + +#define USB_MAXCONF 256 // bytes of configuration descriptor we keep + +struct usb_dev { + const struct usb_hc_ops *ops; + void *hc; // the controller's own handle for this device + int slot; + int speed; + int port; // ROOT hub port this whole branch hangs off + + // Where the device sits in the tree. + // + // A USB device has no address of its own that describes its position -- the + // controller finds it by being told the path. `route` is xHCI's route + // string: five nibbles, one per tier, each holding the downstream port + // number taken at that tier. Tier 0 is a device on a root port, and its + // route is 0. + uint32 route; + int tier; + + // Transaction translator, for a full or low speed device behind a + // high-speed hub. The controller has to know which hub is doing the + // speed conversion on its behalf, because it is the hub, not the device, + // that it actually schedules against. + int tt_slot, tt_port; + + int in_use; + + struct usb_device_desc desc; + uchar conf[USB_MAXCONF]; // the configuration descriptor and everything + int conflen; // that follows it, exactly as the device sent + + // The first interface, which is all a boot-protocol or bulk-only device + // needs, and the endpoints belonging to it. + struct usb_interface_desc iface; + struct usb_endpoint_desc intr_in; + struct usb_endpoint_desc bulk_in; + struct usb_endpoint_desc bulk_out; + int has_intr_in, has_bulk_in, has_bulk_out; + + // Filled in by whichever class driver claimed the device. + const char *driver; + void *drvdata; + void (*complete)(struct usb_dev *, void *buf, int len); +}; + +// One row per class driver. Matching is on the *interface* descriptor, +// because bDeviceClass is very often 0 ("look at the interfaces"). +struct usb_driver { + const char *name; + uint8 class, subclass, protocol; // 0xFF matches anything + // What the rest of the kernel should consider this device to be, once this + // driver has claimed it. Distinct from `class` above, which is the USB + // interface class the descriptor advertises: the driver knows what it made + // of the device, the descriptor only says what the device claims to be. + enum dev_class devclass; + int (*probe)(struct usb_dev *); +}; + +// Called by a host controller once a device is addressed and its device +// descriptor has been read. The core reads the configuration, selects it, and +// offers the device to the class drivers. +void usb_attach(struct usb_dev *dev); + diff --git a/include/user.h b/include/user.h new file mode 100644 index 0000000..7983a2d --- /dev/null +++ b/include/user.h @@ -0,0 +1,117 @@ +#pragma once +#ifndef USER_H +#define USER_H + +#include "types.h" +#include "date.h" + +struct stat; +struct rtcdate; +struct mouse_data; + +// --- system calls --- +int fork(void); +void exit(void) __attribute__((noreturn)); +int wait(void); +int pipe(int*); +int write(int, void*, int); +int read(int, void*, int); +int close(int); +int kill(int); +int exec(char*, char**); +int open(char*, int); +int mknod(char*, short, short); +int unlink(char*); +int fstat(int fd, struct stat*); +int link(char*, char*); +int mkdir(char*); +int chdir(char*); +int dup(int); +int dup2(int, int); +int fcntl(int, int, int); +long lseek(int, long, int); +int getpid(void); +char* sbrk(uint64); +int sleep(int); +int uptime(void); +int vga_sync(void*); +int getmouse(struct mouse_data*); +int reboot(void); +int shutdown(void); +int sigfillset(sigset_t *set); +int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); +int sigwait(const sigset_t *set, int *sig); +int alarm(int seconds); +int waitpid(int pid, int *status, int options); +int setsid(void); +void* mmap(void*, uint64, int, int, int, uint64); +// Shared memory. shmat returns the attach address, or a small negative value +// on failure — there is no errno in this runtime, so check for < 0. +int shmget(int key, uint64 size, int flags); +void* shmat(int id, void *addr, int flags); +int shmdt(void *addr); +int munmap(void*, uint64); +int delete(char*); +int show(char*); +int showstat(char*, struct stat*); +int ftruncate(int, int); +int truncate(char*, int); +int rename(const char*, const char*); +int symlink(char*, char*); +int readlink(char*, char*, int); +int getuid(void); +int geteuid(void); +int nanosleep(void*); +int mprotect(void*, uint64, int); +int ioctl(int, uint64, void*); +char* getcwd(char*, int); +int arch_prctl(int, uint64); +int set_tid_address(int*); +int set_robust_list(void*, int); +int futex(int*, int, int, void*, int*, int); +int clone(uint64, void*, void*, void*, void*); +void exit_group(int) __attribute__((noreturn)); +int wait4(int, int*, int, void*); +int getgid(void); +int getegid(void); +int umask(int); +int writev(int, void*, int); +int readv(int, void*, int); +void* brk(void*); +int prlimit(int, int, void*, void*); +int lstat(const char*, struct stat*); +int access(const char*, int); +int openat(int, const char*, int, ...); +int fchdir(int); +int enable_linux_abi(void); +int getrlimit(int, void*); +int setuid(int); +int setgid(int); +int getsid(int); +int dup3(int, int, int); +int pipe2(int*, int); +int clock_gettime(int, void*); +int getppid(void); +int rt_sigaction(int, void*, void*, uint64); +int mount(const char *src, const char *tgt, const char *fstype, uint64 flags, void *data); + +// Sockets. `struct sockaddr` and the AF_*/SOCK_* constants are in socket.h; +// include it as well as this header to use them. +struct sockaddr; +int socket(int domain, int type, int protocol); +int bind(int fd, const struct sockaddr *addr, int addrlen); +int listen(int fd, int backlog); +int accept(int fd, struct sockaddr *addr, int *addrlen); +int connect(int fd, const struct sockaddr *addr, int addrlen); +int socketpair(int domain, int type, int protocol, int sv[2]); +int sendto(int fd, const void *buf, int len, int flags, const struct sockaddr*, int); +int recvfrom(int fd, void *buf, int len, int flags, struct sockaddr*, int*); +int sockshutdown(int fd, int how); +int setsockopt(int fd, int level, int opt, const void *val, int len); +int getsockopt(int fd, int level, int opt, void *val, int *len); + +// --- ulib.c --- +int stat(const char*, struct stat*); +char* gets(char*, int max); + +#endif // USER_H \ No newline at end of file diff --git a/include/virtio.h b/include/virtio.h new file mode 100644 index 0000000..6719f75 --- /dev/null +++ b/include/virtio.h @@ -0,0 +1,174 @@ +#pragma once + +// virtio 1.0 over PCI — the transport, and virtio-gpu's 2D protocol. +// +// Written from the OASIS specification (virtio 1.1, chapters 2, 4.1 and 5.7), +// which is a public document with no licence on what you write from it. Same +// reasoning as kernel/drivers/xhci.c. +// +// Why virtio-gpu at all, when there is already a framebuffer: the VBE +// framebuffer is a flat block of memory the loader happened to be told about. +// It has no mode setting, no notion of a frame being complete, and no way to +// ask the host to present anything -- so a compositor drawing into it is +// racing the scanout with no way to synchronise. virtio-gpu has resources, +// explicit transfer and an explicit flush, which is the model every real GPU +// driver has. It is the smallest device that teaches the right shape. + +// --- PCI transport --------------------------------------------------------- + +#define VIRTIO_VENDOR 0x1AF4 +// Modern (1.0) device IDs are 0x1040 + the virtio device type. GPU is type 16. +#define VIRTIO_DEV_GPU 0x1050 + +// Vendor-specific PCI capability, which is how a virtio device says where in +// its BARs each configuration structure lives. +#define PCI_CAP_ID_VNDR 0x09 + +#define VIRTIO_PCI_CAP_COMMON_CFG 1 +#define VIRTIO_PCI_CAP_NOTIFY_CFG 2 +#define VIRTIO_PCI_CAP_ISR_CFG 3 +#define VIRTIO_PCI_CAP_DEVICE_CFG 4 + +// Offsets within the common configuration structure. Written out rather than +// declared as a struct: the fields are little-endian by specification and of +// mixed width, and a struct invites the compiler to pad or a caller to forget +// that these are MMIO and must be accessed at exactly the stated width. +#define VCOMMON_DFEAT_SEL 0x00 // le32 +#define VCOMMON_DFEAT 0x04 // le32 +#define VCOMMON_GFEAT_SEL 0x08 // le32 +#define VCOMMON_GFEAT 0x0C // le32 +#define VCOMMON_MSIX_CFG 0x10 // le16 +#define VCOMMON_NUM_QUEUES 0x12 // le16 +#define VCOMMON_STATUS 0x14 // u8 +#define VCOMMON_CFG_GEN 0x15 // u8 +#define VCOMMON_Q_SELECT 0x16 // le16 +#define VCOMMON_Q_SIZE 0x18 // le16 +#define VCOMMON_Q_MSIX 0x1A // le16 +#define VCOMMON_Q_ENABLE 0x1C // le16 +#define VCOMMON_Q_NOTIFY_OFF 0x1E // le16 +#define VCOMMON_Q_DESC 0x20 // le64 +#define VCOMMON_Q_DRIVER 0x28 // le64 +#define VCOMMON_Q_DEVICE 0x30 // le64 + +// device_status bits, set in this order during bring-up. +#define VSTATUS_ACK 1 +#define VSTATUS_DRIVER 2 +#define VSTATUS_DRIVER_OK 4 +#define VSTATUS_FEATURES_OK 8 +#define VSTATUS_FAILED 0x80 + +#define VIRTIO_F_VERSION_1 32 // feature bit: this is a 1.0 device + +// --- split virtqueue ------------------------------------------------------- + +#define VRING_DESC_F_NEXT 1 +#define VRING_DESC_F_WRITE 2 // device writes it; i.e. this is our buffer + +struct vring_desc { + uint64 addr; + uint32 len; + uint16 flags; + uint16 next; +} __attribute__((packed)); + +struct vring_avail { + uint16 flags; + uint16 idx; + uint16 ring[]; +} __attribute__((packed)); + +struct vring_used_elem { + uint32 id; + uint32 len; +} __attribute__((packed)); + +struct vring_used { + uint16 flags; + uint16 idx; + struct vring_used_elem ring[]; +} __attribute__((packed)); + +// --- virtio-gpu, 2D -------------------------------------------------------- + +#define VIRTIO_GPU_CMD_GET_DISPLAY_INFO 0x0100 +#define VIRTIO_GPU_CMD_RESOURCE_CREATE_2D 0x0101 +#define VIRTIO_GPU_CMD_RESOURCE_UNREF 0x0102 +#define VIRTIO_GPU_CMD_SET_SCANOUT 0x0103 +#define VIRTIO_GPU_CMD_RESOURCE_FLUSH 0x0104 +#define VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D 0x0105 +#define VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING 0x0106 + +#define VIRTIO_GPU_RESP_OK_NODATA 0x1100 +#define VIRTIO_GPU_RESP_OK_DISPLAY_INFO 0x1101 + +#define VIRTIO_GPU_MAX_SCANOUTS 16 + +// B8G8R8X8, which is what a 32-bit little-endian 0x00RRGGBB word looks like in +// memory -- the same layout vga.c already draws into, so a framebuffer can be +// handed over without a conversion pass. +#define VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM 2 + +struct virtio_gpu_ctrl_hdr { + uint32 type; + uint32 flags; + uint64 fence_id; + uint32 ctx_id; + uint32 padding; +} __attribute__((packed)); + +struct virtio_gpu_rect { + uint32 x, y, width, height; +} __attribute__((packed)); + +struct virtio_gpu_display_one { + struct virtio_gpu_rect r; + uint32 enabled; + uint32 flags; +} __attribute__((packed)); + +struct virtio_gpu_resp_display_info { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_display_one pmodes[VIRTIO_GPU_MAX_SCANOUTS]; +} __attribute__((packed)); + +struct virtio_gpu_resource_create_2d { + struct virtio_gpu_ctrl_hdr hdr; + uint32 resource_id; + uint32 format; + uint32 width; + uint32 height; +} __attribute__((packed)); + +struct virtio_gpu_mem_entry { + uint64 addr; + uint32 length; + uint32 padding; +} __attribute__((packed)); + +struct virtio_gpu_resource_attach_backing { + struct virtio_gpu_ctrl_hdr hdr; + uint32 resource_id; + uint32 nr_entries; +} __attribute__((packed)); + +struct virtio_gpu_set_scanout { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_rect r; + uint32 scanout_id; + uint32 resource_id; +} __attribute__((packed)); + +struct virtio_gpu_transfer_to_host_2d { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_rect r; + uint64 offset; + uint32 resource_id; + uint32 padding; +} __attribute__((packed)); + +struct virtio_gpu_resource_flush { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_rect r; + uint32 resource_id; + uint32 padding; +} __attribute__((packed)); diff --git a/include/x86.h b/include/x86.h new file mode 100644 index 0000000..fb17e91 --- /dev/null +++ b/include/x86.h @@ -0,0 +1,219 @@ +#pragma once + +struct dtr { + ushort limit; + uint64 base; +} __attribute__((packed)); + +static inline uchar +inb(ushort port) +{ + uchar data; + asm volatile("in %1,%0" : "=a" (data) : "d" (port)); + return data; +} + +static inline void +insl(int port, void *addr, int cnt) +{ + asm volatile("cld; rep insl" : + "=D" (addr), "=c" (cnt) : + "d" (port), "0" (addr), "1" (cnt) : + "memory", "cc"); +} + +static inline void +outb(ushort port, uchar data) +{ + asm volatile("out %0,%1" : : "a" (data), "d" (port)); +} + +static inline uint +inl(ushort port) +{ + uint data; + asm volatile("inl %1,%0" : "=a" (data) : "d" (port)); + return data; +} + +static inline void +outw(ushort port, ushort data) +{ + asm volatile("out %0,%1" : : "a" (data), "d" (port)); +} + +// PCI configuration space is reached through a pair of 32-bit ports, so this +// is not optional decoration -- see kernel/dev/pci.c. +static inline void +outl(ushort port, uint data) +{ + asm volatile("outl %0,%1" : : "a" (data), "d" (port)); +} + +static inline void +outsl(int port, const void *addr, int cnt) +{ + asm volatile("cld; rep outsl" : + "=S" (addr), "=c" (cnt) : + "d" (port), "0" (addr), "1" (cnt) : + "cc"); +} + +static inline void +stosb(void *addr, int data, int cnt) +{ + asm volatile("cld; rep stosb" : + "=D" (addr), "=c" (cnt) : + "0" (addr), "1" (cnt), "a" (data) : + "memory", "cc"); +} + +// 64-bit-only helpers. `rep stosq` and `xchgq` do not exist in 32-bit mode, so +// these must not even be parsed by the -m32 bootloader build -- they compiled +// there before only because uint64 was accidentally 32 bits wide, which is the +// bug include/types.h now asserts against. +#ifdef __x86_64__ +static inline void +stosq(void *addr, uint64 data, int cnt) +{ + asm volatile("cld; rep stosq" : + "=D" (addr), "=c" (cnt) : + "0" (addr), "1" (cnt), "a" (data) : + "memory", "cc"); +} + +struct segdesc; + +static inline void +lgdt(struct segdesc *p, int size) +{ + struct dtr d; + d.limit = size - 1; + d.base = (uint64)p; + asm volatile("lgdt (%0)" : : "r" (&d)); +} + +struct gatedesc; + +static inline void +lidt(struct gatedesc *p, int size) +{ + struct dtr d; + d.limit = size - 1; + d.base = (uint64)p; + asm volatile("lidt (%0)" : : "r" (&d)); +} + +static inline void +ltr(ushort sel) +{ + asm volatile("ltr %0" : : "r" (sel)); +} + +static inline uint64 +readeflags(void) +{ + uint64 flags; + asm volatile("pushfq; pop %0" : "=r" (flags)); + return flags; +} + +static inline void +cli(void) +{ + asm volatile("cli"); +} + +static inline void +sti(void) +{ + asm volatile("sti"); +} + +static inline void +hlt(void) +{ + asm volatile("hlt"); +} + +static inline uint64 +xchg(volatile uint64 *addr, uint64 newval) +{ + uint64 result; + asm volatile("lock; xchgq %0, %1" : + "+m" (*addr), "=a" (result) : + "1" (newval) : + "cc"); + return result; +} +#endif /* __x86_64__ */ + +static inline uint64 +rcr2(void) +{ + uint64 val; + asm volatile("mov %%cr2,%0" : "=r" (val)); + return val; +} + +static inline void +lcr3(uint64 val) +{ + asm volatile("mov %0,%%cr3" : : "r" (val)); +} + +// Invalidate the TLB entry for one page. Needed any time a PTE is changed +// or cleared for an address space that may still be the active CR3 — +// otherwise the CPU can keep translating through the stale entry until the +// next full CR3 reload (context switch), silently reading/writing the +// wrong physical page. +static inline void +invlpg(void *va) +{ + asm volatile("invlpg (%0)" : : "r" (va) : "memory"); +} + +static inline void +wrmsr(uint32 msr, uint64 val) +{ + uint32 low = (uint32)val; + uint32 high = (uint32)(val >> 32); + asm volatile("wrmsr" : : "c" (msr), "a" (low), "d" (high)); +} + +static inline uint64 +rdmsr(uint32 msr) +{ + uint32 low, high; + asm volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr)); + return ((uint64)high << 32) | low; +} + +static inline uint64 +readcs(void) +{ + uint64 val; + asm volatile("mov %%cs, %0" : "=r" (val)); + return val; +} + +// CPUID. `leaf` in EAX, results in EAX/EBX/ECX/EDX. +// +// %rbx is callee-saved *and* the PIC base register on some builds, so it is +// exchanged out rather than named as an operand -- naming it directly is the +// classic way to get "inline asm clobbers reserved register" or, worse, silent +// corruption in the caller. +static inline void +cpuid_leaf(uint32 leaf, uint32 *a, uint32 *b, uint32 *c, uint32 *d) +{ + uint32 ra, rb, rc, rd; + asm volatile("xchgq %%rbx, %q1\n\t" + "cpuid\n\t" + "xchgq %%rbx, %q1" + : "=a"(ra), "=&r"(rb), "=c"(rc), "=d"(rd) + : "0"(leaf), "2"(0)); + if (a) *a = ra; + if (b) *b = rb; + if (c) *c = rc; + if (d) *d = rd; +} diff --git a/include/xhci.h b/include/xhci.h new file mode 100644 index 0000000..d0c5760 --- /dev/null +++ b/include/xhci.h @@ -0,0 +1,161 @@ +#pragma once + +// eXtensible Host Controller Interface -- the register and data-structure +// definitions from the xHCI 1.2 specification. +// +// Why xHCI and not UHCI/OHCI/EHCI: xHCI is the only host controller interface +// that speaks every USB speed, so one driver covers USB 1.1 through 3.x. The +// older controllers would each need their own, and a machine with all of them +// needs the companion-controller handover dance on top. There is no hardware +// worth supporting that has no xHCI. + +// --------------------------------------------------------------------------- +// Capability registers -- at the start of BAR0, read-only +// --------------------------------------------------------------------------- +#define XHCI_CAPLENGTH 0x00 // byte: where the operational regs begin +#define XHCI_HCIVERSION 0x02 // word +#define XHCI_HCSPARAMS1 0x04 +#define XHCI_HCSPARAMS2 0x08 +#define XHCI_HCSPARAMS3 0x0C +#define XHCI_HCCPARAMS1 0x10 +#define XHCI_DBOFF 0x14 // doorbell array offset from BAR0 +#define XHCI_RTSOFF 0x18 // runtime register offset from BAR0 + +#define HCS1_MAXSLOTS(x) ((x) & 0xFF) +#define HCS1_MAXINTRS(x) (((x) >> 8) & 0x7FF) +#define HCS1_MAXPORTS(x) (((x) >> 24) & 0xFF) + +// Scratchpad buffer count is split across two fields, high part first. +#define HCS2_SPB_HI(x) (((x) >> 21) & 0x1F) +#define HCS2_SPB_LO(x) (((x) >> 27) & 0x1F) + +#define HCC1_AC64 (1 << 0) // 64-bit addressing +#define HCC1_CSZ (1 << 2) // contexts are 64 bytes, not 32 +#define HCC1_XECP(x) (((x) >> 16) & 0xFFFF) // extended caps, in dwords + +// --------------------------------------------------------------------------- +// Operational registers -- at BAR0 + CAPLENGTH +// --------------------------------------------------------------------------- +#define XHCI_USBCMD 0x00 +#define XHCI_USBSTS 0x04 +#define XHCI_PAGESIZE 0x08 +#define XHCI_DNCTRL 0x14 +#define XHCI_CRCR 0x18 // 64-bit +#define XHCI_DCBAAP 0x30 // 64-bit +#define XHCI_CONFIG 0x38 +#define XHCI_PORTSC(p) (0x400 + 0x10 * ((p) - 1)) // ports are 1-based + +#define CMD_RS (1 << 0) // run/stop +#define CMD_HCRST (1 << 1) // host controller reset +#define CMD_INTE (1 << 2) // interrupter enable +#define CMD_HSEE (1 << 3) + +#define STS_HCH (1 << 0) // halted +#define STS_HSE (1 << 2) // host system error +#define STS_EINT (1 << 3) // event interrupt (write 1 to clear) +#define STS_PCD (1 << 4) // port change detect (write 1 to clear) +#define STS_CNR (1 << 11) // controller not ready + +#define CRCR_RCS (1 << 0) // ring cycle state + +// PORTSC. The change bits are write-1-to-clear, and so is PED -- writing back +// a value read from this register clears whatever happened to be set. Every +// write has to mask them off first. +#define PORT_CCS (1 << 0) // current connect status +#define PORT_PED (1 << 1) // port enabled (RW1C!) +#define PORT_OCA (1 << 3) +#define PORT_PR (1 << 4) // port reset +#define PORT_PLS(x) (((x) >> 5) & 0xF) +#define PORT_PP (1 << 9) // port power +#define PORT_SPEED(x) (((x) >> 10) & 0xF) +#define PORT_CSC (1 << 17) +#define PORT_PEC (1 << 18) +#define PORT_PRC (1 << 21) +#define PORT_RW1C 0x00FE0002u // change bits 17..23, plus PED + +// PORTSC speed encoding. These are the same numbers as USB_SPEED_* in usb.h, +// which is not a coincidence -- the core uses this encoding directly so that +// nothing has to be translated on its way to a slot context. +#define XSPEED_FULL USB_SPEED_FULL +#define XSPEED_LOW USB_SPEED_LOW +#define XSPEED_HIGH USB_SPEED_HIGH +#define XSPEED_SUPER USB_SPEED_SUPER + +// --------------------------------------------------------------------------- +// Runtime registers -- at BAR0 + RTSOFF. Interrupter n is at 0x20 + 32*n. +// --------------------------------------------------------------------------- +#define XHCI_MFINDEX 0x00 +#define XHCI_IR0 0x20 +#define IR_IMAN 0x00 +#define IR_IMOD 0x04 +#define IR_ERSTSZ 0x08 +#define IR_ERSTBA 0x10 // 64-bit +#define IR_ERDP 0x18 // 64-bit + +#define IMAN_IP (1 << 0) // interrupt pending (RW1C) +#define IMAN_IE (1 << 1) // interrupt enable +#define ERDP_EHB (1 << 3) // event handler busy (RW1C) + +// --------------------------------------------------------------------------- +// Transfer Request Blocks +// --------------------------------------------------------------------------- +struct trb { + uint64 param; + uint32 status; + uint32 control; +} __attribute__((packed)); + +#define TRB_TYPE(t) (((t) & 0x3F) << 10) +#define TRB_GET_TYPE(c) (((c) >> 10) & 0x3F) +#define TRB_C (1 << 0) // cycle bit +#define TRB_TC (1 << 1) // toggle cycle (link TRBs) +#define TRB_ISP (1 << 2) +#define TRB_CH (1 << 4) // chain +#define TRB_IOC (1 << 5) // interrupt on completion +#define TRB_IDT (1 << 6) // immediate data +#define TRB_SLOT(s) ((uint32)(s) << 24) +#define TRB_GET_SLOT(c) (((c) >> 24) & 0xFF) +#define TRB_GET_EPID(c) (((c) >> 16) & 0x1F) // transfer events + +// Transfer TRBs +#define TRB_NORMAL 1 +#define TRB_SETUP 2 +#define TRB_DATA 3 +#define TRB_STATUS 4 +#define TRB_LINK 6 +// Command TRBs +#define TRB_ENABLE_SLOT 9 +#define TRB_DISABLE_SLOT 10 +#define TRB_ADDRESS_DEV 11 +#define TRB_CONFIG_EP 12 +#define TRB_EVAL_CTX 13 +#define TRB_RESET_EP 14 +#define TRB_NOOP_CMD 23 +// Event TRBs +#define TRB_XFER_EVENT 32 +#define TRB_CMD_COMPLETE 33 +#define TRB_PORT_STATUS 34 + +#define TRB_CC(status) (((status) >> 24) & 0xFF) +#define CC_SUCCESS 1 +#define CC_SHORT_PACKET 13 + +// Setup Stage transfer type, and Data Stage direction. +#define TRT_NONE 0 +#define TRT_OUT 2 +#define TRT_IN 3 +#define DIR_IN (1 << 16) + +// Endpoint types in an endpoint context. Direction is part of the type, and +// the numbering is not arbitrary: OUT types are 1-3, control is 4, and the IN +// types are the OUT ones plus four. +#define EPTYPE_ISOCH_OUT 1 +#define EPTYPE_BULK_OUT 2 +#define EPTYPE_INT_OUT 3 +#define EPTYPE_CONTROL 4 +#define EPTYPE_ISOCH_IN 5 +#define EPTYPE_BULK_IN 6 +#define EPTYPE_INT_IN 7 + +// Doorbell targets: 0 is the command ring; for a device slot, DCI 1 is EP0. +#define DCI_EP0 1 diff --git a/kernel/arch/x86_64/acpi.c b/kernel/arch/x86_64/acpi.c new file mode 100644 index 0000000..7d42537 --- /dev/null +++ b/kernel/arch/x86_64/acpi.c @@ -0,0 +1,264 @@ +// Find the processors, the way firmware from this century describes them. +// +// mpinit() walks the Intel MP table, which is from 1994. Modern firmware fills +// it in minimally or omits it: measured 2026-08-08, QEMU/SeaBIOS with -smp 4 +// publishes a 208-byte MP table containing exactly *one* processor entry, then +// buses and interrupt assignments. Everything since has expected the operating +// system to read the ACPI MADT instead. +// +// The consequence was not that SMP was slow, it was that ncpu was 1 and SMP was +// silently never exercised. Machines whose firmware does publish a full MP +// table -- VMware, older hardware -- took the other path, started their APs, +// and triple faulted. So this file is a prerequisite for debugging that: until +// the CPUs are visible under QEMU there is no way to reproduce the crash except +// on the hardware it happens on. +// +// Written from the ACPI specification. No table layout here is copied from +// another kernel; they are all in chapter 5 of the published standard. + +#include "types.h" +#include "defs.h" +#include "param.h" +#include "memlayout.h" +#include "mmu.h" +#include "proc.h" +#include "x86.h" + +extern struct cpu cpus[NCPU]; +extern int ncpu; +extern uchar ioapicid; +extern volatile uint *lapic; + +// The Root System Description Pointer. Found by signature, not by being told +// where it is -- it sits either in the Extended BIOS Data Area or in the BIOS +// read-only region, on a 16-byte boundary. +struct acpi_rsdp { + char sig[8]; // "RSD PTR " + uint8 checksum; // over the first 20 bytes + char oemid[6]; + uint8 revision; // 0 = ACPI 1.0 (RSDT), 2+ = 2.0 (XSDT) + uint32 rsdt_addr; + // ACPI 2.0 and later only, and only valid when revision >= 2. + uint32 length; + uint64 xsdt_addr; + uint8 ext_checksum; // over `length` bytes + uint8 reserved[3]; +} __attribute__((packed)); + +// Every ACPI table starts with this. +struct acpi_sdt { + char sig[4]; + uint32 length; + uint8 revision; + uint8 checksum; + char oemid[6]; + char oem_table_id[8]; + uint32 oem_revision; + uint32 creator_id; + uint32 creator_revision; +} __attribute__((packed)); + +// The Multiple APIC Description Table: signature "APIC". +struct acpi_madt { + struct acpi_sdt h; + uint32 lapic_addr; + uint32 flags; // bit 0: legacy 8259 PICs are present +} __attribute__((packed)); + +#define MADT_PCAT_COMPAT 1 + +// MADT entry types. Only these three are read; the rest are interrupt +// routing overrides that ioapic.c does not consult yet. +#define MADT_LAPIC 0 +#define MADT_IOAPIC 1 +#define MADT_LAPIC_OVERRIDE 5 + +struct madt_entry { + uint8 type; + uint8 length; +} __attribute__((packed)); + +struct madt_lapic { + struct madt_entry e; + uint8 acpi_id; + uint8 apic_id; + uint32 flags; // bit 0: enabled, bit 1: online-capable +} __attribute__((packed)); + +#define LAPIC_ENABLED 1 +#define LAPIC_ONLINE_CAPABLE 2 + +struct madt_ioapic { + struct madt_entry e; + uint8 id; + uint8 reserved; + uint32 addr; + uint32 gsi_base; +} __attribute__((packed)); + +struct madt_lapic_override { + struct madt_entry e; + uint16 reserved; + uint64 addr; +} __attribute__((packed)); + +static int +checksum_ok(const void *p, uint32 len) +{ + const uint8 *b = p; + uint8 sum = 0; + for (uint32 i = 0; i < len; i++) + sum += b[i]; + return sum == 0; +} + +// Scan a physical range for the RSDP signature. It is 16-byte aligned by +// specification, which makes this cheap enough to do twice. +static struct acpi_rsdp * +scan_rsdp(uint64 base, uint64 len) +{ + for (uint64 off = 0; off + sizeof(struct acpi_rsdp) <= len; off += 16) { + struct acpi_rsdp *r = (struct acpi_rsdp *)P2V(base + off); + if (memcmp(r->sig, "RSD PTR ", 8) != 0) + continue; + // Signature alone is not enough: the string can appear in unrelated data, + // and following a bad pointer here means faulting before there is anything + // to report the fault with. + if (!checksum_ok(r, 20)) + continue; + return r; + } + return 0; +} + +static struct acpi_rsdp * +find_rsdp(void) +{ + // The EBDA, whose segment address the BIOS leaves at 0x40E. + uint16 ebda_seg = *(uint16 *)P2V(0x40E); + if (ebda_seg) { + struct acpi_rsdp *r = scan_rsdp((uint64)ebda_seg << 4, 1024); + if (r) + return r; + } + return scan_rsdp(0xE0000, 0x20000); +} + +// Walk the RSDT or XSDT looking for a table by signature. +// +// Two nearly identical loops rather than one clever one: the only difference is +// the pointer width -- 32-bit entries in the RSDT, 64-bit in the XSDT -- and +// reading a 64-bit pointer out of a 32-bit array is exactly the sort of bug +// that produces a plausible address pointing at nothing. +static struct acpi_sdt * +find_table(struct acpi_rsdp *rsdp, const char *sig) +{ + struct acpi_sdt *root; + int wide; + + if (rsdp->revision >= 2 && rsdp->xsdt_addr) { + root = (struct acpi_sdt *)P2V(rsdp->xsdt_addr); + wide = 1; + } else { + root = (struct acpi_sdt *)P2V((uint64)rsdp->rsdt_addr); + wide = 0; + } + + if (!checksum_ok(root, root->length)) + return 0; + + uint32 n = (root->length - sizeof(struct acpi_sdt)) / (wide ? 8 : 4); + for (uint32 i = 0; i < n; i++) { + uint64 pa; + if (wide) { + // Byte-wise, because the array is packed and 8-byte entries in it are + // not guaranteed to be 8-byte aligned. + uint8 *p = (uint8 *)(root + 1) + i * 8; + pa = 0; + for (int b = 7; b >= 0; b--) + pa = (pa << 8) | p[b]; + } else { + pa = ((uint32 *)(root + 1))[i]; + } + struct acpi_sdt *t = (struct acpi_sdt *)P2V(pa); + if (memcmp(t->sig, sig, 4) == 0) + return t; + } + return 0; +} + +// Returns 1 if the processors were enumerated, 0 to fall back to mpinit(). +int +acpi_init(void) +{ + struct acpi_rsdp *rsdp = find_rsdp(); + if (!rsdp) + return 0; + + struct acpi_madt *madt = (struct acpi_madt *)find_table(rsdp, "APIC"); + if (!madt || !checksum_ok(madt, madt->h.length)) + return 0; + + lapic = (uint *)P2V((uint64)madt->lapic_addr); + + uint8 *p = (uint8 *)madt + sizeof(struct acpi_madt); + uint8 *e = (uint8 *)madt + madt->h.length; + int found_ioapic = 0; + + while (p + sizeof(struct madt_entry) <= e) { + struct madt_entry *ent = (struct madt_entry *)p; + // A zero length would spin here forever. Firmware tables are not always + // well formed, and an infinite loop this early is indistinguishable from a + // hang with no output at all. + if (ent->length < sizeof(struct madt_entry)) + break; + + switch (ent->type) { + case MADT_LAPIC: { + struct madt_lapic *l = (struct madt_lapic *)p; + // Skip processors that are neither enabled nor online-capable: those are + // sockets the firmware is describing but not offering. + if (!(l->flags & (LAPIC_ENABLED | LAPIC_ONLINE_CAPABLE))) + break; + if (ncpu < NCPU) { + cpus[ncpu].apicid = l->apic_id; + ncpu++; + } + break; + } + case MADT_IOAPIC: { + struct madt_ioapic *io = (struct madt_ioapic *)p; + // The first one only. Multi-I/O-APIC routing needs the interrupt source + // overrides too, which nothing here reads yet, so claiming to support it + // would be worse than not. + if (!found_ioapic) { + ioapicid = io->id; + found_ioapic = 1; + } + break; + } + case MADT_LAPIC_OVERRIDE: { + struct madt_lapic_override *o = (struct madt_lapic_override *)p; + lapic = (uint *)P2V(o->addr); + break; + } + } + p += ent->length; + } + + if (ncpu == 0) + return 0; + + // The 8259s are still there and still wired to the CPU. On a system with an + // IMCR, this switches interrupt delivery from the PICs to the APIC; on one + // without, the ports are unclaimed and the writes go nowhere. mpinit() does + // the same thing guarded by the MP table's imcrp flag. + if (madt->flags & MADT_PCAT_COMPAT) { + outb(0x22, 0x70); + outb(0x23, inb(0x23) | 1); + } + + cprintf("acpi: %d cpu%s, lapic at %p, ioapic id %d\n", + ncpu, ncpu == 1 ? "" : "s", lapic, ioapicid); + return 1; +} diff --git a/kernel/arch/x86_64/e820.c b/kernel/arch/x86_64/e820.c new file mode 100644 index 0000000..bc977b1 --- /dev/null +++ b/kernel/arch/x86_64/e820.c @@ -0,0 +1,105 @@ +// Find out how much memory this machine actually has. +// +// PHYSTOP used to be a constant: 0xE000000, 224 MB, inherited from xv6 and +// never revisited. That is not a limit on how much memory the kernel *uses* -- +// 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 +// 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. +// +// 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 +// use -- and leaves the result in low memory. stage2main.c already parses it to +// print detected RAM on the splash. The kernel simply never read it. + +#include "types.h" +#include "defs.h" +#include "memlayout.h" +#include "mmu.h" + +// Set before kinit1() and never again. Starts at the old constant so that a +// crash between entry and e820_init() behaves the way it always did rather +// than in some new way. +uint64 phystop = PHYSTOP_FALLBACK; + +// Where stage2 left the map. Must match E820_COUNT_ADDR / E820_MAP_ADDR in +// boot/stage2main.c, which are themselves relative to VBE_INFO_ADDR. +#define E820_COUNT_ADDR (0x30000 + 0x200) +#define E820_MAP_ADDR (0x30000 + 0x208) + +#define E820_USABLE 1 +#define E820_MAXENTRIES 32 + +struct e820entry { + uint64 base; + uint64 length; + uint32 type; + uint32 acpi_ext; +} __attribute__((packed)); + +void +e820_init(void) +{ + uint32 count = *(uint32 *)P2V(E820_COUNT_ADDR); + struct e820entry *e = (struct e820entry *)P2V(E820_MAP_ADDR); + + // A count of zero means the firmware declined; anything absurd means we are + // reading something that is not a memory map. Either way the constant is the + // only honest answer left. + if (count == 0 || count > E820_MAXENTRIES) { + cprintf("e820: no usable map (count %d), assuming %d MB\n", + count, (int)(PHYSTOP_FALLBACK / (1024 * 1024))); + return; + } + + // The end of the usable region that *contains the kernel*, not the highest + // usable address anywhere. + // + // This distinction matters and is easy to get wrong. A memory map is not one + // run of RAM: there are reserved holes in it -- ACPI tables, firmware + // scratch, the legacy hole below 1 MB -- and kalloc's freerange() walks + // straight from the end of the kernel image to phystop handing out every page + // between. Taking the global maximum would step over a reserved region and + // put firmware tables on the free list, which fails later, elsewhere, and + // looks like anything but a memory map problem. + uint64 top = 0; + for (uint32 i = 0; i < count; i++) { + if (e[i].type != E820_USABLE) + continue; + uint64 base = e[i].base, end = base + e[i].length; + if (base <= EXTMEM && EXTMEM < end) { + top = end; + break; + } + } + + if (top == 0) { + cprintf("e820: no usable region covers 0x%x, assuming %d MB\n", + EXTMEM, (int)(PHYSTOP_FALLBACK / (1024 * 1024))); + return; + } + + // kvmalloc() maps physical 0-4 GB with four 1 GB pages, and marks the top one + // uncached because that is where PCI BARs and the framebuffer live. So 3 GB + // is the ceiling for anything the kernel will treat as RAM: above it the + // direct map either does not exist or is device memory that would be + // catastrophically slow to allocate from and is not ours to hand out. + if (top > PHYSTOP_MAX) + top = PHYSTOP_MAX; + + top &= ~(uint64)(PGSIZE - 1); + + // 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. + if (top < PHYSTOP_MIN) { + cprintf("e820: only %d MB usable; Schunix needs at least %d MB\n", + (int)(top / (1024 * 1024)), (int)(PHYSTOP_MIN / (1024 * 1024))); + // Left at the fallback deliberately rather than lowered: a machine this + // small is going to fail, and it should fail having said why. + return; + } + + phystop = top; + cprintf("e820: %d MB usable (%d entries)\n", + (int)(phystop / (1024 * 1024)), count); +} diff --git a/kernel/arch/x86_64/entry.S b/kernel/arch/x86_64/entry.S new file mode 100644 index 0000000..5ead585 --- /dev/null +++ b/kernel/arch/x86_64/entry.S @@ -0,0 +1,174 @@ +/* entry.S + * + * Copyright (c) 2013 Brian Swetland + * Modified by Nexoniarz + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#define mboot_magic 0x1badb002 +#define mboot_flags 0x00010000 +#include "mmu.h" + +.code64 +.global mboot_header +.global mboot_entry + +mboot_header: + .long mboot_magic + .long mboot_flags + .long (-mboot_magic -mboot_flags) + .long mboot_load_addr + .long mboot_load_addr + .long mboot_load_end + .long mboot_bss_end + .long mboot_entry_addr + +.code32 +mboot_entry: + mov %eax, %ebp + + # bootstrap page tables (0x1000 - 0x3000) + xor %eax, %eax + mov $0x1000, %edi + mov $0x2000, %ecx + rep stosb + + # Bootstrap page tables (Identity mapping 4GB) + # PML4T[0] i PML4T[256] -> PDPT pod 0x2000 + mov $(0x2000 | PTE_P | PTE_W), %edx + mov %edx, 0x1000 + mov %edx, 0x1800 + + # PDPT mapping 4GB using 1GB huge pages + mov $(0x00000000 | PTE_P | PTE_PS | PTE_W), %edx + mov %edx, 0x2000 + mov $(0x40000000 | PTE_P | PTE_PS | PTE_W), %edx + mov %edx, 0x2008 + mov $(0x80000000 | PTE_P | PTE_PS | PTE_W), %edx + mov %edx, 0x2010 + mov $(0xC0000000 | PTE_P | PTE_PS | PTE_W), %edx + mov %edx, 0x2018 + + mov %ebp, %ebx + +.global entry32mp +entry32mp: + mov $0x1000, %eax + mov %eax, %cr3 + + lgdt (gdtr64 - mboot_header + mboot_load_addr) + + mov %cr4, %eax + bts $5, %eax + mov %eax, %cr4 + + mov $MSR_EFER, %ecx + rdmsr + bts $0, %eax + bts $8, %eax + wrmsr + + mov %cr0, %eax + orl $(CR0_PG | CR0_WP | CR0_MP), %eax + mov %eax, %cr0 + + ljmp $8, $(entry64low - mboot_header + mboot_load_addr) + +.align 16 +gdtr64: + .word gdt64_end - gdt64_begin - 1; + .quad gdt64_begin - mboot_header + mboot_load_addr + +.align 16 +gdt64_begin: + .long 0x00000000 + .long 0x00000000 + .long 0x00000000 # 64-bit code + .long 0x00209800 + .long 0x00000000 # 64-bit data + .long 0x00009000 +gdt64_end: + +.align 16 +.code64 +entry64low: + movabs $entry64high, %rax + jmp *%rax + +.global _start +_start: +entry64high: + xor %rax, %rax + mov %ax, %ss + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + + # Is this an application processor, or the boot processor? + # + # This check used to be a comment saying it had not been written yet, and + # every AP fell straight through into the BSP path below: it set RSP to the + # *boot processor's* stack, passed its own flag to kmain() as a framebuffer + # address, and re-ran the entire bootstrap -- e820_init, kinit1, kvmalloc -- + # on a second core sharing one stack with the first. That is the SMP triple + # fault. QEMU hid it for years by never reporting more than one CPU (see + # kernel/arch/x86_64/acpi.c); VMware did not. + # + # EBX is the discriminator, and entryother.S sets it to 1 immediately before + # entering long mode for exactly this purpose. It is safe: on the boot + # processor EBX carries the VESA framebuffer address from the loader, which is + # either zero or a physical MMIO address, and can never be 1. + cmp $1, %ebx + je entry64mp + + # Setup initial stack + movabs $0xFFFF800000010000, %rax + mov %rax, %rsp + + # Pass VESA address to main (1st argument in RDI) + mov %rbx, %rdi + + call kmain + +.global __deadloop +__deadloop: + jmp . + +entry64mp: + mov $0x7000, %rax + mov -16(%rax), %rsp + jmp mpenter + +.global wrmsr +wrmsr: + mov %rdi, %rcx + mov %rsi, %rax + shr $32, %rsi + mov %rsi, %rdx + wrmsr + retq + +.global ignore_sysret +ignore_sysret: + mov $-38, %rax + sysretq \ No newline at end of file diff --git a/kernel/arch/x86_64/entryother.S b/kernel/arch/x86_64/entryother.S new file mode 100644 index 0000000..a2e98e6 --- /dev/null +++ b/kernel/arch/x86_64/entryother.S @@ -0,0 +1,78 @@ +#include "asm.h" +#include "memlayout.h" +#include "mmu.h" + +# Each non-boot CPU ("AP") is started up in response to a STARTUP +# IPI from the boot CPU. Section B.4.2 of the Multi-Processor +# Specification says that the AP will start in real mode with CS:IP +# set to XY00:0000, where XY is an 8-bit value sent with the +# STARTUP. Thus this code must start at a 4096-byte boundary. +# +# Because this code sets DS to zero, it must sit +# at an address in the low 2^16 bytes. +# +# Startothers (in main.c) sends the STARTUPs one at a time. +# It copies this code (start) at 0x7000. It puts the address of +# a newly allocated per-core stack in start-4,the address of the +# place to jump to (mpenter) in start-8, and the physical address +# of entrypgdir in start-12. +# +# This code is identical to bootasm.S except: +# - it does not need to enable A20 +# - it uses the address at start-4, start-8, and start-12 + +.code16 +.global start +start: + cli + + xorw %ax,%ax + movw %ax,%ds + movw %ax,%es + movw %ax,%ss + + lgdt gdtdesc + movl %cr0, %eax + orl $CR0_PE, %eax + movl %eax, %cr0 + + ljmpl $(SEG_KCODE<<3), $(start32) +//PAGEBREAK! + +.code32 +start32: + movw $(SEG_KDATA<<3), %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw $0, %ax + movw %ax, %fs + movw %ax, %gs + + # defer paging until we switch to 64bit mode + # set ebx=1 so shared boot code knows we're booting a secondary core + mov $1, %ebx + + # Switch to the stack allocated by startothers() + movl (start-4), %esp + # Call mpenter() + call *(start-8) + + movw $0x8a00, %ax + movw %ax, %dx + outw %ax, %dx + movw $0x8ae0, %ax + outw %ax, %dx +spin: + jmp spin + +.p2align 2 +gdt: + SEG_NULLASM + SEG_ASM(STA_X|STA_R, 0, 0xffffffff) + SEG_ASM(STA_W, 0, 0xffffffff) + + +gdtdesc: + .word (gdtdesc - gdt - 1) + .long gdt diff --git a/kernel/arch/x86_64/ioapic.c b/kernel/arch/x86_64/ioapic.c new file mode 100644 index 0000000..3fc6525 --- /dev/null +++ b/kernel/arch/x86_64/ioapic.c @@ -0,0 +1,102 @@ +// The I/O APIC manages hardware interrupts for an SMP system. +// http://www.intel.com/design/chipsets/datashts/29056601.pdf +// See also picirq.c. + +#include "types.h" +#include "defs.h" +#include "traps.h" +#include "memlayout.h" + +#define IOAPIC 0xFEC00000 // Default physical address of IO APIC + +#define REG_ID 0x00 // Register index: ID +#define REG_VER 0x01 // Register index: version +#define REG_TABLE 0x10 // Redirection table base + +// The redirection table starts at REG_TABLE and uses +// two registers to configure each interrupt. +// The first (low) register in a pair contains configuration bits. +// The second (high) register contains a bitmask telling which +// CPUs can serve that interrupt. +#define INT_DISABLED 0x00010000 // Interrupt disabled +#define INT_LEVEL 0x00008000 // Level-triggered (vs edge-) +#define INT_ACTIVELOW 0x00002000 // Active low (vs high) +#define INT_LOGICAL 0x00000800 // Destination is CPU id (vs APIC ID) + +volatile struct ioapic *ioapic; + +// IO APIC MMIO structure: write reg, then read or write data. +struct ioapic { + uint reg; + uint pad[3]; + uint data; +}; + +static uint +ioapicread(int reg) +{ + ioapic->reg = reg; + return ioapic->data; +} + +static void +ioapicwrite(int reg, uint data) +{ + ioapic->reg = reg; + ioapic->data = data; +} + +void +ioapicinit(void) +{ + int i, id, maxintr; + + ioapic = P2V((volatile struct ioapic*)IOAPIC); + maxintr = (ioapicread(REG_VER) >> 16) & 0xFF; + id = ioapicread(REG_ID) >> 24; + if(id != ioapicid) + cprintf("ioapicinit: id isn't equal to ioapicid; not a MP\n"); + + // Mark all interrupts edge-triggered, active high, disabled, + // and not routed to any CPUs. + for(i = 0; i <= maxintr; i++){ + ioapicwrite(REG_TABLE+2*i, INT_DISABLED | (T_IRQ0 + i)); + ioapicwrite(REG_TABLE+2*i+1, 0); + } +} + +// Route an interrupt to a CPU and unmask it. +// +// `level_low` picks PCI's signalling instead of ISA's. This distinction did +// not matter while every interrupt in the kernel came from an ISA-era device +// at a fixed pin, all of which are edge-triggered and active high -- which is +// why the original ioapicenable() hardcoded exactly that. A PCI device wired +// through an INTx pin is the opposite on both counts, and configuring it as +// edge/high does not fail cleanly: the device raises the line, we take one +// interrupt, and because the level never goes away there is no second edge +// and the device is never heard from again. +void +ioapicroute(int irq, int cpunum, int level_low) +{ + uint lo = T_IRQ0 + irq; + + if(level_low) + lo |= INT_LEVEL | INT_ACTIVELOW; + + // Program the destination before unmasking, so the entry is never briefly + // live pointing at CPU 0 when it was meant for another. + ioapicwrite(REG_TABLE+2*irq+1, cpunum << 24); + ioapicwrite(REG_TABLE+2*irq, lo); +} + +void +ioapicmask(int irq) +{ + ioapicwrite(REG_TABLE+2*irq, INT_DISABLED | (T_IRQ0 + irq)); +} + +void +ioapicenable(int irq, int cpunum) +{ + ioapicroute(irq, cpunum, 0); +} diff --git a/kernel/arch/x86_64/lapic.c b/kernel/arch/x86_64/lapic.c new file mode 100644 index 0000000..404bda7 --- /dev/null +++ b/kernel/arch/x86_64/lapic.c @@ -0,0 +1,245 @@ +// The local APIC manages internal (non-I/O) interrupts. +// See Chapter 8 & Appendix C of Intel processor manual volume 3. + +#include "param.h" +#include "types.h" +#include "defs.h" +#include "date.h" +#include "memlayout.h" +#include "traps.h" +#include "mmu.h" +#include "x86.h" +#include "proc.h" // ncpu + +// Local APIC registers, divided by 4 for use as uint[] indices. +#define ID (0x0020/4) // ID +#define VER (0x0030/4) // Version +#define TPR (0x0080/4) // Task Priority +#define EOI (0x00B0/4) // EOI +#define SVR (0x00F0/4) // Spurious Interrupt Vector + #define ENABLE 0x00000100 // Unit Enable +#define ESR (0x0280/4) // Error Status +#define ICRLO (0x0300/4) // Interrupt Command + #define SINIT 0x00000500 // INIT/RESET + #define STARTUP 0x00000600 // Startup IPI + #define DELIVS 0x00001000 // Delivery status + #define ASSERT 0x00004000 // Assert interrupt (vs deassert) + #define LEVEL 0x00008000 // Level triggered + #define BCAST 0x00080000 // Send to all APICs, including self. + #define BUSY 0x00001000 +#define ICRHI (0x0310/4) // Interrupt Command [63:32] +#define TIMER (0x0320/4) // Local Vector Table 0 (TIMER) + #define X1 0x0000000B // divide counts by 1 + #define PERIODIC 0x00020000 // Periodic +#define PCINT (0x0340/4) // Performance Counter LVT +#define LINT0 (0x0350/4) // Local Vector Table 1 (LINT0) +#define LINT1 (0x0360/4) // Local Vector Table 2 (LINT1) +#define ERROR (0x0370/4) // Local Vector Table 3 (ERROR) + #define MASKED 0x00010000 // Interrupt masked +#define TICR (0x0380/4) // Timer Initial Count +#define TCCR (0x0390/4) // Timer Current Count +#define TDCR (0x03E0/4) // Timer Divide Configuration + +volatile uint *lapic; // Initialized in mp.c + +static void +lapicw(int index, int value) +{ + lapic[index] = value; + lapic[ID]; // wait for write to finish, by reading +} + +void +lapicinit(void) +{ + if(!lapic) + return; + + // Enable local APIC; set spurious interrupt vector. + lapicw(SVR, ENABLE | (T_IRQ0 + IRQ_SPURIOUS)); + + // The timer repeatedly counts down at bus frequency + // from lapic[TICR] and then issues an interrupt. + // If xv6 cared more about precise timekeeping, + // TICR would be calibrated using an external time source. + lapicw(TDCR, X1); + lapicw(TIMER, PERIODIC | (T_IRQ0 + IRQ_TIMER)); + lapicw(TICR, 10000000); + + // Disable logical interrupt lines. + lapicw(LINT0, MASKED); + lapicw(LINT1, MASKED); + + // Disable performance counter overflow interrupts + // on machines that provide that interrupt entry. + if(((lapic[VER]>>16) & 0xFF) >= 4) + lapicw(PCINT, MASKED); + + // Map error interrupt to IRQ_ERROR. + lapicw(ERROR, T_IRQ0 + IRQ_ERROR); + + // Clear error status register (requires back-to-back writes). + lapicw(ESR, 0); + lapicw(ESR, 0); + + // Ack any outstanding interrupts. + lapicw(EOI, 0); + + // Send an Init Level De-Assert to synchronise arbitration ID's. + lapicw(ICRHI, 0); + lapicw(ICRLO, BCAST | SINIT | LEVEL); + while(lapic[ICRLO] & DELIVS) + ; + + // Enable interrupts on the APIC (but not on the processor). + lapicw(TPR, 0); +} + +int +cpunum(void) +{ + int apicid, i; + + // Cannot call cpu when interrupts are enabled: + // result not guaranteed to last long enough to be used! + // Would prefer to panic but even printing is chancy here: + // almost everything, including cprintf and panic, calls cpu, + // often indirectly through acquire and release. + if(readeflags()&FL_IF){ + static int n; + if(n++ == 0) + cprintf("cpu called from %x with interrupts enabled\n", + __builtin_return_address(0)); + } + + if (!lapic) + return 0; + + apicid = lapic[ID] >> 24; + for (i = 0; i < ncpu; ++i) { + if (cpus[i].apicid == apicid) + return i; + } + panic("unknown apicid\n"); +} + +// Acknowledge interrupt. +void +lapiceoi(void) +{ + if(lapic) + lapicw(EOI, 0); +} + +// Spin for a given number of microseconds. +// On real hardware would want to tune this dynamically. +void +microdelay(int us) +{ +} + +#define CMOS_PORT 0x70 +#define CMOS_RETURN 0x71 + +// Start additional processor running entry code at addr. +// See Appendix B of MultiProcessor Specification. +void +lapicstartap(uchar apicid, uint addr) +{ + int i; + ushort *wrv; + + // "The BSP must initialize CMOS shutdown code to 0AH + // and the warm reset vector (DWORD based at 40:67) to point at + // the AP startup code prior to the [universal startup algorithm]." + outb(CMOS_PORT, 0xF); // offset 0xF is shutdown code + outb(CMOS_PORT+1, 0x0A); + wrv = (ushort*)P2V((0x40<<4 | 0x67)); // Warm reset vector + wrv[0] = 0; + wrv[1] = addr >> 4; + + // "Universal startup algorithm." + // Send INIT (level-triggered) interrupt to reset other CPU. + lapicw(ICRHI, apicid<<24); + lapicw(ICRLO, SINIT | LEVEL | ASSERT); + microdelay(200); + lapicw(ICRLO, SINIT | LEVEL); + microdelay(100); // should be 10ms, but too slow in Bochs! + + // Send startup IPI (twice!) to enter code. + // Regular hardware is supposed to only accept a STARTUP + // when it is in the halted state due to an INIT. So the second + // should be ignored, but it is part of the official Intel algorithm. + // Bochs complains about the second one. Too bad for Bochs. + for(i = 0; i < 2; i++){ + lapicw(ICRHI, apicid<<24); + lapicw(ICRLO, STARTUP | (addr>>12)); + microdelay(200); + } +} + +#define CMOS_STATA 0x0a +#define CMOS_STATB 0x0b +#define CMOS_UIP (1 << 7) // RTC update in progress + +#define SECS 0x00 +#define MINS 0x02 +#define HOURS 0x04 +#define DAY 0x07 +#define MONTH 0x08 +#define YEAR 0x09 + +static uint cmos_read(uint reg) +{ + outb(CMOS_PORT, reg); + microdelay(200); + + return inb(CMOS_RETURN); +} + +static void fill_rtcdate(struct rtcdate *r) +{ + r->second = cmos_read(SECS); + r->minute = cmos_read(MINS); + r->hour = cmos_read(HOURS); + r->day = cmos_read(DAY); + r->month = cmos_read(MONTH); + r->year = cmos_read(YEAR); +} +//PAGEBREAK! + +// qemu seems to use 24-hour GWT and the values are BCD encoded +void cmostime(struct rtcdate *r) +{ + struct rtcdate t1, t2; + int sb, bcd; + + sb = cmos_read(CMOS_STATB); + + bcd = (sb & (1 << 2)) == 0; + + // make sure CMOS doesn't modify time while we read it + for(;;) { + fill_rtcdate(&t1); + if(cmos_read(CMOS_STATA) & CMOS_UIP) + continue; + fill_rtcdate(&t2); + if(memcmp(&t1, &t2, sizeof(t1)) == 0) + break; + } + + // convert + if(bcd) { +#define CONV(x) (t1.x = ((t1.x >> 4) * 10) + (t1.x & 0xf)) + CONV(second); + CONV(minute); + CONV(hour ); + CONV(day ); + CONV(month ); + CONV(year ); +#undef CONV + } + + *r = t1; + r->year += 2000; +} diff --git a/kernel/arch/x86_64/mp.c b/kernel/arch/x86_64/mp.c new file mode 100644 index 0000000..9e68624 --- /dev/null +++ b/kernel/arch/x86_64/mp.c @@ -0,0 +1,159 @@ +// Multiprocessor support +// Search memory for MP description structures. +// http://developer.intel.com/design/pentium/datashts/24201606.pdf + +#include "types.h" +#include "defs.h" +#include "param.h" +#include "memlayout.h" +#include "mp.h" +#include "x86.h" +#include "mmu.h" +#include "proc.h" + +struct cpu cpus[NCPU]; +// Processors the firmware says exist. +int ncpu; + +// Processors actually running, which is not the same number and must not be +// confused with it. Enumeration is cheap and startup is where the difficulty +// is: right now the APs are found and deliberately not started, so this stays +// at 1 while ncpu is 2, 4 or 16. +// +// /proc/cpuinfo reports *this* one, matching Linux, where cpuinfo lists online +// CPUs. Reporting ncpu there told a VM with four processors that it had four +// working ones, which was a comfortable thing to read and false. +int ncpu_online = 1; +uchar ioapicid; + +static uchar +sum(uchar *addr, int len) +{ + int i, sum; + + sum = 0; + for(i=0; iphysaddr == 0) + return 0; + conf = (struct mpconf*) P2V((addr_t) mp->physaddr); + if(memcmp(conf, "PCMP", 4) != 0) + return 0; + if(conf->version != 1 && conf->version != 4) + return 0; + if(sum((uchar*)conf, conf->length) != 0) + return 0; + *pmp = mp; + return conf; +} + +void +mpinit(void) +{ + uchar *p, *e; + struct mp *mp; + struct mpconf *conf; + struct mpproc *mproc; + struct mpioapic *ioapic; + + if((conf = mpconfig(&mp)) == 0) { + cprintf("No other CPUs found.\n"); + return; + } + lapic = (uint*)P2V(conf->lapicaddr_p); + for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; papicid; // apicid may differ from ncpu + ncpu++; + } + p += sizeof(struct mpproc); + continue; + case MPIOAPIC: + ioapic = (struct mpioapic*)p; + ioapicid = ioapic->apicno; + p += sizeof(struct mpioapic); + continue; + case MPBUS: + case MPIOINTR: + case MPLINTR: + p += 8; + continue; + default: + panic("Major problem parsing mp config."); + break; + } + } + // "Seems we are" is doing a lot of work here, and the number is usually + // wrong. This walks the *legacy Intel MP table* (1994), which modern firmware + // fills in minimally or not at all -- QEMU/SeaBIOS emits exactly one + // processor entry regardless of -smp, because it expects the OS to enumerate + // CPUs from the ACPI MADT instead. Verified 2026-08-08: with -smp 4 the table + // is 208 bytes and contains one type-0 entry, then buses, an I/O APIC and + // interrupt assignments. So ncpu is 1 on QEMU no matter what, and SMP is + // silently never exercised there. + // + // See docs/roadmap.md "Known broken" -- this is half of the SMP bug, and the + // reason the other half (AP startup triple-faulting) cannot be reproduced + // under QEMU until the MADT is parsed. + cprintf("Seems we are SMP, ncpu = %d\n",ncpu); + if(mp->imcrp){ + // Bochs doesn't support IMCR, so this doesn't run on Bochs. + // But it would on real hardware. + outb(0x22, 0x70); // Select IMCR + outb(0x23, inb(0x23) | 1); // Mask external interrupts. + } +} diff --git a/kernel/arch/x86_64/swtch.S b/kernel/arch/x86_64/swtch.S new file mode 100644 index 0000000..c8005d8 --- /dev/null +++ b/kernel/arch/x86_64/swtch.S @@ -0,0 +1,30 @@ +# Context switch +# +# void swtch(struct context **old, struct context *new); +# +# Save current register context in old +# and then load register context from new. + +.global swtch +swtch: + # Save old callee-save registers + pushq %rbp + pushq %rbx + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + + # Switch stacks + movq %rsp, (%rdi) + movq %rsi, %rsp + + # Load new callee-save registers + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbx + popq %rbp + + retq #?? diff --git a/kernel/arch/x86_64/trap.c b/kernel/arch/x86_64/trap.c new file mode 100644 index 0000000..e79397e --- /dev/null +++ b/kernel/arch/x86_64/trap.c @@ -0,0 +1,159 @@ +#include "types.h" +#include "defs.h" +#include "irq.h" +#include "param.h" +#include "memlayout.h" +#include "mmu.h" +#include "proc.h" +#include "x86.h" +#include "traps.h" +#include "spinlock.h" +#include "posix.h" + +uint *idt; +extern addr_t vectors[]; +struct spinlock tickslock; +uint ticks; + +static void +mkgate(uint *idt, uint n, addr_t kva, uint pl) +{ + uint64 addr = (uint64) kva; + + n *= 4; + idt[n+0] = (addr & 0xFFFF) | (KERNEL_CS << 16); + idt[n+1] = (addr & 0xFFFF0000) | 0x8E00 | ((pl & 3) << 13); + idt[n+2] = addr >> 32; + idt[n+3] = 0; +} + +void idtinit(void) +{ + struct { + ushort limit; + uint64 base; + } __attribute__((packed)) idtdesc; + + idtdesc.limit = PGSIZE - 1; + idtdesc.base = (uint64)idt; + + asm volatile("lidt %0" : : "m" (idtdesc)); +} + +void tvinit(void) +{ + int n; + idt = (uint*) kalloc(); + memset(idt, 0, PGSIZE); + for (n = 0; n < 256; n++) + mkgate(idt, n, vectors[n], 0); + mkgate(idt, T_SYSCALL, vectors[T_SYSCALL], 3); +} + +uint +uptime(void) +{ + uint xticks; + + acquire(&tickslock); + xticks = ticks; + release(&tickslock); + return xticks; +} + +// Which signal a CPU fault corresponds to, so a process killed by a fault is +// reported to wait() as died-by-signal with a sensible cause rather than a +// blanket SIGKILL. +static int +trapsig(uint64 trapno) +{ + switch(trapno){ + case T_DIVIDE: return SIGFPE; + case T_ILLOP: return SIGILL; + case T_GPFLT: return SIGSEGV; + case T_PGFLT: return SIGSEGV; + case T_BRKPT: return SIGTRAP; + case T_DEBUG: return SIGTRAP; + default: return SIGSEGV; + } +} + +void +trap(struct trapframe *tf) +{ + kstack_check_canary("trap entry"); + switch(tf->trapno){ + case T_IRQ0 + IRQ_TIMER: + if(cpunum() == 0){ + acquire(&tickslock); + ticks++; + wakeup(&ticks); + release(&tickslock); + } + lapiceoi(); + break; + case T_IRQ0 + IRQ_SPURIOUS: + cprintf("cpu%d: spurious interrupt at %p:%p\n", + cpunum(), tf->cs, tf->rip); + lapiceoi(); + break; + + default: + // Every other IOAPIC pin goes through the registration table. The device + // interrupts used to be listed here one case at a time, which cannot work + // for anything found on the PCI bus: a driver does not know its line + // until it reads the device's config space at probe time, so there is no + // constant to write a case label for. See include/irq.h. + if(tf->trapno >= T_IRQ0 && tf->trapno < T_IRQ0 + NIRQ){ + irq_dispatch(tf->trapno - T_IRQ0); + lapiceoi(); + break; + } + + if(myproc() == 0 || (tf->cs&3) == 0){ + cprintf("unexpected trap %d from cpu %d rip %p (cr2=0x%p) err=0x%p\n", + tf->trapno, cpunum(), tf->rip, rcr2(), tf->err); + if (myproc()) + cprintf("proc id: %d\n", myproc()->pid); + if (tf->trapno == T_GPFLT) { + uint64 *iretframe = (uint64*)tf->rsp; + cprintf("iretq frame @ %p: rip=%p cs=%p rflags=%p rsp=%p ss=%p\n", + iretframe, iretframe[0], iretframe[1], iretframe[2], + iretframe[3], iretframe[4]); + if (myproc()) + cprintf("this tf=%p myproc()->tf=%p myproc()->kstack=%p (tf-kstack=%p)\n", + tf, myproc()->tf, myproc()->kstack, (uint64)tf - (uint64)myproc()->kstack); + } + panic("trap"); + } + cprintf("pid %d %s: trap %d err %d on cpu %d " + "rip 0x%p addr 0x%p--kill proc\n", + myproc()->pid, myproc()->name, tf->trapno, tf->err, cpunum(), tf->rip, + rcr2()); + // General-purpose register dump. This used to be followed by ~25 lines + // that walked musl's mallocng group/meta structures out of rax/rdi and + // dumped the user stack -- scaffolding for the boot-crash investigation + // recorded in docs/architecture/kernel-history.md section 1. That + // investigation is closed and the underlying kernel bugs are fixed, so + // the allocator-specific part is gone; the registers stay, since they are + // useful for any fault. + if (tf->trapno == T_GPFLT) { + cprintf(" rax=%p rbx=%p rcx=%p rdx=%p rsi=%p rdi=%p rbp=%p rsp=%p\n", + tf->rax, tf->rbx, tf->rcx, tf->rdx, tf->rsi, tf->rdi, tf->rbp, tf->rsp); + } + myproc()->killed = 1; + if(myproc()->killsig == 0) + myproc()->killsig = trapsig(tf->trapno); + } + + if(myproc() && myproc()->killed && (tf->cs&3) == DPL_USER) + exit(W_EXITCODE(0, myproc()->killsig ? myproc()->killsig : SIGKILL)); + + if(myproc() && myproc()->state == RUNNING && tf->trapno == T_IRQ0+IRQ_TIMER) + yield(); + + if(myproc() && myproc()->killed && (tf->cs&3) == DPL_USER) + exit(W_EXITCODE(0, myproc()->killsig ? myproc()->killsig : SIGKILL)); + + kstack_check_canary("trap exit"); +} diff --git a/kernel/arch/x86_64/trapasm.S b/kernel/arch/x86_64/trapasm.S new file mode 100644 index 0000000..faf9bee --- /dev/null +++ b/kernel/arch/x86_64/trapasm.S @@ -0,0 +1,257 @@ +# trapasm.S — kernel/user entry/exit with FS_BASE swapping for TLS +# +# The kernel uses __thread struct cpu *cpu and __thread struct proc *proc, +# accessed via %fs (IA32_FS_BASE MSR, 0xC0000100). seginit() sets this to +# kernel_fs_base. User-space TLS (musl) uses the same MSR via arch_prctl +# ARCH_SET_FS (saved in proc->fs_base). +# +# Rule: on ENTRY from user (syscall or interrupt), restore kernel FS_BASE. +# on EXIT to user (sysretq or iretq), write proc->fs_base to MSR. +# +# proc->fs_base is at byte offset 0x18 (24) inside struct proc. +# proc pointer is at %gs:24 (PERCPU_PROC in include/proc.h); cpu is at %gs:16. + +# ----------------------------------------------------------------------- +# Helper macro: write kernel_fs_base to IA32_FS_BASE. +# Clobbers %rax, %rcx, %rdx. Caller must save them if needed. +# ----------------------------------------------------------------------- +# Read from %gs, not from a global. +# +# This used to be `movq kernel_fs_base(%rip), %rax`, and kernel_fs_base was a +# single global that every CPU wrote during seginit(). With one processor that +# is merely untidy. With two it is fatal: whichever CPU ran seginit() last wins, +# and from the first trap onward *every* CPU restores that one CPU's per-CPU +# block -- so `cpu` and `proc` are shared, pushcli/popcli nesting counts collide, +# and the kernel dies in panic("sched locks") shortly after the APs start. +# +# GS base is set per CPU by seginit() to the same value as FS base, and %gs:0 +# holds the block's self-pointer. So this reads *this* CPU's kernel FS base with +# no global involved. +# +# No swapgs, deliberately. The usual reason for it is that userspace owns GS; +# here it does not -- sys_arch_prctl() implements only ARCH_SET_FS/ARCH_GET_FS +# and rejects everything else, musl uses FS for TLS on x86-64, and the only +# other writes to %gs are selector loads in entry.S and entryother.S that happen +# before seginit(). GS is the kernel's alone, so it can simply stay pointing at +# the per-CPU block. If ARCH_SET_GS is ever implemented, this must become a +# proper swapgs pair. +.macro RESTORE_KERNEL_FS + movq %gs:0, %rax + movq %rax, %rdx + shrq $32, %rdx + movl $0xC0000100, %ecx + wrmsr +.endm + +# ----------------------------------------------------------------------- +# Helper macro: write proc->fs_base to IA32_FS_BASE. +# Requires %fs to still hold the kernel base. +# Clobbers %rax, %rcx, %rdx. Caller must save them if needed. +# ----------------------------------------------------------------------- +.macro WRITE_USER_FS + # proc, from the per-CPU block at %gs:24 (PERCPU_PROC in include/proc.h). + # This used to be %fs:(-8), the __thread slot, which no longer exists -- + # see the comment in include/proc.h for why those stopped being __thread. + movq %gs:24, %rax # proc pointer + movq 0x18(%rax), %rax # proc->fs_base (offset 24 = 0x18) + movq %rax, %rdx + shrq $32, %rdx + movl $0xC0000100, %ecx + wrmsr +.endm + +# ----------------------------------------------------------------------- +# alltraps — IDT interrupt/fault entry +# Stack on entry (from user mode, CPU has done privilege switch): +# [rsp+0] trapno (pushed by vectors.S) +# [rsp+8] errorcode +# [rsp+16] rip +# [rsp+24] cs ← bit 1:0 == 3 means user mode +# [rsp+32] rflags +# [rsp+40] user_rsp +# [rsp+48] user_ss +# ----------------------------------------------------------------------- +.global alltraps +alltraps: + # Always restore kernel FS_BASE before touching %fs:, even when the + # saved cs says we were already in kernel mode. A fault/interrupt can + # land in that narrow kernel-mode window after syscall_trapret/trapret + # have already done WRITE_USER_FS (cs is still 0x8 there, but FS_BASE + # is the *user* value) — the old cs-based skip trusted that combination + # never happens and read %fs:(-8) as garbage (proc/cpu == NULL) in that + # case. RESTORE_KERNEL_FS is just a wrmsr of an already-known value when + # we truly were in the kernel, so doing it unconditionally is cheap and + # always correct. + pushq %rax + pushq %rcx + pushq %rdx + RESTORE_KERNEL_FS + popq %rdx + popq %rcx + popq %rax + + # Build trap frame. + pushq %r15 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %r11 + pushq %r10 + pushq %r9 + pushq %r8 + pushq %rdi + pushq %rsi + pushq %rbp + pushq %rdx + pushq %rcx + pushq %rbx + pushq %rax + + movq %rsp, %rdi # frame in arg1 + callq trap +# Return falls through to trapret... + +.global trapret +trapret: + popq %rax + popq %rbx + popq %rcx + popq %rdx + popq %rbp + popq %rsi + popq %rdi + popq %r8 + popq %r9 + popq %r10 + popq %r11 + popq %r12 + popq %r13 + popq %r14 + popq %r15 + + addq $16, %rsp # discard trapno and errorcode + + # If returning to user mode, write proc->fs_base to FS_BASE MSR. + # Stack now: [rsp+0]=rip, [rsp+8]=cs, [rsp+16]=rflags, [rsp+24]=rsp, [rsp+32]=ss + testb $3, 8(%rsp) + jz .Ltrapret_kret + + # cli before WRITE_USER_FS: close the same race as in syscall_trapret. + # iretq will atomically restore RFLAGS (IF=1) when switching to user mode. + pushq %rax + pushq %rcx + pushq %rdx + cli + WRITE_USER_FS + popq %rdx + popq %rcx + popq %rax + +.Ltrapret_kret: + iretq + +# ----------------------------------------------------------------------- +# syscall_entry — SYSCALL instruction entry point +# On entry: rcx=user rip, r11=user rflags, rsp=user stack, IF cleared. +# FS_BASE may be the user's TLS value (set at last sysretq). +# ----------------------------------------------------------------------- +.global syscall_entry +syscall_entry: + # Swap FS_BASE to kernel value BEFORE any %fs: access. + # Save rax/rcx/rdx to single-CPU scratch globals (IF is off, no race). + movq %rax, _sc_rax(%rip) + movq %rcx, _sc_rcx(%rip) # user rip (SYSCALL stores it here) + movq %rdx, _sc_rdx(%rip) + RESTORE_KERNEL_FS # clobbers rax, rcx, rdx — that's OK + movq _sc_rax(%rip), %rax + movq _sc_rcx(%rip), %rcx + movq _sc_rdx(%rip), %rdx + + # Switch to kernel stack: store user rsp at top of proc->kstack. + # + # The scratch slot is %fs:(8), NOT %fs:(0). %fs:(0) is the TCB + # self-pointer -- the x86-64 TLS ABI reserves the word at the thread + # pointer to hold the thread pointer itself, and a compiler is entitled to + # read it to materialise the TP before applying a variable's offset. + # + # It used to be %fs:(0), and that survived for years only because GCC + # compiles `proc`/`cpu` into direct `%fs:-8` segment references and never + # touches the word. clang at -O0 does `movq %fs:0, %rax; addq $-8, %rax; + # (%rax)` instead -- so it read the syscall number this line had just + # stored (7, SYS_exec, from initcode), computed 7-8 = -1, and page-faulted + # on the very first syscall of the very first process. + # + # Positive offsets are safe: the TLS block occupies negative offsets + # (-16 = cpu, -8 = proc) and seginit puts the thread pointer 2048 bytes + # into a 4096-byte page, so %fs:(8) onward is 2040 bytes we own outright. + movq %rax, %fs:(8) # save rax in per-CPU scratch slot + movq %gs:24, %rax # proc pointer (PERCPU_PROC) + movq 0x10(%rax), %rax # proc->kstack (offset 16) + addq $(4096-16), %rax # point to tf->rsp slot + movq %rsp, (%rax) # save user rsp + movq %rax, %rsp # switch to kernel stack + movq %fs:(8), %rax # restore rax + + pushq %r11 # rflags + pushq $0 # cs (ignored) + pushq %rcx # rip (next user instruction) + + pushq $0 # err + pushq $0 # trapno (ignored) + + pushq %r15 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %r11 + pushq %r10 + pushq %r9 + pushq %r8 + pushq %rdi + pushq %rsi + pushq %rbp + pushq %rdx + pushq %rcx + pushq %rbx + pushq %rax + + movq %rsp, %rdi # frame in arg1 + callq syscall +# Return falls through to syscall_trapret... + +# ----------------------------------------------------------------------- +# syscall_trapret — return path for SYSCALL-based syscalls +# ----------------------------------------------------------------------- +.global syscall_trapret +syscall_trapret: + # Disable interrupts BEFORE writing user FS_BASE to the MSR. + # Without cli here, a timer IRQ between WRITE_USER_FS and the cli below + # would arrive in ring-0 with user FS_BASE set, causing %fs:(-8) to return + # garbage (proc=NULL) → panic in the interrupt handler. + # rax/rcx/rdx are clobbered by WRITE_USER_FS then restored by the pops. + cli + WRITE_USER_FS + + popq %rax + popq %rbx + popq %rcx + popq %rdx + popq %rbp + popq %rsi + popq %rdi + popq %r8 + popq %r9 + popq %r10 + popq %r11 + popq %r12 + popq %r13 + popq %r14 + popq %r15 + + addq $40, %rsp # discard trapno, errorcode, rip, cs, rflags + + # Mask interrupts: sysretq is unsafe with IF set on non-canonical RSP. + # See https://www.felixcloutier.com/x86/sysret + cli + movq (%rsp), %rsp # restore the user stack + sysretq diff --git a/kernel/arch/x86_64/vectors.S b/kernel/arch/x86_64/vectors.S new file mode 100644 index 0000000..264bb77 --- /dev/null +++ b/kernel/arch/x86_64/vectors.S @@ -0,0 +1,1281 @@ +# generated by vectors.pl - do not edit +# handlers +.global alltraps +vector0: + push $0 + push $0 + jmp alltraps +vector1: + push $0 + push $1 + jmp alltraps +vector2: + push $0 + push $2 + jmp alltraps +vector3: + push $0 + push $3 + jmp alltraps +vector4: + push $0 + push $4 + jmp alltraps +vector5: + push $0 + push $5 + jmp alltraps +vector6: + push $0 + push $6 + jmp alltraps +vector7: + push $0 + push $7 + jmp alltraps +vector8: + push $8 + jmp alltraps +vector9: + push $0 + push $9 + jmp alltraps +vector10: + push $10 + jmp alltraps +vector11: + push $11 + jmp alltraps +vector12: + push $12 + jmp alltraps +vector13: + push $13 + jmp alltraps +vector14: + push $14 + jmp alltraps +vector15: + push $0 + push $15 + jmp alltraps +vector16: + push $0 + push $16 + jmp alltraps +vector17: + push $17 + jmp alltraps +vector18: + push $0 + push $18 + jmp alltraps +vector19: + push $0 + push $19 + jmp alltraps +vector20: + push $0 + push $20 + jmp alltraps +vector21: + push $0 + push $21 + jmp alltraps +vector22: + push $0 + push $22 + jmp alltraps +vector23: + push $0 + push $23 + jmp alltraps +vector24: + push $0 + push $24 + jmp alltraps +vector25: + push $0 + push $25 + jmp alltraps +vector26: + push $0 + push $26 + jmp alltraps +vector27: + push $0 + push $27 + jmp alltraps +vector28: + push $0 + push $28 + jmp alltraps +vector29: + push $0 + push $29 + jmp alltraps +vector30: + push $0 + push $30 + jmp alltraps +vector31: + push $0 + push $31 + jmp alltraps +vector32: + push $0 + push $32 + jmp alltraps +vector33: + push $0 + push $33 + jmp alltraps +vector34: + push $0 + push $34 + jmp alltraps +vector35: + push $0 + push $35 + jmp alltraps +vector36: + push $0 + push $36 + jmp alltraps +vector37: + push $0 + push $37 + jmp alltraps +vector38: + push $0 + push $38 + jmp alltraps +vector39: + push $0 + push $39 + jmp alltraps +vector40: + push $0 + push $40 + jmp alltraps +vector41: + push $0 + push $41 + jmp alltraps +vector42: + push $0 + push $42 + jmp alltraps +vector43: + push $0 + push $43 + jmp alltraps +vector44: + push $0 + push $44 + jmp alltraps +vector45: + push $0 + push $45 + jmp alltraps +vector46: + push $0 + push $46 + jmp alltraps +vector47: + push $0 + push $47 + jmp alltraps +vector48: + push $0 + push $48 + jmp alltraps +vector49: + push $0 + push $49 + jmp alltraps +vector50: + push $0 + push $50 + jmp alltraps +vector51: + push $0 + push $51 + jmp alltraps +vector52: + push $0 + push $52 + jmp alltraps +vector53: + push $0 + push $53 + jmp alltraps +vector54: + push $0 + push $54 + jmp alltraps +vector55: + push $0 + push $55 + jmp alltraps +vector56: + push $0 + push $56 + jmp alltraps +vector57: + push $0 + push $57 + jmp alltraps +vector58: + push $0 + push $58 + jmp alltraps +vector59: + push $0 + push $59 + jmp alltraps +vector60: + push $0 + push $60 + jmp alltraps +vector61: + push $0 + push $61 + jmp alltraps +vector62: + push $0 + push $62 + jmp alltraps +vector63: + push $0 + push $63 + jmp alltraps +vector64: + push $0 + push $64 + jmp alltraps +vector65: + push $0 + push $65 + jmp alltraps +vector66: + push $0 + push $66 + jmp alltraps +vector67: + push $0 + push $67 + jmp alltraps +vector68: + push $0 + push $68 + jmp alltraps +vector69: + push $0 + push $69 + jmp alltraps +vector70: + push $0 + push $70 + jmp alltraps +vector71: + push $0 + push $71 + jmp alltraps +vector72: + push $0 + push $72 + jmp alltraps +vector73: + push $0 + push $73 + jmp alltraps +vector74: + push $0 + push $74 + jmp alltraps +vector75: + push $0 + push $75 + jmp alltraps +vector76: + push $0 + push $76 + jmp alltraps +vector77: + push $0 + push $77 + jmp alltraps +vector78: + push $0 + push $78 + jmp alltraps +vector79: + push $0 + push $79 + jmp alltraps +vector80: + push $0 + push $80 + jmp alltraps +vector81: + push $0 + push $81 + jmp alltraps +vector82: + push $0 + push $82 + jmp alltraps +vector83: + push $0 + push $83 + jmp alltraps +vector84: + push $0 + push $84 + jmp alltraps +vector85: + push $0 + push $85 + jmp alltraps +vector86: + push $0 + push $86 + jmp alltraps +vector87: + push $0 + push $87 + jmp alltraps +vector88: + push $0 + push $88 + jmp alltraps +vector89: + push $0 + push $89 + jmp alltraps +vector90: + push $0 + push $90 + jmp alltraps +vector91: + push $0 + push $91 + jmp alltraps +vector92: + push $0 + push $92 + jmp alltraps +vector93: + push $0 + push $93 + jmp alltraps +vector94: + push $0 + push $94 + jmp alltraps +vector95: + push $0 + push $95 + jmp alltraps +vector96: + push $0 + push $96 + jmp alltraps +vector97: + push $0 + push $97 + jmp alltraps +vector98: + push $0 + push $98 + jmp alltraps +vector99: + push $0 + push $99 + jmp alltraps +vector100: + push $0 + push $100 + jmp alltraps +vector101: + push $0 + push $101 + jmp alltraps +vector102: + push $0 + push $102 + jmp alltraps +vector103: + push $0 + push $103 + jmp alltraps +vector104: + push $0 + push $104 + jmp alltraps +vector105: + push $0 + push $105 + jmp alltraps +vector106: + push $0 + push $106 + jmp alltraps +vector107: + push $0 + push $107 + jmp alltraps +vector108: + push $0 + push $108 + jmp alltraps +vector109: + push $0 + push $109 + jmp alltraps +vector110: + push $0 + push $110 + jmp alltraps +vector111: + push $0 + push $111 + jmp alltraps +vector112: + push $0 + push $112 + jmp alltraps +vector113: + push $0 + push $113 + jmp alltraps +vector114: + push $0 + push $114 + jmp alltraps +vector115: + push $0 + push $115 + jmp alltraps +vector116: + push $0 + push $116 + jmp alltraps +vector117: + push $0 + push $117 + jmp alltraps +vector118: + push $0 + push $118 + jmp alltraps +vector119: + push $0 + push $119 + jmp alltraps +vector120: + push $0 + push $120 + jmp alltraps +vector121: + push $0 + push $121 + jmp alltraps +vector122: + push $0 + push $122 + jmp alltraps +vector123: + push $0 + push $123 + jmp alltraps +vector124: + push $0 + push $124 + jmp alltraps +vector125: + push $0 + push $125 + jmp alltraps +vector126: + push $0 + push $126 + jmp alltraps +vector127: + push $0 + push $127 + jmp alltraps +vector128: + push $0 + push $128 + jmp alltraps +vector129: + push $0 + push $129 + jmp alltraps +vector130: + push $0 + push $130 + jmp alltraps +vector131: + push $0 + push $131 + jmp alltraps +vector132: + push $0 + push $132 + jmp alltraps +vector133: + push $0 + push $133 + jmp alltraps +vector134: + push $0 + push $134 + jmp alltraps +vector135: + push $0 + push $135 + jmp alltraps +vector136: + push $0 + push $136 + jmp alltraps +vector137: + push $0 + push $137 + jmp alltraps +vector138: + push $0 + push $138 + jmp alltraps +vector139: + push $0 + push $139 + jmp alltraps +vector140: + push $0 + push $140 + jmp alltraps +vector141: + push $0 + push $141 + jmp alltraps +vector142: + push $0 + push $142 + jmp alltraps +vector143: + push $0 + push $143 + jmp alltraps +vector144: + push $0 + push $144 + jmp alltraps +vector145: + push $0 + push $145 + jmp alltraps +vector146: + push $0 + push $146 + jmp alltraps +vector147: + push $0 + push $147 + jmp alltraps +vector148: + push $0 + push $148 + jmp alltraps +vector149: + push $0 + push $149 + jmp alltraps +vector150: + push $0 + push $150 + jmp alltraps +vector151: + push $0 + push $151 + jmp alltraps +vector152: + push $0 + push $152 + jmp alltraps +vector153: + push $0 + push $153 + jmp alltraps +vector154: + push $0 + push $154 + jmp alltraps +vector155: + push $0 + push $155 + jmp alltraps +vector156: + push $0 + push $156 + jmp alltraps +vector157: + push $0 + push $157 + jmp alltraps +vector158: + push $0 + push $158 + jmp alltraps +vector159: + push $0 + push $159 + jmp alltraps +vector160: + push $0 + push $160 + jmp alltraps +vector161: + push $0 + push $161 + jmp alltraps +vector162: + push $0 + push $162 + jmp alltraps +vector163: + push $0 + push $163 + jmp alltraps +vector164: + push $0 + push $164 + jmp alltraps +vector165: + push $0 + push $165 + jmp alltraps +vector166: + push $0 + push $166 + jmp alltraps +vector167: + push $0 + push $167 + jmp alltraps +vector168: + push $0 + push $168 + jmp alltraps +vector169: + push $0 + push $169 + jmp alltraps +vector170: + push $0 + push $170 + jmp alltraps +vector171: + push $0 + push $171 + jmp alltraps +vector172: + push $0 + push $172 + jmp alltraps +vector173: + push $0 + push $173 + jmp alltraps +vector174: + push $0 + push $174 + jmp alltraps +vector175: + push $0 + push $175 + jmp alltraps +vector176: + push $0 + push $176 + jmp alltraps +vector177: + push $0 + push $177 + jmp alltraps +vector178: + push $0 + push $178 + jmp alltraps +vector179: + push $0 + push $179 + jmp alltraps +vector180: + push $0 + push $180 + jmp alltraps +vector181: + push $0 + push $181 + jmp alltraps +vector182: + push $0 + push $182 + jmp alltraps +vector183: + push $0 + push $183 + jmp alltraps +vector184: + push $0 + push $184 + jmp alltraps +vector185: + push $0 + push $185 + jmp alltraps +vector186: + push $0 + push $186 + jmp alltraps +vector187: + push $0 + push $187 + jmp alltraps +vector188: + push $0 + push $188 + jmp alltraps +vector189: + push $0 + push $189 + jmp alltraps +vector190: + push $0 + push $190 + jmp alltraps +vector191: + push $0 + push $191 + jmp alltraps +vector192: + push $0 + push $192 + jmp alltraps +vector193: + push $0 + push $193 + jmp alltraps +vector194: + push $0 + push $194 + jmp alltraps +vector195: + push $0 + push $195 + jmp alltraps +vector196: + push $0 + push $196 + jmp alltraps +vector197: + push $0 + push $197 + jmp alltraps +vector198: + push $0 + push $198 + jmp alltraps +vector199: + push $0 + push $199 + jmp alltraps +vector200: + push $0 + push $200 + jmp alltraps +vector201: + push $0 + push $201 + jmp alltraps +vector202: + push $0 + push $202 + jmp alltraps +vector203: + push $0 + push $203 + jmp alltraps +vector204: + push $0 + push $204 + jmp alltraps +vector205: + push $0 + push $205 + jmp alltraps +vector206: + push $0 + push $206 + jmp alltraps +vector207: + push $0 + push $207 + jmp alltraps +vector208: + push $0 + push $208 + jmp alltraps +vector209: + push $0 + push $209 + jmp alltraps +vector210: + push $0 + push $210 + jmp alltraps +vector211: + push $0 + push $211 + jmp alltraps +vector212: + push $0 + push $212 + jmp alltraps +vector213: + push $0 + push $213 + jmp alltraps +vector214: + push $0 + push $214 + jmp alltraps +vector215: + push $0 + push $215 + jmp alltraps +vector216: + push $0 + push $216 + jmp alltraps +vector217: + push $0 + push $217 + jmp alltraps +vector218: + push $0 + push $218 + jmp alltraps +vector219: + push $0 + push $219 + jmp alltraps +vector220: + push $0 + push $220 + jmp alltraps +vector221: + push $0 + push $221 + jmp alltraps +vector222: + push $0 + push $222 + jmp alltraps +vector223: + push $0 + push $223 + jmp alltraps +vector224: + push $0 + push $224 + jmp alltraps +vector225: + push $0 + push $225 + jmp alltraps +vector226: + push $0 + push $226 + jmp alltraps +vector227: + push $0 + push $227 + jmp alltraps +vector228: + push $0 + push $228 + jmp alltraps +vector229: + push $0 + push $229 + jmp alltraps +vector230: + push $0 + push $230 + jmp alltraps +vector231: + push $0 + push $231 + jmp alltraps +vector232: + push $0 + push $232 + jmp alltraps +vector233: + push $0 + push $233 + jmp alltraps +vector234: + push $0 + push $234 + jmp alltraps +vector235: + push $0 + push $235 + jmp alltraps +vector236: + push $0 + push $236 + jmp alltraps +vector237: + push $0 + push $237 + jmp alltraps +vector238: + push $0 + push $238 + jmp alltraps +vector239: + push $0 + push $239 + jmp alltraps +vector240: + push $0 + push $240 + jmp alltraps +vector241: + push $0 + push $241 + jmp alltraps +vector242: + push $0 + push $242 + jmp alltraps +vector243: + push $0 + push $243 + jmp alltraps +vector244: + push $0 + push $244 + jmp alltraps +vector245: + push $0 + push $245 + jmp alltraps +vector246: + push $0 + push $246 + jmp alltraps +vector247: + push $0 + push $247 + jmp alltraps +vector248: + push $0 + push $248 + jmp alltraps +vector249: + push $0 + push $249 + jmp alltraps +vector250: + push $0 + push $250 + jmp alltraps +vector251: + push $0 + push $251 + jmp alltraps +vector252: + push $0 + push $252 + jmp alltraps +vector253: + push $0 + push $253 + jmp alltraps +vector254: + push $0 + push $254 + jmp alltraps +vector255: + push $0 + push $255 + jmp alltraps + +# vector table +.data +.global vectors +vectors: + .quad vector0 + .quad vector1 + .quad vector2 + .quad vector3 + .quad vector4 + .quad vector5 + .quad vector6 + .quad vector7 + .quad vector8 + .quad vector9 + .quad vector10 + .quad vector11 + .quad vector12 + .quad vector13 + .quad vector14 + .quad vector15 + .quad vector16 + .quad vector17 + .quad vector18 + .quad vector19 + .quad vector20 + .quad vector21 + .quad vector22 + .quad vector23 + .quad vector24 + .quad vector25 + .quad vector26 + .quad vector27 + .quad vector28 + .quad vector29 + .quad vector30 + .quad vector31 + .quad vector32 + .quad vector33 + .quad vector34 + .quad vector35 + .quad vector36 + .quad vector37 + .quad vector38 + .quad vector39 + .quad vector40 + .quad vector41 + .quad vector42 + .quad vector43 + .quad vector44 + .quad vector45 + .quad vector46 + .quad vector47 + .quad vector48 + .quad vector49 + .quad vector50 + .quad vector51 + .quad vector52 + .quad vector53 + .quad vector54 + .quad vector55 + .quad vector56 + .quad vector57 + .quad vector58 + .quad vector59 + .quad vector60 + .quad vector61 + .quad vector62 + .quad vector63 + .quad vector64 + .quad vector65 + .quad vector66 + .quad vector67 + .quad vector68 + .quad vector69 + .quad vector70 + .quad vector71 + .quad vector72 + .quad vector73 + .quad vector74 + .quad vector75 + .quad vector76 + .quad vector77 + .quad vector78 + .quad vector79 + .quad vector80 + .quad vector81 + .quad vector82 + .quad vector83 + .quad vector84 + .quad vector85 + .quad vector86 + .quad vector87 + .quad vector88 + .quad vector89 + .quad vector90 + .quad vector91 + .quad vector92 + .quad vector93 + .quad vector94 + .quad vector95 + .quad vector96 + .quad vector97 + .quad vector98 + .quad vector99 + .quad vector100 + .quad vector101 + .quad vector102 + .quad vector103 + .quad vector104 + .quad vector105 + .quad vector106 + .quad vector107 + .quad vector108 + .quad vector109 + .quad vector110 + .quad vector111 + .quad vector112 + .quad vector113 + .quad vector114 + .quad vector115 + .quad vector116 + .quad vector117 + .quad vector118 + .quad vector119 + .quad vector120 + .quad vector121 + .quad vector122 + .quad vector123 + .quad vector124 + .quad vector125 + .quad vector126 + .quad vector127 + .quad vector128 + .quad vector129 + .quad vector130 + .quad vector131 + .quad vector132 + .quad vector133 + .quad vector134 + .quad vector135 + .quad vector136 + .quad vector137 + .quad vector138 + .quad vector139 + .quad vector140 + .quad vector141 + .quad vector142 + .quad vector143 + .quad vector144 + .quad vector145 + .quad vector146 + .quad vector147 + .quad vector148 + .quad vector149 + .quad vector150 + .quad vector151 + .quad vector152 + .quad vector153 + .quad vector154 + .quad vector155 + .quad vector156 + .quad vector157 + .quad vector158 + .quad vector159 + .quad vector160 + .quad vector161 + .quad vector162 + .quad vector163 + .quad vector164 + .quad vector165 + .quad vector166 + .quad vector167 + .quad vector168 + .quad vector169 + .quad vector170 + .quad vector171 + .quad vector172 + .quad vector173 + .quad vector174 + .quad vector175 + .quad vector176 + .quad vector177 + .quad vector178 + .quad vector179 + .quad vector180 + .quad vector181 + .quad vector182 + .quad vector183 + .quad vector184 + .quad vector185 + .quad vector186 + .quad vector187 + .quad vector188 + .quad vector189 + .quad vector190 + .quad vector191 + .quad vector192 + .quad vector193 + .quad vector194 + .quad vector195 + .quad vector196 + .quad vector197 + .quad vector198 + .quad vector199 + .quad vector200 + .quad vector201 + .quad vector202 + .quad vector203 + .quad vector204 + .quad vector205 + .quad vector206 + .quad vector207 + .quad vector208 + .quad vector209 + .quad vector210 + .quad vector211 + .quad vector212 + .quad vector213 + .quad vector214 + .quad vector215 + .quad vector216 + .quad vector217 + .quad vector218 + .quad vector219 + .quad vector220 + .quad vector221 + .quad vector222 + .quad vector223 + .quad vector224 + .quad vector225 + .quad vector226 + .quad vector227 + .quad vector228 + .quad vector229 + .quad vector230 + .quad vector231 + .quad vector232 + .quad vector233 + .quad vector234 + .quad vector235 + .quad vector236 + .quad vector237 + .quad vector238 + .quad vector239 + .quad vector240 + .quad vector241 + .quad vector242 + .quad vector243 + .quad vector244 + .quad vector245 + .quad vector246 + .quad vector247 + .quad vector248 + .quad vector249 + .quad vector250 + .quad vector251 + .quad vector252 + .quad vector253 + .quad vector254 + .quad vector255 diff --git a/kernel/arch/x86_64/vm.c b/kernel/arch/x86_64/vm.c new file mode 100644 index 0000000..fa23d52 --- /dev/null +++ b/kernel/arch/x86_64/vm.c @@ -0,0 +1,631 @@ +#include "param.h" +#include "types.h" +#include "defs.h" +#include "x86.h" +#include "memlayout.h" +#include "mmu.h" +#include "proc.h" + +int mappages(pml4e_t *pgdir, void *va, addr_t size, addr_t pa, int perm); +static pte_t * walkpgdir(pml4e_t *pml4, const void *va, int alloc); + + +// `cpu` and `proc` are no longer __thread variables; they live at fixed offsets +// in the per-CPU block and are read through %gs at each use. See the long +// comment in include/proc.h for why -- the short version is that __thread means +// per *thread*, the compiler caches the thread pointer across calls on that +// basis, and a kernel thread changes CPU at every sched(). + +// Kernel FS_BASE set by seginit(); read by trapasm.S to restore after user TLS +uint64 kernel_fs_base; +// Single-CPU scratch for syscall_entry FS swap (safe while IF cleared by SYSCALL/SFMASK) +uint64 _sc_rax, _sc_rcx, _sc_rdx; + +static pml4e_t *kpml4; +static pdpe_t *kpdpt; + +struct tassdesc { + uint lim_15_0 : 16; + uint base_15_0 : 16; + uint base_23_16 : 8; + uint type : 4; + uint s : 1; + uint dpl : 2; + uint p : 1; + uint lim_19_16 : 4; + uint avl : 1; + uint l : 1; + uint d : 1; + uint g : 1; + uint base_31_24 : 8; + uint32 base_63_32; + uint32 res; +}; + +void +syscallinit(void) +{ + // SYSRETQ does NOT use USER_CS/USER_DS directly. Per the AMD64/Intel + // convention, it computes CS = STAR[63:48]+16 and SS = STAR[63:48]+8 + // (RPL forced to 3), so STAR[63:48] must hold the *compat* 32-bit user + // code selector (SEG_UCODE32), relying on the GDT's consecutive + // [UCODE32, UDATA, UCODE] layout — NOT USER_CS itself. Using USER_CS + // here made every sysretq load CS=USER_CS+16 (an invalid selector, + // pointing past UCODE into the TSS descriptor) and SS=USER_CS+8. QEMU's + // TCG apparently doesn't validate segment descriptors on SYSRET, so this + // went unnoticed until an interrupt forced a strictly-validated iretq + // with that same bogus CS still loaded, which correctly #GP'd. + wrmsr(MSR_STAR, + ((((uint64)((SEG_UCODE32 << 3) | DPL_USER) << 16) | (uint64)KERNEL_CS) << 32)); + wrmsr(MSR_LSTAR, (addr_t)syscall_entry); + wrmsr(MSR_CSTAR, (addr_t)ignore_sysret); + wrmsr(MSR_SFMASK, FL_TF|FL_DF|FL_IF|FL_IOPL_MASK|FL_AC|FL_NT); +} + +void +seginit(void) +{ + struct segdesc *gdt; + uint *tss; + uint64 addr; + void *local; + struct cpu *c; + + // The per-CPU page, preallocated by the boot processor for every AP. + // + // It must not be kalloc()'d here on an application processor. kalloc takes a + // spinlock; acquire() calls holding(); holding() reads `cpu`, which is a + // __thread variable reached through %fs -- and %fs is set up four lines + // below. So an AP allocating its own page reads the per-CPU pointer before + // the per-CPU pointer exists, and the kernel dies in panic("acquire") with + // every lock appearing to be held. + // + // startothers() fills c->local in before starting each AP, on the boot + // processor, where locking works. + c = &cpus[cpunum()]; + local = c->local; + if (local == 0) { + local = kalloc(); // the boot processor's own, taken normally + memset(local, 0, PGSIZE); + } + + gdt = (struct segdesc*) local; + tss = (uint*) (((char*) local) + 1024); + tss[16] = 0x00680000; + + kernel_fs_base = ((uint64) local) + 2048; + wrmsr(0xC0000100, kernel_fs_base); + + // The TCB self-pointer: the word at %fs:0 must hold the thread pointer. + // + // This is part of the x86-64 TLS ABI and it was missing, which worked only + // by accident. GCC with -mtls-direct-seg-refs compiles `cpu = c` into a + // single `movq %rcx, %fs:-0x10` and never needs the thread pointer as a + // value, so nothing ever read this word. clang materialises it instead -- + // `movq %fs:0x0, %rax; addq $-0x10, %rax; movq %rcx, (%rax)` -- which read + // the zero left by the memset above and stored through address + // 0xfffffffffffffff0, three instructions later. + // + // Writing it costs one store per CPU and removes the dependency on a + // particular compiler's TLS optimisation. + *(uint64 *) kernel_fs_base = kernel_fs_base; + + // Clear the two per-CPU slots before anything can read them. Their offsets + // are PERCPU_CPU and PERCPU_PROC in include/proc.h and are shared with + // trapasm.S, which reads %gs:16 for proc on the way out to user mode. + ((uint64 *) kernel_fs_base)[2] = 0; // struct cpu * (PERCPU_CPU) + ((uint64 *) kernel_fs_base)[3] = 0; // struct proc * (PERCPU_PROC) + + // The same address in GS base, per CPU. + // + // trapasm.S needs to find *this* CPU's kernel FS base on every entry from + // user mode, and it has no register to work from at that instant -- which is + // why it used to read the kernel_fs_base global. That global is written by + // every CPU during its own seginit(), so with more than one processor the + // last writer wins and every CPU restores one CPU's per-CPU block. GS base is + // per-CPU in hardware, so %gs:0 answers the question with no global at all. + // + // Safe because GS belongs entirely to the kernel here: sys_arch_prctl() + // implements ARCH_SET_FS and ARCH_GET_FS only, and musl uses FS for TLS on + // x86-64. See the comment on RESTORE_KERNEL_FS. + wrmsr(0xC0000101, kernel_fs_base); // IA32_GS_BASE + + c->local = local; + + cpu_set(c); + proc_set(0); + + // Two of the entries below are deliberately null descriptors, and neither is + // dead code even though both look it: + // + // SEG_UCODE32 is never loaded, but SYSRETQ computes CS from STAR[63:48]+16 + // and SS from +8, so the *slot* must exist to keep the + // [UCODE32, UDATA, UCODE] triple consecutive. See syscallinit. + // 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 + // index has to stay occupied or SEG_TSS stops landing at 7. + // + // Deleting either moves every descriptor after it and breaks sysret. + addr = (uint64) tss; + gdt[0] = (struct segdesc) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + gdt[SEG_KCODE] = SEG(STA_X|STA_R, 0, 0, 0); + gdt[SEG_KDATA] = SEG(STA_W, 0, 0, 0); + gdt[SEG_UCODE32] = (struct segdesc) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + gdt[SEG_UDATA] = SEG(STA_W, 0, 0, DPL_USER); + gdt[SEG_UCODE] = SEG(STA_X|STA_R, 0, 0, DPL_USER); + gdt[SEG_KCPU] = (struct segdesc) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + struct tassdesc *td = (struct tassdesc*)(gdt + SEG_TSS); + td->lim_15_0 = 0x67; + td->base_15_0 = addr & 0xffff; + td->base_23_16 = (addr >> 16) & 0xff; + td->type = STS_T64A; + td->s = 0; + td->dpl = 0; + td->p = 1; + td->lim_19_16 = 0; + td->avl = 0; + td->l = 0; + td->d = 0; + td->g = 0; + td->base_31_24 = (addr >> 24) & 0xff; + td->base_63_32 = (addr >> 32) & 0xffffffff; + td->res = 0; + + lgdt((void*) gdt, (NSEGS+1) * sizeof(struct segdesc)); + ltr(SEG_TSS << 3); +} + +pml4e_t* +setupkvm(void) +{ + pml4e_t *pml4 = (pml4e_t*) kalloc(); + if(pml4 == 0) return 0; + memset(pml4, 0, PGSIZE); + + pml4[PMX(KERNBASE)] = v2p(kpdpt) | PTE_P | PTE_W; + + // The framebuffer is deliberately NOT mapped here. + // + // This used to identity-map 0xfd000000 for 800*600*4 bytes, user-writable, + // into every process that ever existed. Three things were wrong with that. + // The address and the size were both guesses that only hold on QEMU's + // stdvga at one resolution; setupkvm runs before vga_init, so on the first + // call nothing had even read the VBE block yet; and every process could + // scribble on the screen without asking anyone. + // + // Nothing used it -- userspace reaches the framebuffer through + // mmap("/dev/fb0"), which maps the real base at the real size. So it is + // gone, and a process gets the framebuffer exactly when it asks for it. + + return pml4; +} + +void +kvmalloc(void) +{ + kpml4 = (pml4e_t*) kalloc(); + memset(kpml4, 0, PGSIZE); + + kpdpt = (pdpe_t*) kalloc(); + memset(kpdpt, 0, PGSIZE); + + kpml4[0] = v2p(kpdpt) | PTE_P | PTE_W; + kpml4[PMX(KERNBASE)] = v2p(kpdpt) | PTE_P | PTE_W; + + for(uint64 i = 0; i < 4; i++) { + uint64 flags = PTE_PS | PTE_P | PTE_W; + if(i >= 3) { + flags |= PTE_PCD | PTE_PWT; + } + kpdpt[i] = (i << 30) | flags; + } + + switchkvm(); +} + +void +switchuvm(struct proc *p) +{ + pushcli(); + if(p->pgdir == 0) + panic("switchuvm: no pgdir"); + uint *tss = (uint*) (((char*) mycpu()->local) + 1024); + const addr_t stktop = (addr_t)p->kstack + KSTACKSIZE; + tss[1] = (uint)stktop; + tss[2] = (uint)(stktop >> 32); + lcr3(v2p(p->pgdir)); + popcli(); +} + +static pte_t * +walkpgdir(pml4e_t *pml4, const void *va, int alloc) +{ + pml4e_t *pml4e; + pdpe_t *pdp, *pdpe; + pde_t *pd, *pde; + pte_t *pgtab; + + pml4e = &pml4[PMX(va)]; + if(*pml4e & PTE_P) + pdp = (pdpe_t*)P2V(PTE_ADDR(*pml4e)); + else { + if(!alloc || (pdp = (pdpe_t*)kalloc()) == 0) + return 0; + memset(pdp, 0, PGSIZE); + *pml4e = V2P(pdp) | PTE_P | PTE_W | PTE_U; + } + + pdpe = &pdp[PDPX(va)]; + if(*pdpe & PTE_P) + pd = (pde_t*)P2V(PTE_ADDR(*pdpe)); + else { + if(!alloc || (pd = (pde_t*)kalloc()) == 0) + return 0; + memset(pd, 0, PGSIZE); + *pdpe = V2P(pd) | PTE_P | PTE_W | PTE_U; + } + + pde = &pd[PDX(va)]; + if(*pde & PTE_P) + pgtab = (pte_t*)P2V(PTE_ADDR(*pde)); + else { + if(!alloc || (pgtab = (pte_t*)kalloc()) == 0) + return 0; + memset(pgtab, 0, PGSIZE); + *pde = V2P(pgtab) | PTE_P | PTE_W | PTE_U; + } + + return (pte_t*)&pgtab[PTX(va)]; +} + +void +switchkvm(void) +{ + lcr3(v2p(kpml4)); +} + +int +mappages(pml4e_t *pgdir, void *va, addr_t size, addr_t pa, int perm) +{ + char *a, *last; + pte_t *pte; + + a = (char*)PGROUNDDOWN((addr_t)va); + last = (char*)PGROUNDDOWN(((addr_t)va) + size - 1); + for(;;){ + if((pte = walkpgdir(pgdir, a, 1)) == 0) + return -1; + if(*pte & PTE_P) + panic("remap"); + *pte = pa | perm | PTE_P | PTE_U; + invlpg(a); + if(a == last) + break; + a += PGSIZE; + pa += PGSIZE; + } + return 0; +} + +void +vm_unmap_range(pml4e_t *pgdir, uint64 va, uint64 length) +{ + uint64 a = PGROUNDDOWN(va); + uint64 end = PGROUNDUP(va + length); + for (; a < end; a += PGSIZE) { + pte_t *pte = walkpgdir(pgdir, (void*)a, 0); + if (pte && (*pte & PTE_P)) { + uint64 pa = PTE_ADDR(*pte); + kfree((char*)P2V(pa)); + *pte = 0; + invlpg((void*)a); + } + } +} + +// Tear down a mapping without freeing what is underneath it. +// +// vm_unmap_range() kfree()s every page it unmaps, which is right for an +// anonymous mapping and catastrophic for anything shared: the framebuffer is +// device memory that was never allocated, and a shared memory segment's pages +// belong to the segment, not to whichever process happens to be detaching. +// Handing either of those to kfree puts them on the free list while another +// process is still reading and writing them. +void +vm_unmap_norelease(pml4e_t *pgdir, uint64 va, uint64 length) +{ + uint64 a = PGROUNDDOWN(va); + uint64 end = PGROUNDUP(va + length); + for (; a < end; a += PGSIZE) { + pte_t *pte = walkpgdir(pgdir, (void*)a, 0); + if (pte && (*pte & PTE_P)) { + *pte = 0; + invlpg((void*)a); + } + } +} + +// Duplicate an mmap()'d VMA region from src into dst for fork(). +// Framebuffer mappings are re-pointed at the same physical MMIO range +// (shared, never copied/freed); anonymous mappings get fresh pages with +// the parent's contents copied in — mirrors what copyuvm() does for the +// [0, sz) heap range, which never covers mmap()'d addresses. +int +copy_vma_range(pml4e_t *dstpgdir, pml4e_t *srcpgdir, uint64 va, uint64 length, int share) +{ + uint64 a = PGROUNDDOWN(va); + uint64 end = PGROUNDUP(va + length); + for (; a < end; a += PGSIZE) { + if (share) { + // Point the child at the very same physical pages, whatever they are. + // + // This used to special-case the framebuffer and map vga_fb_phys() + // explicitly. Reading the parent's own PTE instead covers device memory + // and shared memory segments with one rule, and cannot disagree with + // what the parent actually has mapped -- which the explicit version + // could, and did, when the address was hardcoded. + pte_t *spte = walkpgdir(srcpgdir, (void*)a, 0); + if (!spte || !(*spte & PTE_P)) + continue; + if (mappages(dstpgdir, (void*)a, PGSIZE, PTE_ADDR(*spte), PTE_FLAGS(*spte)) < 0) + return -1; + continue; + } + pte_t *spte = walkpgdir(srcpgdir, (void*)a, 0); + if (!spte || !(*spte & PTE_P)) + continue; + char *mem = kalloc(); + if (!mem) + return -1; + memmove(mem, (char*)P2V(PTE_ADDR(*spte)), PGSIZE); + if (mappages(dstpgdir, (void*)a, PGSIZE, V2P(mem), PTE_FLAGS(*spte)) < 0) { + kfree(mem); + return -1; + } + } + return 0; +} + +void +inituvm(pde_t *pgdir, char *sinit, uint64 sz) +{ + char *mem; + + if(sz >= PGSIZE) + panic("inituvm: more than a page"); + mem = kalloc(); + memset(mem, 0, PGSIZE); + mappages(pgdir, 0, PGSIZE, v2p(mem), PTE_W|PTE_U); + memmove(mem, sinit, sz); +} + +int +loaduvm(pml4e_t *pgdir, char *addr, struct inode *ip, uint64 offset, uint64 sz) +{ + uint64 done, n, off_in_page; + addr_t pa; + pte_t *pte; + char *cur_page; + + for(done = 0; done < sz; done += n){ + cur_page = (char*)PGROUNDDOWN((uint64)(addr + done)); + off_in_page = (uint64)(addr + done) - (uint64)cur_page; + if((pte = walkpgdir(pgdir, cur_page, 0)) == 0) + panic("loaduvm: address should exist"); + pa = PTE_ADDR(*pte); + n = PGSIZE - off_in_page; + if(n > sz - done) + n = sz - done; + if(readi(ip, 0, (uint64)(P2V(pa) + off_in_page), offset + done, n) != (int)n) + return -1; + } + return 0; +} + +uint64 +allocuvm(pml4e_t *pgdir, uint64 oldsz, uint64 newsz) +{ + char *mem; + addr_t a; + + if(newsz >= KERNBASE) + return 0; + if(newsz < oldsz) + return oldsz; + + a = PGROUNDUP(oldsz); + for(; a < newsz; a += PGSIZE){ + mem = kalloc(); + if(mem == 0){ + deallocuvm(pgdir, newsz, oldsz); + return 0; + } + memset(mem, 0, PGSIZE); + if(mappages(pgdir, (char*)a, PGSIZE, V2P(mem), PTE_W|PTE_U) < 0){ + deallocuvm(pgdir, newsz, oldsz); + kfree(mem); + return 0; + } + } + return newsz; +} + +uint64 +deallocuvm(pml4e_t *pgdir, uint64 oldsz, uint64 newsz) +{ + pte_t *pte; + addr_t a, pa; + + if(newsz >= oldsz) + return oldsz; + + a = PGROUNDUP(newsz); + for(; a < oldsz; a += PGSIZE){ + pte = walkpgdir(pgdir, (char*)a, 0); + if(pte && (*pte & PTE_P) != 0){ + pa = PTE_ADDR(*pte); + if(pa == 0) + panic("kfree"); + if(pa < PHYSTOP) { + char *v = P2V(pa); + kfree(v); + } + *pte = 0; + } + } + return newsz; +} + +void +freevm(pml4e_t *pml4) +{ + uint i, j, k, l; + pdpe_t *pdp; + pde_t *pd; + pte_t *pt; + + if(pml4 == 0) + panic("freevm: no pgdir"); + + for(i = 0; i < (512/2); i++){ + if(pml4[i] & PTE_P){ + pdp = (pdpe_t*)P2V(PTE_ADDR(pml4[i])); + for(j = 0; j < 512; j++){ + if(pdp[j] & PTE_P){ + pd = (pde_t*)P2V(PTE_ADDR(pdp[j])); + for(k = 0; k < 512; k++){ + if(pd[k] & PTE_P) { + pt = (pte_t*)P2V(PTE_ADDR(pd[k])); + for(l = 0; l < 512; l++){ + if(pt[l] & PTE_P) { + addr_t pa = PTE_ADDR(pt[l]); + if(pa < PHYSTOP && pa != 0) { + kfree(P2V(pa)); + } + } + } + kfree((char*)pt); + } + } + kfree((char*)pd); + } + } + kfree((char*)pdp); + } + } + kfree((char*)pml4); +} + +void +clearpteu(pml4e_t *pgdir, char *uva) +{ + pte_t *pte; + pte = walkpgdir(pgdir, uva, 0); + if(pte == 0) + panic("clearpteu"); + *pte &= ~PTE_U; +} + +pml4e_t* +copyuvm(pml4e_t *pgdir, uint64 sz) +{ + pml4e_t *d; + pte_t *pte; + addr_t pa, i, flags; + char *mem; + + if((d = setupkvm()) == 0) + return 0; + for(i = 0; i < sz; i += PGSIZE){ + if((pte = walkpgdir(pgdir, (void*)i, 0)) == 0) + continue; + if(!(*pte & PTE_P)) + continue; + pa = PTE_ADDR(*pte); + flags = PTE_FLAGS(*pte); + + if(pa < PHYSTOP) { + if((mem = kalloc()) == 0) + goto bad; + memmove(mem, (char*)P2V(pa), PGSIZE); + if(mappages(d, (void*)i, PGSIZE, V2P(mem), flags) < 0) { + kfree(mem); + goto bad; + } + } + } + return d; + + bad: + freevm(d); + return 0; +} + +char* +uva2ka(pml4e_t *pgdir, char *uva) +{ + if((addr_t)uva >= KERNBASE) + return 0; + + pte_t *pte; + pte = walkpgdir(pgdir, uva, 0); + if(pte == 0 || (*pte & PTE_P) == 0) + return 0; + if((*pte & PTE_U) == 0) + return 0; + addr_t pa = (*pte) & 0x000FFFFFFFFFF000ull; + // Include uva's in-page offset — callers dereference the returned pointer + // directly at uva's address, not just somewhere within its page. + return (char*)P2V(pa) + ((addr_t)uva & 0xFFF); +} + +int +copyout(pml4e_t *pgdir, addr_t va, void *p, uint64 len) +{ + char *buf, *pa0; + addr_t n, va0; + + buf = (char*)p; + while(len > 0){ + va0 = PGROUNDDOWN(va); + pa0 = uva2ka(pgdir, (char*)va0); + + if(pa0 == 0) { + return -1; + } + + n = PGSIZE - (va - va0); + if(n > len) + n = len; + memmove(pa0 + (va - va0), buf, n); + + len -= n; + buf += n; + va += n; + } + return 0; +} + +int +copyin(pml4e_t *pgdir, addr_t srcva, void *dst, uint64 len) +{ + uint64 n, va0; + char *pa0; + char *dst_buf = (char*)dst; + + while(len > 0){ + va0 = PGROUNDDOWN(srcva); + pa0 = uva2ka(pgdir, (char*)va0); + if(pa0 == 0) + return -1; + n = PGSIZE - (srcva - va0); + if(n > len) + n = len; + memmove(dst_buf, pa0 + (srcva - va0), n); + len -= n; + dst_buf += n; + srcva += n; + } + return 0; +} diff --git a/kernel/core/console.c b/kernel/core/console.c new file mode 100644 index 0000000..6062e24 --- /dev/null +++ b/kernel/core/console.c @@ -0,0 +1,810 @@ +#include +#include "types.h" +#include "defs.h" +#include "theme.h" +#include "irq.h" +#include "param.h" +#include "traps.h" +#include "spinlock.h" +#include "sleeplock.h" +#include "fs.h" +#include "file.h" +#include "memlayout.h" +#include "mmu.h" +#include "proc.h" +#include "posix.h" +#include "x86.h" + +void consputc(int); +// Set by panic() once the crash screen has been painted: after that, consputc +// spins instead of writing, so nothing else can scribble over the report. +int panicked = 0; + +// When set, console output goes to the serial line only and the framebuffer +// is left alone. +// +// **Starts set, on purpose.** The display is the product; the serial line is +// the diagnostics. A machine that boots by printing "pci: 6 devices" and +// "vga: display controller 1234:1111, aperture fd000000" to the screen the +// user is looking at is showing them a developer's log, and that single fact +// is most of what makes an OS look like a hobby project. +// +// Nothing is lost: every one of those lines still goes out the UART, which is +// where tools/bootcheck.ps1 reads them from and where you want them when +// something goes wrong. console_takeover() clears this once userspace is up +// and the display genuinely belongs to the console. The F8 verbose boot never +// sets it, so "show me everything" still works. +int cons_serial_only = 1; +extern void vga_screen_reset(void); + +// Text colour used when drawing to the framebuffer. Changed by SGR escapes +// (see sgr() below); reset to the default by ESC[0m and ESC c. +// +// This was initialised to 7, a leftover from when it was a VGA text-mode +// attribute byte. vga_putc takes a 32-bit RGB value, so 7 meant "very dark +// blue" -- it looked black against the cream background purely by accident. +static uint32 cons_fg = SCH_FG; + +static struct { + struct spinlock lock; + int locking; +} cons; + +static char digits[] = "0123456789abcdef"; + +static void +print_int(int64 xx, int base, int sign) +{ + char buf[64]; + int i; + uint64 x; + + if(sign && (sign = (xx < 0))) + x = -xx; + else + x = xx; + + i = 0; + do { + buf[i++] = digits[x % base]; + } while((x /= base) != 0); + + if(sign) + buf[i++] = '-'; + + while(--i >= 0) + consputc(buf[i]); +} + +void +cprintf(char *fmt, ...) +{ + va_list ap; + int i, c, locking; + char *s; + + va_start(ap, fmt); + + locking = cons.locking; + if (locking) + acquire(&cons.lock); + + if (fmt == 0) + panic("null fmt"); + + for (i = 0; (c = fmt[i] & 0xff) != 0; i++) { + if (c != '%') { + consputc(c); + continue; + } + c = fmt[++i] & 0xff; + if (c == 0) + break; + switch(c) { + case 'd': + print_int(va_arg(ap, int), 10, 1); + break; + case 'u': + print_int(va_arg(ap, uint32), 10, 0); + break; + case 'l': + print_int(va_arg(ap, int64), 10, 1); + break; + case 'x': + print_int(va_arg(ap, uint32), 16, 0); + break; + case 'p': + print_int(va_arg(ap, uint64), 16, 0); + break; + case 'b': + print_int(va_arg(ap, uint32), 2, 0); + break; + case 's': + if ((s = va_arg(ap, char*)) == 0) + s = "(null)"; + while (*s) + consputc(*(s++)); + break; + case '%': + consputc('%'); + break; + default: + consputc('%'); + consputc(c); + break; + } + } + + if (locking) + release(&cons.lock); +} + +// Hand the console over to panic(). +// +// Two things change. The lock stops being taken, so a panic can report itself +// from anywhere — including from inside a routine that already holds it. And +// output stops going to the framebuffer, because from here on the framebuffer +// belongs to the crash screen: without this the report would scroll straight +// over the panel that is trying to display it. +void +cons_panic_mode(void) +{ + cons.locking = 0; + cons_serial_only = 1; +} + +// Hand the display over to the text console. +// +// Called once, when userspace is far enough along that the screen should stop +// being a boot splash and start being a terminal. Until this runs the kernel +// has been talking to the serial line only (see cons_serial_only), so this is +// the moment the framebuffer changes owner -- which is why it clears first +// rather than scrolling the shell prompt in underneath the splash. +void +console_takeover(void) +{ + if (!cons_serial_only) + return; // verbose boot: the console never left + cons_serial_only = 0; + vga_screen_reset(); +} + +// Foreground process group of the console, i.e. the controlling terminal. +// tcgetpgrp()/tcsetpgrp() read and write this through TIOCGPGRP/TIOCSPGRP in +// sys_fs.c. Initialised to 1 -- init's process group -- so the first shell, +// which inherits that group, already sees itself as the foreground job and +// does not immediately stop itself with SIGTTIN. +int tty_fg_pgrp = 1; + +#define BACKSPACE 0x100 + +// --------------------------------------------------------------------------- +// Output: an ANSI escape parser, and UTF-8 +// +// The console used to print every byte it was given, which meant every escape +// sequence any program emitted appeared on screen as literal text -- `clear` +// drew "^[[2J^[[H" and left the screen exactly as it found it. Colour, cursor +// addressing, and anything full-screen were all equally impossible. +// +// The serial line does NOT go through any of this. On the other end of it is +// a real terminal emulator that already understands ANSI far better than this +// ever will, so escapes are passed through to it verbatim and interpreted +// only for the framebuffer. Two consumers, two right answers. +// --------------------------------------------------------------------------- + +// The sixteen ANSI colours as RGB, for a linear framebuffer. +// +// consoleinit() used to program these into the VGA DAC with set_vga_palette(), +// which does nothing at all in a 32bpp linear mode -- there is no palette to +// index. The colours had to live somewhere real, and this is it. +static const uint32 ansi_rgb[16] = { + 0x000000, 0xAA0000, 0x00AA00, 0xAA5500, // black red green yellow(brown) + 0x0000AA, 0xAA00AA, 0x00AAAA, 0xAAAAAA, // blue magenta cyan white + 0x555555, 0xFF5555, 0x55FF55, 0xFFFF55, // bright versions + 0x5555FF, 0xFF55FF, 0x55FFFF, 0xFFFFFF, +}; + +#define CONS_DEFAULT_FG SCH_FG // see include/theme.h +#define CONS_DEFAULT_BG SCH_BG + +static uint32 cons_bg = CONS_DEFAULT_BG; +static int cons_bold = 0; + +// Escape parser state. +enum { E_NORMAL, E_ESC, E_CSI }; +static int esc_state = E_NORMAL; +static int esc_parm[8]; +static int esc_nparm; +static int esc_private; // saw '?' after CSI +static int saved_col, saved_row; + +// UTF-8 decoder state. A codepoint arrives as up to four bytes and has to be +// reassembled before it can be turned into a glyph. +static uint32 u8_cp; +static int u8_need; + +// --------------------------------------------------------------------------- +// Unicode -> glyph +// +// The font's upper half is CP437, not Latin-1, so a codepoint cannot be used +// as an index. It looks like it can -- font.h's own comments say so, labelling +// each glyph with the Unicode character of the same number -- but the bitmaps +// disagree: index 0xE9 draws a capital theta, and rendering U+00E9 there turns +// "cafe" into "caf" followed by a theta. Every accented character came out as +// an unrelated symbol, consistently enough to look almost deliberate. +// +// So: a table. Entry i covers codepoint 0x80 + i, and 0 means "this font has +// no glyph for that". The C1 range (0x80-0x9F) has no printable characters at +// all, hence the leading run of zeros. +// --------------------------------------------------------------------------- +static const uchar latin1_to_cp437[128] = { + /* 0x80-0x9F: C1 controls, nothing to draw */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + /* 0xA0 */ 0x20, 0xAD, 0x9B, 0x9C, 0, 0x9D, 0, 0x15, + /* 0xA8 */ 0, 0, 0xA6, 0xAE, 0xAA, 0x2D, 0, 0, + /* 0xB0 */ 0xF8, 0xF1, 0xFD, 0, 0, 0xE6, 0x14, 0xFA, + /* 0xB8 */ 0, 0, 0xA7, 0xAF, 0xAC, 0xAB, 0, 0xA8, + /* 0xC0 */ 0, 0, 0, 0, 0x8E, 0x8F, 0x92, 0x80, + /* 0xC8 */ 0, 0x90, 0, 0, 0, 0, 0, 0, + /* 0xD0 */ 0, 0xA5, 0, 0, 0, 0, 0x99, 0, + /* 0xD8 */ 0, 0, 0, 0, 0x9A, 0, 0, 0xE1, + /* 0xE0 */ 0x85, 0xA0, 0x83, 0, 0x84, 0x86, 0x91, 0x87, + /* 0xE8 */ 0x8A, 0x82, 0x88, 0x89, 0x8D, 0xA1, 0x8C, 0x8B, + /* 0xF0 */ 0, 0xA4, 0x95, 0xA2, 0x93, 0, 0x94, 0xF6, + /* 0xF8 */ 0, 0x97, 0xA3, 0x96, 0x81, 0, 0, 0x98, +}; + +// The handful of characters above U+00FF that CP437 does have. Box drawing +// and block elements matter because they are what every text-mode program +// draws frames and progress bars out of. +struct cp_pair { uint32 cp; uchar glyph; }; +static const struct cp_pair cp437_extra[] = { + { 0x2022, 0x07 }, /* bullet */ + { 0x2500, 0xC4 }, { 0x2502, 0xB3 }, /* light horizontal/vertical */ + { 0x250C, 0xDA }, { 0x2510, 0xBF }, + { 0x2514, 0xC0 }, { 0x2518, 0xD9 }, + { 0x251C, 0xC3 }, { 0x2524, 0xB4 }, + { 0x252C, 0xC2 }, { 0x2534, 0xC1 }, { 0x253C, 0xC5 }, + { 0x2550, 0xCD }, { 0x2551, 0xBA }, /* double */ + { 0x2554, 0xC9 }, { 0x2557, 0xBB }, + { 0x255A, 0xC8 }, { 0x255D, 0xBC }, + { 0x2580, 0xDF }, { 0x2584, 0xDC }, { 0x2588, 0xDB }, + { 0x258C, 0xDD }, { 0x2590, 0xDE }, + { 0x2591, 0xB0 }, { 0x2592, 0xB1 }, { 0x2593, 0xB2 }, + { 0x25A0, 0xFE }, /* black square */ + { 0x221A, 0xFB }, { 0x221E, 0xEC }, /* root, infinity */ + { 0x2260, 0, }, { 0x2264, 0xF3 }, { 0x2265, 0xF2 }, + { 0x2248, 0xF7 }, { 0x2261, 0xF0 }, +}; + +// Returns the glyph to draw for a codepoint, or 0 if there is none. +static int +glyph_for(uint32 cp) +{ + if (cp < 0x80) + return (int)cp; // ASCII is CP437's lower half + if (cp < 0x100) + return latin1_to_cp437[cp - 0x80]; + + for (unsigned i = 0; i < NELEM(cp437_extra); i++) + if (cp437_extra[i].cp == cp) + return cp437_extra[i].glyph; + return 0; +} + +static void +sgr(void) +{ + for (int i = 0; i < esc_nparm; i++) { + int p = esc_parm[i]; + + if (p == 0) { + cons_fg = CONS_DEFAULT_FG; + cons_bg = CONS_DEFAULT_BG; + cons_bold = 0; + } else if (p == 1) { + cons_bold = 1; + // Re-apply brightness to a colour already chosen. + for (int j = 0; j < 8; j++) + if (cons_fg == ansi_rgb[j]) { cons_fg = ansi_rgb[j + 8]; break; } + } else if (p == 22) { + cons_bold = 0; + } else if (p >= 30 && p <= 37) { + cons_fg = ansi_rgb[(p - 30) + (cons_bold ? 8 : 0)]; + } else if (p == 39) { + cons_fg = CONS_DEFAULT_FG; + } else if (p >= 40 && p <= 47) { + cons_bg = ansi_rgb[p - 40]; + } else if (p == 49) { + cons_bg = CONS_DEFAULT_BG; + } else if (p >= 90 && p <= 97) { + cons_fg = ansi_rgb[(p - 90) + 8]; + } else if (p >= 100 && p <= 107) { + cons_bg = ansi_rgb[(p - 100) + 8]; + } + } + vga_set_bg(cons_bg); +} + +// One final byte of a CSI sequence, with esc_parm[] already filled in. +static void +csi_dispatch(int final) +{ + int col, row; + int n = esc_nparm > 0 ? esc_parm[0] : 0; + int n1 = n ? n : 1; // most sequences default to 1 + + vga_cursor_get(&col, &row); + + switch (final) { + case 'A': vga_cursor_set(col, row - n1); break; + case 'B': vga_cursor_set(col, row + n1); break; + case 'C': vga_cursor_set(col + n1, row); break; + case 'D': vga_cursor_set(col - n1, row); break; + case 'E': vga_cursor_set(0, row + n1); break; + case 'F': vga_cursor_set(0, row - n1); break; + case 'G': vga_cursor_set(n1 - 1, row); break; + case 'd': vga_cursor_set(col, n1 - 1); break; + + case 'H': case 'f': { + int r = esc_nparm > 0 && esc_parm[0] ? esc_parm[0] : 1; + int c = esc_nparm > 1 && esc_parm[1] ? esc_parm[1] : 1; + vga_cursor_set(c - 1, r - 1); // ANSI counts from 1 + break; + } + + case 'J': vga_erase_display(n); break; + case 'K': vga_erase_line(n); break; + + case 'm': sgr(); break; + + case 's': saved_col = col; saved_row = row; break; + case 'u': vga_cursor_set(saved_col, saved_row); break; + + // Cursor visibility (DECTCEM) and the other private modes. There is no + // hardware cursor being drawn, so there is nothing to show or hide -- + // swallowing them silently is the correct behaviour, and far better than + // printing "?25l" into the middle of someone's output. + case 'h': case 'l': break; + + default: break; // unknown: drop it, do not print it + } +} + +// Feed one output byte to the framebuffer side. Returns nothing; the serial +// side has already had the raw byte. +static void +vga_feed(int c) +{ + switch (esc_state) { + case E_ESC: + if (c == '[') { + esc_state = E_CSI; + esc_nparm = 0; + esc_private = 0; + for (int i = 0; i < 8; i++) esc_parm[i] = 0; + return; + } + esc_state = E_NORMAL; + if (c == 'c') { // RIS -- full reset + cons_fg = CONS_DEFAULT_FG; + cons_bg = CONS_DEFAULT_BG; + vga_screen_reset(); + } + return; // other two-byte escapes: ignored + + case E_CSI: + if (c == '?') { esc_private = 1; return; } + if (c >= '0' && c <= '9') { + if (esc_nparm == 0) esc_nparm = 1; + if (esc_nparm <= 8) + esc_parm[esc_nparm - 1] = esc_parm[esc_nparm - 1] * 10 + (c - '0'); + return; + } + if (c == ';') { + if (esc_nparm < 8) esc_nparm++; + return; + } + esc_state = E_NORMAL; + if (!esc_private) + csi_dispatch(c); + return; + } + + // E_NORMAL + if (c == '\x1b') { esc_state = E_ESC; return; } + + // UTF-8 continuation. A codepoint the font cannot draw becomes '?' -- the + // one thing it must not become is a *different* character, which is exactly + // what indexing the font by codepoint did. + if (u8_need > 0) { + if ((c & 0xC0) != 0x80) { // malformed: abandon the sequence + u8_need = 0; + vga_putc('?', cons_fg); + return; + } + u8_cp = (u8_cp << 6) | (c & 0x3F); + if (--u8_need > 0) + return; + int g = glyph_for(u8_cp); + vga_putc(g ? g : '?', cons_fg); + return; + } + + if (c >= 0xF0) { u8_cp = c & 0x07; u8_need = 3; return; } + else if (c >= 0xE0) { u8_cp = c & 0x0F; u8_need = 2; return; } + else if (c >= 0xC0) { u8_cp = c & 0x1F; u8_need = 1; return; } + else if (c >= 0x80) { vga_putc('?', cons_fg); return; } // stray continuation + + vga_putc(c, cons_fg); +} + +void +consputc(int c) +{ + if (panicked) { + cli(); + for(;;) hlt(); + } + + if (c == BACKSPACE) { + uartputc('\b'); uartputc(' '); uartputc('\b'); + if (!cons_serial_only) + vga_putc(c, cons_fg); + return; + } + + uartputc(c); + if (!cons_serial_only) + vga_feed(c & 0xff); +} + +#define INPUT_BUF 256 +struct { + struct spinlock lock; + char buf[INPUT_BUF]; + uint r; + uint w; + uint e; + uint abort_read; + // Set by EOF (Ctrl-D) on an empty line. Canonical-mode end of input is not + // a character -- it is the *absence* of one -- so it cannot be signalled by + // putting something in the buffer. The old code pushed a literal ^D in and + // had consoleread() pick it back out, which meant a ^D typed mid-line was + // indistinguishable from one typed alone. + uint eof; +} input; + +#define C(x) ((x)-'@') + +// --------------------------------------------------------------------------- +// The line discipline +// +// TCGETS used to return a hardcoded set of flags and TCSETS threw its argument +// away, so the terminal was permanently in one mode: line-at-a-time, always +// echoing. Anything wanting a keypress at a time -- a pager, an editor, a +// shell doing its own line editing, which is most of what zsh is -- had no way +// to ask for one. This is the real thing: a struct programs can write, that +// changes what the kernel actually does. +// --------------------------------------------------------------------------- + +static struct termios tio = { + .c_iflag = ICRNL, + .c_oflag = OPOST | ONLCR, + .c_cflag = CS8 | CREAD | CLOCAL, + .c_lflag = ISIG | ICANON | ECHO | ECHOE, + .c_cc = { + [VINTR] = C('C'), [VQUIT] = C('\\'), [VERASE] = '\x7f', [VKILL] = C('U'), + [VEOF] = C('D'), [VSUSP] = C('Z'), [VWERASE] = C('W'), [VMIN] = 1, + }, + .c_ispeed = 15, .c_ospeed = 15, +}; + +void +cons_get_termios(struct termios *out) +{ + acquire(&input.lock); + *out = tio; + release(&input.lock); +} + +void +cons_set_termios(const struct termios *in) +{ + acquire(&input.lock); + tio = *in; + // Switching out of canonical mode has to hand over whatever has been typed + // but not yet submitted, or a shell that turns off ICANON mid-line silently + // eats the characters already in the edit buffer. + if (!(tio.c_lflag & ICANON)) + input.w = input.e; + release(&input.lock); + wakeup(&input.r); +} + +static void +echo(int c) +{ + if (c == '\n' || c == '\r') { + if ((tio.c_lflag & ECHO) || (tio.c_lflag & ECHONL)) + consputc('\n'); + return; + } + if (!(tio.c_lflag & ECHO)) + return; + // Control characters echo as ^X, the way every other terminal shows them. + if (c < 32 && c != '\t') { + consputc('^'); + consputc(c + '@'); + } else { + consputc(c); + } +} + +// Rub out the last character of the current line. +static void +erase_one(void) +{ + if (input.e == input.w) + return; + input.e--; + if (tio.c_lflag & ECHOE) + consputc(BACKSPACE); +} + +void +consoleintr(int (*getc)(void)) +{ + int c; + + acquire(&input.lock); + while((c = getc()) >= 0){ + if (c == 0) + continue; + + // Input mapping, before anything looks at the character. + if (tio.c_iflag & ISTRIP) c &= 0x7f; + if (c == '\r') { + if (tio.c_iflag & IGNCR) continue; + if (tio.c_iflag & ICRNL) c = '\n'; + } else if (c == '\n' && (tio.c_iflag & INLCR)) { + c = '\r'; + } + + // Signals. These are the characters that must not reach the reader. + // + // Ctrl-C used to do `myproc()->killed = 1` -- and `proc` in an interrupt + // handler is whatever happened to be running on this CPU when the key was + // pressed, which is almost never the program the user is looking at. It + // also set a kill flag rather than raising a signal, so nothing could + // catch it and the shell never learned the job had died. Both wrong; + // both fixed by sending a real signal to the foreground process group, + // which the kernel has been tracking in tty_fg_pgrp all along. + if (tio.c_lflag & ISIG) { + int sig = 0; + if (c == tio.c_cc[VINTR]) sig = SIGINT; + else if (c == tio.c_cc[VQUIT]) sig = SIGQUIT; + else if (c == tio.c_cc[VSUSP]) sig = SIGTSTP; + if (sig) { + echo(c); + input.e = input.w = input.r; // discard the partial line + input.abort_read = 1; + release(&input.lock); + sigsend_pgrp(tty_fg_pgrp, sig); + acquire(&input.lock); + wakeup(&input.r); + continue; + } + } + + // Ctrl-P: dump the process table. Not POSIX, but it is the one debugging + // aid that works when everything else has stopped responding. + if (c == C('P')) { + procdump(); + continue; + } + + if (tio.c_lflag & ICANON) { + if (c == tio.c_cc[VERASE] || c == C('H')) { + erase_one(); + continue; + } + if (c == tio.c_cc[VKILL]) { + while (input.e != input.w && + input.buf[(input.e-1) % INPUT_BUF] != '\n') + erase_one(); + continue; + } + if (c == tio.c_cc[VWERASE]) { + while (input.e != input.w && + input.buf[(input.e-1) % INPUT_BUF] == ' ') + erase_one(); + while (input.e != input.w && + input.buf[(input.e-1) % INPUT_BUF] != ' ') + erase_one(); + continue; + } + if (c == tio.c_cc[VEOF]) { + if (input.e == input.w) + input.eof = 1; // empty line: end of input + input.w = input.e; // otherwise just submit what is there + wakeup(&input.r); + continue; + } + } + + if (input.e - input.r >= INPUT_BUF) + continue; // buffer full: drop it + + // Everything else goes in, including bytes above 127 -- those are UTF-8 + // continuation bytes, and the old `c >= 32 && c <= 126` test silently + // refused every non-ASCII character anyone tried to type. + input.buf[input.e++ % INPUT_BUF] = c; + echo(c); + + // Canonical mode hands over a line at a time; raw mode hands over + // everything as it arrives. + if (!(tio.c_lflag & ICANON) || + c == '\n' || input.e == input.r + INPUT_BUF) { + input.w = input.e; + wakeup(&input.r); + } + } + release(&input.lock); +} + +int +consoleread(struct inode *ip, uint off, char *dst, int n) +{ + uint target; + int c; + static uint32 prng_seed = 0x9A7B3C1D; + + if (ip->minor == 2) { + return 0; + } + + if (ip->minor == 4) { + for (int i = 0; i < n; i++) { + prng_seed ^= prng_seed << 13; + prng_seed ^= prng_seed >> 17; + prng_seed ^= prng_seed << 5; + dst[i] = prng_seed & 0xFF; + } + return n; + } + + iunlock(ip); + target = n; + acquire(&input.lock); + while(n > 0){ + while(input.r == input.w){ + if (input.eof) { + input.eof = 0; + release(&input.lock); + ilock(ip); + return 0; // end of input + } + if (myproc()->killed || input.abort_read) { + input.abort_read = 0; + release(&input.lock); + ilock(ip); + return -1; + } + sleep(&input.r, &input.lock); + } + c = input.buf[input.r++ % INPUT_BUF]; + *dst++ = c; + --n; + + // Canonical mode returns a line at a time. Raw mode returns whatever has + // arrived: a program that asked for a keypress must not be made to wait + // for a newline that is never coming. + if (tio.c_lflag & ICANON) { + if (c == '\n') + break; + } else { + if (target - n >= (uint)(tio.c_cc[VMIN] ? tio.c_cc[VMIN] : 1)) + break; + } + } + release(&input.lock); + ilock(ip); + + return target - n; +} + +// Nonzero if a completed input line is waiting — poll(2)'s POLLIN answer +// for the console tty. Mirrors the r/w cursors consoleread() blocks on. +int +console_input_ready(void) +{ + int ready; + + acquire(&input.lock); + ready = input.r != input.w; + release(&input.lock); + return ready; +} + +int +consolewrite(struct inode *ip, uint off, char *buf, int n) +{ + int i; + + if (ip->minor == 2 || ip->minor == 3 || ip->minor == 4) { + return n; + } + + iunlock(ip); + acquire(&cons.lock); + for(i = 0; i < n; i++) + consputc(buf[i] & 0xff); + release(&cons.lock); + ilock(ip); + + return n; +} + +void +disable_blink(void) +{ + inb(0x3DA); + outb(0x3C0, 0x10 | 0x20); + uchar dummy = inb(0x3C1); + outb(0x3C0, dummy & ~0x08); +} + +static void +set_vga_palette(uchar index, uchar r, uchar g, uchar b) +{ + outb(0x3C6, 0xFF); + outb(0x3C8, index); + outb(0x3C9, r & 0x3F); + outb(0x3C9, g & 0x3F); + outb(0x3C9, b & 0x3F); +} + +// The keyboard handler lives in kbd.c, but the console is what owns the +// keyboard as an input source, so this is where the line gets claimed. +static void +kbd_irq(void *arg) +{ + (void)arg; + kbdintr(); +} + +void +consoleinit(void) +{ + initlock(&cons.lock, "console"); + initlock(&input.lock, "input"); + + memset(&input, 0, sizeof(input)); + + devsw[CONSOLE].write = consolewrite; + devsw[CONSOLE].read = consoleread; + cons.locking = 1; + + disable_blink(); + + set_vga_palette(0, 0, 0, 0); // Black + set_vga_palette(1, 0, 0, 42); // Blue + set_vga_palette(2, 0, 42, 0); // Green + set_vga_palette(3, 0, 42, 42); // Cyan + set_vga_palette(4, 42, 0, 0); // Red + set_vga_palette(5, 42, 0, 42); // Magenta + set_vga_palette(6, 42, 21, 0); // Brown + set_vga_palette(7, 42, 42, 42); // Light Gray + set_vga_palette(8, 21, 21, 21); // Dark Gray + set_vga_palette(9, 21, 21, 63); // Light Blue + set_vga_palette(10, 21, 63, 21); // Light Green + set_vga_palette(11, 21, 63, 63); // Light Cyan + set_vga_palette(12, 63, 21, 21); // Light Red + set_vga_palette(13, 21, 21, 63); // Light Magenta + set_vga_palette(14, 63, 63, 21); // Yellow + set_vga_palette(15, 63, 63, 63); // White + + irq_register(IRQ_KBD, kbd_irq, 0, "ps2-kbd", 0); +} diff --git a/kernel/core/dma.c b/kernel/core/dma.c new file mode 100644 index 0000000..d926db7 --- /dev/null +++ b/kernel/core/dma.c @@ -0,0 +1,191 @@ +// Physically contiguous memory for devices. See include/dma.h. + +#include "types.h" +#include "defs.h" +#include "param.h" +#include "memlayout.h" +#include "mmu.h" +#include "spinlock.h" +#include "dma.h" + +#define DMA_GRAIN 64 // one cache line; also xHCI's ring alignment +#define NEXTENT 64 // free extents we can track + +struct extent { + addr_t base; // kernel virtual address + uint64 len; +}; + +static struct { + struct spinlock lock; + struct extent free[NEXTENT]; + int n; // free extents, kept sorted by base + addr_t lo, hi; + uint64 total; +} arena; + +static uint64 +roundup(uint64 v, uint64 to) +{ + return (v + to - 1) & ~(to - 1); +} + +void +dma_init(void *vstart, void *vend) +{ + initlock(&arena.lock, "dma"); + arena.lo = roundup((addr_t)vstart, PGSIZE); + arena.hi = (addr_t)vend & ~(addr_t)(PGSIZE - 1); + if(arena.hi <= arena.lo) + panic("dma_init: empty arena"); + arena.free[0].base = arena.lo; + arena.free[0].len = arena.hi - arena.lo; + arena.n = 1; + arena.total = arena.free[0].len; +} + +// Remove free[i], shifting the tail down. +static void +drop(int i) +{ + int j; + for(j = i; j + 1 < arena.n; j++) + arena.free[j] = arena.free[j+1]; + arena.n--; +} + +// Insert a free extent at index i, shifting the tail up. Returns 0 if the +// table is full, in which case the memory is leaked rather than corrupting +// the list -- a leak is recoverable by rebooting, a corrupt free list hands +// two drivers the same ring. +static int +insert(int i, addr_t base, uint64 len) +{ + int j; + + if(arena.n >= NEXTENT) + return 0; + for(j = arena.n; j > i; j--) + arena.free[j] = arena.free[j-1]; + arena.free[i].base = base; + arena.free[i].len = len; + arena.n++; + return 1; +} + +void * +dma_alloc(uint64 size, uint64 align) +{ + int i; + addr_t start; + + if(size == 0) + return 0; + if(align < DMA_GRAIN) + align = DMA_GRAIN; + if(align & (align - 1)) + panic("dma_alloc: alignment not a power of two"); + size = roundup(size, DMA_GRAIN); + + acquire(&arena.lock); + + for(i = 0; i < arena.n; i++){ + addr_t base = arena.free[i].base; + uint64 len = arena.free[i].len; + uint64 lead; + + start = roundup(base, align); + lead = start - base; + if(lead + size > len) + continue; + + // Three cases: the request consumes the extent, sits at its head, sits + // at its tail, or sits in the middle and splits it in two. + if(lead == 0 && size == len){ + drop(i); + } else if(lead == 0){ + arena.free[i].base += size; + arena.free[i].len -= size; + } else if(lead + size == len){ + arena.free[i].len = lead; + } else { + uint64 tail_len = len - lead - size; + arena.free[i].len = lead; + if(!insert(i + 1, start + size, tail_len)){ + // No room to record the tail. Give the whole extent to the caller + // rather than lose track of where the tail was. + arena.free[i].len = len; + continue; + } + } + + release(&arena.lock); + memset((void*)start, 0, size); + return (void*)start; + } + + release(&arena.lock); + cprintf("dma_alloc: out of DMA memory (wanted %d bytes, %d free)\n", + (int)size, (int)dma_free_bytes()); + return 0; +} + +void +dma_free(void *p, uint64 size) +{ + addr_t base = (addr_t)p; + int i; + + if(p == 0) + return; + size = roundup(size, DMA_GRAIN); + if(base < arena.lo || base + size > arena.hi) + panic("dma_free: not DMA memory"); + + acquire(&arena.lock); + + // Find the first extent that starts after this block, so the list stays + // sorted and neighbours end up adjacent for coalescing. + for(i = 0; i < arena.n && arena.free[i].base < base; i++) + ; + + if(i > 0 && arena.free[i-1].base + arena.free[i-1].len == base){ + arena.free[i-1].len += size; // merge with the block before + i--; + } else if(!insert(i, base, size)){ + release(&arena.lock); + cprintf("dma_free: extent table full, leaking %d bytes\n", (int)size); + return; + } + + if(i + 1 < arena.n && + arena.free[i].base + arena.free[i].len == arena.free[i+1].base){ + arena.free[i].len += arena.free[i+1].len; // and with the block after + drop(i + 1); + } + + release(&arena.lock); +} + +addr_t +dma_phys(const void *p) +{ + return V2P((addr_t)p); +} + +uint64 +dma_free_bytes(void) +{ + uint64 n = 0; + int i; + + for(i = 0; i < arena.n; i++) + n += arena.free[i].len; + return n; +} + +uint64 +dma_total_bytes(void) +{ + return arena.total; +} diff --git a/kernel/core/kalloc.c b/kernel/core/kalloc.c new file mode 100644 index 0000000..82aeecf --- /dev/null +++ b/kernel/core/kalloc.c @@ -0,0 +1,124 @@ +// Physical memory allocator, intended to allocate +// memory for user processes, kernel stacks, page table pages, +// and pipe buffers. Allocates 4096-byte pages. + +#include "types.h" +#include "defs.h" +#include "param.h" +#include "memlayout.h" +#include "mmu.h" +#include "spinlock.h" + +void freerange(void *vstart, void *vend); +extern char end[]; // first address after kernel loaded from ELF file + + +struct run { + struct run *next; +}; + +struct { + struct spinlock lock; + int use_lock; + struct run *freelist; +} kmem; + +// Catch kmem.freelist corruption at the point it's touched, rather than +// letting a bad pointer be silently returned by kalloc() and crash whatever +// code dereferences it minutes later on an unrelated call stack. +static void +check_run(struct run *r, char *where) +{ + if(r == 0) + return; + if((addr_t)r % PGSIZE || (char*)r < end || V2P(r) >= PHYSTOP){ + cprintf("kalloc: corrupt freelist entry %p at %s\n", r, where); + panic("kalloc: corrupt freelist"); + } +} + +void +kinit1(void *vstart, void *vend) +{ + initlock(&kmem.lock, "kmem"); + kmem.use_lock = 0; + kmem.freelist = 0; // empty + freerange(vstart, vend); +} + +void +kinit2() +{ + kmem.use_lock = 1; +} + +void +freerange(void *vstart, void *vend) +{ + char *p; + p = (char*)PGROUNDUP((addr_t)vstart); + for(; p + PGSIZE <= (char*)vend; p += PGSIZE) + kfree(p); +} + +// Free the page of physical memory pointed at by v, +// which normally should have been returned by a +// call to kalloc(). (The exception is when +// initializing the allocator; see kinit above.) +void +kfree(char *v) +{ + struct run *r; + + if((addr_t)v % PGSIZE || v < end || V2P(v) >= PHYSTOP) + panic("kfree"); + + // Fill with junk to catch dangling refs. + memset(v, 1, PGSIZE); + + if(kmem.use_lock) + acquire(&kmem.lock); + check_run(kmem.freelist, "kfree entry"); + r = (struct run*)v; + r->next = kmem.freelist; + kmem.freelist = r; + if(kmem.use_lock) + release(&kmem.lock); +} + +// Allocate one 4096-byte page of physical memory. +// Returns a pointer that the kernel can use. +// Returns 0 if the memory cannot be allocated. +char* +kalloc(void) +{ + struct run *r; + + if(kmem.use_lock) + acquire(&kmem.lock); + check_run(kmem.freelist, "kalloc entry"); + r = kmem.freelist; + if(r) + kmem.freelist = r->next; + + if(kmem.use_lock) + release(&kmem.lock); + return (char*)r; +} + +// Total free physical memory, in bytes. Walks the free list; only /proc +// readers call it, so the O(n) scan is not on any hot path. +uint64 +kalloc_free_bytes(void) +{ + struct run *r; + uint64 n = 0; + + if(kmem.use_lock) + acquire(&kmem.lock); + for(r = kmem.freelist; r; r = r->next) + n += PGSIZE; + if(kmem.use_lock) + release(&kmem.lock); + return n; +} diff --git a/kernel/core/main.c b/kernel/core/main.c new file mode 100644 index 0000000..f95f9d0 --- /dev/null +++ b/kernel/core/main.c @@ -0,0 +1,231 @@ +#include "types.h" +#include "defs.h" +#include "param.h" +#include "memlayout.h" +#include "mmu.h" +#include "proc.h" +#include "x86.h" +#include "irq.h" +#include "dma.h" + +static void startothers(void); +static void mpmain(void) __attribute__((noreturn)); +extern char end[]; // first address after kernel loaded from ELF file + +// 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, +// before anything else, so subsystem init can log its own steps. +int boot_verbose; + +// Must match BOOT_VERBOSE_FLAG_ADDR in boot/stage2main.c exactly: just past +// the VBE info block, not 0x7000 (startothers() below uses that address for +// the AP boot trampoline). +#define BOOT_VERBOSE_FLAG_ADDR (0x30000 + 0x100) + +// Bootstrap processor starts running C code here. +// Allocate a real stack and switch to it, first +// doing some setup required for memory allocator to work. +int +kmain(uint32 fb_addr) +{ + boot_verbose = *(uchar*)P2V(BOOT_VERBOSE_FLAG_ADDR); + + uartearlyinit(); + if (boot_verbose) cprintf("verbose boot: uartearlyinit done\n"); + // The DMA arena is carved off the top of physical memory *before* kalloc is + // given the rest, because a device needs physically contiguous memory and + // kalloc's free list makes no such promise -- two pages from it are adjacent + // only by chance. Taking it first is the only way to be sure the region + // exists; asking for it later would mean asking kalloc for something it + // fundamentally cannot provide. See include/dma.h. + // Before anything touches PHYSTOP, which is now a variable read from the + // firmware's memory map rather than a constant asserting 224 MB exists. + e820_init(); + kinit1(end, P2V(PHYSTOP - DMA_ARENA_BYTES)); + if (boot_verbose) cprintf("verbose boot: kinit1 done\n"); + dma_init(P2V(PHYSTOP - DMA_ARENA_BYTES), P2V(PHYSTOP)); + if (boot_verbose) cprintf("verbose boot: dma_init done\n"); + kvmalloc(); + if (boot_verbose) cprintf("verbose boot: kvmalloc done\n"); + // ACPI first, the legacy MP table only if it finds nothing. Modern firmware + // publishes a complete MADT and an MP table with one processor in it, so + // asking the older interface first means never seeing more than one CPU. + // See kernel/arch/x86_64/acpi.c. + if (!acpi_init()) + mpinit(); + if (boot_verbose) cprintf("verbose boot: cpu enumeration done\n"); + lapicinit(); + if (boot_verbose) cprintf("verbose boot: lapicinit done\n"); + tvinit(); + if (boot_verbose) cprintf("verbose boot: tvinit done\n"); + seginit(); + if (boot_verbose) cprintf("verbose boot: seginit done\n"); + ioapicinit(); + if (boot_verbose) cprintf("verbose boot: ioapicinit done\n"); + irq_init(); // must precede any driver init that registers a handler + if (boot_verbose) cprintf("verbose boot: irq_init done\n"); + // Before the keyboard and mouse, which start producing events the moment + // their handlers are registered. + inputinit(); + if (boot_verbose) cprintf("verbose boot: inputinit done\n"); + consoleinit(); + if (boot_verbose) cprintf("verbose boot: consoleinit done\n"); + uartinit(); + if (boot_verbose) cprintf("verbose boot: uartinit done\n"); + mouseinit(); + if (boot_verbose) cprintf("verbose boot: mouseinit done\n"); + vga_init(fb_addr); + if (boot_verbose) cprintf("verbose boot: vga_init done (fb=0x%x)\n", fb_addr); + // No splash drawing here on purpose. The loader owns the splash, logo and + // all, and vga_init() deliberately does not clear -- so it is still on the + // display right through to console_takeover(). Painting it again from here + // would land in the last few hundred milliseconds of boot and change nothing. + // After vga_init, because the display driver cross-checks the framebuffer + // address it finds on the bus against the one VBE reported -- and it can + // only do that once vga.c has read the VBE block. + // The devices that are simply known to be on a PC rather than enumerated by + // any bus. Registered before pci_init() so that /proc/devices lists them + // first, which puts the machine's fixed furniture above whatever happened to + // be plugged into it. + platform_register_devices(); + pci_init(); + if (boot_verbose) cprintf("verbose boot: pci_init done\n"); + pinit(); + if (boot_verbose) cprintf("verbose boot: pinit done\n"); + binit(); + if (boot_verbose) cprintf("verbose boot: binit done\n"); + fileinit(); + if (boot_verbose) cprintf("verbose boot: fileinit done\n"); + sockinit(); + if (boot_verbose) cprintf("verbose boot: sockinit done\n"); + // After the timer is running, so boot_epoch can subtract the uptime so far, + // and before userspace, so the very first timestamp any program takes is + // already real. Reading the RTC is slow, which is exactly why it happens once + // here rather than on every gettimeofday(). + time_init(); + ideinit(); + if (boot_verbose) cprintf("verbose boot: ideinit done\n"); + ramdiskinit(); + if (boot_verbose) cprintf("verbose boot: ramdiskinit done\n"); + // Start the application processors. + // + // This was broken from the beginning of the project and is fixed as of + // 2026-08-08. Five distinct bugs, each hidden behind the one before it, and + // all of them invisible under QEMU because it publishes only one processor in + // the legacy MP table -- see kernel/arch/x86_64/acpi.c. VMware published the + // real count, which is why the triple fault only ever appeared there. + // + // 1. entry64high had no AP branch at all; the check was a comment saying it + // had never been written. Every AP fell into the boot processor's path, + // took the BSP's stack, and ran kmain() a second time. + // 2. seginit() called kalloc() for its per-CPU page. kalloc locks, locking + // reads `cpu`, and `cpu` is what seginit() was about to set up. + // 3. kernel_fs_base was one global for all CPUs, and trapasm.S read it on + // every entry from user mode, so both CPUs shared one per-CPU block. + // 4. `cpu` and `proc` were __thread. That means per *thread*, so the compiler + // cached the thread pointer across calls -- but %fs here is per *CPU*, and + // a kernel thread changes CPU at every sched(). See include/proc.h. + // 5. The new per-CPU slots collided with syscall_entry's scratch word at + // %fs:(8), which is the same memory as %gs:8. + // + int smp_start_aps = 1; + if (smp_start_aps) { + startothers(); + if (boot_verbose) cprintf("verbose boot: startothers done\n"); + } else if (ncpu > 1) { + cprintf("smp: %d cpus found, running on 1 (AP startup is broken)\n", ncpu); + } + kinit2(); + if (boot_verbose) cprintf("verbose boot: kinit2 done\n"); + sinit(); + if (boot_verbose) cprintf("verbose boot: sinit done\n"); + mpmain(); +} + +// Other CPUs jump here from entryother.S. +void +mpenter(void) +{ + switchkvm(); + seginit(); + lapicinit(); + mpmain(); +} + +// Enable SSE/FXSAVE so user binaries can use XMM registers. +static void +enable_sse(void) +{ + uint64 cr0, cr4; + asm volatile("mov %%cr0, %0" : "=r"(cr0)); + cr0 &= ~(1UL << 2); // clear CR0.EM (no FP emulation) + cr0 |= (1UL << 1); // set CR0.MP (monitor coprocessor) + asm volatile("mov %0, %%cr0" :: "r"(cr0)); + asm volatile("mov %%cr4, %0" : "=r"(cr4)); + cr4 |= (1UL << 9); // CR4.OSFXSR — OS handles FXSAVE/FXRSTOR + cr4 |= (1UL << 10); // CR4.OSXMMEXCPT — OS handles SSE exceptions + asm volatile("mov %0, %%cr4" :: "r"(cr4)); +} + +// Common CPU setup code. +static void +mpmain(void) +{ + cprintf("cpu%d: starting\n", cpunum()); + enable_sse(); // allow user XMM/SSE instructions + idtinit(); // load idt register + syscallinit(); // syscall set up + xchg(&mycpu()->started, 1); // tell startothers() we're up + scheduler(); // start running processes +} + +void entry32mp(void); + +// Start the non-boot (AP) processors. +static void +startothers(void) +{ + extern uchar _binary_entryother_start[], _binary_entryother_size[]; + uchar *code; + struct cpu *c; + char *stack; + + // Write entry code to unused memory at 0x7000. + // The linker has placed the image of entryother.S in + // _binary_entryother_start. + code = P2V(0x7000); + memmove(code, _binary_entryother_start, + (addr_t)_binary_entryother_size); + + for(c = cpus; c < cpus+ncpu; c++){ + if(c == cpus+cpunum()) // We've started already. + continue; + + // Tell entryother.S what stack to use, where to enter, and what + // pgdir to use. We cannot use kpgdir yet, because the AP processor + // is running in low memory, so we use entrypgdir for the APs too. + // The AP's per-CPU page, allocated here rather than by the AP itself. + // seginit() explains why: an AP cannot call kalloc() before %fs is set up, + // because kalloc locks and locking reads the per-CPU pointer. + if (c->local == 0) { + c->local = kalloc(); + memset(c->local, 0, PGSIZE); + } + + stack = kalloc(); + *(uint32*)(code-4) = 0x8000; // enough stack to get us to entry64mp + *(uint32*)(code-8) = v2p(entry32mp); + *(uint64*)(code-16) = (uint64) (stack + KSTACKSIZE); + + lapicstartap(c->apicid, V2P(code)); + + // wait for cpu to finish mpmain() + while(c->started == 0) + ; + + // Counted here, on the boot processor, after the AP has actually reported + // in -- not by the AP itself. This is serialised by the loop, so it needs + // no atomic, and it cannot overcount a processor that started and died. + ncpu_online++; + } +} diff --git a/kernel/core/panic.c b/kernel/core/panic.c new file mode 100644 index 0000000..903d962 --- /dev/null +++ b/kernel/core/panic.c @@ -0,0 +1,543 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// PSOGM — the Schunix crash screen. +// +// 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: +// +// *It does not clear the screen.* Whatever was being displayed stays there, +// dimmed and pushed back, with the report floating over it. A crash screen that +// wipes the display tells you the machine is gone; one that leaves your work +// visible underneath tells you it stopped, which is both truer and much less +// alarming. +// +// *It is not frightening.* No red, no capitals, no "FATAL". A calm sentence, a +// face that is obviously a cartoon, and then the facts. Whoever is reading this +// is already having a bad time. +// +// *It says considerably more than it needs to.* The screen is the only artefact +// of a kernel panic — there is no core dump and no log to go back to — so +// everything cheap to collect is collected: which CPU, which process, how far +// into the boot, where the kernel is loaded, and a call chain. Anything left +// out here is gone. +// +// Everything is also written to the serial console, in the same order. That is +// what tools/bootcheck.ps1 reads, and it is what you get when the crash happens +// before there is a framebuffer at all. + +#include "types.h" +#include "defs.h" +#include "param.h" +#include "memlayout.h" +#include "mmu.h" +#include "x86.h" +#include "proc.h" +#include "spinlock.h" +// Purple, because the name says so, and white on it because nothing else is +// legible at every brightness a monitor might be set to. The palette lives in +// theme.h with everything else; this file used to keep its own copy under the +// same names but with different values, which meant theme.h described a crash +// screen nobody had ever seen. +#include "theme.h" +#include "qr.h" + +extern uint ticks; +extern int panicked; + +/* ------------------------------------------------------------------ */ +/* Small formatting helpers */ +/* */ +/* cprintf goes to the console, which during a panic is also the screen */ +/* being painted over -- so the panel builds its strings itself and */ +/* places them with vga_text_at. */ +/* ------------------------------------------------------------------ */ + +static char * +put_str(char *p, char *end, const char *s) +{ + while (*s && p < end - 1) + *p++ = *s++; + *p = '\0'; + return p; +} + +static char * +put_dec(char *p, char *end, uint64 v) +{ + char tmp[24]; + int i = 0; + if (v == 0) + tmp[i++] = '0'; + while (v && i < (int)sizeof(tmp)) { tmp[i++] = '0' + (v % 10); v /= 10; } + while (i-- && p < end - 1) + *p++ = tmp[i]; + *p = '\0'; + return p; +} + +static char * +put_hex(char *p, char *end, uint64 v, int digits) +{ + const char *d = "0123456789abcdef"; + if (p < end - 2) { *p++ = '0'; *p++ = 'x'; } + for (int i = digits - 1; i >= 0 && p < end - 1; i--) + *p++ = d[(v >> (i * 4)) & 0xF]; + *p = '\0'; + return p; +} + +/* ------------------------------------------------------------------ */ +/* The face */ +/* */ +/* ":(" — two dots and a parenthesis, drawn large. It is a sad face */ +/* only if you tilt your head, which is exactly why it works: it is */ +/* legible as a mood without being a picture of anything, and it does */ +/* not pretend the machine has feelings about what just happened. */ +/* */ +/* Drawn from primitives rather than stored as a bitmap, so it scales */ +/* with the display and costs no space in a kernel image that stage2 */ +/* loads one sector at a time by PIO. */ +/* ------------------------------------------------------------------ */ + +static int +isqrt(int v) +{ + if (v <= 0) + return 0; + + // Newton's method, iterated only while the estimate is still *decreasing*. + // + // The obvious "stop when it stops changing" version does not terminate: on a + // non-square it settles into a two-cycle rather than a fixed point, and + // isqrt(3) alternates between 1 and 2 forever. In a panic handler that is a + // hang with the screen half drawn and no way to find out why. + int x = v; + int y = (x + 1) / 2; + while (y < x) { + x = y; + y = (x + v / x) / 2; + } + return x; +} + +// The "(" of ":(" — the left half of a squashed circle, so the tips point right +// and the middle bulges left, the way the glyph does. +static void +draw_paren(int cx, int cy, int h, int thick, uint32 color) +{ + int r = h / 2; + for (int dy = -r; dy <= r; dy++) { + int dx = isqrt(r * r - dy * dy); + // Narrow it: a true half-circle reads as a bracket, not a parenthesis. + int x = cx - (dx * 45) / 100; + vga_fill_circle(x, cy + dy, thick / 2, color); + } +} + +static void +draw_sad_face(int x, int y, int h, uint32 color) +{ + int dot = h / 12; + int gap = h / 4; + + // The colon. + vga_fill_circle(x + dot, y + h / 2 - gap, dot, color); + vga_fill_circle(x + dot, y + h / 2 + gap, dot, color); + + // The parenthesis, a little to the right of it. + draw_paren(x + dot * 2 + h / 2, y + h / 2, h, dot * 2, color); +} + +/* ------------------------------------------------------------------ */ +/* The report */ +/* ------------------------------------------------------------------ */ + +struct field { + const char *label; + char value[72]; +}; + +#define NFIELD 10 + +static struct field fields[NFIELD]; +static int nfields; + +static struct field * +field(const char *label) +{ + if (nfields >= NFIELD) + return &fields[NFIELD - 1]; + struct field *f = &fields[nfields++]; + f->label = label; + f->value[0] = '\0'; + return f; +} + +// Collect everything worth knowing while the machine is still in the state +// that produced the fault. Interrupts are already off and no lock is taken: +// a panic that deadlocks trying to report itself tells you nothing at all. +// A short, shoutable name for the failure, derived from the panic message +// rather than declared at every call site. +// +// Windows stop codes are genuinely useful: they are the thing you search for, +// and they stay the same across builds while the prose around them changes. +// Taking the message up to its first colon (or its first few words) gets that +// for free -- "sysrq: crash requested" becomes SYSRQ, "short filewrite" becomes +// SHORT_FILEWRITE -- with no risk of a call site forgetting to supply one. +static void +stop_code(char *out, int cap, const char *reason) +{ + int n = 0; + for (int i = 0; reason[i] && n < cap - 1; i++) { + char c = reason[i]; + if (c == ':') + break; + if (c == ' ' || c == '\t') { + if (n == 0 || out[n-1] == '_') + continue; + out[n++] = '_'; + continue; + } + if (c >= 'a' && c <= 'z') c = c - 'a' + 'A'; + if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') + out[n++] = c; + } + while (n > 0 && out[n-1] == '_') + n--; + if (n == 0) + { out[n++] = 'P'; out[n++] = 'A'; out[n++] = 'N'; out[n++] = 'I'; out[n++] = 'C'; } + out[n] = '\0'; +} + +static void +gather(char *reason, addr_t *pcs, int npcs) +{ + char *e; + struct field *f; + + nfields = 0; + + f = field("Stop code"); + stop_code(f->value, sizeof(f->value), reason); + + f = field("Reason"); + put_str(f->value, f->value + sizeof(f->value), reason); + + f = field("CPU"); + e = f->value + sizeof(f->value); + put_dec(f->value, e, mycpu() ? (uint64)mycpu()->id : 0); + if (!mycpu()) + put_str(f->value, e, "unknown (very early boot)"); + + f = field("Process"); + e = f->value + sizeof(f->value); + if (myproc()) { + char *p = put_str(f->value, e, myproc()->name); + p = put_str(p, e, " pid "); + put_dec(p, e, (uint64)myproc()->pid); + } else { + put_str(f->value, e, "none -- in the kernel, not on anybody's behalf"); + } + + f = field("Uptime"); + e = f->value + sizeof(f->value); + { + char *p = put_dec(f->value, e, (uint64)ticks); + p = put_str(p, e, " ticks (about "); + p = put_dec(p, e, (uint64)ticks / 100); + put_str(p, e, " s)"); + } + + // Every address below is a link-time address. Printing where the kernel + // actually sits is what lets addr2line resolve them afterwards, and it is + // the single most useful line here when the trace is all you have. + f = field("Kernel base"); + e = f->value + sizeof(f->value); + put_hex(f->value, e, (uint64)KERNBASE, 16); + + f = field("Fault PC"); + e = f->value + sizeof(f->value); + if (npcs > 0 && pcs[0]) + put_hex(f->value, e, (uint64)pcs[0], 16); + else + put_str(f->value, e, "unavailable"); +} + +/* ------------------------------------------------------------------ */ +/* The QR code */ +/* */ +/* A panic report is only worth what can be carried away from it, and */ +/* at this point there is no network, no log to write to, and often no */ +/* second machine on the desk. Photographing the screen works but */ +/* turns a call chain into something that has to be retyped by hand, */ +/* with sixteen hex digits per frame and no way to tell 8 from B. */ +/* */ +/* A phone camera is a working out-of-band channel that needs no */ +/* driver on our side at all. See kernel/core/qr.c. */ +/* ------------------------------------------------------------------ */ + +// Deliberately not a URL. This encodes the report itself, so it goes wherever +// the person holding the phone decides -- and reaches nothing on its own. +// +// Compact because the budget is 134 bytes for the largest symbol this encoder +// builds, and a crash with a deep call chain is exactly when the budget is +// tightest. Two decisions buy most of the room: frames are stored as offsets +// from the kernel base rather than absolute addresses, which halves 16 hex +// digits to 8, and the fields are single letters. The base is included, so +// nothing is lost -- addr2line wants the link-time address and can be given it. +// +// Fields are appended in priority order and the loop simply stops when the +// buffer is full, so a long reason string costs call-chain depth rather than +// producing a report that will not encode. +static int +build_qr_payload(char *buf, int cap, char *reason, addr_t *pcs, int npcs) +{ + char *p = buf, *end = buf + cap; + + // Magic and format version, so whatever reads this later can tell what it is + // looking at and can change the layout without ambiguity. + p = put_str(p, end, "SXPSOGM1\n"); + + // The reason, not the stop code: the stop code is derived from the reason by + // stop_code() and carries strictly less, so encoding both would spend bytes + // on something the reader can recompute. + // + // Held back from the end of the buffer so that a long message costs some of + // the call chain but never all of it. A report with a sentence and no + // addresses is much harder to act on than one with addresses and a truncated + // sentence. + { + char *reason_end = end - 34; // three frames and their separators + if (reason_end > p) + p = put_str(p, reason_end, reason); + } + + p = put_str(p, end, "\nc"); + p = put_dec(p, end, mycpu() ? (uint64)mycpu()->id : 0); + p = put_str(p, end, " p"); + p = put_dec(p, end, myproc() ? (uint64)myproc()->pid : 0); + p = put_str(p, end, " t"); + p = put_dec(p, end, (uint64)ticks); + if (myproc()) { + p = put_str(p, end, " "); + p = put_str(p, end, myproc()->name); + } + + p = put_str(p, end, "\nb"); + p = put_hex(p, end, (uint64)KERNBASE, 16); + + p = put_str(p, end, "\n"); + for (int i = 0; i < npcs && pcs[i]; i++) { + // Nine bytes: eight hex digits and the separator. Stopping here rather than + // letting put_hex truncate matters -- half an address in a crash report is + // worse than one fewer address, because it looks like a real one. + if (end - p < 10) + break; + if (i) + p = put_str(p, end, " "); + // put_hex prefixes "0x", which is 14 wasted bytes across seven frames. + { + const char *d = "0123456789abcdef"; + uint64 off = (uint64)pcs[i] - (uint64)KERNBASE; + for (int k = 7; k >= 0; k--) + *p++ = d[(off >> (k * 4)) & 0xF]; + *p = '\0'; + } + } + + return (int)(p - buf); +} + +// One static symbol rather than a local: struct qr is about 3.4 KB and the +// panic path runs on whatever stack the fault left behind, which may not have +// that much room. It is only ever touched here, after everything else has +// stopped. +static struct qr panic_qr; + +// Returns the width used, so the text column knows what it may not overlap. +static int +draw_qr_panel(int sw, int sh, int ch, char *reason, addr_t *pcs, int npcs) +{ + char payload[QR_MAX_BYTES]; + int n = build_qr_payload(payload, sizeof(payload), reason, pcs, npcs); + + if (n <= 0 || qr_encode(&panic_qr, (unsigned char *)payload, n) != 0) + return 0; + + // Four modules of quiet zone, which the standard requires and which decoders + // genuinely need -- without it many will not find the symbol at all. + const int quiet = 4; + int cells = panic_qr.size + 2 * quiet; + + // Scale to about a quarter of the display, then clamp. The lower bound is + // what a phone can still resolve from a photograph of a monitor; the upper + // bound stops the thing dominating a screen whose actual job is the text. + int scale = (sw / 4) / cells; + if (scale < 3) scale = 3; + if (scale > 8) scale = 8; + + int card = cells * scale; + int x0 = sw - card - sw / 24; + int y0 = sh / 8; + + vga_fill_rect(x0, y0, card, card, PSOGM_CARD); + for (int y = 0; y < panic_qr.size; y++) + for (int x = 0; x < panic_qr.size; x++) + if (panic_qr.mod[y][x]) + vga_fill_rect(x0 + (x + quiet) * scale, y0 + (y + quiet) * scale, + scale, scale, PSOGM_INK); + + vga_text_at(x0, y0 + card + ch, "Scan for a text copy", PSOGM_DIM); + vga_text_at(x0, y0 + card + ch * 2 + 2, "of this report.", PSOGM_DIM); + + return card + sw / 24; +} + +// The frame pointers, one per line, as one string per row. +static void +trace_line(char *buf, int cap, int i, addr_t pc) +{ + char *e = buf + cap; + char *p = put_str(buf, e, " #"); + p = put_dec(p, e, (uint64)i); + p = put_str(p, e, i < 10 ? " " : " "); + put_hex(p, e, (uint64)pc, 16); +} + +/* ------------------------------------------------------------------ */ + +static void +paint(char *reason, addr_t *pcs, int npcs) +{ + int sw, sh; + vga_dims(&sw, &sh); + + int ch = vga_char_h(); + int cw = vga_char_w(); + + // The whole display, one colour. An earlier version dimmed the previous + // screen and floated a panel over it, which looked good and was wrong: the + // thing is called a Purple Screen, and half a screen of somebody's abandoned + // work behind the report is a distraction at the worst possible moment. + vga_clear(PSOGM_BG); + // Glyphs are drawn with their background filled, so the console's cream has + // to become the background or every line of text arrives in its own box. + vga_set_bg(PSOGM_BG); + + // The symbol goes first, because it decides how much width the text has. It + // is drawn before anything can fail: if the encoder refuses the payload the + // screen simply has no card and the report is unchanged. + draw_qr_panel(sw, sh, ch, reason, pcs, npcs); + + int left = sw / 8; + if (left > 110) left = 110; + int y = sh / 8; + + int face_h = 96; + draw_sad_face(left, y, face_h, PSOGM_FG); + y += face_h + ch * 2; + + // Left-aligned, not centred. Centred text reads as a poster; this is a + // report, and a report is read down the left edge. + vga_text_at(left, y, "Schunix ran into a problem and needs to restart.", + PSOGM_FG); + y += ch + ch / 2; + vga_text_at(left, y, "Nothing on your disks was touched by this.", + PSOGM_DIM); + + // A rule in the boot splash's accent, the same width as the one under the + // wordmark there, tying this screen to the one the machine started with. + // + // Equal space above and below on purpose: at any less it sits close enough to + // the line above to read as an underline of that sentence rather than as a + // divider before the facts. + y += ch * 2; + vga_fill_rect(left, y, 120, 2, SCH_ACCENT); + y += ch; + + // Facts: quiet labels down the left, bright values in a second column. + int vx = left + 14 * cw; + for (int i = 0; i < nfields; i++) { + vga_text_at(left, y, fields[i].label, PSOGM_DIM); + vga_text_at(vx, y, fields[i].value, PSOGM_FG); + y += ch + 2; + } + + y += ch; + vga_text_at(left, y, "Call chain", PSOGM_DIM); + y += ch + 2; + + for (int i = 0; i < npcs && pcs[i]; i++) { + char line[48]; + trace_line(line, sizeof(line), i, pcs[i]); + vga_text_at(vx - 3 * cw, y, line, PSOGM_FG); + y += ch; + if (y > sh - ch * 5) + break; + } + + // Two closing lines, bottom left: what to do with the numbers above, and + // what this screen is called, so it can be searched for by name. Shortened + // from the full command line, which at 62 characters ran under the QR card. + vga_text_at(left, sh - ch * 3, + "Resolve: addr2line -e kernel

", PSOGM_DIM); + vga_text_at(left, sh - ch * 3 + ch + 4, + "PSOGM -- Purple Screen of Guru Meditation", PSOGM_DIM); +} + +// Same report, down the serial line. This is the copy that survives: it is what +// bootcheck reads, and the only one that exists when the framebuffer does not. +static void +report_serial(char *reason, addr_t *pcs, int npcs) +{ + cprintf("\n"); + cprintf(" :(\n\n"); + cprintf(" Schunix ran into a problem and needs to restart.\n"); + cprintf(" PSOGM -- Purple Screen of Guru Meditation\n\n"); + + for (int i = 0; i < nfields; i++) { + // Pad the label out so the values line up, without a printf width + // specifier -- cprintf has no such thing. + int n = 0; + while (fields[i].label[n]) n++; + cprintf(" %s", fields[i].label); + for (int pad = n; pad < 14; pad++) + cprintf(" "); + cprintf("%s\n", fields[i].value); + } + + cprintf("\n Call chain\n"); + for (int i = 0; i < npcs && pcs[i]; i++) + cprintf(" #%d %p\n", i, pcs[i]); + + cprintf("\n Resolve with: addr2line -e build/kernel/kernel
\n"); + cprintf(" Reason: %s\n", reason); + cprintf(" System halted.\n"); +} + +__attribute__((noreturn)) +void +panic(char *s) +{ + addr_t pcs[10]; + + cli(); + // Stop every other path from writing to the console. consputc checks this + // and spins, which is what keeps another CPU from painting over the report + // while it is being drawn. + cons_panic_mode(); + + for (int i = 0; i < 10; i++) + pcs[i] = 0; + getcallerpcs(&s, pcs); + + gather(s, pcs, 10); + report_serial(s, pcs, 10); + + if (vga_ready()) + paint(s, pcs, 10); + + panicked = 1; + for (;;) + hlt(); +} diff --git a/kernel/core/qr.c b/kernel/core/qr.c new file mode 100644 index 0000000..f24d41c --- /dev/null +++ b/kernel/core/qr.c @@ -0,0 +1,456 @@ +// QR encoder. See include/qr.h for why it exists and why it is this small. +// +// Freestanding on purpose: no allocation, no floating point, no libc beyond +// memset/memmove. It has to run in panic context, where the heap may be exactly +// what is broken. Every buffer here is either on the caller's struct or a +// bounded local. +// +// The structure follows ISO/IEC 18004 in the order the standard describes it, +// which is also the only order in which any of it can be checked: +// +// 1. encode the payload into data codewords +// 2. append Reed-Solomon error correction, per block +// 3. interleave the blocks +// 4. draw the function patterns (finders, timing, alignment, format area) +// 5. lay the codeword bits into the remaining modules in a zigzag +// 6. try all 8 masks, score each, keep the best +// +// Verified by scanning the output with a phone, which is the only test that +// matters and is also literally the feature. + +#ifdef QR_HOST +#include +#else +#include "types.h" +#include "defs.h" +#endif + +#include "qr.h" + +// --------------------------------------------------------------------------- +// Version table +// --------------------------------------------------------------------------- +// +// Per version, at error correction level L: total codewords, error correction +// codewords per block, and number of blocks. These are from the standard's +// tables and cannot be derived, so they are the one part of this file that has +// to be right by transcription rather than by reasoning. +// +// A useful check on them: total - ecc*blocks must be divisible by blocks for +// every row below, because levels 1..6 at L happen to have equally sized +// blocks. qr_encode() asserts exactly that at runtime, which is what turns a +// mistyped number here into a visible failure instead of an unscannable symbol. +static const struct { + short total; // total codewords in the symbol + unsigned char ecc; // EC codewords per block + unsigned char blocks; // number of RS blocks +} vinfo[QR_MAX_VERSION + 1] = { + { 0, 0, 0 }, // version 0 does not exist; keeps indexing natural + { 26, 7, 1 }, + { 44, 10, 1 }, + { 70, 15, 1 }, + { 100, 20, 1 }, + { 134, 26, 1 }, + { 172, 18, 2 }, +}; + +int +qr_capacity(int version) +{ + if (version < 1 || version > QR_MAX_VERSION) + return 0; + // Data codewords, less the two bytes of framing: a 4-bit mode indicator, an + // 8-bit character count (versions 1-9), and a 4-bit terminator come to + // exactly two codewords' worth of overhead. + int data = vinfo[version].total - vinfo[version].ecc * vinfo[version].blocks; + return data - 2; +} + +// --------------------------------------------------------------------------- +// GF(256) and Reed-Solomon +// --------------------------------------------------------------------------- + +// Multiply in GF(256) modulo x^8 + x^4 + x^3 + x^2 + 1 (0x11D). +// +// Done by shift-and-add rather than log/exp tables. Two 256-byte tables plus +// their initialisation is more code than this loop, and this needs no init step +// at all -- which matters when the caller is a panic handler that cannot assume +// any particular earlier function ran. +static unsigned char +gmul(unsigned char x, unsigned char y) +{ + unsigned char z = 0; + for (int i = 7; i >= 0; i--) { + z = (unsigned char)((z << 1) ^ ((z >> 7) * 0x1D)); + z ^= (unsigned char)(((y >> i) & 1) * x); + } + return z; +} + +// Coefficients of the degree-`degree` generator polynomial, highest power +// first, with the leading 1 left implicit. +static void +rs_divisor(int degree, unsigned char *result) +{ + memset(result, 0, degree); + result[degree - 1] = 1; // start at the monomial x^0 + + // Multiply by (x - r) for r = 1, a, a^2, ... Each pass shifts the polynomial + // up one degree and folds in the new root. + unsigned char root = 1; + for (int i = 0; i < degree; i++) { + for (int j = 0; j < degree; j++) { + result[j] = gmul(result[j], root); + if (j + 1 < degree) + result[j] ^= result[j + 1]; + } + root = gmul(root, 0x02); + } +} + +// The remainder of data[] divided by the generator: the EC codewords. +static void +rs_remainder(const unsigned char *data, int len, + const unsigned char *gen, int degree, unsigned char *result) +{ + memset(result, 0, degree); + for (int i = 0; i < len; i++) { + unsigned char factor = data[i] ^ result[0]; + memmove(&result[0], &result[1], degree - 1); + result[degree - 1] = 0; + for (int j = 0; j < degree; j++) + result[j] ^= gmul(gen[j], factor); + } +} + +// --------------------------------------------------------------------------- +// Module access +// --------------------------------------------------------------------------- + +static void +set_fn(struct qr *q, int x, int y, int dark) +{ + if (x < 0 || y < 0 || x >= q->size || y >= q->size) + return; + q->mod[y][x] = (unsigned char)(dark != 0); + q->fn[y][x] = 1; +} + +static int +absi(int v) +{ + return v < 0 ? -v : v; +} + +static int +cheb(int dx, int dy) +{ + int ax = absi(dx), ay = absi(dy); + return ax > ay ? ax : ay; +} + +// --------------------------------------------------------------------------- +// Function patterns +// --------------------------------------------------------------------------- + +// A finder plus its separator, as one 9x9 stamp centred on (cx, cy). +// +// Writing it by Chebyshev distance rather than as a literal bitmap is not +// cleverness for its own sake: the concentric rings *are* the definition -- dark +// 3x3 core, light ring, dark ring, light separator -- and the edge stamps run +// off the symbol, which set_fn() clips. +static void +draw_finder(struct qr *q, int cx, int cy) +{ + for (int dy = -4; dy <= 4; dy++) + for (int dx = -4; dx <= 4; dx++) { + int d = cheb(dx, dy); + set_fn(q, cx + dx, cy + dy, d != 2 && d != 4); + } +} + +// The 5x5 alignment pattern: dark 3x3 outline with a light ring inside. +static void +draw_alignment(struct qr *q, int cx, int cy) +{ + for (int dy = -2; dy <= 2; dy++) + for (int dx = -2; dx <= 2; dx++) + set_fn(q, cx + dx, cy + dy, cheb(dx, dy) != 1); +} + +// The 15-bit format information, twice, plus the always-dark module. +// +// Called once with the real mask at the end, and once early with mask 0 purely +// to *reserve* these modules -- the zigzag below skips anything marked as a +// function pattern, so the reservation has to exist before data is placed. +static void +draw_format(struct qr *q, int mask) +{ + // 0b01 is error correction level L. Five data bits, then a BCH(15,5) check + // computed with generator 0x537, then XOR 0x5412 so an all-zero format never + // produces an all-zero pattern. + int data = (1 << 3) | mask; + int rem = data; + for (int i = 0; i < 10; i++) + rem = (rem << 1) ^ ((rem >> 9) * 0x537); + int bits = ((data << 10) | rem) ^ 0x5412; + + int n = q->size; + + // First copy: down the left of the top-right finder, then left along the top + // of the bottom-left one. The 6/7 and 7/8 jogs skip the timing pattern. + for (int i = 0; i <= 5; i++) + set_fn(q, 8, i, (bits >> i) & 1); + set_fn(q, 8, 7, (bits >> 6) & 1); + set_fn(q, 8, 8, (bits >> 7) & 1); + set_fn(q, 7, 8, (bits >> 8) & 1); + for (int i = 9; i < 15; i++) + set_fn(q, 14 - i, 8, (bits >> i) & 1); + + // Second copy, so the format survives damage to either corner. + for (int i = 0; i < 8; i++) + set_fn(q, n - 1 - i, 8, (bits >> i) & 1); + for (int i = 8; i < 15; i++) + set_fn(q, 8, n - 15 + i, (bits >> i) & 1); + + set_fn(q, 8, n - 8, 1); // the dark module, always set, always here +} + +static void +draw_function_patterns(struct qr *q) +{ + int n = q->size; + + // Timing patterns first: the finders overwrite their ends, which is correct. + for (int i = 0; i < n; i++) { + set_fn(q, 6, i, i % 2 == 0); + set_fn(q, i, 6, i % 2 == 0); + } + + draw_finder(q, 3, 3); + draw_finder(q, n - 4, 3); + draw_finder(q, 3, n - 4); + + // For versions 2-6 the alignment centres are {6, n-7}, and three of those + // four combinations collide with a finder. Only the bottom-right survives, + // which is why there is no position table here. Version 7 would need one. + if (q->size > 21) + draw_alignment(q, n - 7, n - 7); + + draw_format(q, 0); // reserve; overwritten once a mask is chosen +} + +// --------------------------------------------------------------------------- +// Masking +// --------------------------------------------------------------------------- + +static int +mask_bit(int mask, int x, int y) +{ + switch (mask) { + case 0: return (x + y) % 2 == 0; + case 1: return y % 2 == 0; + case 2: return x % 3 == 0; + case 3: return (x + y) % 3 == 0; + case 4: return (x / 3 + y / 2) % 2 == 0; + case 5: return x * y % 2 + x * y % 3 == 0; + case 6: return (x * y % 2 + x * y % 3) % 2 == 0; + case 7: return ((x + y) % 2 + x * y % 3) % 2 == 0; + } + return 0; +} + +static void +apply_mask(struct qr *q, int mask) +{ + for (int y = 0; y < q->size; y++) + for (int x = 0; x < q->size; x++) + if (!q->fn[y][x]) + q->mod[y][x] ^= (unsigned char)mask_bit(mask, x, y); +} + +// The standard's four penalty rules. Lower is better. +// +// A decoder will read any legal mask, so this is not correctness -- it is scan +// reliability, which is the whole point when the reader is a handheld camera +// pointed at a screen. Rule 3 in particular exists to stop the data accidentally +// containing something that looks like a finder pattern. +static int +penalty(const struct qr *q) +{ + int n = q->size, score = 0, dark = 0; + + for (int y = 0; y < n; y++) { + for (int x = 0; x < n; x++) + dark += q->mod[y][x]; + + // Rule 1, both directions: runs of five or more identical modules. + for (int dir = 0; dir < 2; dir++) { + int run = 1; + int prev = dir ? q->mod[0][y] : q->mod[y][0]; + for (int i = 1; i < n; i++) { + int cur = dir ? q->mod[i][y] : q->mod[y][i]; + if (cur == prev) { + run++; + } else { + if (run >= 5) score += 3 + (run - 5); + run = 1; + prev = cur; + } + } + if (run >= 5) score += 3 + (run - 5); + } + } + + // Rule 2: every 2x2 block of one colour. + for (int y = 0; y + 1 < n; y++) + for (int x = 0; x + 1 < n; x++) { + int c = q->mod[y][x]; + if (c == q->mod[y][x + 1] && c == q->mod[y + 1][x] && c == q->mod[y + 1][x + 1]) + score += 3; + } + + // Rule 3: the finder-lookalike 1011101 with four light modules on either + // side, in either direction. + for (int dir = 0; dir < 2; dir++) + for (int a = 0; a < n; a++) { + unsigned bits = 0; + for (int b = 0; b < n; b++) { + int m = dir ? q->mod[b][a] : q->mod[a][b]; + bits = ((bits << 1) | (unsigned)m) & 0x7FF; + if (b >= 10 && (bits == 0x05D || bits == 0x5D0)) + score += 40; + } + } + + // Rule 4: deviation from an even split of dark and light, in 5% steps. + int total = n * n; + int k = (absi(dark * 20 - total * 10) + total - 1) / total; + score += k * 10; + + return score; +} + +// --------------------------------------------------------------------------- +// Encode +// --------------------------------------------------------------------------- + +static void +put_bits(unsigned char *buf, int *pos, unsigned val, int n) +{ + for (int i = n - 1; i >= 0; i--) { + buf[*pos >> 3] |= (unsigned char)(((val >> i) & 1) << (7 - (*pos & 7))); + (*pos)++; + } +} + +int +qr_encode(struct qr *q, const unsigned char *data, int len) +{ + int v; + + if (len < 0) + return -1; + for (v = 1; v <= QR_MAX_VERSION; v++) + if (len <= qr_capacity(v)) + break; + if (v > QR_MAX_VERSION) + return -1; + + int total = vinfo[v].total; + int ecclen = vinfo[v].ecc; + int blocks = vinfo[v].blocks; + int datacw = total - ecclen * blocks; + + // The table claims equal-sized blocks for every version this file supports. + // If that is ever untrue the interleave below is silently wrong, so check it + // rather than trust it. + if (datacw % blocks != 0) + return -1; + int blocklen = datacw / blocks; + + // --- 1. payload -> data codewords --------------------------------------- + unsigned char cw[172]; // >= max total codewords + memset(cw, 0, sizeof(cw)); + + int pos = 0; + put_bits(cw, &pos, 0x4, 4); // byte mode + put_bits(cw, &pos, (unsigned)len, 8); + for (int i = 0; i < len; i++) + put_bits(cw, &pos, data[i], 8); + + // Terminator, up to four zero bits, then round up to a whole codeword. + int spare = datacw * 8 - pos; + put_bits(cw, &pos, 0, spare < 4 ? spare : 4); + if (pos & 7) + put_bits(cw, &pos, 0, 8 - (pos & 7)); + + // Fill the rest with the standard alternating pad bytes. They are specified + // values, not arbitrary filler: a decoder uses the character count to know + // where the data ends, but the pad pattern keeps the symbol from having large + // uniform regions that mask selection would then have to fight. + for (int i = pos / 8; i < datacw; i++) + cw[i] = (i - pos / 8) % 2 == 0 ? 0xEC : 0x11; + + // --- 2 and 3. error correction, then interleave ------------------------- + unsigned char gen[30]; + unsigned char ec[4][30]; + rs_divisor(ecclen, gen); + for (int b = 0; b < blocks; b++) + rs_remainder(&cw[b * blocklen], blocklen, gen, ecclen, ec[b]); + + unsigned char out[172]; + int o = 0; + for (int i = 0; i < blocklen; i++) + for (int b = 0; b < blocks; b++) + out[o++] = cw[b * blocklen + i]; + for (int i = 0; i < ecclen; i++) + for (int b = 0; b < blocks; b++) + out[o++] = ec[b][i]; + + // --- 4. function patterns ------------------------------------------------ + memset(q, 0, sizeof(*q)); + q->size = 17 + 4 * v; + draw_function_patterns(q); + + // --- 5. zigzag placement ------------------------------------------------- + // + // Two-module-wide columns walked from the right edge leftwards, alternating + // upward and downward. Column 6 is skipped entirely because it is the vertical + // timing pattern -- without that step every subsequent column lands one place + // out and the symbol is quietly unreadable. + int bit = 0; + int nbits = o * 8; + for (int right = q->size - 1; right >= 1; right -= 2) { + if (right == 6) + right = 5; + for (int vert = 0; vert < q->size; vert++) { + for (int j = 0; j < 2; j++) { + int x = right - j; + int upward = ((right + 1) & 2) == 0; + int y = upward ? q->size - 1 - vert : vert; + if (!q->fn[y][x] && bit < nbits) { + q->mod[y][x] = (unsigned char)((out[bit >> 3] >> (7 - (bit & 7))) & 1); + bit++; + } + } + } + } + + // --- 6. pick a mask ------------------------------------------------------ + int best = 0, bestscore = 0; + for (int m = 0; m < 8; m++) { + apply_mask(q, m); + draw_format(q, m); + int s = penalty(q); + if (m == 0 || s < bestscore) { + bestscore = s; + best = m; + } + apply_mask(q, m); // XOR again to undo; masking is involutive + } + apply_mask(q, best); + draw_format(q, best); + + return 0; +} diff --git a/kernel/core/sleeplock.c b/kernel/core/sleeplock.c new file mode 100644 index 0000000..987dd34 --- /dev/null +++ b/kernel/core/sleeplock.c @@ -0,0 +1,55 @@ +// Sleeping locks + +#include "types.h" +#include "defs.h" +#include "param.h" +#include "x86.h" +#include "memlayout.h" +#include "mmu.h" +#include "proc.h" +#include "spinlock.h" +#include "sleeplock.h" + +void +initsleeplock(struct sleeplock *lk, char *name) +{ + initlock(&lk->lk, "sleep lock"); + lk->name = name; + lk->locked = 0; + lk->pid = 0; +} + +void +acquiresleep(struct sleeplock *lk) +{ + acquire(&lk->lk); + while (lk->locked) { + sleep(lk, &lk->lk); + } + lk->locked = 1; + if (myproc()) { + lk->pid = myproc()->pid; + } else { + lk->pid = 0; + } + release(&lk->lk); +} + +void +releasesleep(struct sleeplock *lk) +{ + acquire(&lk->lk); + lk->locked = 0; + lk->pid = 0; + wakeup(lk); + release(&lk->lk); +} + +int +holdingsleep(struct sleeplock *lk) +{ + acquire(&lk->lk); + int r = lk->locked; + release(&lk->lk); + return r; +} diff --git a/kernel/core/spinlock.c b/kernel/core/spinlock.c new file mode 100644 index 0000000..7b593db --- /dev/null +++ b/kernel/core/spinlock.c @@ -0,0 +1,115 @@ +#include "types.h" +#include "defs.h" +#include "param.h" +#include "x86.h" +#include "memlayout.h" +#include "mmu.h" +#include "proc.h" +#include "spinlock.h" + +void +initlock(struct spinlock *lk, char *name) +{ + lk->name = name; + lk->locked = 0; + lk->cpu = 0; +} + +void +acquire(struct spinlock *lk) +{ + pushcli(); + if(holding(lk)) + panic("acquire"); + + { + uint64 spins = 0; + while(xchg(&lk->locked, 1) != 0){ + if(++spins == 200000000ULL){ + cprintf("acquire: stuck on \"%s\" held by cpu=%p pcs0=%p pcs1=%p pcs2=%p, acquirer cpu=%p\n", + lk->name, lk->cpu, lk->pcs[0], lk->pcs[1], lk->pcs[2], mycpu()); + panic("acquire: deadlock"); + } + } + } + + __sync_synchronize(); + + lk->cpu = mycpu(); + getcallerpcs(&lk, lk->pcs); +} + +void +release(struct spinlock *lk) +{ + if(!holding(lk)) + panic("release"); + + lk->pcs[0] = 0; + lk->cpu = 0; + + __sync_synchronize(); + + asm volatile("movq $0, %0" : "+m" (lk->locked) : ); + + popcli(); +} + +void +getcallerpcs(void *v, addr_t pcs[]) +{ + addr_t *rbp; + + asm volatile("mov %%rbp, %0" : "=r" (rbp)); + getstackpcs(rbp, pcs); +} + +void +getstackpcs(addr_t *rbp, addr_t pcs[]) +{ + int i; + + for(i = 0; i < 10; i++){ + if(rbp == 0 || rbp < (addr_t*)KERNBASE || rbp == (addr_t*)0xffffffff) + break; + pcs[i] = rbp[1]; + rbp = (addr_t*)rbp[0]; + } + for(; i < 10; i++) + pcs[i] = 0; +} + +int +holding(struct spinlock *lock) +{ + return lock->locked && lock->cpu == mycpu(); +} + +void +pushcli(void) +{ + int eflags; + + eflags = readeflags(); + cli(); + if(mycpu() == 0){ + extern uint64 kernel_fs_base; + cprintf("pushcli: cpu==NULL cs=0x%p kernel_fs_base=0x%p actual_fs_base=0x%p\n", + readcs(), kernel_fs_base, rdmsr(0xC0000100)); + panic("pushcli: cpu is NULL"); + } + if(mycpu()->ncli == 0) + mycpu()->intena = eflags & FL_IF; + mycpu()->ncli += 1; +} + +void +popcli(void) +{ + if(readeflags()&FL_IF) + panic("popcli - interruptible"); + if(--mycpu()->ncli < 0) + panic("popcli"); + if(mycpu()->ncli == 0 && mycpu()->intena) + sti(); +} diff --git a/kernel/core/string.c b/kernel/core/string.c new file mode 100644 index 0000000..91f50ce --- /dev/null +++ b/kernel/core/string.c @@ -0,0 +1,113 @@ +#include "types.h" +#include "x86.h" + +void* +memset(void *dst, int c, uint64 n) +{ + uint64 c64; + + if ((addr_t)dst % 8 == 0 && n % 8 == 0) { + c &= 0xFF; + c64 = (uint64)c; + c64 = (c64 << 56) | (c64 << 48) | (c64 << 40) | (c64 << 32) | + (c64 << 24) | (c64 << 16) | (c64 << 8) | c64; + stosq(dst, c64, n / 8); + } else { + stosb(dst, c, n); + } + return dst; +} + +int +memcmp(const void *v1, const void *v2, uint n) +{ + const uchar *s1, *s2; + + s1 = v1; + s2 = v2; + while(n-- > 0){ + if(*s1 != *s2) + return *s1 - *s2; + s1++, s2++; + } + + return 0; +} + +void* +memmove(void *dst, const void *src, uint n) +{ + const char *s; + char *d; + + s = src; + d = dst; + if(s < d && s + n > d){ + s += n; + d += n; + while(n-- > 0) + *--d = *--s; + } else + while(n-- > 0) + *d++ = *s++; + + return dst; +} + +void* +memcpy(void *dst, const void *src, uint n) +{ + return memmove(dst, src, n); +} + +int +strncmp(const char *p, const char *q, uint n) +{ + while(n > 0 && *p && *p == *q) + n--, p++, q++; + if(n == 0) + return 0; + return (uchar)*p - (uchar)*q; +} + +char* +strncpy(char *s, const char *t, int n) +{ + char *os = s; + while(n-- > 0 && (*s++ = *t++) != 0) + ; + while(n-- > 0) + *s++ = 0; + return os; +} + +char* +safestrcpy(char *s, const char *t, int n) +{ + char *os = s; + if(n <= 0) + return os; + while(--n > 0 && (*s++ = *t++) != 0) + ; + *s = 0; + return os; +} + +int +strlen(const char *s) +{ + int n; + + for(n = 0; s[n]; n++) + ; + return n; +} + +int +strnlen(const char *s, int max) +{ + int n; + for(n = 0; n < max && s[n]; n++) + ; + return n; +} diff --git a/kernel/core/time.c b/kernel/core/time.c new file mode 100644 index 0000000..d61f6a6 --- /dev/null +++ b/kernel/core/time.c @@ -0,0 +1,116 @@ +// Wall-clock time. +// +// 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 +// 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 +// 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 +// counting from the wrong place rather than not counting at all. +// +// cmostime() in kernel/arch/x86_64/lapic.c has been able to read the hardware +// clock the whole time. Nothing called it. +// +// The arrangement here is the usual one: read the RTC once at boot, convert it +// to a Unix timestamp, and add uptime to it thereafter. The RTC is slow to read +// (it is polled over two I/O ports and has to be sampled twice to catch it +// mid-update) so reading it on every gettimeofday would be absurd; and `ticks` +// is a perfectly good interval clock once it has something to count from. + +#include "types.h" +#include "defs.h" +#include "date.h" +#include "param.h" +#include "spinlock.h" + +extern uint ticks; + +// Seconds between the Unix epoch and the moment this machine booted. Zero until +// time_init() runs, which makes the behaviour before that point exactly what it +// used to be -- uptime presented as absolute time -- rather than something new +// and differently wrong. +uint64 boot_epoch; + +// Days from 1970-01-01 to the given civil date, proleptic Gregorian. +// +// Howard Hinnant's days_from_civil. It is worth using rather than a loop over +// years because it is branchless, exact for any year, and has no table to get +// wrong; the alternative -- accumulating 365 or 366 days per year since 1970 -- +// gets leap centuries wrong unless you remember that 1900 was not a leap year +// and 2000 was, which is precisely the sort of thing that is discovered on a +// February morning years later. +// +// The trick is shifting the year so that March is month 1, which puts the leap +// day at the *end* of the year and makes the leap rule depend only on the year +// number rather than on where in the year you are. +static int64 +days_from_civil(int64 y, unsigned m, unsigned d) +{ + y -= m <= 2; + const int64 era = (y >= 0 ? y : y - 399) / 400; + const unsigned yoe = (unsigned)(y - era * 400); // [0, 399] + const unsigned doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; + const unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096] + return era * 146097 + (int64)doe - 719468; +} + +// Read the hardware clock and work out when we booted. +// +// The RTC is read in UTC. That is not universally true on a PC -- a machine +// that has had Windows installed on it usually keeps the RTC in local time -- +// but there is nowhere to store a timezone yet and no way to ask, and UTC is +// the honest default for a system with no configuration. When there is a +// settings store, this is where the offset goes. +void +time_init(void) +{ + struct rtcdate r; + + cmostime(&r); + + // cmostime() returns a two-digit year on hardware that only stores one. + // 2000-2099 is the right guess now and stays right for a lifetime; a machine + // reporting 70 means the battery is flat, and the epoch is as good an answer + // as any for that. + int64 year = r.year; + if (year < 100) + year += 2000; + + // A wildly implausible reading means the CMOS is not telling us anything. + // Leaving boot_epoch at zero keeps the old behaviour, which is wrong but + // predictable, rather than putting the machine somewhere in the Bronze Age. + if (r.month < 1 || r.month > 12 || r.day < 1 || r.day > 31 || + r.hour > 23 || r.minute > 59 || r.second > 60 || year < 1970) { + cprintf("time: CMOS clock is not plausible, staying at the epoch\n"); + return; + } + + int64 days = days_from_civil(year, r.month, r.day); + uint64 now = (uint64)(days * 86400) + r.hour * 3600 + r.minute * 60 + r.second; + + // Subtract the uptime so far, so boot_epoch is the moment of boot rather than + // the moment this function ran. It is only a fraction of a second, but it + // keeps boot_epoch meaning exactly what its name says. + uint64 up = ticks / 100; + boot_epoch = now > up ? now - up : now; + + cprintf("time: %d-%d-%d %d:%d:%d UTC from the hardware clock\n", + (int)year, r.month, r.day, r.hour, r.minute, r.second); +} + +// Seconds and microseconds since the epoch. One place, so gettimeofday, +// clock_gettime and anything added later cannot disagree about what time it is. +void +wallclock(uint64 *sec, uint64 *usec) +{ + uint xticks; + + acquire(&tickslock); + xticks = ticks; + release(&tickslock); + + if (sec) + *sec = boot_epoch + xticks / 100; + if (usec) + *usec = (uint64)(xticks % 100) * 10000; +} diff --git a/kernel/core/uaccess.c b/kernel/core/uaccess.c new file mode 100644 index 0000000..2280e64 --- /dev/null +++ b/kernel/core/uaccess.c @@ -0,0 +1,79 @@ +// User-memory access helpers — see include/uaccess.h for the rules. +// +// Everything here validates against the *current* process's page table +// (myproc()->pgdir), which is also the live CR3 while a syscall runs, so a +// range that passes access_ok() can be dereferenced directly by kernel +// code for the remainder of the syscall (single-threaded processes can't +// unmap it out from under us mid-call). + +#include "types.h" +#include "defs.h" +#include "param.h" +#include "memlayout.h" +#include "mmu.h" +#include "proc.h" +#include "errno.h" +#include "uaccess.h" + +int +access_ok(addr_t uaddr, uint64 size) +{ + addr_t a, end; + + if(size == 0) + return 1; + end = uaddr + size; + if(end < uaddr || end > KERNBASE) + return 0; + for(a = PGROUNDDOWN(uaddr); a < end; a += PGSIZE) + if(uva2ka(myproc()->pgdir, (char*)a) == 0) + return 0; + return 1; +} + +void* +user_ptr(addr_t uaddr, uint64 size) +{ + if(uaddr == 0 || !access_ok(uaddr, size)) + return 0; + return (void*)uaddr; +} + +int +copy_from_user(void *dst, addr_t uaddr, uint64 n) +{ + if(uaddr + n < uaddr || uaddr + n > KERNBASE) + return -EFAULT; + if(copyin(myproc()->pgdir, uaddr, dst, n) < 0) + return -EFAULT; + return 0; +} + +int +copy_to_user(addr_t uaddr, const void *src, uint64 n) +{ + if(uaddr + n < uaddr || uaddr + n > KERNBASE) + return -EFAULT; + if(copyout(myproc()->pgdir, uaddr, (void*)src, n) < 0) + return -EFAULT; + return 0; +} + +long +strlen_user(addr_t uaddr) +{ + addr_t a = uaddr; + + while(a - uaddr < USER_STR_MAX){ + // Scan through the per-page kernel alias so an unmapped page is a + // clean failure instead of a fault. + char *ka = uva2ka(myproc()->pgdir, (char*)a); + if(ka == 0) + return -EFAULT; + addr_t pgend = PGROUNDDOWN(a) + PGSIZE; + for(; a < pgend; a++, ka++) + if(*ka == 0) + return a - uaddr; + } + return -EFAULT; +} diff --git a/kernel/dev/bio.c b/kernel/dev/bio.c new file mode 100644 index 0000000..7685c87 --- /dev/null +++ b/kernel/dev/bio.c @@ -0,0 +1,160 @@ +// Buffer cache. +// +// The buffer cache is a linked list of buf structures holding +// cached copies of disk block contents. Caching disk blocks +// in memory reduces the number of disk reads and also provides +// a synchronization point for disk blocks used by multiple processes. +// +// Interface: +// * To get a buffer for a particular disk block, call bread. +// * After changing buffer data, call bwrite to write it to disk. +// * When done with the buffer, call brelse. +// * Do not use the buffer after calling brelse. +// * Only one process at a time can use a buffer, +// so do not keep them longer than necessary. +// +// The implementation uses two state flags internally: +// * B_VALID: the buffer data has been read from the disk. +// * B_DIRTY: the buffer data has been modified +// and needs to be written to disk. + +#include "types.h" +#include "defs.h" +#include "param.h" +#include "spinlock.h" +#include "sleeplock.h" +#include "fs.h" +#include "buf.h" + +struct { + struct spinlock lock; + struct buf buf[NBUF]; + + // Linked list of all buffers, through prev/next. + // head.next is most recently used. + struct buf head; +} bcache; + +void +binit(void) +{ + struct buf *b; + + initlock(&bcache.lock, "bcache"); +//PAGEBREAK! + + // Create linked list of buffers + bcache.head.prev = &bcache.head; + bcache.head.next = &bcache.head; + for(b = bcache.buf; b < bcache.buf+NBUF; b++){ + b->next = bcache.head.next; + b->prev = &bcache.head; + initsleeplock(&b->lock, "buffer"); + bcache.head.next->prev = b; + bcache.head.next = b; + } +} + +// Route a request to the driver that owns b->dev. Everything above this line +// is device-agnostic; everything below picks a backend. RAMDISK_DEV is served +// out of memory (kernel/dev/ramdisk.c), USBDISK_DEV by bulk transfers to a +// USB stick, everything else by the IDE driver. +static void +bdevrw(struct buf *b) +{ + if(b->dev == RAMDISK_DEV){ + ramdiskrw(b); + return; + } + if(b->dev == USBDISK_DEV){ + usb_storage_rw(b); + return; + } + iderw(b); +} + +// Look through buffer cache for block on device dev. +// If not found, allocate a buffer. +// In either case, return locked buffer. +static struct buf* +bget(uint dev, uint blockno) +{ + struct buf *b; + + acquire(&bcache.lock); + + // Is the block already cached? + for(b = bcache.head.next; b != &bcache.head; b = b->next){ + if(b->dev == dev && b->blockno == blockno){ + b->refcnt++; + release(&bcache.lock); + acquiresleep(&b->lock); + return b; + } + } + + // Not cached; recycle some unused buffer and clean buffer + // "clean" because B_DIRTY and not locked means log.c + // hasn't yet committed the changes to the buffer. + for(b = bcache.head.prev; b != &bcache.head; b = b->prev){ + if(b->refcnt == 0 && (b->flags & B_DIRTY) == 0) { + b->dev = dev; + b->blockno = blockno; + b->flags = 0; + b->refcnt = 1; + release(&bcache.lock); + acquiresleep(&b->lock); + return b; + } + } + panic("bget: no buffers"); +} + +// Return a locked buf with the contents of the indicated block. +struct buf* +bread(uint dev, uint blockno) +{ + struct buf *b; + + b = bget(dev, blockno); + if(!(b->flags & B_VALID)) { + bdevrw(b); + } + return b; +} + +// Write b's contents to disk. Must be locked. +void +bwrite(struct buf *b) +{ + if(!holdingsleep(&b->lock)) + panic("bwrite"); + b->flags |= B_DIRTY; + bdevrw(b); +} + +// Release a locked buffer. +// Move to the head of the MRU list. +void +brelse(struct buf *b) +{ + if(!holdingsleep(&b->lock)) + panic("brelse"); + + releasesleep(&b->lock); + + acquire(&bcache.lock); + b->refcnt--; + if (b->refcnt == 0) { + // no one is waiting for it. + b->next->prev = b->prev; + b->prev->next = b->next; + b->next = bcache.head.next; + b->prev = &bcache.head; + bcache.head.next->prev = b; + bcache.head.next = b; + } + + release(&bcache.lock); +} +//PAGEBREAK! diff --git a/kernel/dev/cdev.c b/kernel/dev/cdev.c new file mode 100644 index 0000000..004fe9f --- /dev/null +++ b/kernel/dev/cdev.c @@ -0,0 +1,107 @@ +#include "types.h" +#include "defs.h" +#include "param.h" +#include "spinlock.h" +#include "sleeplock.h" +#include "fs.h" +#include "file.h" +#include "x86.h" +#include "errno.h" + +extern int consoleread(struct inode*, uint, char*, int); +extern int consolewrite(struct inode*, uint, char*, int); +extern int mouseread(struct inode*, uint, char*, int); + +static uint64 rseed = 0x2A99554433221100ULL; + +int +nullwrite(struct inode *ip, uint off, char *dst, int n) +{ + return n; +} + +int +nullread(struct inode *ip, uint off, char *dst, int n) +{ + return 0; +} + +int +zeroread(struct inode *ip, uint off, char *dst, int n) +{ + memset(dst, 0, n); + return n; +} + +int +randomread(struct inode *ip, uint off, char *dst, int n) +{ + for(int i = 0; i < n; i++){ + rseed = rseed * 6364136223846793005ULL + 1442695040888963407ULL; + dst[i] = (rseed >> 32) & 0xFF; + } + return n; +} + +// /dev/full — reads as an endless run of zero bytes, every write fails with +// ENOSPC. Programs use it to exercise their out-of-disk-space paths. +int +fullwrite(struct inode *ip, uint off, char *dst, int n) +{ + return -ENOSPC; +} + +int +mousewrite(struct inode *ip, uint off, char *dst, int n) +{ + return n; +} + +int +memread(struct inode *ip, uint off, char *dst, int n) +{ + switch(ip->minor) { + case 1: return consoleread(ip, off, dst, n); + case 2: return nullread(ip, off, dst, n); + case 3: return consoleread(ip, off, dst, n); + case 5: return zeroread(ip, off, dst, n); + case 7: return zeroread(ip, off, dst, n); // /dev/full reads as zeros + case 8: + case 9: return randomread(ip, off, dst, n); + default: return -1; + } +} + +int +memwrite(struct inode *ip, uint off, char *dst, int n) +{ + switch(ip->minor) { + case 1: return consolewrite(ip, off, dst, n); + case 7: return fullwrite(ip, off, dst, n); // /dev/full: always ENOSPC + case 2: + case 5: + case 8: + case 9: return nullwrite(ip, off, dst, n); + default: return -1; + } +} + +struct devsw devsw[] = { + [0] = { 0, 0 }, + [1] = { memread, memwrite }, + // /dev/fb0 (major 2) — the framebuffer, kernel/dev/fb.c. This used to be + // { nullread, nullwrite }, so writing pixels to it succeeded and did + // nothing. + // The close hook gives the text console its screen back when whatever was + // drawing on the framebuffer exits — see fbclose(). + [2] = { fbread, fbwrite, 0, fbclose }, + [3] = { mouseread, mousewrite }, + [4] = { 0, 0 }, + // /dev/tty (major 5) — alias for the console + [5] = { memread, memwrite }, + // /proc status files (major 6) — see kernel/dev/procfs.c + [6] = { procread, procwrite }, + // /dev/input/eventN (major 7) — raw evdev events, kernel/dev/input.c. The + // minor is the device index, so event0 is the keyboard and event1 the mouse. + [7] = { inputread, inputwrite, inputready, inputclose, inputopen }, +}; diff --git a/kernel/dev/device.c b/kernel/dev/device.c new file mode 100644 index 0000000..db0906a --- /dev/null +++ b/kernel/dev/device.c @@ -0,0 +1,308 @@ +// The device model. See include/device.h for why it exists. +// +// A fixed table rather than a linked list: this is populated once during boot +// by whichever bus found each device, and read afterwards. Nothing is removed +// yet -- hot-unplug would need it, and when that arrives the in_use flag is +// already the hook for it. +// +// No lock. Every device_add() happens during single-threaded boot, before +// userspace exists, and every reader afterwards only walks. If a bus ever +// enumerates at runtime -- USB hotplug is the obvious one -- this needs a +// spinlock, and the reader in procfs needs to take it. + +#include "types.h" +#include "defs.h" +#include "param.h" +#include "device.h" +#include "display.h" +#include "theme.h" +#include "text.h" + +static struct device devices[NDEVICE]; +static int ndevices; + +static const char *bus_names[DEVBUS_NBUS] = { + [DEVBUS_PLATFORM] = "platform", + [DEVBUS_PCI] = "pci", + [DEVBUS_USB] = "usb", +}; + +static const char *class_names[DEVCLASS_NCLASS] = { + [DEVCLASS_OTHER] = "other", + [DEVCLASS_DISPLAY] = "display", + [DEVCLASS_INPUT] = "input", + [DEVCLASS_STORAGE] = "storage", + [DEVCLASS_NET] = "net", + [DEVCLASS_BUS] = "bus", +}; + +const char * +dev_bus_name(enum dev_bus b) +{ + if (b < 0 || b >= DEVBUS_NBUS || !bus_names[b]) + return "?"; + return bus_names[b]; +} + +const char * +dev_class_name(enum dev_class c) +{ + if (c < 0 || c >= DEVCLASS_NCLASS || !class_names[c]) + return "?"; + return class_names[c]; +} + +// How many devices already share this base name, so "vga" becomes vga0, vga1. +static int +count_base(const char *base) +{ + int n = 0; + for (int i = 0; i < ndevices; i++) { + const char *a = devices[i].name, *b = base; + while (*b && *a == *b) { a++; b++; } + // Matched the whole base and the rest is the index we appended. + if (*b == '\0' && *a >= '0' && *a <= '9') + n++; + } + return n; +} + +struct device * +device_add(const char *base, enum dev_bus bus, enum dev_class class, + const char *driver) +{ + if (ndevices >= NDEVICE) + return 0; + + struct device *d = &devices[ndevices++]; + d->bus = bus; + d->class = class; + d->driver = driver; + d->in_use = 1; + + int idx = count_base(base); + int n = 0; + while (base[n] && n < DEV_NAMELEN - 3) { + d->name[n] = base[n]; + n++; + } + // Single digit is enough for NDEVICE of 32 per base name, and a two-digit + // path that is never taken is a two-digit path that is never tested. + if (idx > 9) + idx = 9; + d->name[n++] = (char)('0' + idx); + d->name[n] = '\0'; + + return d; +} + +void +device_set_desc(struct device *d, const char *s) +{ + if (!d) + return; + int n = 0; + while (s[n] && n < (int)sizeof(d->desc) - 1) { + d->desc[n] = s[n]; + n++; + } + d->desc[n] = '\0'; +} + +struct device * +device_at(int i) +{ + if (i < 0 || i >= ndevices) + return 0; + return &devices[i]; +} + +int +device_count(void) +{ + return ndevices; +} + +struct device * +device_find_class(enum dev_class class) +{ + for (int i = 0; i < ndevices; i++) + // Unclaimed devices are deliberately skipped. A display nobody drives is + // not a display you can draw on, and returning it would push the "is there + // a driver" check out to every caller. + if (devices[i].class == class && devices[i].driver) + return &devices[i]; + return 0; +} + +// --- the display class ----------------------------------------------------- +// +// Thin wrappers over device_find_class() plus a null check on each op. They +// exist so that consumers are not each written around a vtable that may be +// absent -- a compositor asking to present on a machine with no display driver +// should be a no-op, not a null dereference in the middle of a frame. + +struct device * +display_get(void) +{ + return device_find_class(DEVCLASS_DISPLAY); +} + +int +display_mode(struct display_mode *out) +{ + struct device *d = display_get(); + if (!d || !d->ops || !((struct display_ops *)d->ops)->mode) + return -1; + ((struct display_ops *)d->ops)->mode(d, out); + return 0; +} + +void * +display_acquire(uint32 *stride_out) +{ + struct device *d = display_get(); + if (!d || !d->ops || !((struct display_ops *)d->ops)->acquire) + return 0; + return ((struct display_ops *)d->ops)->acquire(d, stride_out); +} + +void +display_present(int x, int y, int w, int h) +{ + struct device *d = display_get(); + if (!d || !d->ops || !((struct display_ops *)d->ops)->present) + return; + ((struct display_ops *)d->ops)->present(d, x, y, w, h); +} + +void +display_wait_vblank(void) +{ + struct device *d = display_get(); + if (!d || !d->ops || !((struct display_ops *)d->ops)->wait_vblank) + return; + ((struct display_ops *)d->ops)->wait_vblank(d); +} + +// Drive the whole display path once and report what happened: find the class, +// read the mode, acquire a back buffer, draw into RAM, present it. +// +// A self-test rather than a unit test because none of this can be checked +// without a display: the assertion is "did the right pixels reach the screen", +// and the only instrument for that is a screendump. Triggered with +// `echo d > /proc/sysrq` and photographed by tools/dispshot.ps1. +// +// The pattern is chosen to be wrong in visible ways. Four solid quadrants in +// theme colours catch a stride error (the bands would slant) and a bpp error +// (the colours would be wrong); the white frame one pixel inside the edge +// catches an off-by-one in the present rectangle; and the fact that it is +// drawn entirely into RAM before a single byte reaches the framebuffer is what +// double buffering means. +void +display_selftest(void) +{ + struct display_mode m; + uint32 stride; + + if (display_mode(&m) != 0) { + cprintf("display: no display bound\n"); + return; + } + cprintf("display: %dx%d %dbpp stride %d\n", m.width, m.height, m.bpp, m.stride); + + unsigned char *b = display_acquire(&stride); + if (!b) { + cprintf("display: no back buffer available\n"); + return; + } + + static const uint32 quad[4] = { + SCH_ACCENT, SCH_ACCENT_DIM, SCH_DIM, SCH_BG + }; + for (int y = 0; y < m.height; y++) { + uint32 *row = (uint32 *)(b + (uint64)y * stride); + int top = y < m.height / 2; + for (int x = 0; x < m.width; x++) { + int left = x < m.width / 2; + row[x] = quad[(top ? 0 : 2) + (left ? 0 : 1)]; + } + } + for (int x = 1; x < m.width - 1; x++) { + *(uint32 *)(b + 1 * (uint64)stride + x * 4) = SCH_FG; + *(uint32 *)(b + (uint64)(m.height - 2) * stride + x * 4) = SCH_FG; + } + for (int y = 1; y < m.height - 1; y++) { + *(uint32 *)(b + (uint64)y * stride + 1 * 4) = SCH_FG; + *(uint32 *)(b + (uint64)y * stride + (m.width - 2) * 4) = SCH_FG; + } + + // Between frames, so the blit does not land halfway down a scan-out. + display_wait_vblank(); + display_present(0, 0, m.width, m.height); + cprintf("display: presented a full frame\n"); +} + +// Draw a text specimen through the display class. `echo t > /proc/sysrq`. +// +// It exercises the three things a character-cell console cannot do, so a +// screenshot says whether the layer works rather than whether it compiled: +// glyphs on a common baseline at arbitrary x (not multiples of eight), text +// blended over an existing background rather than drawn into cleared cells, and +// codepoints above 255. +void +text_selftest(void) +{ + struct display_mode m; + uint32 stride; + + if (display_mode(&m) != 0) { + cprintf("text: no display\n"); + return; + } + unsigned char *b = display_acquire(&stride); + if (!b) { + cprintf("text: no back buffer\n"); + return; + } + + struct surface s = { b, stride, m.width, m.height }; + struct font *f = font_builtin(); + + // A background with structure in it, so blending is visible as blending + // rather than as drawing onto a flat colour. + for (int y = 0; y < m.height; y++) { + uint32 *row = (uint32 *)(b + (uint64)y * stride); + for (int x = 0; x < m.width; x++) + row[x] = ((x / 32 + y / 32) & 1) ? SCH_BG : SCH_ACCENT_DIM; + } + + int base = f->ops->baseline(f); + int line = f->ops->height(f) + 6; + int y = 80; + + text_draw(&s, f, 60, y + base, "Schunix text rendering", SCH_FG); + y += line * 2; + + // Deliberately not on a multiple of eight. On the old console this string + // could only start at x = 56 or x = 64. + text_draw(&s, f, 61, y + base, "positioned at x=61, off the cell grid", SCH_DIM); + y += line; + text_draw(&s, f, 63, y + base, "and here at x=63", SCH_DIM); + y += line * 2; + + // Above U+00FF, which a 256-entry table cannot index at all. + text_draw(&s, f, 60, y + base, + "utf-8: \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x90 " + "\xe2\x96\x88\xe2\x96\x93\xe2\x96\x92\xe2\x96\x91 " + "\xc2\xb0 \xc2\xb1 \xe2\x86\x92 \xe2\x80\xa2", SCH_ACCENT); + y += line * 2; + + // Measure, then centre on it -- the thing you cannot do without metrics. + const char *msg = "measured and centred"; + int w = text_measure(f, msg); + text_draw(&s, f, (m.width - w) / 2, y + base, msg, SCH_FG); + + display_present(0, 0, m.width, m.height); + cprintf("text: drew a specimen, \"%s\" measures %d px\n", msg, w); +} diff --git a/kernel/dev/fb.c b/kernel/dev/fb.c new file mode 100644 index 0000000..8c652cf --- /dev/null +++ b/kernel/dev/fb.c @@ -0,0 +1,202 @@ +// /dev/fb0 -- the linear framebuffer as a file. +// +// Until now this node existed but was wired to major 2, whose devsw entry was +// { nullread, nullwrite }: reads returned end-of-file and writes were thrown +// away, silently. The only thing that actually worked was mmap, and only +// because sys_mmap special-cased the major number. +// +// Reads and writes here address the framebuffer by byte offset, so lseek +// positions the "cursor" and a whole frame can be written with one write(). +// That is slower than mmap and always will be -- it is a copy -- but it is +// what makes the device inspectable from a shell, which is worth a great deal +// while there is no GUI yet to inspect it with. + +#include "types.h" +#include "defs.h" +#include "param.h" +#include "mmu.h" +#include "proc.h" +#include "spinlock.h" +#include "sleeplock.h" +#include "fs.h" +#include "file.h" +#include "fb.h" +#include "uaccess.h" +#include "errno.h" + +// Describe one colour channel. A channel that does not exist gets length 0, +// which is how callers are supposed to detect "no alpha" rather than by +// assuming from bits_per_pixel. +static void +chan(struct fb_bitfield *f, unsigned int offset, unsigned int length) +{ + f->offset = offset; + f->length = length; + f->msb_right = 0; +} + +// Pixel layout for the depths vga_draw_pixel knows how to write. Keeping the +// two in step matters: this is the kernel telling userspace how to build a +// pixel, and if it disagrees with how the kernel builds one, every colour +// drawn by a program is wrong in a way that looks like a hardware fault. +static void +pixel_format(struct fb_var_screeninfo *v, unsigned int bpp) +{ + switch (bpp) { + case 32: + chan(&v->red, 16, 8); chan(&v->green, 8, 8); chan(&v->blue, 0, 8); + chan(&v->transp, 24, 0); // the byte is there; nothing honours it + break; + case 24: + chan(&v->red, 16, 8); chan(&v->green, 8, 8); chan(&v->blue, 0, 8); + chan(&v->transp, 0, 0); + break; + case 16: + // RGB565, matching the packing vga_draw_pixel does for this depth. + chan(&v->red, 11, 5); chan(&v->green, 5, 6); chan(&v->blue, 0, 5); + chan(&v->transp, 0, 0); + break; + default: + chan(&v->red, 0, 0); chan(&v->green, 0, 0); chan(&v->blue, 0, 0); + chan(&v->transp, 0, 0); + break; + } +} + +int +fbread(struct inode *ip, uint off, char *dst, int n) +{ + volatile uchar *fb = vga_fb_ptr(); + uint64 size = vga_fb_size(); + + if (!fb) + return -ENODEV; + if (n < 0) + return -EINVAL; + if ((uint64)off >= size) + return 0; // past the end of the screen: EOF + if ((uint64)off + (uint64)n > size) + n = (int)(size - (uint64)off); + + memmove(dst, (void*)(fb + off), n); + return n; +} + +// Set once something has drawn through this device, so that fbclose knows +// whether the screen still belongs to the text console. Reading the +// framebuffer, or asking it its geometry, does not count -- `fbinfo` with no +// arguments must not wipe its own output off the screen. +static int fb_dirty; + +// Called from sys_mmap when /dev/fb0 is mapped. A mapping is a licence to +// draw, and the drawing happens with no further syscalls, so this is the last +// point at which the kernel hears about it at all. +void +fb_mapped(void) +{ + fb_dirty = 1; +} + +int +fbwrite(struct inode *ip, uint off, char *src, int n) +{ + volatile uchar *fb = vga_fb_ptr(); + uint64 size = vga_fb_size(); + + if (!fb) + return -ENODEV; + if (n < 0) + return -EINVAL; + if ((uint64)off >= size) + return -ENOSPC; // a screen cannot be extended + if ((uint64)off + (uint64)n > size) + n = (int)(size - (uint64)off); + + memmove((void*)(fb + off), src, n); + fb_dirty = 1; + return n; +} + +// The last descriptor on /dev/fb0 is going away. +// +// Whatever was drawing has finished, and the screen still holds its final +// frame -- so the shell prompt underneath is invisible and the machine looks +// hung. It is not: the process exited cleanly and the console is writing +// happily into a framebuffer nobody can read any more. There is no character +// backing store to repaint from (the console draws glyphs straight into the +// framebuffer and scrolls with a memmove), so the honest recovery is to clear +// and go home rather than to pretend the old text can be restored. +void +fbclose(struct inode *ip) +{ + if (!fb_dirty) + return; + fb_dirty = 0; + + // Said out loud, because a screen clearing on its own is otherwise + // indistinguishable from a bug -- and this is the only place in the system + // that wipes the display without being asked to. + cprintf("fb0: released by pid %d, console restored\n", myproc() ? myproc()->pid : -1); + vga_screen_reset(); +} + +// FBIO* handling, called from sys_ioctl once it has established that the fd +// refers to this device. `arg` is the raw user address; each request +// validates it for the size it is actually going to touch, rather than for +// the largest struct here -- fb_fix_screeninfo is half the size of +// fb_var_screeninfo, and a buffer sitting near the end of a mapping is a +// legitimate place to put the smaller one. +int +fb_ioctl(int request, addr_t arg) +{ + int w, h; + + if (!vga_fb_ptr()) + return -ENODEV; + + vga_dims(&w, &h); + + switch (request) { + case FBIOGET_VSCREENINFO: { + struct fb_var_screeninfo *v = + (struct fb_var_screeninfo *)user_ptr(arg, sizeof(*v)); + if (!v) + return -EFAULT; + memset(v, 0, sizeof(*v)); + v->xres = v->xres_virtual = (unsigned int)w; + v->yres = v->yres_virtual = (unsigned int)h; + v->bits_per_pixel = vga_fb_bpp(); + v->activate = FB_ACTIVATE_NOW; + pixel_format(v, v->bits_per_pixel); + // height/width (physical millimetres) and every timing field stay zero: + // VBE does not report them and a guess would be worse than an admission. + return 0; + } + + case FBIOGET_FSCREENINFO: { + struct fb_fix_screeninfo *f = + (struct fb_fix_screeninfo *)user_ptr(arg, sizeof(*f)); + if (!f) + return -EFAULT; + memset(f, 0, sizeof(*f)); + safestrcpy(f->id, "schunixfb", sizeof(f->id)); + f->smem_start = (unsigned long)vga_fb_phys(); + f->smem_len = (unsigned int)vga_fb_size(); + f->type = FB_TYPE_PACKED_PIXELS; + f->visual = FB_VISUAL_TRUECOLOR; + f->line_length = vga_fb_stride(); + return 0; + } + + // The mode came from the bootloader's VBE call and we have no way to + // change it. Saying so is more useful than accepting the request and + // leaving the caller to discover, by drawing, that nothing happened. + case FBIOPUT_VSCREENINFO: + return -EINVAL; + + case FBIOBLANK: + return -EINVAL; + } + + return -ENOTTY; +} diff --git a/kernel/dev/ide.c b/kernel/dev/ide.c new file mode 100644 index 0000000..be33f9c --- /dev/null +++ b/kernel/dev/ide.c @@ -0,0 +1,208 @@ +// Simple PIO-based (non-DMA) IDE driver code. + +#include "types.h" +#include "defs.h" +#include "irq.h" +#include "param.h" +#include "memlayout.h" +#include "mmu.h" +#include "proc.h" +#include "x86.h" +#include "traps.h" +#include "spinlock.h" +#include "sleeplock.h" +#include "fs.h" +#include "buf.h" + +#define SECTOR_SIZE 512 +#define IDE_BSY 0x80 +#define IDE_DRDY 0x40 +#define IDE_DF 0x20 +#define IDE_ERR 0x01 + +#define IDE_CMD_READ 0x20 +#define IDE_CMD_WRITE 0x30 +#define IDE_CMD_RDMUL 0xc4 +#define IDE_CMD_WRMUL 0xc5 + +// idequeue points to the buf now being read/written to the disk. +// idequeue->qnext points to the next buf to be processed. +// You must hold idelock while manipulating queue. + +static struct spinlock idelock; +static struct buf *idequeue; + +static int havedisk0; +static int havedisk1; +static void idestart(struct buf*); + +// Wait for the drive to become ready, or give up. +// +// This used to be an unbounded `while`. On a machine with nothing attached to +// the primary channel the status register reads 0xFF forever, so the very +// first call from ideinit() hung the kernel -- no panic, no message, just a +// dead machine right after the VGA banner. That is not an exotic +// configuration: it is every CD boot, and most hardware newer than IDE. +// +// The bound is deliberately enormous. A real drive answers in microseconds; +// this only expires when there is nothing there at all. +static int +idewait(int checkerr) +{ + int r = 0; + + for(int i = 0; i < 20000000; i++){ + r = inb(0x1f7); + if((r & (IDE_BSY|IDE_DRDY)) == IDE_DRDY){ + if(checkerr && (r & (IDE_DF|IDE_ERR)) != 0) + return -1; + return 0; + } + } + return -1; +} + +static void +ide_irq(void *arg) +{ + (void)arg; + ideintr(); +} + +void +ideinit(void) +{ + initlock(&idelock, "ide"); + // ISA signalling: edge-triggered, active high. Everything at a fixed + // legacy port is wired this way; PCI devices are not. + irq_register(IRQ_IDE, ide_irq, 0, "ide", 0); + + // A timeout here means there is no drive on this channel. Say so and leave + // havedisk0/1 clear: with a ramdisk root there is nothing else the system + // needs from IDE, and booting on is strictly better than stopping. + if(idewait(0) < 0){ + cprintf("ide: no drive on the primary channel\n"); + return; + } + havedisk0 = 1; + + // Check if disk 1 is present + outb(0x1f6, 0xe0 | (1<<4)); + for(int i=0; i<1000; i++){ + if(inb(0x1f7) != 0){ + havedisk1 = 1; + break; + } + } + + // Switch back to disk 0. + outb(0x1f6, 0xe0 | (0<<4)); +} + +// Is there actually a drive there? Callers that probe -- rather than callers +// that know what they are looking for -- have to ask, because reading an +// absent drive is a bug and iderw() treats it as one. +int +ide_disk_present(int dev) +{ + return dev == 0 ? havedisk0 : havedisk1; +} + +// Start the request for b. Caller must hold idelock. +static void +idestart(struct buf *b) +{ + if(b == 0) + panic("idestart"); + if(b->blockno >= FSSIZE) + panic("incorrect blockno"); + int sector_per_block = BSIZE/SECTOR_SIZE; + int sector = b->blockno * sector_per_block; + int read_cmd = (sector_per_block == 1) ? IDE_CMD_READ : IDE_CMD_RDMUL; + int write_cmd = (sector_per_block == 1) ? IDE_CMD_WRITE : IDE_CMD_WRMUL; + + if (sector_per_block > 7) panic("idestart"); + + idewait(0); + outb(0x3f6, 0); // generate interrupt + outb(0x1f2, sector_per_block); // number of sectors + outb(0x1f3, sector & 0xff); + outb(0x1f4, (sector >> 8) & 0xff); + outb(0x1f5, (sector >> 16) & 0xff); + outb(0x1f6, 0xe0 | ((b->dev&1)<<4) | ((sector>>24)&0x0f)); + if(b->flags & B_DIRTY){ + outb(0x1f7, write_cmd); + outsl(0x1f0, b->data, BSIZE/4); + } else { + outb(0x1f7, read_cmd); + } +} + +// Interrupt handler. +void +ideintr(void) +{ + struct buf *b; + + // First queued buffer is the active request. + acquire(&idelock); + if((b = idequeue) == 0){ + release(&idelock); + // cprintf("spurious IDE interrupt\n"); + return; + } + idequeue = b->qnext; + + // Read data if needed. + if(!(b->flags & B_DIRTY) && idewait(1) >= 0) + insl(0x1f0, b->data, BSIZE/4); + + // Wake process waiting for this buf. + b->flags |= B_VALID; + b->flags &= ~B_DIRTY; + wakeup(b); + + // Start disk on next buf in queue. + if(idequeue != 0) + idestart(idequeue); + + release(&idelock); +} + +//PAGEBREAK! +// Sync buf with disk. +// If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID. +// Else if B_VALID is not set, read buf from disk, set B_VALID. +void +iderw(struct buf *b) +{ + struct buf **pp; + + if(!holdingsleep(&b->lock)) + panic("iderw: buf not locked"); + if((b->flags & (B_VALID|B_DIRTY)) == B_VALID) + panic("iderw: nothing to do"); + if(b->dev != 0 && !havedisk1) + panic("iderw: ide disk 1 not present"); + if(b->dev == 0 && !havedisk0) + panic("iderw: ide disk 0 not present"); + + acquire(&idelock); //DOC:acquire-lock + + // Append b to idequeue. + b->qnext = 0; + for(pp=&idequeue; *pp; pp=&(*pp)->qnext) //DOC:insert-queue + ; + *pp = b; + + // Start disk if necessary. + if(idequeue == b) + idestart(b); + + // Wait for request to finish. + while((b->flags & (B_VALID|B_DIRTY)) != B_VALID){ + sleep(b, &idelock); + } + + release(&idelock); +} diff --git a/kernel/dev/input.c b/kernel/dev/input.c new file mode 100644 index 0000000..7f019ac --- /dev/null +++ b/kernel/dev/input.c @@ -0,0 +1,394 @@ +// Raw input event devices -- /dev/input/event0 and /dev/input/event1. +// +// Everything that produces input feeds this: the PS/2 keyboard and mouse, and +// the USB HID driver. The console keeps its own path and is unaffected; these +// nodes are a *second* consumer of the same interrupts, so a program can read +// keys while the shell still gets characters. +// +// Two devices rather than one because they are two devices. A compositor +// grabs the pointer and leaves the keyboard alone, or the other way round, and +// merging them into a single stream makes that impossible to express. + +#include "types.h" +#include "defs.h" +#include "param.h" +#include "mmu.h" +#include "proc.h" +#include "spinlock.h" +#include "sleeplock.h" +#include "fs.h" +#include "file.h" +#include "input.h" +#include "errno.h" + +#define NEVENT 256 // per device; ~10 seconds of frantic typing + +struct input_dev { + struct spinlock lock; + struct input_event ev[NEVENT]; + uint r, w; // free-running; the difference is the count + + // Exclusive grab (EVIOCGRAB). While set, keys still arrive here but stop + // being handed to the console's line discipline. + // + // Without this a full-screen program does not really own the keyboard: it + // reads /dev/input/event0 *and* the shell behind it reads the same keystrokes + // off the tty. The observed failure was a full-screen program quietly typing + // its entire session into the shell underneath, so the first Enter after + // exiting ran whatever had accumulated. The grab is also exactly what a + // compositor needs, which is why it lives here rather than in any one client. + int grabbed; + + // How many descriptors are open on this device. + // + // Events are only queued while this is non-zero, and the backlog is dropped + // on the first open. Both halves matter: without them the ring is a log of + // every key pressed since boot, and the next program to open the device is + // handed the lot as though the user had just typed it. + int opens; +}; + +static struct input_dev idev[NINPUTDEV]; +static int input_up; + +extern uint ticks; + +void +inputinit(void) +{ + int i; + + for(i = 0; i < NINPUTDEV; i++) + initlock(&idev[i].lock, "input"); + + // Producers run from interrupt handlers and can fire before this point in + // boot. Until the locks exist, an event has nowhere safe to go. + __sync_synchronize(); + input_up = 1; +} + +// Append one event. Called from interrupt context, so it never sleeps and +// never blocks on a full ring. +void +input_report(int dev, int type, int code, int value) +{ + struct input_dev *d; + struct input_event *e; + + if(!input_up || dev < 0 || dev >= NINPUTDEV) + return; + d = &idev[dev]; + + // Nobody is listening, so there is nowhere for this to go. Linux does the + // same: an evdev device with no clients does not accumulate. + if(d->opens == 0) + return; + + acquire(&d->lock); + + // A full ring drops the *oldest* event, not the newest. Dropping the newest + // is the obvious choice and it is wrong: the event most likely to be lost is + // then a key release, and a lost release leaves the key held down forever + // as far as every reader is concerned. Losing the oldest costs history, not + // state. + if(d->w - d->r >= NEVENT) + d->r++; + + e = &d->ev[d->w % NEVENT]; + e->time.tv_sec = ticks / 100; + e->time.tv_usec = (ticks % 100) * 10000; + e->type = (uint16)type; + e->code = (uint16)code; + e->value = (int32)value; + d->w++; + + release(&d->lock); +} + +// End a report. A reader that acts on each event as it arrives will see a +// diagonal mouse move as two separate moves; the SYN is how it knows the two +// axes belong to the same physical motion. +void +input_sync(int dev) +{ + if(!input_up || dev < 0 || dev >= NINPUTDEV) + return; + input_report(dev, EV_SYN, SYN_REPORT, 0); + wakeup(&idev[dev]); +} + +int +input_ready(int dev) +{ + int n; + + if(!input_up || dev < 0 || dev >= NINPUTDEV) + return 0; + acquire(&idev[dev].lock); + n = idev[dev].w != idev[dev].r; + release(&idev[dev].lock); + return n; +} + +// A descriptor has been opened on this device. +// +// The backlog is discarded, which is the whole point. Events queued before a +// program opened the device were meant for whoever had it *then* -- almost +// always the shell, which already consumed them as a command line. Replaying +// them into the new owner means a program is handed the keystrokes that +// launched it, as input, the instant it starts. That was a real crash and not a +// cosmetic one: the replayed characters were interpreted as commands, and one of +// them asked for a mode the program had not initialised yet. +// +// Linux gets this for free by giving every open its own client queue. One +// shared ring plus "start from now" is the same answer for a single reader, +// which is the case that exists. +void +inputopen(struct inode *ip) +{ + int dev = ip->minor; + + if(dev < 0 || dev >= NINPUTDEV) + return; + acquire(&idev[dev].lock); + idev[dev].opens++; + idev[dev].r = idev[dev].w; // start from now, not from boot + release(&idev[dev].lock); +} + +// The devsw ready hook: would a read block? +int +inputready(struct inode *ip) +{ + return input_ready(ip->minor); +} + +// Is this device grabbed? Asked by the keyboard drivers before they hand a +// character to the console. +int +input_is_grabbed(int dev) +{ + if(!input_up || dev < 0 || dev >= NINPUTDEV) + return 0; + return idev[dev].grabbed; +} + +// EVIOCGRAB. Linux's semantics: one holder at a time, and it is not an error +// to grab what you already hold. +int +input_grab(int dev, int on) +{ + if(!input_up || dev < 0 || dev >= NINPUTDEV) + return -ENODEV; + on = on ? 1 : 0; + if(idev[dev].grabbed != on){ + idev[dev].grabbed = on; + // Said out loud. A grabbed keyboard is a console that has gone deaf on + // purpose, and that is indistinguishable from one that has gone deaf by + // accident unless the kernel says which it was. + cprintf("input: event%d %s by pid %d\n", dev, + on ? "grabbed" : "released", myproc() ? myproc()->pid : -1); + } + return 0; +} + +// The last descriptor on this device is going away. +// +// Releasing the grab here is not tidiness, it is the difference between a +// crashed game and a machine you have to reboot: a program that grabs the +// keyboard and dies without ungrabbing would leave the console permanently +// deaf. The close hook makes the release unconditional. +void +inputclose(struct inode *ip) +{ + int dev = ip->minor; + + if(dev < 0 || dev >= NINPUTDEV) + return; + if(idev[dev].opens > 0) + idev[dev].opens--; + if(idev[dev].grabbed){ + idev[dev].grabbed = 0; + cprintf("input: event%d grab released\n", dev); + } +} + +// ioctl on /dev/input/eventN. Only EVIOCGRAB so far; the EVIOCG* query +// requests (name, id, capability bitmaps) can arrive when something needs +// them. +int +input_ioctl(struct inode *ip, int request, addr_t arg) +{ + int on; + + if(request == EVIOCGRAB){ + // Linux passes the flag *by value* in the argument, not by pointer. + on = (int)arg; + return input_grab(ip->minor, on); + } + return -ENOTTY; +} + +// A read returns whole events only. Handing back a partial struct would +// desynchronise the reader permanently -- every later event would be split +// across two reads and reassembled wrong. +int +inputread(struct inode *ip, uint off, char *dst, int n) +{ + struct input_dev *d; + int got = 0; + int dev = ip->minor; + + if(dev < 0 || dev >= NINPUTDEV) + return -ENODEV; + if(n < (int)sizeof(struct input_event)) + return -EINVAL; + d = &idev[dev]; + + acquire(&d->lock); + while(d->r == d->w){ + if(myproc()->killed){ + release(&d->lock); + return -EINTR; + } + sleep(d, &d->lock); + } + + while(d->r != d->w && got + (int)sizeof(struct input_event) <= n){ + memmove(dst + got, &d->ev[d->r % NEVENT], sizeof(struct input_event)); + d->r++; + got += sizeof(struct input_event); + } + release(&d->lock); + return got; +} + +// evdev accepts writes to set keyboard LEDs. There are no LEDs to set here, +// and a program that writes one should not see an error for it. +int +inputwrite(struct inode *ip, uint off, char *src, int n) +{ + return n; +} + +// --------------------------------------------------------------------------- +// Producers +// --------------------------------------------------------------------------- + +// AT scancode set 1, E0-prefixed. The unprefixed bytes need no table at all: +// Linux's keycodes were numbered from this set and still match it below 0x54. +// These are the ones that do not. +static const struct { uint8 sc; uint8 key; } e0map[] = { + {0x1C, 96}, // KP_ENTER + {0x1D, KEY_RIGHTCTRL}, + {0x35, 98}, // KP_SLASH + {0x38, KEY_RIGHTALT}, + {0x47, KEY_HOME}, + {0x48, KEY_UP}, + {0x49, KEY_PAGEUP}, + {0x4B, KEY_LEFT}, + {0x4D, KEY_RIGHT}, + {0x4F, KEY_END}, + {0x50, KEY_DOWN}, + {0x51, KEY_PAGEDOWN}, + {0x52, KEY_INSERT}, + {0x53, KEY_DELETE}, + {0x5B, KEY_LEFTMETA}, + {0x5C, KEY_RIGHTMETA}, +}; + +// One byte from the PS/2 port, before it has been turned into a character. +void +input_ps2_scancode(int raw, int e0) +{ + int code = raw & 0x7F; + int down = (raw & 0x80) ? 0 : 1; + int key = 0; + unsigned i; + + if(e0){ + for(i = 0; i < sizeof(e0map)/sizeof(e0map[0]); i++) + if(e0map[i].sc == code){ + key = e0map[i].key; + break; + } + if(key == 0) + return; // an E0 key nothing has a name for + } else { + if(code == 0 || code > 0x58) + return; + key = code; + } + + input_report(INPUT_KBD, EV_KEY, key, down); + input_sync(INPUT_KBD); +} + +// USB HID usage -> Linux keycode. The mapping is not derivable: HID numbers +// keys by position on a US layout starting at 'a', and the AT set numbers them +// by the order IBM wired the matrix. The table is the same one Linux carries +// for the same reason. +static const uint8 hid_keycode[] = { + 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, + 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, + 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, + 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, + 72, 73, 82, 83, 86,127,116,117, +}; + +// The eight modifier bits in a boot report, in bit order. +static const uint8 hid_modkey[8] = { + KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA, + KEY_RIGHTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT, KEY_RIGHTMETA, +}; + +int +input_hid_keycode(int usage) +{ + if(usage >= 0xE0 && usage <= 0xE7) + return hid_modkey[usage - 0xE0]; + if(usage < 0 || usage >= (int)sizeof(hid_keycode)) + return 0; + return hid_keycode[usage]; +} + +void +input_key(int usage, int down) +{ + int key = input_hid_keycode(usage); + + if(key == 0) + return; + input_report(INPUT_KBD, EV_KEY, key, down); + input_sync(INPUT_KBD); +} + +// One mouse report: relative motion plus the current button state. `buttons` +// is a bitmask in the order both PS/2 and HID boot protocol use -- left, +// right, middle -- which is why neither caller has to reorder it. +void +input_mouse(int dx, int dy, int buttons) +{ + static int last; + static const int btncode[3] = { BTN_LEFT, BTN_RIGHT, BTN_MIDDLE }; + int i; + + if(dx) + input_report(INPUT_MOUSE, EV_REL, REL_X, dx); + if(dy) + input_report(INPUT_MOUSE, EV_REL, REL_Y, dy); + + // Only transitions. A button held down for a second is one press event, not + // a hundred -- a reader that has to filter repeats itself cannot tell a held + // button from a very fast double-click. + for(i = 0; i < 3; i++){ + int now = (buttons >> i) & 1; + if(now != ((last >> i) & 1)) + input_report(INPUT_MOUSE, EV_KEY, btncode[i], now); + } + last = buttons; + + input_sync(INPUT_MOUSE); +} diff --git a/kernel/dev/irq.c b/kernel/dev/irq.c new file mode 100644 index 0000000..578b834 --- /dev/null +++ b/kernel/dev/irq.c @@ -0,0 +1,214 @@ +// Hardware interrupt registration. See include/irq.h for why this exists. + +#include "types.h" +#include "defs.h" +#include "param.h" +#include "traps.h" +#include "spinlock.h" +#include "irq.h" + +struct irq_action { + irq_handler_t fn; + void *arg; + const char *name; + uint64 count; +}; + +static struct { + struct irq_action act[NCHAIN]; + int n; // handlers installed; only ever grows during boot + int enabled; + int level_low; + uint64 unhandled; +} line[NIRQ]; + +// Guards registration against itself. The *dispatch* path deliberately does +// not take it: an interrupt handler that blocked on a lock held by whoever +// was registering would deadlock the CPU it fired on. Instead registration +// publishes an entry by writing all of its fields, issuing a barrier, and +// only then incrementing n -- so a concurrent dispatcher either does not see +// the entry at all or sees it complete. +// +// Removal is the harder direction, because compacting the array *does* move +// entries a dispatcher may be walking. irq_unregister therefore masks the +// line first and only re-routes it once the chain has been rewritten: with +// the line masked no new interrupt can arrive, and any handler already +// running holds no reference past its own return. +static struct spinlock irqlock; + +void +irq_init(void) +{ + initlock(&irqlock, "irq"); +} + +// IRQ_ERROR and IRQ_SPURIOUS are not IOAPIC pins -- they are local APIC +// vectors that xv6 numbered as though they were, so T_IRQ0+19 and T_IRQ0+31 +// are already spoken for. A PCI device routed to pin 19 would deliver on the +// same vector as the LAPIC error interrupt. Refuse it here rather than let it +// be debugged later. +static int +reserved(int irq) +{ + return irq == IRQ_ERROR || irq == IRQ_SPURIOUS || irq == IRQ_TIMER; +} + +int +irq_register(int irq, irq_handler_t fn, void *arg, const char *name, + int level_low) +{ + struct irq_action *a; + + if(irq < 0 || irq >= NIRQ || fn == 0) + return -1; + if(reserved(irq)){ + cprintf("irq_register: %s wants irq %d, which is reserved\n", name, irq); + return -1; + } + + acquire(&irqlock); + + if(line[irq].n >= NCHAIN){ + release(&irqlock); + cprintf("irq_register: irq %d chain full, %s not attached\n", irq, name); + return -1; + } + + // Two devices sharing a line must agree on how it is signalled; they + // physically cannot be wired both ways. + if(line[irq].n > 0 && line[irq].level_low != level_low){ + release(&irqlock); + cprintf("irq_register: irq %d shared with conflicting trigger mode " + "(%s)\n", irq, name); + return -1; + } + + a = &line[irq].act[line[irq].n]; + a->fn = fn; + a->arg = arg; + a->name = name; + a->count = 0; + __sync_synchronize(); // publish the entry before it is reachable + line[irq].n++; + + if(!line[irq].enabled){ + line[irq].level_low = level_low; + ioapicroute(irq, 0, level_low); + line[irq].enabled = 1; + } + + release(&irqlock); + return 0; +} + +void +irq_unregister(int irq, irq_handler_t fn, void *arg) +{ + int i, j; + + if(irq < 0 || irq >= NIRQ) + return; + + acquire(&irqlock); + for(i = 0; i < line[irq].n; i++){ + if(line[irq].act[i].fn == fn && line[irq].act[i].arg == arg){ + // Mask before touching the chain, always -- not only when this is the + // last handler. Compacting the array moves entries that a dispatcher on + // another CPU may be walking, so the line has to be quiet for the + // duration, and then brought back only if anything is left on it. + ioapicmask(irq); + line[irq].enabled = 0; + + for(j = i; j + 1 < line[irq].n; j++) + line[irq].act[j] = line[irq].act[j+1]; + line[irq].n--; + __sync_synchronize(); + + if(line[irq].n > 0){ + ioapicroute(irq, 0, line[irq].level_low); + line[irq].enabled = 1; + } + break; + } + } + release(&irqlock); +} + +void +irq_dispatch(int irq) +{ + int i, n; + + if(irq < 0 || irq >= NIRQ) + return; + + n = line[irq].n; + if(n == 0){ + line[irq].unhandled++; + return; + } + + // Every handler on a shared line is offered the interrupt; each one is + // responsible for recognising that its device is idle and returning. + for(i = 0; i < n; i++){ + line[irq].act[i].count++; + line[irq].act[i].fn(line[irq].act[i].arg); + } +} + +// --------------------------------------------------------------------------- +// /proc/interrupts +// --------------------------------------------------------------------------- + +static int +emit(char *buf, int cap, int off, const char *s) +{ + while(*s && off < cap) + buf[off++] = *s++; + return off; +} + +static int +emit_dec(char *buf, int cap, int off, uint64 v, int width) +{ + char tmp[24]; + int n = 0, i; + + if(v == 0) + tmp[n++] = '0'; + while(v > 0){ + tmp[n++] = '0' + (v % 10); + v /= 10; + } + for(i = n; i < width && off < cap; i++) + buf[off++] = ' '; + while(n > 0 && off < cap) + buf[off++] = tmp[--n]; + return off; +} + +int +irq_info(char *buf, int cap) +{ + int irq, i, off = 0; + + for(irq = 0; irq < NIRQ; irq++){ + if(line[irq].n == 0 && line[irq].unhandled == 0) + continue; + off = emit_dec(buf, cap, off, irq, 4); + off = emit(buf, cap, off, ": "); + for(i = 0; i < line[irq].n; i++){ + off = emit_dec(buf, cap, off, line[irq].act[i].count, 10); + off = emit(buf, cap, off, " "); + off = emit(buf, cap, off, + line[irq].act[i].name ? line[irq].act[i].name : "?"); + off = emit(buf, cap, off, i + 1 < line[irq].n ? ", " : ""); + } + if(line[irq].n == 0) + off = emit(buf, cap, off, "(unhandled)"); + if(line[irq].unhandled) + off = emit(buf, cap, off, " [spurious]"); + off = emit(buf, cap, off, line[irq].level_low ? " level\n" : " edge\n"); + } + return off; +} diff --git a/kernel/dev/kbd.c b/kernel/dev/kbd.c new file mode 100644 index 0000000..2808870 --- /dev/null +++ b/kernel/dev/kbd.c @@ -0,0 +1,75 @@ +#include "types.h" +#include "x86.h" +#include "defs.h" +#include "kbd.h" +#include "input.h" + +int +kbdgetc(void) +{ + static uint shift; + static uchar *charcode[4] = { + normalmap, shiftmap, ctlmap, ctlmap + }; + uint st, data, c; + + st = inb(KBSTATP); + if((st & KBS_DIB) == 0) + return -1; + + if(st & 0x20) + return -1; + + data = inb(KBDATAP); + + if(data == 0xE0){ + shift |= E0ESC; + return 0; + } + + // Feed /dev/input/event0 before the byte is turned into a character. This + // has to happen here rather than in a second handler because the byte can + // only be read from the port once -- whoever reads it owes it to everyone + // else. The console path below is untouched: both consumers see every key. + input_ps2_scancode(data, (shift & E0ESC) != 0); + + // While something holds an exclusive grab on the keyboard, the console gets + // nothing. The shift/caps state below is still tracked, so releasing the + // grab does not leave the line discipline believing a modifier is held. + if(input_is_grabbed(INPUT_KBD)){ + if(data & 0x80){ + data = (shift & E0ESC ? data : data & 0x7F); + shift &= ~(shiftcode[data] | E0ESC); + } else { + shift |= shiftcode[data]; + shift ^= togglecode[data]; + } + return 0; + } + + if(data & 0x80){ + data = (shift & E0ESC ? data : data & 0x7F); + shift &= ~(shiftcode[data] | E0ESC); + return 0; + } else if(shift & E0ESC){ + data |= 0x80; + shift &= ~E0ESC; + } + + shift |= shiftcode[data]; + shift ^= togglecode[data]; + c = charcode[shift & (CTL | SHIFT)][data]; + if(shift & CAPSLOCK){ + if('a' <= c && c <= 'z') + c += 'A' - 'a'; + else if('A' <= c && c <= 'Z') + c += 'a' - 'A'; + } + return c; +} + +void +kbdintr(void) +{ + consoleintr(kbdgetc); +} diff --git a/kernel/dev/mouse.c b/kernel/dev/mouse.c new file mode 100644 index 0000000..3f3a25f --- /dev/null +++ b/kernel/dev/mouse.c @@ -0,0 +1,214 @@ +#include "types.h" +#include "defs.h" +#include "irq.h" +#include "x86.h" +#include "traps.h" +#include "spinlock.h" +#include "sleeplock.h" +#include "fs.h" +#include "file.h" + +#define KBD_S_STAT 0x64 +#define KBD_S_DATA 0x60 +#define KBD_C_WRITE 0xD4 +#define MOUSE_ACK 0xFA + +struct { + struct spinlock lock; + int x; + int y; + uint8 buttons; +} mouse_state; + +static void +mouse_wait(int type) +{ + int timeout = 100000; + if(type == 0){ + while(timeout-- && !(inb(KBD_S_STAT) & 0x01)); + } else { + while(timeout-- && (inb(KBD_S_STAT) & 0x02)); + } +} + +static void +mouse_write(uchar data) +{ + mouse_wait(1); + outb(KBD_S_STAT, KBD_C_WRITE); + mouse_wait(1); + outb(KBD_S_DATA, data); +} + +static uchar +mouse_read(void) +{ + mouse_wait(0); + return inb(KBD_S_DATA); +} + +static void +mouse_irq(void *arg) +{ + (void)arg; + mouseintr(); +} + +// Move the pointer. Caller holds mouse_state.lock. +// +// Positive dy is *down*, matching both the screen and USB HID. The PS/2 +// packet reports the opposite, which is why its caller negates first -- +// there is one pointer and two protocols disagreeing about which way is up, +// and the conversion belongs at the edge rather than in here. +static void +mouse_move_locked(int dx, int dy) +{ + mouse_state.x += dx; + mouse_state.y += dy; + + if(mouse_state.x < 0) mouse_state.x = 0; + if(mouse_state.y < 0) mouse_state.y = 0; + if(mouse_state.x >= 800) mouse_state.x = 799; + if(mouse_state.y >= 600) mouse_state.y = 599; +} + +// The same pointer, moved by something that is not the PS/2 port. USB HID +// uses this; anything else that produces motion events should too. +void +mouse_inject(int dx, int dy, int buttons) +{ + acquire(&mouse_state.lock); + mouse_state.buttons = buttons; + mouse_move_locked(dx, dy); + release(&mouse_state.lock); + + input_mouse(dx, dy, buttons); +} + +void +mouseintr(void) +{ + static uchar buf[3]; + static int phase = 0; + uchar status; + + status = inb(KBD_S_STAT); + + if(!(status & 0x01) || !(status & 0x20)){ + return; + } + + uchar data = inb(KBD_S_DATA); + + acquire(&mouse_state.lock); + + if(phase == 0 && !(data & 0x08)){ + release(&mouse_state.lock); + return; + } + + buf[phase++] = data; + + if(phase == 3){ + phase = 0; + + mouse_state.buttons = buf[0] & 0x07; + int dx = (buf[0] & 0x10) ? (int)buf[1] - 256 : buf[1]; + int dy = (buf[0] & 0x20) ? (int)buf[2] - 256 : buf[2]; + + // The overflow bits mean the delta saturated and is meaningless; moving + // by it would throw the pointer across the screen. + if(!(buf[0] & 0x40) && !(buf[0] & 0x80)) + mouse_move_locked(dx, -dy); + else + dx = dy = 0; + + release(&mouse_state.lock); + + // Outside the lock: input_report takes its own, and holding two at once + // is how a lock ordering rule gets invented by accident. + input_mouse(dx, -dy, buf[0] & 0x07); + return; + } + + release(&mouse_state.lock); +} + +int get_mouse_x(void) { + int x; + acquire(&mouse_state.lock); + x = mouse_state.x; + release(&mouse_state.lock); + return x; +} + +int get_mouse_y(void) { + int y; + acquire(&mouse_state.lock); + y = mouse_state.y; + release(&mouse_state.lock); + return y; +} + +uint8 get_mouse_buttons(void) { + uint8 b; + acquire(&mouse_state.lock); + b = mouse_state.buttons; + release(&mouse_state.lock); + return b; +} + +int +mouseread(struct inode *ip, uint off, char *dst, int n) +{ + struct mouse_data m; + int size = sizeof(struct mouse_data); + + if(n < size) { + return -1; + } + + m.x = get_mouse_x(); + m.y = get_mouse_y(); + m.buttons = get_mouse_buttons(); + + memmove(dst, &m, size); + + return size; +} + +void +mouseinit(void) +{ + initlock(&mouse_state.lock, "mouse"); + mouse_state.x = 400; + mouse_state.y = 300; + + while(inb(KBD_S_STAT) & 0x01) + inb(KBD_S_DATA); + + mouse_wait(1); + outb(KBD_S_STAT, 0xA8); + + mouse_wait(1); + outb(KBD_S_STAT, 0x20); + mouse_wait(0); + uchar cb = inb(KBD_S_DATA); + + cb |= 0x02; + cb |= 0x01; + cb &= ~0x20; + + mouse_wait(1); + outb(KBD_S_STAT, 0x60); + mouse_wait(1); + outb(KBD_S_DATA, cb); + + mouse_write(0xF6); + mouse_read(); + + mouse_write(0xF4); + mouse_read(); + + irq_register(IRQ_MOUSE, mouse_irq, 0, "ps2-mouse", 0); +} \ No newline at end of file diff --git a/kernel/dev/pci.c b/kernel/dev/pci.c new file mode 100644 index 0000000..b8f8d78 --- /dev/null +++ b/kernel/dev/pci.c @@ -0,0 +1,492 @@ +// PCI bus enumeration. +// +// Everything here is done through the two-port configuration mechanism at +// 0xCF8/0xCFC: write a (bus, slot, function, register) address to one port, +// read or write the value at the other. It is the oldest and least clever way +// to reach config space, and it is the one that works everywhere without +// first having to find an ACPI table to tell you where the memory-mapped +// version lives. +// +// The scan is recursive rather than a flat sweep of all 256 buses. A flat +// sweep does find everything on a PC, but it also probes 8192 slots that are +// not there, and it cannot tell you which bridge a device sits behind -- and +// that matters as soon as interrupt routing does. + +#include "types.h" +#include "defs.h" +#include "param.h" +#include "x86.h" +#include "spinlock.h" +#include "sleeplock.h" +#include "fs.h" +#include "file.h" +#include "pci.h" +#include "device.h" + +static struct pci_dev devs[NPCI]; +static int ndevs; + +static void scan_bus(uint8 bus); + +// --------------------------------------------------------------------------- +// Configuration space access +// --------------------------------------------------------------------------- + +static uint32 +cfg_addr(uint8 bus, uint8 slot, uint8 func, uint8 off) +{ + return 0x80000000u + | ((uint32)bus << 16) + | ((uint32)slot << 11) + | ((uint32)func << 8) + | (off & 0xFC); // the low two bits are not part of the address +} + +uint32 +pci_read32(uint8 bus, uint8 slot, uint8 func, uint8 off) +{ + outl(PCI_CONFIG_ADDR, cfg_addr(bus, slot, func, off)); + return inl(PCI_CONFIG_DATA); +} + +void +pci_write32(uint8 bus, uint8 slot, uint8 func, uint8 off, uint32 val) +{ + outl(PCI_CONFIG_ADDR, cfg_addr(bus, slot, func, off)); + outl(PCI_CONFIG_DATA, val); +} + +// Config space is only addressable in dwords, so narrower reads are a shift +// and a mask of the containing dword rather than a narrower bus cycle. +uint16 +pci_read16(uint8 bus, uint8 slot, uint8 func, uint8 off) +{ + return (uint16)(pci_read32(bus, slot, func, off) >> ((off & 2) * 8)); +} + +uint8 +pci_read8(uint8 bus, uint8 slot, uint8 func, uint8 off) +{ + return (uint8)(pci_read32(bus, slot, func, off) >> ((off & 3) * 8)); +} + +void +pci_enable(struct pci_dev *d, uint16 bits) +{ + uint32 cmd = pci_read32(d->bus, d->slot, d->func, PCI_COMMAND); + pci_write32(d->bus, d->slot, d->func, PCI_COMMAND, cmd | bits); +} + +// --------------------------------------------------------------------------- +// Capabilities +// +// Everything a device can do beyond the 64 bytes of standard config header -- +// MSI, MSI-X, power management, and the whole of virtio's configuration -- is +// described by a singly linked list of capability structures living in the +// device's config space. A driver that needs any of it has to walk that list. +// --------------------------------------------------------------------------- + +// Returns the config-space offset of the first capability with this ID, or 0. +uint8 +pci_find_cap(struct pci_dev *d, uint8 id) +{ + uint8 off; + int guard; + + if(!(pci_read16(d->bus, d->slot, d->func, PCI_STATUS) & PCI_STATUS_CAPLIST)) + return 0; + + off = pci_read8(d->bus, d->slot, d->func, PCI_CAP_PTR) & 0xFC; + + // The list is built by the device, so it can be circular if the device is + // broken or if we misread it. 48 is more capabilities than the 192 usable + // bytes can hold; past that we are certainly looping. + for(guard = 0; off >= 0x40 && guard < 48; guard++){ + if(pci_read8(d->bus, d->slot, d->func, off) == id) + return off; + off = pci_read8(d->bus, d->slot, d->func, off + 1) & 0xFC; + } + return 0; +} + +// Point a device's MSI at a CPU and a vector. +// +// MSI is not a wire: it is a memory write the device performs to a magic +// address that the local APIC decodes as an interrupt. That makes it strictly +// better than INTx for anything modern -- no sharing, no level/edge question, +// and no chance of the interrupt arriving before the DMA it announces, since +// both are posted writes travelling the same path in order. +// +// Returns 0 on success, -1 if the device has no MSI capability. +int +pci_msi_enable(struct pci_dev *d, int vector, int cpu) +{ + uint8 cap = pci_find_cap(d, PCI_CAP_MSI); + uint16 ctl; + + if(cap == 0) + return -1; + + ctl = pci_read16(d->bus, d->slot, d->func, cap + 2); + + // 0xFEE00000 | (apic id << 12) is the LAPIC's message address; the data + // word is the vector, with delivery mode 000 (fixed) and edge trigger. + pci_write32(d->bus, d->slot, d->func, cap + 4, + 0xFEE00000u | ((uint32)cpu << 12)); + + if(ctl & (1 << 7)){ // 64-bit address capable: data moved to +12 + pci_write32(d->bus, d->slot, d->func, cap + 8, 0); + pci_write32(d->bus, d->slot, d->func, cap + 12, (uint32)vector); + } else { + pci_write32(d->bus, d->slot, d->func, cap + 8, (uint32)vector); + } + + // Enable, and request exactly one vector (multiple-message-enable = 0). + // Message control shares its dword with the capability ID and next pointer, + // and config space is only writable a dword at a time, so read-modify-write + // the whole thing rather than clobbering the list this capability is on. + { + uint32 dw = pci_read32(d->bus, d->slot, d->func, cap); + ctl = (ctl & ~0x0070) | 1; + dw = (dw & 0x0000FFFF) | ((uint32)ctl << 16); + pci_write32(d->bus, d->slot, d->func, cap, dw); + } + + // INTx must be masked or the device will signal both. + pci_write32(d->bus, d->slot, d->func, PCI_COMMAND, + pci_read32(d->bus, d->slot, d->func, PCI_COMMAND) | (1 << 10)); + return 0; +} + +// --------------------------------------------------------------------------- +// Base address registers +// --------------------------------------------------------------------------- + +// A BAR does not report its own size. You find it by writing all ones and +// reading back: the device leaves the bits it does not decode as zero, so the +// size is one more than the inverse of what comes back. The original value +// has to be put back afterwards -- this is a live device whose decoder is +// briefly pointed at the top of the address space while we look. +static void +read_bars(struct pci_dev *d) +{ + for (int i = 0; i < 6; i++) { + uint8 off = PCI_BAR0 + i * 4; + uint32 lo = pci_read32(d->bus, d->slot, d->func, off); + + if (lo == 0) + continue; + + pci_write32(d->bus, d->slot, d->func, off, 0xFFFFFFFF); + uint32 mask = pci_read32(d->bus, d->slot, d->func, off); + pci_write32(d->bus, d->slot, d->func, off, lo); + + if (mask == 0) + continue; + + if (lo & 1) { // I/O space + d->bar[i].is_io = 1; + d->bar[i].base = lo & ~0x3u; + d->bar[i].size = (~(mask & ~0x3u) + 1) & 0xFFFF; + continue; + } + + d->bar[i].prefetch = (lo >> 3) & 1; + + if (((lo >> 1) & 3) == 2) { // 64-bit BAR: eats the next slot + uint32 hi = pci_read32(d->bus, d->slot, d->func, off + 4); + pci_write32(d->bus, d->slot, d->func, off + 4, 0xFFFFFFFF); + uint32 hmask = pci_read32(d->bus, d->slot, d->func, off + 4); + pci_write32(d->bus, d->slot, d->func, off + 4, hi); + + d->bar[i].is_64 = 1; + d->bar[i].base = ((uint64)hi << 32) | (lo & ~0xFu); + d->bar[i].size = ~(((uint64)hmask << 32) | (mask & ~0xFu)) + 1; + i++; // the upper half is not its own BAR + continue; + } + + d->bar[i].base = lo & ~0xFu; + d->bar[i].size = (~(mask & ~0xFu) + 1) & 0xFFFFFFFF; + } +} + +// --------------------------------------------------------------------------- +// Enumeration +// --------------------------------------------------------------------------- + +static void +add_func(uint8 bus, uint8 slot, uint8 func) +{ + uint16 vendor = pci_read16(bus, slot, func, PCI_VENDOR_ID); + + if (vendor == 0xFFFF) // nothing plugged in + return; + + if (ndevs >= NPCI) { + cprintf("pci: more than %d devices, ignoring the rest\n", NPCI); + return; + } + + struct pci_dev *d = &devs[ndevs++]; + d->bus = bus; + d->slot = slot; + d->func = func; + + d->vendor = vendor; + d->device = pci_read16(bus, slot, func, PCI_DEVICE_ID); + d->revision = pci_read8(bus, slot, func, PCI_REVISION); + d->prog_if = pci_read8(bus, slot, func, PCI_PROG_IF); + d->subclass = pci_read8(bus, slot, func, PCI_SUBCLASS); + d->class = pci_read8(bus, slot, func, PCI_CLASS); + d->header_type = pci_read8(bus, slot, func, PCI_HEADER_TYPE); + d->irq = pci_read8(bus, slot, func, PCI_INTERRUPT_LINE); + + // Only header type 0 has six BARs. A bridge (type 1) has two and a very + // different layout, and reading it as though it had six would hand out + // window registers as if they were device apertures. + if ((d->header_type & 0x7F) == 0) + read_bars(d); + + // Walk down through a PCI-to-PCI bridge to whatever is behind it. + if ((d->header_type & 0x7F) == 1) { + uint8 secondary = pci_read8(bus, slot, func, PCI_SECONDARY_BUS); + if (secondary != 0 && secondary != bus) + scan_bus(secondary); + } +} + +static void +scan_bus(uint8 bus) +{ + for (uint8 slot = 0; slot < 32; slot++) { + if (pci_read16(bus, slot, 0, PCI_VENDOR_ID) == 0xFFFF) + continue; + + add_func(bus, slot, 0); + + // Bit 7 of the header type says the device has more than one function. + // Probing all eight unconditionally is harmless on real hardware but + // produces phantom entries on some emulated devices, which answer every + // function with a copy of function 0. + if (pci_read8(bus, slot, 0, PCI_HEADER_TYPE) & 0x80) + for (uint8 func = 1; func < 8; func++) + add_func(bus, slot, func); + } +} + +// --------------------------------------------------------------------------- +// Lookup +// --------------------------------------------------------------------------- + +int +pci_count(void) +{ + return ndevs; +} + +struct pci_dev * +pci_get(int i) +{ + return (i >= 0 && i < ndevs) ? &devs[i] : 0; +} + +struct pci_dev * +pci_find_class(uint8 class, uint8 subclass) +{ + for (int i = 0; i < ndevs; i++) + if (devs[i].class == class && devs[i].subclass == subclass) + return &devs[i]; + return 0; +} + +struct pci_dev * +pci_find_id(uint16 vendor, uint16 device) +{ + for (int i = 0; i < ndevs; i++) + if (devs[i].vendor == vendor && devs[i].device == device) + return &devs[i]; + return 0; +} + +// --------------------------------------------------------------------------- +// Driver binding +// --------------------------------------------------------------------------- + +static int +matches(const struct pci_match *m, struct pci_dev *d) +{ + if (m->vendor != PCI_ANY) + return m->vendor == d->vendor && + (m->device == PCI_ANY || m->device == d->device); + + // A class match, for drivers that handle a kind of device rather than a + // particular model. + return m->class == d->class && + (m->subclass == 0xFF || m->subclass == d->subclass); +} + +// Offer every unclaimed device to a driver. Called by pci_init() for each +// entry in the registry; see kernel/drivers/registry.c. +// Defined further down with the /proc/pci formatting it was written for. +static const char *class_name(uint8 class, uint8 subclass); + +// Translate a PCI class code into the bus-agnostic one the device model uses. +// +// The two vocabularies are deliberately separate. PCI's class byte describes +// how the card presents itself on that bus; DEVCLASS describes what the rest of +// the kernel can *do* with it, and a USB disk has to land in the same bucket as +// a SATA one despite sharing no numbering with it at all. +enum dev_class +pci_class_of(const struct pci_dev *d) +{ + switch (d->class) { + case PCI_CLASS_DISPLAY: return DEVCLASS_DISPLAY; + case PCI_CLASS_STORAGE: return DEVCLASS_STORAGE; + case PCI_CLASS_NETWORK: return DEVCLASS_NET; + case PCI_CLASS_SERIAL_BUS: return DEVCLASS_BUS; + default: return DEVCLASS_OTHER; + } +} + +// Human-readable description, the same text /proc/pci prints for the device. +void +pci_describe(const struct pci_dev *d, char *out, int cap) +{ + const char *s = class_name(d->class, d->subclass); + int n = 0; + while (s[n] && n < cap - 1) { + out[n] = s[n]; + n++; + } + out[n] = '\0'; +} + +void +pci_bind(const struct pci_driver *drv) +{ + for (int i = 0; i < ndevs; i++) { + struct pci_dev *d = &devs[i]; + if (d->driver) + continue; + for (const struct pci_match *m = drv->match; m->vendor || m->class; m++) { + if (!matches(m, d)) + continue; + if (drv->probe(d) == 0) { + d->driver = drv->name; + // Publish it in the bus-agnostic device list. Done here rather than in + // each driver's probe() so that a driver cannot forget to, and so the + // list is populated in bind order -- which is the order a device + // manager should show. + struct device *dev = device_add(drv->devname ? drv->devname : drv->name, + DEVBUS_PCI, pci_class_of(d), drv->name); + if (dev) { + dev->ops = (void *)drv->ops; + dev->vendor = d->vendor; + dev->product = d->device; + dev->b = d->bus; dev->s = d->slot; dev->f = d->func; + pci_describe(d, dev->desc, sizeof(dev->desc)); + } + } + break; + } + } +} + +// --------------------------------------------------------------------------- + +// Fixed-width lowercase hex, the way lspci prints addresses. +static int +put_hex(char *out, uint64 v, int digits) +{ + static const char d[] = "0123456789abcdef"; + for (int i = digits - 1; i >= 0; i--) + *out++ = d[(v >> (i * 4)) & 0xF]; + return digits; +} + +static int +put_str(char *out, const char *s) +{ + int n = 0; + while (s[n]) { out[n] = s[n]; n++; } + return n; +} + +static const char * +class_name(uint8 class, uint8 subclass) +{ + switch (class) { + case PCI_CLASS_STORAGE: + return subclass == 0x01 ? "IDE controller" + : subclass == 0x06 ? "SATA controller" + : subclass == 0x08 ? "NVMe controller" + : "storage controller"; + case PCI_CLASS_NETWORK: return "network controller"; + case PCI_CLASS_DISPLAY: return "display controller"; + case PCI_CLASS_MULTIMEDIA: return "multimedia device"; + case PCI_CLASS_BRIDGE: + return subclass == 0x00 ? "host bridge" + : subclass == 0x01 ? "ISA bridge" + : subclass == 0x04 ? "PCI bridge" + : "bridge"; + case PCI_CLASS_SERIAL_BUS: + return subclass == 0x03 ? "USB controller" : "serial bus controller"; + } + return "device"; +} + +// Fills a buffer for /proc/pci. Returns bytes written. +// +// There is no snprintf in the kernel, so this appends by hand in the same +// style as kernel/dev/procfs.c. The output is deliberately lspci-shaped -- +// "bus:slot.func vendor:device description" -- because that is the format +// anyone reading it will already know how to scan. +int +pci_info(char *buf, int cap) +{ + int len = 0; + + for (int i = 0; i < ndevs; i++) { + struct pci_dev *d = &devs[i]; + + if (len > cap - 96) // room for one more line + break; + + len += put_hex(buf + len, d->bus, 2); + buf[len++] = ':'; + len += put_hex(buf + len, d->slot, 2); + buf[len++] = '.'; + len += put_hex(buf + len, d->func, 1); + buf[len++] = ' '; + len += put_hex(buf + len, d->vendor, 4); + buf[len++] = ':'; + len += put_hex(buf + len, d->device, 4); + buf[len++] = ' '; + len += put_str(buf + len, class_name(d->class, d->subclass)); + len += put_str(buf + len, " ["); + len += put_str(buf + len, d->driver ? d->driver : "-"); + buf[len++] = ']'; + buf[len++] = '\n'; + } + + return len; +} + +void +pci_init(void) +{ + ndevs = 0; + + // If there is no host bridge at 0:0.0 there is no PCI, and every config + // read will come back 0xFFFFFFFF. Saying so once beats 8192 silent probes. + if (pci_read16(0, 0, 0, PCI_VENDOR_ID) == 0xFFFF) { + cprintf("pci: no host bridge; bus not present\n"); + return; + } + + scan_bus(0); + cprintf("pci: %d device%s\n", ndevs, ndevs == 1 ? "" : "s"); + + pci_bind_all(); +} diff --git a/kernel/dev/procfs.c b/kernel/dev/procfs.c new file mode 100644 index 0000000..95aea5a --- /dev/null +++ b/kernel/dev/procfs.c @@ -0,0 +1,431 @@ +// /proc — synthesised kernel status files. +// +// Each file is a character device node under major PROCFS_MAJOR, distinguished +// by its minor number, created by init at boot. Reading one renders the whole +// text into a scratch buffer and returns the slice starting at the caller's +// file offset, so a normal read-until-zero loop terminates. +// +// SCOPE: these are the *global* files. Per-process directories (/proc//…) +// are not here, because they need something this kernel does not have yet: +// synthetic directories, i.e. a directory whose entries are generated at +// lookup and getdents time rather than read from disk. That is a real VFS +// feature touching iget/ilock/dirlookup/getdents, and it is the natural +// companion to the SchFS work rather than a bolt-on to the current fs.c. +// The namespace (which files exist, including one directory per process) is +// kernel/fs/procfs.c; this file only generates the *content* of the global +// files. `ps` and `top` work through the former. + +#include "types.h" +#include "defs.h" +#include "irq.h" +#include "x86.h" +#include "device.h" +#include "display.h" +#include "param.h" +#include "memlayout.h" +#include "mmu.h" +#include "spinlock.h" +#include "sleeplock.h" +#include "fs.h" +#include "file.h" +#include "proc.h" +#include "uaccess.h" +#include "errno.h" + +#define PROC_BUFSZ 2048 + +// --- tiny formatting helpers (no snprintf in the kernel) ------------------- + +struct sbuf { + char *p; + int len; + int cap; +}; + +static void +sb_putc(struct sbuf *sb, char c) +{ + if (sb->len < sb->cap - 1) + sb->p[sb->len++] = c; +} + +static void +sb_puts(struct sbuf *sb, const char *s) +{ + while (*s) + sb_putc(sb, *s++); +} + +// A string in a fixed-width column, space-padded. cprintf has no width +// specifier and neither does this buffer, so tables build their own columns. +// Over-long values are allowed to run past their column rather than be +// truncated: a misaligned row is easier to read than a mangled name. +static void +sb_pad(struct sbuf *sb, const char *s, int width) +{ + int n = 0; + while (s[n]) { + sb_putc(sb, s[n]); + n++; + } + while (n++ < width) + sb_putc(sb, ' '); +} + +// Four lowercase hex digits, zero-padded. PCI and USB identifiers are always +// written this way, and a lookup table keyed on "8086:100e" does not match +// "8086:100E" or "8086:10e". +static void +sb_puthex4(struct sbuf *sb, uint32 v) +{ + static const char hex[] = "0123456789abcdef"; + for (int i = 3; i >= 0; i--) + sb_putc(sb, hex[(v >> (i * 4)) & 0xF]); +} + +static void +sb_putu(struct sbuf *sb, uint64 v) +{ + char tmp[24]; + int i = 0; + if (v == 0) { sb_putc(sb, '0'); return; } + while (v && i < (int)sizeof(tmp)) { tmp[i++] = '0' + (v % 10); v /= 10; } + while (i--) sb_putc(sb, tmp[i]); +} + +// "$t|`_1x*L@CehH;<95*kt_EK8~JvPHN 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 Qzkv8eoR~`jwaGC556%~UyZ`_I literal 0 HcmV?d00001 diff --git a/ports/JetBrains_Mono/JetBrainsMono-VariableFont_wght.ttf b/ports/JetBrains_Mono/JetBrainsMono-VariableFont_wght.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4c96e79855b725416b59ef700f0e2773c444d716 GIT binary patch literal 189028 zcmd3P2Ygk<*6*5Qi0Hldz59K?m;9!!nOSSi+SB%$S^E$pqA+-p z((|%&a@)PW?qedclZYM58$D|5-S*lq6;EtN#$mJS)8F=lu1 zWqXNi14 z>+ijbDBwFH-{?x${2H%Tyc*@FqP(rjRax@QldVC|Ya@}*_?qgv`pM6U$B0Ij5%s&V zrnaP}%zNFXC_e(_eRi>Pm+q8TAW7`pIclw1Dz9R@sEQsTZ_6tD7Evq z)IYA28(NehxyC>k`Ru0M^lrfio4>i|_&*h%HWZp*r`Wmal&+ErJ5Q3M@}4+c*gEZJ z65=Zb{&4>tn{{|--;ckgo;@Hph%-ogTaO4a$tSa`$P1O%@`*?fw?a0Z94sAB2nJC6 zZ6kiJ4gLBpqODYVSSGyP=oaU!Hi$EM3$jpw zH-#fia~(rm(NpNl>s=L0J&_RVM*V3d&7^s>mbTLUy1e269B8)*p~6An2E33;pN6ww zLUE7q3Ms!2VVmKZ3h=YQ{hjiM)(Wx&u9@{3V${2fxnmDf&V^z4gWj(5&kJiltJo2 z@Y}F3_~EP{{6sboema`~e-fJpzmUy=U&X56*RUG+4Qw9#MHpF(EoIB$uVfg7Y&BaA z{~C4;{7vk7_&2ee;NQ${hQFQN3jYpvC;WTaeefS-55j+hJp%tx_89yZ*^BUBVXwj8 z$KHm2fPDb}Lv|Sc$LwSHN7xbg$JnRvKWCrA|B8JN|DO!)V!yIq;s4HlSC0^)XWW}( z{P9-275pF`3_p~I!f(sl!oQD$6aFZFl$cDA$s}Z|914GeEQdc|UZ$S|(PYe$L~5)L zhKq%34=LgaA;x&xi+W(_#1FnFPo6sUd+6D7XPK{`pPw3Fs_1v$pYjUB=u-*$^3+-G z?W5}N#z0bk>G;=wHnvL9lxplfg&J0zQKbCU#5o1YZ%kZJn!Mk{CH0XjP27tjWSNP3 zQ!hEl#C>R{IBeprC`7z&;=VLYEH`m~a)^;89^erVWYN5jfd^3%J7wY>D2DB~;%Hg` zd)dSpwPMehILAt}!^8#ov27+Uo7;jO8NfCgxHsyqGjSgZVGB*X6~$r3)iPne)Srcz zxF6Z+n2GySBF45=2K>`v6Az>~jD8CqL@5+*;;kuw{7k$JVnk!8nkvbK*?TC}Bdnlu zDxzUjf>b8e0#c5=I?6}6D!AtIeJO|Lqm(L>iJS_|EB{`-|EzRAcqs-K4dCRQ7oYnrDbw+?fDV3o;{~nFzw*RL!$AOBHX)^}5JlvsYi<_}Gmv4r-aZNyr{}cXI zJL{Q-^p3!fHTEkw1!ZF(X*i>d1za>J9aXjYVu0VvSnX zC4iKpw$1dT65V&y^RwZ3R3R(@MjOhPA*N~%1zsEQ*C1VmSTknT$|4P|gWm^v;}OdC4{%!IFKHzKY0umPs%X3#}CUJserbWixtCDc-` zjiAy94rha6Jt#Mir#Q4tjl9viHz=-a@NdJYZ9pm2cNMHkw|lsjb{#ONaayn8HjFt{ zN=a=F^5^mg&GmooL~d5 zcI~Xbruxs{VX)!3)&k3H$e;-FwV`)4AS?q+^|9{vup-5q(6m$PuH(6fsN86^q4XVuQFz+$9c*qvB`T1N(_V za;O|93*~INTyB+j%V*?k@__tAej|VOA}@chaIY?2`Cb#f=6S8~y3y+nuYY*$_IktX zpw}_4-@JQx=XsCup5|TVy}|n?@3*`Ud4KMG!uxk0U!O3a&OW_-oIdG3!+pm4T<5dh z=RTiZJ}>y}_4&Z(vsQgumA0yFwWQV4t&aE#-+{ixzSX`9eJ}NW(f2LiLwz%K@2J1Of4G05|6u=N{ssOs{O9=3^Izfrfd3QzFZu8D|Iq&n{~!F%1SAFw z4j2|t60kkszJOf;F9hrj_${zqV02*Lz?8tOz>$HI0*eEy11}A{D)7d@I|4rr{5tSt z;JKi{p!PvsgW`fxgR+B01x*Vo3#toR8nh;8W6;e(JA(evTC@&o-J$iu)|a+^qV<=p ze{B6no6I)(Z6>z4qRl(Ot%HXJFAu&vcvJ8#!S@C~7W`81zTgjozX<*z_)LgTNJvPh zkRBloA--Z4X z#=`=`^1{Z1O$%!XTOM|O*sWprguN8DFYLpxFT#Fo8`^ew+sd}{+g{T4%C?)^zS4Go zI1djDZy(+@JT5#fJTH7q__Xk{@VfA&;cLQQ4Sy&69{S@964S(Xp}P%8t7_zR+=R$FC!8k-a06A~PaKL^eiV z8@Vm=p2$ZdpO1Vq^8Lt9Bae5IomzK_=oH&&MyIu%HgtNd)3crScKV>xH&MY+9in2Q zhDTiybzju3sNGR-M12)?BI?)9)H$ScMCa(vy*lT09@F{i&Np;^yz{=!U)qGNgDuVG zvaPi}ZTs5xLzkE?6S@?3ncbzf%XMA$bU7Iv6Wu3zdi1R5o1@=~{y6&U=+j+0ckSNQ z(Y2uKbzL9p`h3?zT|bWzG4`13m=Q74V`jxv#Vm`tEM`N@OEGW8d><=gJH{r*=EqjV zUJ?69?3dkwyLIR`tlOe)tGZp?ZA-V8yZzcdvis=n6T4s0{o3v~b-%s)%iZ^OKiK`_ z9^pNrdUWfN*<)CbF+D1KH1t@~Yr%V&e+p7REgp_g37m{kruV z)UUSRo&BD)``gp)3+)%%*V(VNZ?)fP-)Vo`{=EGS`vLpe_|W+N@kQ|q;_r?>6o1^& z-!aFr!10{p#{@^hkc9CGOA>BMct7EEVr1gT#1)Ba6SpOvcJ_3}JJX$`oD-cc=L+XG z=Z8t*N!^oDl7=QtNt%^3H)(0os-$a@Zce&0>EWa&lip7HGU<3KSJQu9#-fbZGTUWN%)CBx zcjob|K3Su)7H3_Wbz|0@Sr23#$~u|tpY6)tnEgujk2#%k;&W1S#^kKbxi;s)oIN>T z<@)CK%FW2l&uz?ImAgInm%PxtetDzvO7d3ZZOi*;i1&~VLrR7m9`eJ`l%X?*t{!^- z&_{=UFiZ@K9hNt&a@e)Qo*wqa@POgY;nRk%8vfddRwMe47(SwI#O4tnjreB7ule5j zVfoSd_WVKlBl0Kbm*&^!ugG7Yza@W1{;vF&^AF@7%RiBSc4WZFP9x(-W{w;?(lxSi zKfe$S4?BP*!kp!PNyf z73?V3Rj{YvlY*bdw;CTdzVmp;_<`exjUPYWHNI;6^6?wS-!}fy@dwABnBY4ha>9TK zV<*g+ux!GP39n7~dLm71JF(Zqw231ox+cz@xN71}6L(JBJ@MU%pHDnJDR@%vN$Hac zCY4TFG->su&69RadScQmlMYP!Vltm>o7{JD_T<9J6_b}tUN?E`!+@mx^e1lQy-c7+|<2O zk4!x?En-^tX@jOsnl@|N{Ap{aZJxGc+GEq+ns#j3&(njZcb%Rxef0F=>5bE`n109f zr>5_l{@L{33j+$f6xs`O3da@BDO^&xp>TWQV}-929w|IIqt%QaGty^Fno&Jt#f)oa z+%w~u8E?<{$>s0r>YCtM?z+Zx?@Tsx_{>=|_ZRgnT3YmU(WgZ}6#Ep17569}SiGQk zQ}Guiol4?La!RI^9GR6cYvHV&vtFC^L#c0RaA|7km1PlSpO+6PA6Y)P{GswU%HJzL zF}w5ZfwN0yFP?qp?APY>nv*xDa?YkX2P;AaOU%&NG&;)ROimBE#9l~XIB{Hwga z^3}=%l|NT?s_I)cysEtF;;L;`PglKG?O(m9`dp2zCawyjTwy- z8VegM8?R~H(YUMerN$2$zij+Z42&Nuyet#1-lo#x?tae_ZOU9*mhyph4zKn3kw#OE?mCw zj)iY6JiPGKBELoL7sV~gUUbo->P71oZCtcv(QS+FUG&JJrxv}qXwRYpiw-aPY|#&k z&Mxk?cW@O;@L8GCELJmVLRDg_9gq4{mjns zjy!=U^GW;({uF!?ekwnqJCYhw$uMcATj(Y6>{H=Es-VC!$ow$<1c z*cRH>*zUF6kG1RBE}>n*yF_=1>vBVvFQX}1MEgbuM2AGTjgE+pitZX68{H$icXV=e zTJ+FpS9D4AWnI0xw(lC-wZ7}w*yXXSV>ia$9D7UbJ+ZIEz8B4~o|z2PT7LM;Rjr$ZUC$oG!1D_sg%M zmO~EPAcs&}dt0QI14%;Ays_tKP{~2=Fc4ViL16SI0 zt!aiv{#Ry$Tw45{ee>+qC{xGQurg$QjXgI0(0lr^?##wIvk(?ckDtT-{Ok<4!Dk1- z&rmT{?vI&pbt=~UcNFxF4L_D^L5{^7>u~J8Pp>=H=jcyIpFaBZvErk*9`icpbM(~F z?~gr+lD8kbmFTGdkuTjCj@(Xk)&P?i2@9$fuL z%Ricru;8On@N+&I_)*V~q7L6fbm*x==iXo5^{cKQihGqVPiv`d>@NPgsw<|7>0*YM zDT?t{P$sHGy@ulCL5Ee^uNRB0w5KmX6*@TlDPOFG+aT_O{|ww$;;aml;j%qONhDPF zF{+&0FAqwkZU37;xm#sQ;DEnJ?v?xGe#8!{bn~A(M;^9d@~}LHvyUTI%Iky*y~C}P zjw_wJ#~;6or}I*t#~P+4LpaA zupLe|!l46>!uxMG>WO)AC}lx=l}pjk!q27|cwcR#GX4_YHLs!dbQN7qchN#N2ydJJ zpr`3|dVyY}H|TBpoIaq#&|RLTUvakZJG~1{d^Bs%A}~s9{AJb`@1wbF2ph^~FbA87 zx%m~$(T`GFoKQs4Thy8MV>Wt+I^iw0D;=a5dJp=~FR42n!W{J}Iq56BSAR%pbOJNh zaT)~u|3JL!X3)=+PA4fJit^#;#@X~6jlfw*9{ob2po_hT`LI?rmibWu3!rh#pT@I5 zn!ti+GDhuGoEc2PyK)FkV{NI9^(GhVK((wF&1ZI6!kn~>C1a&Xq7^KaE@5eOF&jWD zS%12mWzkxeNo!aJ-OMJ?7B-HqWO=leji(#gSh|T7(5-9=-OXIIgC1n%^e|2!9%8fE zV5(p-bS=xr3C~k_oBt=(<3uKvzNZd2<(S9f=u(_stYg`9Kbs{T(vJCaxEv$L%dv8# zbjl>?_6Opfe1J^EyZK<5CX=z=G{{Ew6~BXhjoJHK_B}h!196sc0;dFFI3w`qZFm50 z&4Y1v5W;?7^Vk+v%QoVaV-vfMUC*w@?0*AW%vM2LP{pcoLNb@t#$Z_#n!WH*=BYlPDQq1{oKxO$C=1o>~6M$-Gg(HUF>o8BzuBA#hzxn z*>mh!_A+~e?O}IfeYusrgcFii*sJU{_B?bGue1BuW9%8sueaf(WiQ*x-lE%aX0x45 zrrU6i8B8xyD7{Sn^bA(4-4sO6;bii8XuF@qX~tt%&mSir=s#M~lQ^W<1+CL(lz=%p z2{Uys`UqOKPpB^)f!^gP^`?)ZbvZ{v=npDqU1$#LN=2+Am9S1Ui$zf>>rBNgk}6p& zRkQ9?!+OwM)|0AOH`>64(MC3cHnEX(JsV9ou#0Fj8$;KzQFJdWrh8Zs-N#Dk0anUg zd?ug93;7H_UA!sY;yJvX*vF6aulP6oJAQ)y!2ij==HK$~`3L-I{v_YcKj+W#gM1f% zkH5%|@yD>*?uC}-Rjj>x_#6B){sn)IKhKZwqv9R0pZ_F2gns5d@qsubR*4zn8c~TA zc$TX&^aj6(5Mv6kL&11v}%;p=!ed110fmQk*al4o;Hi^f@9b%MtR1}DN zMUA*t>=L($eDM!47OQx*xLDMR>%~Q4xVRB}ooU$T)QKCg)45e_5%Wa3*eL47X7QNV z4&BisV!qf4?a_5&JTyl)iAJm#%f)1|0$QbXku4^PVPdeDD29qb*eTs2vcv;oo5&PT ziHAj=cv3tha>WEOL<|)7im_l9i$COXEM-`Iu(YUyX!JgH zZibUC9J=`9=t%9X&`r@xF}R5`bi53YbX{`T7nxJM9YYl6RjXx zNpvyMC4{qKT19jjVUeXZgyV4NLunmh#l>PpR}vO1tXQ;xuzJx(qHFbG_;p0r6Wu_x zndnBMEkrjF4$|pnqHTngnzj?&N^~31?Sy3;>oyiWx|=YO(>(-bE8RypnxhAZb`m{E z^bpa*gykG-B9=7FNtlK(D`8T?oP|x%SP`-8VwS_ihIx*TV55i~ zBVonFG>BDMZC1Y|ES{JR=^MgM16vKOHCRHi@?bH=8j7V9yALd)SWD>?Vdcakj&)RB z68N3y3^uUX%@XEKhVG9;U|jrA=Z}Q-mEl+#C%`zC_Qh2P+;PC=2Ha{OEU*l>71|J1 zSuC#%XVo~K$60kaF`V?{*tr9-2*TWp=@zpuCST0G%tovWv1r1)j71W&FeYBi!ZIR}eK;`(u>@j?g!LLrHCAkvLRhb{Ok=giqK)+wTNbRmES<1k zW7)>)jRltF5X&X3+H451p@a#Z4OdrTur_0o$Gnbd9NdkhV%HMeMC>|J*BWjhwwc(C#I}&S->?-o zUx;lZb_=oXq;5IfM(lQCcaXa4a2K(=2}j@T9%A>By7zEDu?L9lBz61YAz}}cx&ZMH zVvmx#1F?(PLTAqs+fD2_V$TzMfz&05mx#Sg>=kw0iM>Ybbz*N2 z+e7S4VtWbu0JaZTqX@_H>>XkUh`mefAhGv|y-(^!#UWxJlDbs!5vfZRpAb7j>?kgN zk-As$8L4{}Ul99Jz2LF0iG4%tTU=ovb<^TFv40XfLF@-oS1x{17jxLpgzEt87gEgp0MI_?g ziT5DhlXx%Uy@~fB-j{eB@qWbZ#N&xOh$j$FB<{owD&on+Q;4S$?@xRH@igKCi4P(^ zn0Pwz4C0x@vxsLC&mo>mJdgMg;zNlKBR-t?2;%v~M-m@Jd^GWkh>syYmiRcr+Q`Qf zpP;S)@kzud6Q4qSD)DK=rxPzEK7+W6_)OwO#EXfS5T8Z7lz18Oa^kaz&mmqxypnho z@oM5V#OD&PC0<9oo_GWCdARaK9G8L?5MM}q5%I;umk?h{d>QfO#8(hsN&I5smk_^{ z_$uO;5noMw4K9EYznu6w;#Uw~Py9;aR}sIO_y*$F5Z_4rTH>3CUq}3U;x`cAO#DXT zTL?M;zLogR#J3T@h4^;jw-UdN`0d2+AbuzDyNKUSd_-^9Q5r3Ze3&dX}yjSs;iN8Yp zRpPG^UcLDn>Z&1sllWfZZxP=|{B7d;K)9mDKO}yb_(#M) zCjJTWBgBsqKSumh;-3-!ocI^Sza;(@@vn)0L;PFf-x2>_UEt#XBz}VU55#{Y{uA+& z#D6A!iufh%_8bXpd~kn@lfd>$lJJ5$h=dP`RwR5$;QEO_ zi2xFTB!Wn^CeemOFbQ052_*q_Tw4;juF{S~dlDT;M3Cr6B9cTW5>X^NldzHKLL!<( zR}wKKVo7u((VavO?B+=HBGH=!F7Nau5l5mQ2|I~+5)KjxBoawDNhFcL{ihTXsU-T7 z7(gP8#6S|bIy9I>I*AMtnIy7EWRu7tkxL?v#1IlgNem+~oCGfB?iRKi323wC2^3%dnDc`@d1fL zBt9f@n8ZgUJ|^)Ai6bPAk~l`_9StWJi*bBs-CeBH5Xw zjbs;+(ImT)j3F6IvKz_nBzutTNwOEo-X!~w>`O9^WIvL2lJO)RBojy`l5~pN^%;>=_CtD&LHU`Ig?}&$zqZvBxjK< zC0RzYoaAhhb4XT@tRz`QvYKQK$+;wJN!F39C)q%99?3?M^GPlsxsc={l8Z?$A-R;~ zGLp+lt{}ORVb=>a~#pi#=_gkv){JnocTBkG*maq9ytyVl+{(nP~7m|Qq zm8Sc@=>K~y`hRJ)r`+6ezcTcPGygyMflzmVEA9JD1Xm;f-d82@jQ&@AzafgZf6Grn zxj4W7mLH|*diX{@L7=k3@6SHwdW-;# zk6plr%EQ0<346ZHEZeCt9jn6 zi5HsRG*@PBS8;3QZ7vB+P1r1)=u5k;TJC=3cP4P1hFE@!k=Wd7-7BEv^j+>L0qZ%Q zH&S#zZ>EbD=#^bTEPj-4tw)N7=90~Ecdk{w8Sch_RlHnC$Ht$sj(!yAPZ;=(R?^Y(4HaP z$CSbzPp5Bdss-%=YAOCu*Yc6a=rSEoS8)~%U$7BPbu>=;0+cilbQ&>>nq01^t!OIg zt5kCEFDS)0p+IEQcgaoA?OxU zmKzEx-xI3ZkM^RJfFjkZixPk;DOv3xk~+PM+)}ipl&mzN$^_jNeI;m~AepfbJcv!IE!s&53 zo4{g}4HrvOHe4)2*>JIu%7%-LQZ`&{w6fu1W0VaS8>eizPy;qxY_hW9VpEh27n`bV zxKJN9Tx^E2;lj;m*l@8TWy8fvlnoavRW@9#OxbX;a%IB>YOvvA70QMSXQHs-!l@{1 zxNs^88!nuS9>M=YWy1vyV8g|hC>t*D0UIuG0UIuG0UIv1hC@7Tt+L@_m*XBbY=V>x z7rR2)aIveE4Hw&>Y`EAp%7zPy+GL0|%{cT#*3BdBhF>^@1sqhAZT{r&aPS9(K0(b- z$4y+N|K2g=H{l~FnSi^Qw+r*|uW(uxh-#GJZ#mGhAl;jWX~H;&efYS z0X-Dz3DmPjJaA|{!;ofrgmb)~D@!=M2jl(LOIyN)X-l~7m>?$7WH`tFpo;=-<)*<+ z{0lb~a6dSASd938!xjDoJvSeUCq-9<<^Q4Ui}K1To|UVED>b2tD;EYg0#3>JLe9;{ ze>?07ddexhJ>V37ivDO5ck`^mA%EfAb&`?a(p{)6|Fnn;cjOlYn5&oxiT9#L1M>!Xq zdkninHD**i6Hd`IberPS4Xh>3|3+H1-~AjEJ{4E=C%~z^Y7eLS)nD~XRp)lNmVH~L z|EkXa4P4=K^XnO^et#j_EnzKbK7e|U!>Rg8&T8(e@^Grn?zuAnaVMM`hx=K%=Oy=? z?0#NKeu}<(JxD@ajlj%4P;n)DRo*RIB?rZq%5$#;Y93aycJu7! zSINaKb2r}@Yv-=;a61vd7!IM9v8to+D_&Hn_*3(bqLB@!VD9ItMUi!X0o*R!5Dy451oFD(?|EC0FHCTJ`_o z(1&+`n~(V8aB6*5?NIJbIK`W)uR`_AuYp@t(z9X|2Qm2fqPuYg0{ zvu`8)8XV+*_F;s55RQRU`O0mFdkMII1r6|Y_FCgy2qyrB=ktfk2M>R|@fYrEl*2Rn zEwwrS_d3LX0uJ!1@rEM~9)CX#9zx-wk^dRmy95qpo1T%9n|9dus!)w9C9~de?)e7w zb)J%+lBt?=+|N$+-*a%PFDRJ1&t;gjf+?r!Dwujk>iHGJDLNN&s+`-o`?SK5W}MzWd1ek0ELtNXg@@20M2sOqTnd38O~?!2Z@ z;c+|lJl$~>B7N>V%PF`!u0nS?H_S8NGp@_Nit=#ovhEOik3YdRO!dnabz0Wf^ROzT zaKv7?{J+BC=A&h(a4MKPbm!|iSCAlpyP?BC2vjj74Op_i&F^0;M5wZ#*-S0YW(G!w1TNIrTPr!T0IY_c|baq9bUT)ZC2*g^JqmXK4tHH~2tV8;SRuE1Bdo&r|5%s&4-G= z35U8D;^*Jt1$Q7VUYhs-zW;>2;_s-c13W7|oNDv@7EbAOJ>7Zvz%d#3l^rP4{D*UO z^>?mB!?ilif>^%3Ul2pDF%Byp$-H36qbyHefjy5OzWfz{JFzoyDfT{X-4jejbU$6i zLU6;o8~s7&V093R3$oqmYt|MTydJPfXopL(ud)u%fp%n(xFP#Gi^2`rH<*oeVbQEB z?t}MYG4v~oW!+eJ)`NPpo~#!xhwp*LTiF$zW_{=_*xkfIn`)=NxF;Kji?aQ+Rgn|= z?PFx8c$N$cqf}g!orPBI!)@8Op=TY)2C>1=CYR!_>^m%zWwC6Q1M8hUZND=NcVw@| zCD{jPCvKg8Pl@DY`OwIY!nc%0(`WQMy9nCYvA8aq%nI-giV3(Zn?eWJBzl+1aAo!& zbh1;S&sFwJGoXi^2`y|fbg;8%ErMU0@ z4J=(4#z2j-Yk|Gb8rZfd%a$u(1GJu937e0rv`x%4(8Ug=VYoN@o3WI+0aiw^d%>4& z-hvV-hB_C9pk zhj4>`vesvRgv+y2ptb*weL_z_r+rlGv_FGQ)aUdiF3{cttEMlZ+qP_rzEjpk%C-o0 zL_e~hU@Q7FJH>v1w);1B8rtqN><@MpcC=6xbIt{q+>3j2AKr@lazE}5JETBpzgzP* zuto|o_DSKq9dFM&@CaDnM)FQPig)HV-i1f=t~`dv;%j`}c@N%`_u{>IAKsV8Dcd$4 z4-3@Z1U59}}?On}qM9OyN^uxiekc?kFpsBG}B8@L8}5EaT;THlM>QcqOmm)x3t! z<+Z$y*YgHGk2mu9xUqU8U&t5n#e4~0%9ruwd<9?0FXorrVmb|d0-w#X3o%})m5WX4n z2>%C8Cmw^1(&PLI*epE-%cW;vwX|DXCcOZ=rI%nQ{0eNAUW1L~8+;Ee5ck4TaUZN5 z_w#r70sbyO2>Yh@Ve@o|f5;ERvif8G2|vP*!s6*u*f@O-E2l4EBlR_`q`t*9RRQ~` z-k+Nd|Ii~7Rm zs2^;M;$dNw02?DGERd36ag+)>qyexy8VF0M!6F^DPMNTV%EnF9$6*7N2OFrNu$3AP zi>-WEZ;gU&)kU!18Vg&l0@zkffDP3o*i}t|{nIqqbQOvj!X;*kB2g?##4J$?+o*Eb zcFlpES0!w)s$thP7j|5Au+?gS)m9_yv=+dwN?BDcfmPKqu^cv9D`D$(3GBsI!NzJe z?8nx^&T1WO$=1Wd>MGcaZGe5*M%agKf_>NZumRf)i?A)Q^4bbpt!=R8+76qr+h9|6 z2kgu4f`!-)SeV@lYqR@d<+T%*To1v@>k-(MJql~FU9dWP0v2CSiKoRg;#sj6xPgbVb9zS7R?=C)7();%1$y$c9u5TMMmRG05LLFc9Y%l9i^VKm+US3$i6a8 z_JdVtJZw7?V8f{_I+JAz&Z+vtrZY|3b`F;5GDBwKD+1XvN9M{rIRxKe8U{Pi5i%cE zprhnyScQ&(Md&zL0L#z`a-y6hC(9}L=D;*q+ZW0i(j{l&7Up_73|p@&=o6f|9;FX) z-ueL@!a3d%Su9KBELkecWI4XP!5yippz?8Y*X1l+5?bDz2_~6&00K)q7_b zxlkHGZMCc3J4f^Couh#k>P*9OmLZ*GNM#w8vl9Jsn$VdlhP%uRpB%$Yj^Rd2Ayc=; z9-o`&ou?`J=QT5@P}t)g4!^u6ta8XqSFQh$<}%(xJ!G0?WRR8OGt^KUYEknZT3=pK zT;e~hxu%6ZA<27$mWua?rk2{{6Efup(DWW@WsUU6N_2{xs#5P!9%QqP9I{PgvyD8m z%_GZp%ga2vtQ@aVW!1G+mWZ+q(>d;1rc}0(c8)!8R9Qn+sjIf3vclC+?=#9YO-m;y z!+%s=g{!X2;&hA&JQ#K+d5_gl|FJC^?}#@Hr)pC6_>^2Z4)XOL=TSXLvt@V0XLuKQ zv^mGLEhovVpt&tM24Sv|NRGR0rcF6Hfd%KarNFeMz+qYnIcmqzR8<->{XL=~H6ZC^>IH>Sov- zPF)TI)9GERDf*W-b7x7wk>FR_gk6@YfmzmE#=Bhe>sua&k91dz8#COZpJl|6mFiP& z=$D%zTCShE#_dQ*_MhF1%c7T%95AP}wxp!0!c|pVUgTY&rRH7HBoK_-ELj1TysIpM zR=Ly%ziX>&%1XSeJc=bIi4t_PYLCaBZA6!CSX#Sx$CRZ(44ised; z+0CdgL}( zBe&6Fwy~L6-^Qkq+h~p41OmkDc7izSA3!8eK?ih*jdbY7A z#%taYT2oeHyd{7{y9ra><*cPOG2R-=iFS8AYpzI)wSyR~Q~ z#%mcN-<`I`PGY<@ohHWXr*BVm7`hHa$6@$$xcM{X9fmK5;mcw8a2UQEdUgdq!;jsK z-_Um${v3ucyStp5Z+Cm$bPT_CgWqoG*$o}L!Q*iAXXx1t|JD}9o@mYb_QV9!&IHp= zYt9ASwA1N+4(@!zM}pzY>4qDA5)3~HhMxq}o&?h#r)hVB;WNRVHtk9TiH0Ai8^58SX!uJse3`j4(dp*f-Cj2x!>`le zcN%(5L&s_GB)a)C^qlVJVA46MUKtfNWiFXnQt$H0b5&Nl^Z-dnP4vmBsVm1kAtxhC zY=bIi7Q1+U10UJICzfNIQLc86d~~@OQ&#OYw!E~`CC0fL zd#M7(>jDf#ooEG$I^wGcTKNXQl`uGU!f#Y%NvSEM zin}L{)~1j%iS~Gvsz!SimsHfdd`e7{7a~Kb%zEAAa@FKHy2%x~$rhf> zEMC>X=a>6bTkRILWz~j)!>dj=z8;NlFpaN4!;9dM^r}|;`YOCuV^qw|WUyz#$~Gu; zqP0o5i-)yHTQv+zI^n0OSyA0^tB7f=PP9T}b;RP|TDlzZ@lM}`CAHOY%2PQGdx{+2Bhy z_>v92WP>l+;7d*o!V3##d93yLMUax(jx{B<<<-UNH3i$hV!frv$`}_{gqItwjO}OCTO^Uy09UzHcq;5$V}`WN-9cb z)fc)M2veXrCH3b4V_N`K=|TgmEypizSfo8mHIa_=ELT|7P&u=t76YWpV!(PDg;td_PQ_1`yOh1KIph3ZIP*Vfjc|r=C z35U6P_7rAl6HwE$1kwa^M>M#(Xfw{vt~zw#^13;Ne~RcjZJWTJ?G0^$>J6+e*`c{h z6xO(E)fk>-^(W69)roXR)pa_0)bZ$a7G;k-kEVG*J%rfa1AJbaBRn#iqnbc$bK0Xj zdqj09`@bsHvO-&r3e9r%iJUx@DF%KU-TzM{-W8ud534eML#R z*|Q{Dn;m!Rq^`z~vXXeUcyzA;H5~TcUW%*4u`eV z2Hfcb5|vm+{2{FJd9I3*s-hDAlKJK6{8jbkt_rK3wX<_L>{)&mSE`CHqIC^3>q_da zLMcwait5txBA0p}^)=DzT9s+HXIe{~!`jPZY1Df^Fp?ZlTcR{?7N#I~0+U-4V!U_M zl~-pS( zQhYV2xVlkmpCBj*UR6?K)RalGATz7$%dA*KO|dDRV=dGPc55L|&b3;ZoNF!Q$+=d( z(`+c5W<%k`hN8G?CKLg4G!3WOP&mzo!kLonWpZmgN@3fowkggO>$y8qtVP_JlI>G5 z%cES1-XEi!C1WSHBenG&`KcC{&Qyy_XR6^c)!J@2Q?1_OOf~gW4Zc*ppNA^M>RnDt zO@?%?Pena6Zp9^D+V?4*V}+XAEW>S%2`w$4!)a*}9L_9*)lwiKZMe!x_MKH;QBhJn zvwFVO?hI?Q;><97S*j$5(>w*I89Yww-5qdK4)5;uwdJl-(-E9dG3&H>icU*!>u{QF znbT5rA#K_THIgo0TW^IGvn+m~GqPG}Eq67Hc^$dU3`xMGs+fS$Ue(G>q z`T>X2dcSr!?WSK@@9Pey^?rza!>^@RK-%zQH~d)d^C)lnQ<9s1H+>_AL{mP|;7c}g zwBC!skKxaHp9epteP%oCw5CG9-Ska;Gp9K1hMx8Q?r@Vm>q+hh2(^djKj zH1TOJ9S0H@~JoTlx}|Gigf?fwXz9mL3E0GSA7iyGOaFv=rrk-VoTX;~UBgF`=@-@!0N|$o zSb7uiVai$hEzmRhX3cZPyPvzEpJdwawD?UhuY*Y$R{N67e3u;W^sX$g!bz2PT}e@O zRk5CR;>{?Dk5BSdZv~ZjWt!F{RyR3ImA`pa@W${RjC$TEck^@F}>4?Zb~+1G{gt}kQut#rxJ-g6LTYxUAZNlZwYbF!v2DJz^&Nf;y z9*Ej`06YZ|<_Sk<(zV-r0u6ed(bh9V#Wl3GhBnJ2N~cX1F)9=fRzh^P`<+%}h&T^) z-qQ%wS#HjP-Ki$ci^Y-}2F7_Xsvw^1TT-z`h%RO|^a4XBTGR1(Rs3@^f^?ClQ5D{l zJddO$o93q$s*71Y!`&#W2^OrmWG9c3R-R{5tmpY>xb-|OxI&v{I- z5D&1+Qj4_n0C{4F@PIc*H51XzX{Z9+D!}vFVbQk^**s=RwMg2{(u+`U0qhQQ55s|b z8YTlY5=yWq`|2aQqUy?-zWOvy#VnlmOn;5ro)zb+s5daZwX-LfBeMi^ z)RbV)@YN@U9<>t#%c`sAxMo(*!=m4WQ*SBk3Fb&IAwDwzYT=nB71fQ+h0J+bf;lHk zFz03o=DaMy+K1T_5>f&z22-@+*d&s5BB-fZRMcuH zIMjH_fws$pdaI1I9zQwuOasp}aO-3R@B}e-bQbB4TlmrY>cg%2dwx63_xx5A1z8N5d!|Uzs0+@5)cWZS<+Qp*)j{ z@v-`&Y2YZ)yar^Nw?m!;JJ^ascAM_jCqd!6T#TELE&d@p7 zY>VcJ%QI79-7o`|4aJa)vKztgjE_D$@}ZFLSoRErYqM&y z0y58Lp2%FDSquL}CeQdP^F+q5j6NAr>G!8^OkXwlmY&E>E46aw_F; z%HEV=DJdCI$y<}xCHvaC6rk6-UIy^r_a)O&UBg}wcHsrd0;*Y{f5E2!s*p38ey z^*-L?aF6E|*F6UH=repz_e0%Z?LNMH_V7L3_IKL_e_XfB*pKmhS>t1e4Br!TGUkhn zsF)csV=|%;Qr925e%5t)*Q&0OU3v7*=&jMY(J9fry1d-w-Y#if;-Y&+_p%+fJ#VYA z&5Zx1^N*d65)#`;X69nQuapfjNA%8E;2G@Z^wH( zZiXMzF$BM;c~#2Zh;9)99X54X-C>q}ZYTDK3nD`;&{N>Ehbp1_9!GXrA+_Tv{(X9bM#Kka|Sf4zUb zf22S6+v&H-&*9hJ_hsLEeJA^-w>sYHK&#?bxjrX-4*7(8uf+c#{KD%ouN1EsFOJ`Y z-6^-@9`IV+MvlPk>?d$jJb>df>ZEwr<~V%T37kp!rOE2KwQJG4xV@))#F0EUm@!|p<1)nD>QP9e&uoa_IT z!!TntbI=E6!?lzoKHV;0uM!DJ5G*-TbSi?U8YtE#Sj%)&G~imHR3tt;cOknNe6a~- z+vBV9_~tmiI0X7~R4M1685^ zaRXq_Mw~HU1%Xq%s_*PxieESy$W)%Bi}7np16Wp53DsA;kz$yio29b}@p{m)>-v$9 z6n^DiUX1VX&yXwO&y*|RPm;^wf4NUv@{cqDHlK_Imu{ zNFP-PzYT)AxfO5`ro9TH%HRp+w#sdVI7(zswp`AyRw+X(fP}n~Z`RZVsO9sinw}Tz zyhgy@G6thVW6OC0*c|wjzoJ>BFai_Hjl#(Mq6x-xKFj$Gko|@eRSv~-mf{onr(or! zEOJ#%a0`dhupL9bcBbXvM$K=k<*!_*I5V+(+Eoni9 zHvp58q5El$!#+6?R(s8{}>99Rk&rGH9V-(r; zZ1sgl@RxO$<+5!mPdj(t-Dp~xdEu63)!;{U&~H#}lE$Q9hhA3Ji@Y^G&Q%(b_ zXr);$MYa4qT4<^II=gCV{)L`kmKyijn$`r3NyQz8mVy9Z<`IlJ8~!z|%zc2sK~jnq z1KyStuLeX>yy!v{Gx7A(FHv<^fufkXAL&|+%YrD1Rm9V0q|X3Um6&e1^wCx+)NLLM zR~cHPE=UVcKYgR7HCAJqh4e}b3w~+HY8~dA^qTYY3`8YEetWQ&Y|{ z;!m^!jFfXPEakNAsEHl}lxn47={=AhXJOG0MGJeCw9K?jL#ql9<;(~|UG+pQDF+%U zqh)_3 zh$=B)q~+{iSfxB@wKY8Tvih&b zuicc{u{pMQ>Ax5->{0uV@As$GQ(lQ5KT%SC;KEW)J%OKA!}A5&!HSE4uOhwO&{Gg( zr0&7bPhHjTDvMg`Q-HwrTW*y?UH6O;Vx;`Qg{7Q|pYuw!X5E3B)>Ne3v#x?DTKIXT z)ETKW5C=D@=!M#yKkHgj4mDCn%l=Brsl~t+5(m0KJwRbh`wA=gSz>W`!Uo3E4x}9b z#Jy)wF7 z7c-Ftf+mQH+3DHnHcq4-@F10|FQKvL_9Exr4)E`oc6IxxQhVMuMh+R`=zG zhJq*>kX)Y=eNGq}kem-(pCeW&s~u{;4vTDSAM$@_dlT?Bi)(*a^S)Ya$962+vb=Ay zYKXI?FK9NO=BzR!B*wdQE%oHH|L&YU?j@61n>pD#Yb z7+=91Z?9B6!1U^gUhDU9>mg*N>M+CV07JiRy&sTkBz{3KaACYtryB39+EKLwG2}E} z&p|O>Up0CTC%51xG-|zd5l$A^e$^N)jDt+GhWV&Nyj7z}5KyefEY?_7Npl4m-+_3h zF_Yt>I*1eqMonh|7uwT6^Wj@?-4Mx)5nk6x-H@&oKHF4@qY1a<7+yA@KY&0bQEqt@ zS3f=}17KBvDJ{pSR~jB7F0^#`=fZVLhC2**RBj7%Ra4CDr)5?xEqQ%JjVubd(qYhEA>pbocTk)tlFa!6_9W+K`J?6=!bX#DvA` zrg0x^j)$5`n6jO4y3sou?f_o&2aqI~;y&#@jaK+nj+b}F*iF=3nxJPKm?|^N8O`&URW0Z$}e+0$PtQC)|_FK@M@?LhCn#Wsx963pQUvdqcaVR0`cwUWimxGTxAj zI3x)Fxi!iu2SP(4<>e5T3>)NB+VL2ZBf4#Ym!kd!j4QiKz06Y<^Mp2`t5r*@A~40} zad`mIYFkh`P^&+zQ$=Gbh9t>L{eHmq17ER&EVD2-0xLXEMq@Z1Ys2~K2WMjm4s=&7 z>ZkD;#9x%Sa5@)L#Thw@?g_`uOp~a}Q;G<1g2ceJ5^j ze9yiU|CtLrMjiykaSBi7UUHC!i!IepAR}`8IY(OU&|VJUN0z0`0m|>VO`}B+{9xAs z?}6G#Ym~f?_#Qm9`Y3rF@hQg?$3+Qx8wJOR#G>&5-v!Qmk$jvp%9PxzQ%df26fz%4 z#7Dy;z=9s=NMsl+Q1qC)8}0@-H2xC51jE0QDVAc$NJEyNqyZgi(UI16Cq~9`Jc$DnFpK(!Kx+WF4l<0qvP%6O^%!4l zdn8^#FydewBWBOKsY=1O7!ER@Bo1%^)r}Y-pR9PYh;$E*aAeLP zn-#}_?Re2?hT11ZFdHI6jq*Lik}dsTIi$-a9D}a7PvoV-h#Ez6O~VC zTo4RgR6dLgVBfBM82_1vO7t=WrTis4@jD09QjwQAh(8Yp+tAu$uth07uK2{P<6X2- zA8@gL)%}e)sCl*KRY1HNUV;$^Rgj*-$}0Sq9H5s~W&>X`o-rJhzRS|{@!}kmqYqbH zgC}u-+eX2`4%7icIr=eR@RopswKZ#XqU-|=FTp^e>~*xSzwCAVXAa8HhY^&DIy|Es zh?;intf1brVE$KA25JcS<rag7TEvSrS_A<;dmrw#PAN-~wCvF86v`0gd?fWkOyOiZD$6p$`I4wkaV4#2;?*gV&CssqgM2Uv;50bKgHyt}Y@Bth-bs-K4{)e=b(y~R* zRNp|4qmn+WKBaN8V0_j+g%PojY5tzDRo#JjlZJ;NR33~Tr6u{3_%7qnJEiHR=^Pi> z;lhC}7~-AF4!iAVj8(=)v6p6%R%I_abPsa6E$MIxp1$QEa3^CO54q(3( z;a_C#p0@)d#|}J+%5R8D`Nuku2kk-uu#nX%&+s@S9O8{e)|>k1Kx6<(el0` zDd*1Wl-yZ7nM&^cNFhT^sY?UcT_#I?j>TA7gC2;0{4X;NBjUs}L4GM|l%j8!CWPk< zj%#7Zp=J<>CQ>@iz+yauC-dMq35X0)9}m<9x)_+3iN0b^WR4XD0(UaAc`ku$@of6i1B5Z|KZ zCkRnV)+srwv&i=3xIKh;cTP9Qh5bGBB7~eqEmu?*{vK4NEz|vIIKWaQI(3B+)>qO=rPWvojaU4W^Qp-&cqI9E9$sEcg z`b6gn88SUuDp}`8LF0@@W0Brnf;|i+flRb8a{U)mLMcli0oD&0_G7>lN1Ov1${N<5 z1S9(Bw2J)eMggouvgBAF>J?t zd(?(Y<82Sx9<;(1K>nu)r~NA6JPay_ty2H|h&Z%wp|-Z+H>;P^J_)F5AEpmr6&iJd zf)5)mCASURhOOyVk|5%=or7v?x3yaVit?(5jR9ZGHBuKX+#8X8hfYbqqu^#v{{&$w zIfY3!bU^{y19%<>Oer~0asrTWA0ikiq>t&;^s$1Gf)T`!GadDZprj8Jc2_;UKWgtY2Y3~m+~S;E66Bv{2NorKzvrqPY_T^c?e_Nv7BT0j*_I@ zEkh2?UlGqafcPQ)kF=bV`Yw7Td=Y;JgnEnI*K|(5&4G?d8NrkC{VQQBJOXTx0*s&p zdjK${@IWDG@A?M1y9K(q!SjelD&Gq-J9Jisuype>=NWaK>nk|U%_6)QxPM`H#E9B zVAPr0nFfBzf)6k2eLR_F*6V=CAak+o88Mcih5p7=<8(LTZGj!SAl@rzMeS&w+N=lB z8gDbDdx&=aM~IWIAld}Mw=CFUDNm+6iSIHFJ1pgqti2o;xu=j~8o7?jc*<80M;+k5 z-Gx*Q^WX=KxOUyijXAB4Mu+V6D-QpaWyJ3;+&)mGuFM(Oa)9H&z=yXk`%a;AL9LCI{$Y|v7&)=fF3 ztl)ey_5yBZFyi+GIyeOsDBzddnU4VC4{CUBlN3{qpoNa$Dd`Awp`yOcrL7}qnk!$gf{C)Rx$HG%+RN|{cvPFtrXH7m7!CQ_}|sK+6WV5QO%*Ic^X zS;ZNN$=#vHG^=UseCu_&ki+b~coLScFgLI(vM0gSZid|gn3CH>5|%rrQ6m^==JuiA zHs|)?Ki3JTX#ze6zD4^3L{0zH}VbBtm8VxH$GET#C zJFQbPPFr%BJ~+z23^n6rOM)d~9(|Hrt0pa2-{oGi$Vy%Y+9Ca?O!G@jGZ*n6YM2N@ z6!yR>eGpG7F~z6I>V@sgHIOj^2txYxk>CCJea0GVxv})Ba~eM*ngx3veY<2Y>O#uQ z7m24V^ernYMnb7oc*8(f?N)UWYxL>El?TM51 zClYQ01R-upOC{xnXq}C;m)s+`NPFS#dXa`ULf+3aJ(M&p-0}n=dW||I^`mr>Wf?C) z{GEi7NIV_!S5sf*xJb|=2SVxz%F6+oDE?jSZ6eKjj-srUk2o1#;4O=DLIM9coTmoeE>(!c(g2n5`R6OvDA0L2TRn?BO&pSHws8` zIdg#akN0XA&}UI6s{yIuz?95y;(I;^tybbOV~9^qkRvc?$H9jY7cxg`E$%(U-@}vh z$GwIWGDP`QM3BeBi$06jgfirOfO*|VoMm8Kin~qYl_9CnP1FK$2bdP{$A1tjG3oaL z@-}`ai2;TQ5#qCm$Bvw|woGI9g_Zqm;3np!CE^WPDpN^2ZHA(u|yI7hy|>grt6; z;UNf7#K@oeX6l>xjuhq+Kr)f)B^i&4LmVNMYA!+@Yo2H;J>J{`)PNb~GrE{P{3(#- zRE!PyZ6{ORhWIsFeu4l~$`hcv(^!Y^pqlcq45{-*PFT`JW$F1OBIOF;C`&D4O4|uf z8l)pNT?Sy@0hp3@CJpkDifAMq(f7cjeAoQ0LAF0ZssO=kGd$l+$p$PNHs%R)tme_? zOnS&3YCgOZXc6zw(o54A-e?4fFx5 zPve|0fX}7Z>h$IY`9U0|Ub>ruYR;#RmRd>)W?!hmIM&;|$4nb(&ym@sHP}a2tUt>1 zHxt&>?_eKYG8UWhz=ms6?^c zjzM@a%yqlOC$YmmQxEhMUl+=_|w1Rp@qe1D2n`xbzcqi`CAsv8n zB%_xhD2dmrKh{zbHzK)NtkdLo!AvE&Sf?Zx<4K%P5Dqi+V>0T30$}5SDdxlG!>|g& zv)GN2deUi~nsk~zl6un1Nb|BzNqQO2XkCb;ABxpX-GrOcw&`%^E$lBxc)pu-6uA(P zV*}H7Abzu!Kd4c{Y%A%iCEsB>z?`%b@tt^bsh1FMV;nfH_u@OW0RqR9+VNcmAN}4DDjp;^4-7~bSMY6K_XgTSBMYON_-J*hY((mQ#v?zRFCCp z6vOhcV78QqvM5AVhkaf|5&B8|S))i0lpt{zR!d(Ouj4yXB%&Wt5HD(}V&yMglfPct z$*1X-b9}pr`8sv!H15VqWxA^f>(ZkLL+JINDi~vcnV`zj8<(O6l+!W*x*AY*>0bH( z7UqD`g3l$-==4hyalaTohyyEHkb;{05pFVjfYNY4Yd}I2+|3lW(HBVR60|?=XhYve z`eDMf6nXJp6$ijp0;VLtoBS>yVI4y0hzl<~wT<*ajCiQwpx{2bV)~r}$-_(Fz@Tvu zhxzgK=XxI!K0rOc!+C}XSMn8zhsR%n0AIq3D9w*~PnV28iTEtqjHuJ^k05?Op5gdW ztY6=z%fuQRaU(F&(lbj-eE_NViG7?}BxvLrnWOc}tPz_4Y2DM@!G-HF(T8a0A}X8e1wFy6yjt~QRwp91U@ z?1@w1eRaqKzHrZIGvkVt$R(OYdOu4d;}3z-LEV0Qs9cx}gFn(oyU|WN@Ciee#E%kT zVL=YHU3IwO5fYjBCVc?&Xq*!U;vD;5@V0Xqe^?sg3)vP@b=lBI>6}_9>yT3@UObTp zCDFz~+zCkIVB7gLIo>!`^xd$CC|`hhP7GoMse@GkZ4OuuU`k>jF#t%|8YdX2=;JVY z#l_tTn~3>RKZLgb5c7}^VG$7*k`tkx!g(7;#Lj6^6@Ek9y7mmG?IP++&@L)^90la? z6ZIu0mYe`2Z1?#jbro}Q+!Tio(jlih!$H9fbK&uiTT~rasHVfbkl#}BvcMKoTah0D zDLa{y5yZ@3{dNBF>jg7Rx2TKaH1Tmj6~4syj~fd*Bc zz^_tgw-crWYLBqaCJ68;ccM)T@sYGhry)diwjbZMG8$ivctIEFB;!-CBA&vN(zY_C zovI9E z?|cVOqUdCbd+@fvy)ppS0GJX#9*H)(y17=x^XFgbA}lp{E%lQ6mUZL*Lb(!jotruE(0F{-^q%a$M*R0|ITX ze@w>p58?Z(2oGs-^b|b>@-GqAh%Qj>()4QpHAZ!0!iwoG*h)jOmJOXFpeMP~>8hE- zLBzxTi6F#LD>&K`k-Rny3NHa}1uQ`dnF_6kTLirvXN{sq>p`<{9jX|WDCi3j5A!LM zD{zZ!IHrhVV7NuOXYm$QXVITVwAHN&;?;B%eZnIHuvP-5m=2i^0aBq+p>&`J4WTL- z^g#?c)h!$p+J390l=TKX7aSaA4i;JeR_oCJ>u|>{@m$6{=Q+KQP4;nsTXYx^=?2Eyqg+c6JO3pg zkbm0ahY;mLdLw_U^`{YScE3QwsTGif66PS6IZzOn_L5FV5a8qSgTGRW$oTR8LRyeP zXe-q2ip6OuKSu5+m{vAn(xc>&6A}mlT99G|H~DH~wel4}D1>!gL{EU$WlU?OW;4X; zjzQ~Og<0=#?5Y;E5Kh3N8qQ>z#rPh^Mi8puM=)m1L~5Aq9D>qFHWh(>OM_ku=wJj& zwg{!gya6Lb3VjE+Pis)DD(edIk!{q6bO@1D&*3|zk6J;OBBm%S7q30C9;x>sPX_P{ z6{BCI#}R~Z!D}9s3LTBl2#ZL?+nQ7ipNCdDa&|MVbfTrai|^r)o*+c)eU$F~aOrff z141EO2h<}e733d#TF~-ZOxx+9?A5GQ+%B#0VANd;D>MkYHM&%d29@g&J_k9!8Bc-T z3B*wl-=P-}cJObML%}W9#5Mi4nxSSuRosJ(58`2)m7v6%v{|Lq%58+w(A%VBvy#9D48&zbj$ozN3F{|*1C+)IH`hzAkYqJ7rlNzi0K71pdmc<~zo zphGFd(VI?TOfjQ334_WJPu%h|fVf;VLA6aAj@#}u1rWu7yDXDK!NY)8L5-_S8 zVqO+#AC@sGXGY=!5)hR$gGR9s*bDKI^iq&Q2Er|H21l5R)OW9Gl06oAyO(?-gDraU=bs;<&h9+$-)7H;X+u8*mb*;T2+k=~KE#v8UxhvYdct zv0L8Tu(!gacojdSoNj9G$7wbz_;&Vn${5~Ke;RK%^1EYvSM>9^mwYGPysnS3hr9IMQ2bh!Trl6xO4dyoQy@cwO^)Ou6$AbJMMAL#SP6xfEVL7ce=}c zKW=INvT`qOk$y)#qumhwzuK+PpXwo)xCJ^6_dc6(-*X1uz{tTJ&o-P+QO<78 zYjD#$-SB=B?rW!;+K=K^>fhtG>F^EHA7gDu#d=;A))eWzaD(z1-9e4JqlsU7N8W&Y z-f^$HO0AqkH_hW#>)+w6DDp2Daqo0G=I8XzwO-kao33dkPEl^<=U4cNvw(o(X50{e zA8wo`eEZ}L^7yXDjq`Wm=4#5bOc}&)SKxN~8x=b5MaA9pbi$3IT#KiP@2)VP_rZnJLs?_7@Q0nlsE46r*Kr^ZEnAntR zw7l#uif*UQNoT0>`CmJApNfm<6fk9(3cdaR@p)7N^9(wn4X2CgW^q!JmChK$$#BEU zFK~`i_}=ZsZ{3!6ZZCe{_GLIlYTk|5+<${8U`RQMUPI@8>YU~xv%SbHL{U)OA37$g zLQf*Rtel*4G$?IYs%k?Y#JGbRJBgV9`kph*nPw}snbMr44o9icXli)k^2ayS{db-J z`^_n-3cR_L`KhNw@*Cc@Nl9xv>C{lhpgyWNxQ31TVE$szaXw*Gru|gs(C-IbBjq3r zXDbzl`Y51C6~WV$5XD0|z7U&((y0VJuqgD4=Rl+UZH(b03Wcqwm1QgAg`Kzve@Jy+ z{=O8OgVHgcgNs71I|ush2;OzkI#EtWps}?P<$C>_VXhtOTUuI^z7u-)c%)^%8o{xN zrKI7k3)<}@+B;KM1QWj4;c9HcJs?J-B|XFGwAdF4f%wGT<)~e@q&Po6t9|bG3q|62 zS6NLo{4LOsLTkYPzT8cSVG8T`doileJtjSid575=jE=hK%|EN^OEQ`ek^h zH#RkaT!zI4^urPLLOM{!K2|Ccl5OG3aY+>*{K2^936x6B;IbV!%J%;2igP zy8NEdcRgKQ9`A$`Z8_h!O+zC3JPy?{{!w`3S{KC z8*D9>>}H3*DSlB_pLbi6%-ItiYI;d_as7|Z$2hgjLe9qwQRpL(4q2X2=A8PO4(+uB zXZXt2%0Rstjk1}{)J|iM_ik-z+1k5#vwzt#|7PW6(^OaJzq>X!4G;K*%{PEnPtdTa zkSA;kPIDDmRBHKia3x^(+I)0k#j<6gZ=Z`4H1zp*MOo-ou?#)n&6T0K5vog0&79e#Y&0we9Zz2jx^YqHSOf~Kh&GaVp&N-B zw00b8ZK)OIZ(WfbxiLAuBy*rN(25Z}(2WtUqfqF^2$b}L#JetnH%=vKk3Rt{Qexr@vT6<53heO9jd*~VEHzR);2|X60W1!qVOUJmN%}C8Hre|(@ zZ&5|l-R%jEJhV{PkPROm*`xhfLNR8eJPV<6lwAmgq;T34(o3jqiD9cgihSmkM%!<{T^zjq_7SCNWMu9+?t7e)^ZR4! zY9UnC)k3JO6$vGYml&iSAfZ$%5{g;@x7*KF5?>K$mxL0xF+51?Kw=DC%P9v&s%7YU zk-U8-*z5K7eoMq(p0ICASATz(cywg$qb>W0f8DYFKZ1kP!ygZa3MC&XFFcZ%1)n7S1TL)^8P=vIx0?jM(WAIk zo0_j$%!B&|m!#?qDG7c1MvVze^!p}0XGn-MDktA9>@=G@i~fKP6koObvJ1;XUlkXX zZoPC*edupgo8kEc+6UOvY7`fE0ZzqY4$l0KVo=x3yoR$Pz|AdL{VPkvopTQ5lFa^< z_Rtp82IuBFS}*H}=LHL)QcncWrqIj>r16*36k_qjZu zf{AsKA?KK9cBG?GnUZXPwclj*kCcezbFQ}0x(HV!iIUPJ*E;Db9V{jDxmFvQ9i_0> z$mo#Po2c?nIGq!I`E2X#Y-{y;BQ{&ZxG(fw-$cX8E{_->yDjvnr;Fr(X>ff&%g@uM zx)^9wo5n(=h9C@b9F`d5I6R8c4{0$MLMoI?{w6g7<&fjBgnlWatK~Q>p>iCS{Lwfp zp>iCSP^vEpm0F2uvIdt>IXjVQX~dOKsedGt^pAu>|3E_%G!_2wC3vH}62ivTDUVh* zb)H?iNd12$Jtb{fOWoCrG=p-bFD+%+aAo7%m0??S(FW1lBb94@r)&@ImsB$F1#TrY zTC&)*>t7AGXsSvjlWC_SwVTQ_8ws6cyMxM`64TBbB58FhX<=D6QVWyaPSRLHcDtOP zHMxt6Z42wg6q&QB^9A%ucUMwYs%larHB?!eSCozE+dZ1NLQ^Lfm6+$%QCl!OQ_kW< z>OA39b+)swDlP^4Ct#1m=CBHlqS!A*@zcW8w7qHs{b+(#p)ga=( zea9W&4*kubX4fQC)YVlWB-E^J6?@v&)Z~??509K435^V=Rpbq~ImI4lTbna@DJ3M_<3g|}m z#U#NON*dR~a}~_gY?cU`VDRhyO-=hYfBoyN{;rm1XZ`5ofezvI^!Iy0Pj(CtO)7s8%AX9X#5v8e(v2n_dn2rmz3H23TJHb)jzgDS z-`w5Zd_C%5ymMejI{Z>iq36VPy{&Bl>Q{`7TmGt;mR|^!BL|J%po|_Q)5?*fk9wQ( zTOB<7WFMDmrbVNp6pk&pJ7_{~)#l^r8CDFO(oF8#+AM<0x;lGnt2QrN>6-LS?iHAs zxBBX;r~8MSFG#2hdfZ-*yUL$bVBOi@wyyrd^-Uek4b}eSLhG)9_8`x=m^$;nKZgH> zQ1FkM>qB2BPE)Zz<~(!sf0Fy3&6}<#|D&QTn7RMMf}vd&mH;in&=e{GT0oXowg9zO zE+nFu;!^3vv~a2M2?+E$ng$t0kAs4d<4q@{K#i zKu24vC)hCV@7l-?me#+S+7dwj#1}nX-5#XCPoYOUCmNRpdxlLRqEuu~o6qrXb@rwv7MYz*fW) zk)kSJ58DnK7Z#f2929|@tee~CmAaBCI`ps<;4#K;i=>V4jI_kF#31bjiI?g^LMI~_ zq`e@^C+!7UYO)t3l6o>V-`^qI62c#`7UmT>YA=YWg)rU_^t85h1j{uGA!->= zdy@f6|D(1+r2WaGE4hH}5`jkB6y*SKuwZyhOGM96ooRB0f@#@%k8QjvDOImGCtbPW zaZJim8rNH`>l?-UbF_{CZym<-lkBTSF3dPEoq=CEU$OER%xr3u(qzS?UbK3xo8};@ zLG9k?Q4IzmRD;qovi1^>V$cg=(5qdT1-zY6TalbxQJbOU&in3A9M&pFVxptUI(L#v z!IZg`?*so~pT|O|lwt{`63etwiWjCu+oMEfC=ty}t*D1IH9A$p{8U?OF_pda?6ynd z(~O3+_)9lG`_k5{ zopN|F+1P%tKpETI={z}f(WsN2@#(th={3hYn(O_BVEo>76T3#2F5T$%jyzc1*qN|? zaQUd)=`OeRuAW*QI=Fpld!X0bFw{_4;{q2B6&;ZG@w$#Hdvz$*ZizrU z!({=6-$$Sx1I=E27^my8&b(AtMI*VKqq(h-B{W`B`^WMk-XbTOmlxJT&wqySNXJ@2 zZWXPu{pg>Or0xjE?a^}JHngyOb#OUs7}H!RN2AV*9q2T3a>WQb*->Q5Tb&*S|1Fq9 zMb@rpPEo4Orday%Q<~O6EXO_ls{#XsxU6nXe|u?Tj;dF)>+RjkU$f^II@S#P>`XWPwYd-mFaTesV5qVeT5_U*R(_Pk=D zEOS&>J4jbh3Ainvm;EN6dhZyZq$@Hs+t6jTvE$a{G;xtEF!yN+q}hvP8xD4lq^1Ug zN_y(5u2s|1m$dl(EpDGLp}*4tr{U47EuMj06Zehp8tV2Q@pcD1M?3-2>uW&Ch#Jfb z+o0jeg@Y|oSz&G```~GM<)7HA2322kTOiQZ?8Dc+=jicm0 zW6WH#7i7tbSz8gk7-*}W%DV>gNL-}q>SFE2c`JR9Y0pB=elc(2klVq9u+xl5f^ zx5cDQ1W7a+Wi^3jW%srg*FFV0-PR&kCaM?Eu4mWT1_6*lw;=S1$*xoukjGHb?hJ8MIx2F@ljH1-E4-QrVJYOcE z^}Ek5dnlL?Ix@I^{h+5`D}R4sgWKIu-`uP?W@qPK+_~ZZjO~n6f@ff;tNmzu7e7Fa z>`bCdeFAhzXZ^$arX^F<`Q*f^?qQAQu%p@IX>RH0h!^9i_6uaSpNdp_&=ctP2EEqoKBwunT=LR%MwMx|Gd zXA-X*&(^^D0S1h>Ej-@J-?}1roEDJEf?*d zm^w(*!ZHSNJ0kr7d2x_7X#I956w#_XDZCw=F5(C|h){uC8F;J3K32mIC@e=b1o~vpePD^+|rX?#LF|k&c zmNwM0YAV>-)a+AE&ThB(dbf;*ZWi0xd;xFh7;%R`!h-#u&yoC|eS_lcbN>r|GU;2+ z?$8~jo`H6%zb#J3;hp9#DS4eRb&oP$+ac(HdPa4 ziIHqa32j@t7_=n@N;M$UIv0h4C&CMD66MsPCr*v}u9zHAny&wi(xjd&v3I6Mpxl!s z)B`*!+XujooebGgFG1{{uShkh5JNc%!wuw*UE}>PuAuje9F8IcX_1C^eQDLE+)$jC zZ?om+6-R1{`l#fjLo4T?I6*BUV7Q=!ji^wvq6WpkBV|&!PiTw4wl!by^qdynnG0rD zb#;jEj?Ddi(;lv^LGdxQjfSNKlWw_tq8hz2k$NRQZd&~v5RiWulAkrL#-*N^`Zm#0+XVx@zdz$bZ@`lF6zZ5&{ z#i23rFE%^i0D zQnOeu)shls{2nYcQ)^2uApaUYnsJe({t?FNnwXX5=ujFSo1*4!m0Wd^&o;lmt+lHw z4yN~E%onh(`Bki&4g0-^y?%ah|0n!hQ&yDEsBhv`ccvNx4ckET(}t~`kL2uKNDNnL z7DB|@K`|WKZ_?vK*xB0ApkZt0BWdku(6F^bG>=9wgsmNdl2(v3!`2SjH8l}vlv->F z!*&f}fHu@Hz^-Av_Yqbh_Mdl^`LpW&P_a36S!?Zei!_1wg)h}itIVO&^EL(~fa)ce zYaJ^T)E3;cNz;QTa4MnEQpKiq@d~rVK&6stQK|@Dk}L`B;1y;{n-bH;?nqjd#sjTh z=390#E6nZ+1tv(Wd5#6Vc?--@Q$*}_cV!g|RaGL(yET=WY|I^rE-+`*7HG3Xi0aoo z8?w_iL(c5S6dEFn2inMX_D%R8hVX6v+VW?#jZJ)SL#Xdt5#m@|rg;uRzOr-fw)7aX z)I)kYj(D)I?MO!t)gII1da6FBhftkL2_%b>c$5B-GFZT<`>=mx5uXT6VyONiK9NW# zj(A08yM~6k%ADCkuVgvPx`tjWDaf|#*CY%!mpQW(y~uXv7nGC~6gnI~xWQ2fhse7A zj|bLf05M-=HLafTHN!D z$}!BMS9P!2T)ncnYc*zgm$&$QEpESmRyj%2=!+)q>l|y~Ddk78eh*c*?(AB&(wBBD9x_$bz2AaoaNW29yN7-_L-eZYM2s3mXt;JU5B&ej$mRKIWihKn{9W%+u- z7Aj+4DI;G8`hEk+-a=?AYlJLV02q-Wdz6;OF|77rYzm@B$6>6fk~8O0X9lbec1>u@ z*oa{n8;%O;e%98pZ8)89RlOl-bX8Tj8f$9?R<0NycdVF92pa3k9nRXa%7OJOH%-Oa zyj6L{l_j=vQ(|&|U|{7yXLf^3i@&hgKd;8*ipQs#fAIP?8ePyd6$EmF1?e%}N;(Wn$?3t8fxziKuN{6}w7OUTu1 zxxpdk{ehSzZEeQ~Z5G42w%0r9s$4;@5nyfG-`pPP>8Pq`?)19dekB9T+m)-@8-}Xn zy96EMu94o>R{v1I)#}AE_Zg!7O+09I59`WATbpN^zqxVnkw$h5E&J0VILcIdj}bTorWWeCIKETKTlW^BKYS^#PjnAq5WxH9JPg(_OfhCdr5g!7z35I*FvbYy(EEN07@FfZ0=7yLVz@&xvRWHFM{! zO_y9EH30B&nU>EhX(dqsZ3*oZw-jZ3W zQCK@gn$N%;Q>EfND}Oq@-;}7=CmLrqh5mQ;6-6I<$XuI}Qfn5gvAux%KJv2sPQ;Xy zF~&e;NhOp@D$~l6x?#nGx&}4ryL3mn^%vrh(k`JS?GlHSc80P9ODH5b!W+qtgi84d zq9Q{mE&Hs(tKUJk_4xC)_usDlacDEsH=F|P+MABQSJl|r*+?O;q$CePJl5VE{ z;$#cCG`v@HTpS7g`0@bl*9=^KxhD|tT#omwPGLWwZxSPPhbI8c8zm-S&IV?o+l6@K zjRD{_?-Kt;uaJ$*%^)@Z${wLhxJ~H2L@kfnBKMUQK^If5)oUo*#JA^Wz;D*sy}T1< zDUGYJvT6HE5lnm9Tt*xHRiiPhdP!!gFo}JE;m{RrpFCp_g@=Bf-o3U~JTiCbuMZvi zwbBtfx}4vdm~++96beTkS6Q`m^n&EcNV4Pq@`Swa9d7sj4+$db15#x@`uvC(%e zqg(c<9U?DfisJ5V9r~bgxTAZ;a941B$3VZQV<6akLHG8nq)F9wQ9|8lo6FPJ+SWTV z=x*-lY4(gcC)YQuAd9MYU0dfSm~j{t@E{vXzR5tl0{LxH+L-88gX>hi^4iQg>>K(Y zI0(0ttnANHF2PF?ciLC>XU^S%dXjzTQS`~nxt<_JfWpH=dwNit!_heJ#K$|(5(?Vs zXFm}igZ5I*w@K|sm53=>dTLcEZiJl){+CHvxz@0H#iYPOnsR+;-@&Vae-QZbb_Xzx zGJZ%Ly$gl7)E~UF9=q_3yn7tJEc{NCOk^oC5%ajXJNORvKLIJkN#mKkjYgb$OmV_N z?_wFL&mm5>Aa)=kemzUI)_=$|>zt=$|8wA1Q(sIC%p3 zalss|%yUkb_%DU)4Ax=O+21L}s)Dhgi1z&(ToIoGq@Ow>_e4vnxfq)%us%o&guDvk zunDDO%-JyJS?w8XaBlFdwm0SFHC^s-<>k2?S%Joloo9R#u0X&w;XBj0u`zI1{H>^? z@=SSKVPRYOnaYkL@Pu_wt;HVT(k(-c{T(%y28-D&=g4Fb@v0<*UVI~|*ExQ1u(z$w zgVPGLRMVcxzyH0h*Q5%_2ikTVy_5D|!8SMGttIX#=$zuWq057>2A3T=gsR`C+&H)I z6bNCD1ui#`sWF;|Q=9$D>dX4}u0qls$`K9@P95p_vA8LhMf@qWa^>E@-j%gXVUKe2 z9EVpa-}u=tvJ`+Ps|#LC{@5&M?+d;YyzlC(L1qTR;J6yhur?%ba-!y)4e#96UbKbQ zw~Yr6`!~DYoBfBs+}7XU_GR>tmobx}?YRBz?ft-V_7gk^i>6aC?N|iQb%#!Gmx#7c z6QXJ5`jG{gu&)M~NQcsUzgZ;3jEQ7IzWGbzkd5Am@~tl4uzlNDdAX~l#Z@k9RufxW zMxCPWyQ-XWIbT05sRMKc4h^+A_ z=k&g!J3_%V{MF(1fwgM~4t@2lc1J~pqn%i%gBe!$&h)Mpn?v_3tF+HJDyTPV``FPN z_p`i`eXNHr#o)nf=?mX2x6peIkv%%}-sfav<0QSQ6zs&ijqv72bQbO|n$>|(f}Ba=^#E)H`O@;>idCyttREWQuwl5ey1Eh}Vaw=UG+c-N>$>$9 z&@$!dmZ8=rv8SoEwJCIS6O1f{-e+YkBl}01_67pj$0$ID8t~r1<|F>WrYYa+!M!(K ze(<2Xr(1Z_cMNonyD$*Z+YtwazPGKlkJ?8E%a?jdVR(idE;$gwEU<-ZguH%2A8>iN z8iJ8(39npa$;yb<&oAXWa%{zO%h0Y&-Z_HN^KI_mM3d&=a*dEiQmP~uNu3&&4pB9= zd-v4TZU|SK=g*y;fA+Msc@i#}68!`Zea|=HT+!|Q(wDGFWc^-mSC<#9ukE))JI_)R z(~OlzY~CZotrIagu`DAuV6w5G^;}wdM-x?Ty5!m`4;@;$IyqSkb*~tTyt6?`i3Y3$zWaT2bLBtr#jRDJe&*9nkO_ zNOH+OJRoig{akTiy&2`_U)g3qhVsLAfXQSy56;BlJZv8x5KU_++xGtmk><(g5y*kI zfwczv5C+XW`w$-d{A#mZ7{ykYhc~qU;rn_r56#odg*8-4)}grJCo87F0q+b!k1*1n zif|lj#tuD{f`o#jRD2JhmNeTCuUEmt6kce>hFDYT%?; z_&)wZe+#|!G5&zXclPhFL#uJ#B}r3^TQE|+sOVxNPdGI5++<-Z-6m4kUA$z%)KODg z?{+ya-&a#-smO0AYc){`*#wz}He+Uwo9!8FjBRaj#$s~M^)$tq4Q$@UD}yKCz^ z^?HNf(@$rFNo$EcJ*2Vc+l1q5v7!96OV_GKEQDU#`mYwxxy2Q9qoY zTkJTu7n79>R*$tc=xEh!3XaP)=n2K~mbL^vy(6d4Uz$6)rh3QDO?JF2?XEs}*uRD_hieR$ z1u$FW-U*v!9EJsqOvi73J9qL=w6mO6qG;XD$ZILleCODu4&obPj6B-f1@hFh^sVBN zt_~*|y$~YW(k^wJ^9GLi)ru9Na>5{I)3k1nd2=`(*$>T7wm%1zVjih;coc>G$?}~KQ^8{!FWfnH>{z4Q-FQrKJhyS> z@c2k=bu~`$LJi8?nw1I-Omp^mO8L;C(=&u%W`+>Vh*ySVFof+&NuMo;b1_J(vU>g2 zt?R3+U2ScyYO*Sck(C?!n(FGBLhmY&SFoZpz^3d+Y1pO=_fKZ&JT_%kzQFRHv?;Gt zMZZt1*KEo)o<=c!Vogs)&l>UT(C;_wTv1h00h1C`ymS11_fzLhAD(6|4~zN z-p)Kx#<;z1iQDZZ+!NB4+%nqO+U+SDF7R}IL{&lF0o1cOykvs1hu`uDTYz+o#DfnC(_p8zIW4HPE?cu^+32jcF_2{Zqqu4kf3=TLdD;@TV ziiGjORew<&e^|DB^A|AH@ZFB>n~fW>t6-uL=4ENAxBEj| zXLomJL?6>!gG#%=cZWE8=g8s}6Y-abx7>$wCW zFDf-y3~u;Lg(vhB{4>Ak6RDx!^@*ktkt?!ChSm2s{8iUm?9E!8*JNJ}57uh{4mi_T)vUSZ&a(M+VOUGu~P2FEA_dnV{9GgYRfD>Gz!lb?mnN zGT`JzmZxO_9)j&E;e1w8sf0k**-uI7`JA69+|TJBfsUkeE(rc};AB50@O%;9$*V^2 zV+_YU6maw$obmZKJOsakESY33@X4~wo&y*r9LgM(&QxNCZQN5`-;X5I-xz)5q}kLT%nIXi~dVr?9L zNieGG6IV@4j^LFFyl|A78hN840WTP78&a_Q2JdggY)X-w(;fs1$$&M|`q-tVEnmc( z62aw?+9qzxR$d|kIlp_iBt8aMAKy(o}Qh>MCq%Utb!}@Mvw6zOJtZZc z@-mO@*PT<%OXAhH)-HP`-8bs;ZE0=Y5~%8SIJ&F&Nxfzm^GvHY&jcL|E^ZeOlh{TP z-8!Qkd@21fw8Mt2oj~n|oxVV;w|aG3!|+836ULVEhWzr3x|)5LJ6-Pj+S+#0M8a;< z+J2AUpx1ZS*LK^7J=rCx#aSg)Lp5dgn!>D3It#fQ5|@V>D4_CtR5!i3YD!jVf&m^( zCY!qnb6rPwdd<+jkuyJO^Nbq6ja92xS zt-CdF?X`82zz%ta?ehP2ckSFsC6~u(bg%H(L#rbNk#RU8Utt$dblg$Vc8i{YG$fKj ze__|6SME;@{iocZD!jCS9(vO27XvgEV*O0>0qEx<9_28s(#!d9ZGQv1mrsadN8xp} zZ@Fb8beXoNdJ}p-X4cTVG*ga_P_#0UR_YXyrSOJd4NMBt)ZQga@%nSp0VVHo49^$X z+LtbEw}tLP&W)(EPe2_WX6%xSJrsasvDAj))@t1t>~J@Gf;+})yd`*%JkBJRP}jek zcHxTY(B0#^vPx2N>?wT4mmD*Qw^8QJe|89Mewy|RLFP5fj7IUunIqaZo&`eS@A0>G zUb(IJ0(Wqrqhny8WBvNx<;#0V!=f;{@9LlTj;EQ|dDd=j80&2A>1cKjj`-T!eJl_c zlipi6`_95_1?TJ1%!~YJ!fwknOs;?@x&o8x!O(N%RjX0u zyhB<_7)HXV-XZ53b*Xdr6prJx4&PWq<%;I6mDp0a5ATY#v~+aNDw&;Q_4OOP3$_$u zU!f;}R>9jTN&zIf5Oo%@0=4>D*jYw#XsUOzDcIdiho(-1t7l?*?+agn=+&%gqjxF4 z(&^=D!L4g-U!?*&?~RoBX>wEA041aqg|tw3&X38@D0Y>ezSNRdUXmdX`yv-NANF;E zUf0C?aOt+X+^<2xVQi6n^PbkQbjL-coAxWwv4Ok?>kGXrX2ma_Zois$BgqX|Xfx^U zB>Cxq{9s2G>Voz*r1N{Fup+emE3~dc>=NVJiiJ=ocdqic?;PH^bJEb(Raa3mJA2Va zF&4VNBOv}~?Z9IjFPi-%(D7IWoqkpZyx3=`nCRsBvxBJhCP0co$x5SP3?0}i(o}(^ zqHfx`s=KYPt$WqZO|i&BMS%_?1PZ|9#%NxI8m@+v01@e0i(JDC53=FfEp?$MP$`fM z$Kd_|hq`#O3XAgdi~8sRU)`!edz07bO;|hh+^UNcCQNOW&zDwJl|C<@l}*sRJ61h6 zw6?dSqnBi!`k#ZnXdk2gjQY#i0+3MJxgnv>80fVT=;s*9Ex;J41%N@GR!3fF-W?&K z12Jg{gM>;9-0v8JH3kFM3PBZEQ-l{Q>~iLV_gC1~FO~fg^+k<)UYkM1o;tC(-C)?U z>Eh3@9TeZ8L#QJj3z@$UB`3*Lb3A@9^dkvHC+9v7j>)%!Iq^a(X}+ga3~8p)Ut(OQ zQDbQl-zo5GvjX^>q(6w(M4*XnDou3k(B;7|d??iVFMOydVyQp$rXLfH7qge=h=;L~ zU6-{yH#AbJ9HN>WhSbHuDx$Hgl56ra=S*&hoUCX%n$acAgJ zQ8X3$)%(GtUl#v2w<#sP5)e<<}Ys_t!v%d>m3^MA|$l!2)K9D zi_*}nnw#IeB@o!rHoPVfSVKY90I#yep}la@2q|&(2f`3~Hz=N+Q?B3n#OT~L)K{bg z{ub?unIE?UIEuD!BbX z^Voymw`#Jyx;LSAw9PkeueEfS*EP4)mBDDVPx#kwAMSKj1}wFu!OrH9s;ZIZ&h_QB z={*%qUaB!LN&9cO#$YM&upK@Gjd{R5w$U2<53Z@U^>wY=dSu-tX%!|0sh+m>^loo! z+un<+3;kM*M=DIyYP3%HPuh{C5GvS_^d^&EKHECzY%b4Nar$=X+mSWuun%L{?-c`V zNIvTI&(L;E=&xJPUN4>%J&FldzHV*~kh{(v#$6z7fYfM^uK^;{V7-acT#sCjh<2o@ z(;$bD<{^e){ejcmfHeQkc;E|Rh@?fBF_J`RJ3bAvfBuJTN&NHbC_~(AT_3`8A{@>X`qg#p)sH?j$wjv^;PuBdfw@ zs|cvW-tM6a`~H*S_H~!1RA-Q1(m%A^XY0$E@RAO?9%Xq%?F{eOiyX8^8i*YACelFA zwYlBHJr#Cad6_ML+K6iFOrQKeclKf}yF+*`_pU1zP`nGH-4@N0Tfs7h3 z6kdRqI|O2M&DxCA3kR<*w#T`O-M&?QrPbA?j+z>A(~z&AH}}|&(zEjVI($Q(Dm(jk zt55=Jx5rTeXqmJ$98yAB=9m9^XOAeRU$%FCemDf@hoU=zl0Jo2%fgK!R95CBGKeg$ zWXPU~yu>A{dR8{o3|TVEii;dM83Q%0l|A;#tc?Cz_i~?qc~k9jOJ=3Gsnb>BO)ZEk zPR}VQ%tT%Dfc+>Da=g7nU!hL)Cw;*Rvfcw0tZG5Dg^Isv}8hSKmRyPOq- z$5@joRvW)_4XUQm=Ju@)^sdQB+YyJ#aiEgK?cu5!^5q5c?*C<^f>1+YTR|l~>=Z$9 zL1*YL-rb|}8?|&_L@rKxL~k!zT%IiuZOkm;HiH9G8=qBDK5a8LTM71$wkthN%{|rS z8<$jMTr~IgK7HyEPhic3Z!jruPkMPqp3Rom=X?w`S^cJ8F41eqK zl=Z&|Q-Jlr6qexqUD!J~(KOscEF=}@>wjF_*EKrVvL|@Tkf8@j0bR z;;_2ls;6}WVqPoz-z;8BC+&w$r^oEo;=0h~S1a3!b8-p`$bbbO*MSe5rH|PrqS#a+ ztpR9n&7d+xHhi-}vHh~ayKI^7>Z=1=Tk6&{cSQL6*(~{&*Wj4gmJLnn_LpM$+=cfA zf1y-L8k&^^XB_6>y!#3Lb3WT*b??^Z+BGdfN$WtQ1jn)Z(=ytqZl9&Mq1PxIBPGFD z`)jPTeqJ2M=-URV!mX3oP4rjX2=-f&SG%kiIUZFtc6T?ry1M?#Pgf(|lV;P6!|yz$ zLtb~O8(z**95PtyhM&^vhQl4q($t4eAaq-?6~ly6IjvR`CBi{irtkJOC6(Bd)wH^L z%V_?nrMhCN!H^g?8kcA^q?A`%*5|KJudhqfFSXke-F@yvYnstyOtU79Hw>lOixN$W zVTq}5RiP;>CsChP@3KxzSY7pL`ox?p1}`xvafwCt)S-r<)S8-93eHR@v8VDw*1457>_)M8DS`EjfC^hY$YbKM{X|W`|mD#|~lC z32JEB*~3Z_Ml0&k&|u5N=84cfyVQq1g{NrVuLe@D4~OoV5S#gDc<-}>{_KB><8+om z2&MxdGdR5=UxR#u@&5oe*KaYJplAk6XduRLA|#WC1}-`A+new0zitdme-MEg+Y7hP zPJLsSb*Q}Ube$A?-;NVi^|Ax$Ob$QTa@F$nLq>JZLS{@wtZanz^u=ghLQ59L= z@U44$OJ`5I)7iI9Cm{<-IvWWINeG05AT)tMhyntUT~ttEkUb(Z4mz&5jxvg)GUGDJ zI5X~pI!3?|5p_m!0aTQIkqAlp_V+(^@9lIa0d=0|eV+ICeP1Wtef!?3Q>RXyI(4e* z)Hw|gEt?WLVbvwu#;rnT+oFeOZoB)Rgnu(?C!u!Aj65AmylU%U%11++b0o8rUbARXO*$@enuo$@!6}+`b=6g)aQeoXm%AvVv1m&%4k#3FDIT5S z%FfS#hPuPSMzgAQ5 zeT>5JO%FV9c9Ba8aw+Y-2+1fqh8~;;Lq;j`%=+~`>({dd>?-+A`A&j?6mKahQg{lM zuwla!8#Z{8fXC(`4N0F-;sg<^r>_gu#Cdn(?sk56qIMVXHnLRc_KS)CXyaMlJCU_ zd!G{W#DI&m!Tr*D;r6BlPT#QI?5~nh2t|ye55e;#s^W=!Fq%(P?YydCc#4}E2x zI&tzOy-_W+T_*bnFGnqfP2I6$_OAChVE^Z(9M+~?@6Fq>Ba=#{GB>fOdE0Y58GON6 zjVb(-T^TeZP(FeW_Vk|C);;tFyiTN_tZs7`!CTQIro;hwqd zVQPGEkRWyM^GOBzXz2=(Hk7^66~!q7@CNF%G&ZRd4zS#YkH!t+Xj9$z#=sXYo1eSDt^{WUH&^=oB z0-(GItlxMwGFGpTx6-x!1OiSHz#|-cTf9!66vMAk1HumLL)XxJ(~*H1fSHUo8@su~ zJyd+_oq4YgcD`u$xI8CHD~~AnsHq{@OMBCk*r0sVI(kB-Q%bh&L_DADEQ4imFrZtw zu#cT!f2FYwD|rNmb_SfoB(ADp_C#~B5UDM1RHR%Y24^J2X4nUnW#x^`XiiU#%SanE zWM5jUOP`vSke!o|R+Cdvk(^GK#3i+mcO$v<&&K95ZA$(G`A@t06}`e&8v>Rr@gD+~ zY-_#9AfSw&qWqGI0k@3Ma~oltPD2UuOKdF`TQZ($RpqmiLwCLhIVN%$O)II;q%ne! z%??igC^DTmi{8^Axz9ZT0ng^Pvcs*a5Lbjf0i(CaBi{;m4-*Z<@$SDvx*5bB4~7bo zJPadaG47L=kwJO}wYbvi1L+xUj0-{BdqJny~--_Q%) znAijITBLyC4$t`n&pDiOVli{8D6zx1Khph#=QBw8w|V;a2@}jPGQ>(ZUnv(WIVSIT zI)yKk``r*;{5iohij|(rDQC|JAs2I#IrOA^0d^_~LLR=2;@ci9Afn9YRb0|V;6ORa z%uvwxEPjw=g>z$~mRl{T159AXdLg z5)fQ~orn8q?xyqwr9aS0H@)SaMeteo`#Fd-R&!13HS9Wh@*FYD{qmx%uFbAzp25df zK`6r+}N9$)WPf~l8KO}#-~ zKoE5DWZd6{`vyq+B--D@2~CW3RtFmAC-B)uOSDeRB-5^*k1xPb@1~iff?OwEu9Fv- zLV7&i4`6l{jFW>IVqNz#)CS*Z!Of^u-M`Qj?ze<$oa|kL*;_r=Zhr3kP4C;aKP4 zVs1yb&3Z9_=5`C63zfNDZsY>rF6QxIwON^YQLR7mJPWzh02)Z{o$8E7u{-YIK~8J;!fVtxv0VWDZ@}(6Df5-o)}& zXHEUMkvMDBm3GZaFIS2yy$e_xntGUDV&A!P+7MmaGoy#sG}c#D;8{lp)?VbSr1-d0 zTG@j9b$JVK4OL}2c>AqdXZz$|NYeD5kVO)P4X@)>}YTv%RX)jITxN6_DR%OGW zN;qrZ-GBGPorS2#doO%zA)i*Csu#RIEF?`n&GM;gy_Z^R@XFvrT?JErs+FW)g6Vvj zT2HFq1YxppDbC%`66XAPU4KfQFIIPr2IuGb(;!--LB9(>VtlI+qtAsxmFP72TUO4g zGSFooig3dC6Nzs55Q=^h*FtKc=P8!ncA7QNj2frpVTSELM)`6AwY+Kv-hIZevb{AT zwApqSB4N6`?bW+#2~A)pt=ypG1R;f1WOzRqa9tF7C-sVd4)I?ORRv*|*wr%$Wwo&! z-*WahvMW0Nrqc_7!t-M1@ zcIS(`douWf?pEkwE|>e9GRu^pqh2s)&qV#Et{3%n=U*5gCzGR)^COfQ1`09QFQNUl z`3oK*OO041Hz^uZN`#yscVUA2lzgP^e`SwHt(%pRK+t3a6g?6dX4|>)w zG2r&3qP1^QR&2n-G^@7uq>AfX#r18ClCkG}BW46&^{yBqjn(~?ZU~kPky}{lxdrRm zdC;H*y@X8~#@H`F7&``DF`tsW0eSOOOa?>@M#XDz*7OGKT|xhKDCR90#tg;i7W+6hD$s@< z8(wpx%|WLyR6BFpS70Y5N0lZfmD-wzO$ZB*2%A*ZVk=3k%AZ&{Av7#Jv|08zhNh+t zbvP>Q_KIsJhlGZPG!L6-D^E%;i$>azkR+sx9+H$)7TsKJuSid)bo7au*MkOO(roO~ zWRqT`hw(W@^RtC3VF+pe3mY3Sa?P+Rp(l)1Os#-jo(Oj&z|O`Zr!5d$hnB=Oj-NHL zVnQ2hEy&GmaLsEeD9OtSs>ms*uGrXanm4Inn2{Mwh)L+0Yr3)BG`A^lsPSAdViGnj z3~1kLs>nykLfvQMB% zkpW+3O~uhawpdwroOmB4SM zmo1`&gHoG2Rw~Z((8v)o5Bf#}5cyGss zbs_C-6%9s|1x0!FhO$JsXWF7f^Pq_uqn&n3LV|@HfLvb0rVlSIucqJj!e~U3E@E@r zB8$snva5>n%hJmxnX8f=q=dsIDieW#&-`uF# zikK<<&4g$1`hdwF(Dz^R8}r-n{$$*^?ds)w=ndLlB}wZjAAP_-av3&S8oo*tl%KNM`>QPGZ-0ld|h8bOB?<&Y4>;(u%11XU(i>-P2mLtx2lrd6V8vR67qo zrl5A%Q=)X9ROPuA67ksje4XTnqzP`TPQG_T?7F%@lsG-VbR7~@L zcPpg&p1-n(>xPbs&B%z2kE^RIuUD_m4s;V-ZU?UA99OLH(+)EZ3UU8WR6~;4_$H$S z;&Qu!(Os+{v&tdYVu`sbQ+|&XRL!lzKQDZp53yD9Q$Ouj3ic8%*q%x$O#?ToQp!Lr z>stz)GeKSYltP=@;1?DC$T{WZb4C)=@Idzk9P+l3Sv5JsXCmMccgm}9~m=5Vu%=ZPk1ct5vdCP>?UTb;n zwdrrT-oQWlMBhEqd9eRGE{0G(jIz6DKDiu@Vuw`^5shJAFG_@!yhB-rXC*Zsw|(qg_TzP- zGsC-qZy3pZ($_WZnU_hG@>y(jxnA|=#=1OlOEW(FAQbzSuacz~0YLCWfpZ3pJLTjZ z0@|YwZxmYVUgX^IV%>gXkNxBmu|}AO)HrPw>~{uwq>7WZ%m{tU9?WEUYS7ex10{H=mE&ROv)-u1lY%e6J@D3lATb%&KJ& zu~%ENc(o<3rle^}ijJgeNMbeDkKBLf+L8a5tR9J?qiBojL{nXB$2O^=sYw}?Q5Kzl zBFzv5+lrO*+l<0}YNxk=)ibk91{T1K0h=f8MX#1`NG%KuEJ_i}Xr%1*Ih8<`m5N46yc%UA_XDu< zD$Iv|g`vk^8|EhLGbWF?goT6@jBU-@kX>D!ef7-pVceG8Ty%M@Yv$F%hgxDvW;P9r zj4K&Cr>diE3HhEHK9W120^Y6s6z7keNNjB_8&*}`I)8dzjl=guVnt0&1)WH|e4%zC z5p{V0O-6e;Tn=ixz-(5l{5jWexHYF<2!UnDXn0&DX&i?Wy0BR%8(Y*}<$9&M_+d}Q zCCO%`H~8G=+#kYDkCsDVMLK3o6}@X}YWDYDC#N7pyE|Q9UsY38&p$>Euc@uA8O~h2 zw?@>~)TX4?q^1Z4&pF`LqT-d!S8gH6?7$3@H>H>HQf*#*_#{s|RECc3ALW47%YE_o zg<)d1RLDzMSZsWJY)o97wV=GbASY84v$Dz5IeU;O4q6#YulRWRNd$x}r4RxLeM2v* zR9<3yYeE7(;uDL87Pb}+&9+*zy%$CNX+i>?vR@4=t|=bIKZeG~*AM`Fp!GMi0`^zz z=U@~ii+4U#r_oo}*5+z!V+Hf-=HZ{_Y;>9|naO-7z)tff-<<&8>lD+S1-)y#a1s)@PzFd3)+yh;Nk5B%36qtlG9H(fK z-|MU2G&ObfQErs^Q?VaB(*AgR`|37{qRD-(uVw>yebgEewx4@o`?;M{%g_4L*Cw55 zmY~J<+*~`}do+vCO#TzMXoaOl;3F7TG%%*2&FsQ5)V&3#YWmIw)LOHEzExh(vd@R_XQ|HOBcAT{a4E0^97 z90{N0!OJgu^=%e{W6|M7ty=hQ_U4!|L?KuPiDUV>Bh0ICZo*Es_YS?4!d=^;!-sox z%xup68?&>N7o+0zW@sv=sNCStjECm^&^hm+$aq6=ZWL{^6Ra`NDi-qi1Q`sQ&$P^g z87RgPK&F9x0w6kML9^lX3|i8%v9NCs&F3^66oz@}3t@ve z4eeyj#fd1w7>;owdNJhf>%bOu2Cdb>CKU&G0FQKKCWgzu4T(1q)!4%dEt7)Tj7By) zB-PC6#vUH4V@6|4i2R_y;48!~K7ke<1Rc&7L$r<7#N1+!x4ee*y*@b4?QM0X9^i$0 z2dIS)C#cM!Rg3u6Gf5mP-AKD1zO6V=Z$PUk?V2NhuC}Y%KT=t$+CP+b-rC#F*Z1!) zH){=VAT5adDO1)K$U-a@avEzK5+?nT>Ng|JxwOz`&oFLuz5Bo(SKuf&Ay0=z`QuKT45ueS+lUBKJ2o98_e6l+B9?U^P$f_4muH9s={ zkbPHJj3I#OTnLVU{`@YwE|&xx8u-KyJ0EDhg=l=@%iQAb{*2LMj)$SgmjBY)0Xy%^e!<#-EZVzBSC!f-KItD1^Sj!(N$HkDQiOyyZG zO#YD5xKI6jXsnipK1w{qYpjfwi4oOA3J~`~t(1O{z^OZ^)(Rwz zM|wye5RO!Hc?Yqxc$at=*a0Vgd$~cYg^Fq)Jor-%ft9%LVkJL{3zBeZ@q%C{Q-KIS zEo!X-Aq~kwmaKPZH(Il$@U>a+-P2!ySY1nmrNRxuYN1`&ApBbR4eZ+Q!My5W;Zfmn z;Sa(y!t=skgqMWZgg1n@g`L8C!Uw{~!l$S=q$|a8(01JD8>`U&uec}1SGd2b&|d$O zm(uH6sTCE={zos#J0SS?f1Z=R5Dp55gd@TU;S9W3b_*URAMWj2&mv063?hqA`832ZXEl;Q9dn?px!*b=ss-GDukcD4cMh=0TGWcRQKaQNX- z_Bi_kdj{v+|Dy0M@h%;;z z3Em^N@lScL+CAjU)Qbw=POBy6&(w@R{kpgFd!ei4QQ_1{yDdH)^rRO9e!=GY|5kpn zF9*7-+!I?a{0vXTyZ-Ned=bnCu5n-Lc!@`|7*zsQVkKgv&>&nQjK}K!6htAKAzXno zbXN-32-hK|%SvIbuwM9;aEoxeaJO)u@LS<`h#>f+@RaZ;;m^X~gja;W3vUVU2=5B- z3m*#q7Cuva-qNbmPkH-~Y8ctztw+fSPwO) zW{MBdERpYLtF{ERwaRi@ZW%xRmX;|S$B*CW)GnsrCh3aaeAvJ1n-eQ*{>C-Fkfw~j ze#D6DNApiVs7~!JJ>&YQw~Vw4l!2&z6;d(ny^{$~-%@gCPl+D5n9$+lM@K8g`PBt8 z?pFm?l76de#Px#7OP@fjsoS7y=3!NRDA^uMMWr^y zsK=OYD~+-l)1?yJF;e^z{Gg2_qf`nb0yvTI%0?@PhH+(5f&+N!kw8mte$ z`EtqVl7@y7dfNvNwx{Oh`H|d@Yt}32N*V^|r7DSgdHi9Tl{x}Mnu^dI!HExYL!t39 zJ;%HUDfFcoMlF@Ry;1enq@2PRi|_z7+B@l@Ed1B6Xj^WKgf0zfE5 zs!c3s56v3^q4x8N6< zAn8ry2MwucmZztxx}Sjm*dRk^jfWHvo~6o2245(R-@#$1PSj2_2kIM@hwCu-(<*G_o&Ixp#w9OzQ=N+v`XVxSV@= z3BV3zz(Ntl9R1@YUQ*_BS{f>gQ?N8#kKViqc$|LjIjsT&M=4jKvXo*hwWD%Wzdv@c zl214s4GW$oS2PwI*>;i~na}OvMM9K&jzS+>2z=;_Iz~`%F|AkAzIHfYQJuy@w#s|A zvJm;SxQ5cUxe?5}&3%`+yR8kai2Q83nxAr$9hZ`O8jcNqq-5QT#67!sHeNrUGKENf zKA7x~?datn$+x!g5~ZRxSaMTo$l*CE?BiH+`9>>?WZ_~F*SOb+YuJ{ywhrKex=<>t zljsp$l-C7o#5|>g+s?6RZCfdWd(GB1LjwY8z0{F;aAr4+8Tvsyb&n@HY9 z1PQY;d~QMuxA9s62sJMugI43TkqCEx$|_t^7#>NuXqfompk!A|XG)#e7NRUK8Es8} zo3@H*3sfI?6H6_0qpR@L=u=xLMy!ITl9qj>CMCw;DHXi5l!Oyc$v#qm?)HZ%E<{R< z85#y1`@}W-w6e8wZ$ldNOr_k8eQXO);Li6xN6UEeBFZ66NSl+VBH7PV3LW%YgG6|B zuq{*+VFXCZa}5$f;c1*;eV&Q{DJi|&pixdsOQkBQ7q)51H9CK!)DnHsniAf{JML)| zUf$7x@aigkr?HQedQy)?8n7&-=#kauw`tg=aQ?7UntdHq&+-n$kBQ)rgf9GE=!Hb3 z5$nr)C6S8iQ%@e0j?y?g_E942Tpo9S(u))4FkVlkOo}4QOI1@-xjZ?SI$Rzowx%R? zke1<7tL?2^Sed|8=eVHKY7I%nTMs$tkJlWcjn^KjA*Fydua!5Ym26_wnvobp?TU~R zf(h2l*fb7C{kdGC^$lQdWlJ~7!#1%Het<|6Iy_gg+oX9)8uHUE5!c{#J9}83Ax>q# zm1n6u!HD~yFHo=QARgKccIwlrkj%tSD)0KW>1|p|kn~o0mp7@_658`#j#L_o%0Nx1 zB~d!bSIAbX0OuAK0!h>Rge~@Y!tZp{aI1K3YAce;DwVWV zW%g;C`;#`L20If~=!JY8o=Q;daZWX!FB17^zfXHBDLXpE-5-D4bLGb$vjXK!?bllu zvdaWdDi}*pM?%CxFE)O-us^SIpI$Y3m4*dM?(jH(!&VgsF5{`~wD#-hc!6CZKOkSl z>f{%tD*EK@2xmUjd%W$)s>PSx@XMvp7*9C8sMli;dmqUUg|n3uJTD{=>WLJ1t~`!V z+K@k0WEh^JS2}s0Tu3EAw4ldP-BAXYVN^l~6~H^14+Jl6>PC;sW5}n<83jAyGayJZ ziT8Tm`*>O(JUE_|PEE!4%DfVe<4Sk{7Kel_mcD&HSd+Juj;G`@)u&viuQWvaX?>V@ zPLW7~g?_}WyZ02 zmcGsGiO!_DsHGqUN76q$+EkgQ&b-$ja$uf$ii74W3Oe?Hy!9!3A$ZG<`WI+HK5D~PpPz2Wj@E4WPUYdzJ`sr z&1n4b%6t_IVB7_nKdo2hN2294nXifK`pBA8p`luII!fufc)#DWAeIk$*!d59H6N2Vv8dGxg1gIL^R|atV&ai0DZMv zE^Q#2xRg}osiqAtY;$UgpC&Ig>5I~}zCj$Q_6{z9iK@y-$mOqAF9lO1_KIK)CU8}C z&jCk(esWmD!43@6F>8xDVtGfaUJM`^x%|i3KN?V#F`Wh=;7J`;D;+dY()Ag6ea9Z8 zRq3UrM$dNAz@li?>foY|0N?=?x{3pbZ{ZV0mA`y>jAp2O%v5+48VIHAO-TMlH>og* zvILDo+=OIX6^8S|^R1aSUh(l-!_|+kRH(ccC@{Hp!Z2tsPG+sk!H7=pMffE8OfpWUZwUaN$l-WingpkqLixS zP*p~4?FG;ITuYNreEo%2Q(c0g@bpKOr5BIooXIO?TyB=MWd^He8jKFZ1fXJ%#2uW%ISKy^WZ&ldUGhdNvA zg|KNW<>Uh<$t}JBqpZ~MKEu;9wIr$otsr5Q1vyk1rsU|w@Iu-J1-`+{P+*$QmYIkw<+CEk=uPWcitkrg?SrO`*BH64ai$t`Qmbkrq`TH_}rP( zjN_x>uks0(&^#~NMakoj8Bfng6s0VcU#JXyCTAJGX81o8?}>Jg1gyEw1hq-kytU0zbSpc;`@u|EJ77Xb=N0b)2+T;zd8FTw6*jVY)ySG(OdPXl z=&1O}^8A{SBWv=@L!!;;4JEB@3#QiT2W4ao%FN8%HmbdaO>A9PH+0b$xvA8Wo;PmH zvN7ZGGOTs_vay-h&Xxbzwxp3|Ig75!%gN1KmX`}m>3m2DZ00aQ*kpXK6iXcdGp}b=$xduK~dJoKaQGq&2_V? zMo&+zin=o?DbL(;$;#q}P;*v&T7G>-)|lditSE~kHl{rG*y^``H+hCDH*=>xGi7Ba z;Z%dOP3K|BZYEEuws4hFG`Qffb@RM=&8}A0Hg+o8Ht5ug@ap1H8oTuRAn!k8Jd_IlVcx^ z&+OFuGe!I(nNnWXq&LP@6_1|ms!2%8Nl(Vz&`Fi$E+b2>E*yI)n_!49 z!_3hbYKSX=FDx3sV2i&9Cj}@*ik(hl^Bq%f>(Jgi-!oM?h_^`;?V76Fras}&KncXo zVmV`$R97zcy8-v^t%w75uYi$jFgHhK#65iKReAu_-kp7F8^)-&DV_Lj7{) zO)A?|)|{W;jIT*~%~eI~imIxLDD^t}D5^p~>c!T|c?#370Wc<~z%+mL!#abhmY@3f6yK$KzIZ$ zh#NX2XoM#gg*Au>N~}egH^7C*_`=3PE%gnP$JL!mJd>51mYU)ilxB0p8%G4>4$r7B zU{BUHPaM@;yD;{$@l(R8vzzT$hmj{c23g{Rv#fb3RIY|0##8vX!5p9$OJHgRrW{vb z+XaWYe;ZZ6wXEswT>8_5LHrM6v_UI zNRV{9dUYP1k?tEts$N= zhAYM*g`j56s4FWft{l~{paSueD~&<*LrNQhf*MMP&a^ngMqFyHx&D%G#$H!bbM3fa zI89$$b8@Wi4zW6k2zWRV~-)Va`r1-(S4PZxXKDNyK4KRUu=JL z*DgAKo8_XT^#Wqwgks!k0Q5-JGP_pwu7*_yZwIn#mLt?ExVCa>Pof2K5Yi?bI&Wc)_MahBu@}t?cwf9##>4wEt zONrQ2N>t&bY$&I;_BbV@83U-WQ2bEgNPQ~YhT))4NeLnj;D8m`Iia$A{DW`mk|;jR zg^2K~M4_OmyWto%WX!cK1#jYi-*@N&W%5SE@z2zXcYk(i67Nf z%=IAF_ncTkz>eW0^AF-|aWZMQI0uN~hXx>OIea66NP1gd9?Q?q$WGJ`9-O!CSLIO| z`PZ$ut~n1M`594VH?JFBc(f#u=^s zb>ngibmJbhu$X`kdB7gwj<>s5U^ zec*Jg89Fz6%auk<|WITZMczDp5`2U^`l-NE_;<&}pd0DsIpsv0@;>(*e139%y>UaQfRSzuq);YEx)P zR!&|vX!H_}(I(uVKL0uS?S7Ly)||jTrJ3D`rn*5Hn7id>vT-i?@QBf7_Duho9xQvf zcQE;J#Io3;dPc;EO6wT%~xTwCXQaV^AP+hEeKz%r1`gc!N(M5`_oyk4H$LXn8#LnUUrdnAiPSv>aN2Dpdk9 zcq8U4S)zG~UbIMym?N)7Tm%ZvGhomht~~dN(O|^t4Xx5q2^H|X^>4P;eSL3m1!&vw zU3n0Ccmi-vmv+91?J;R5_aZO$YysUCbGkvl)~l2wNODuF_z!ov`&_F=K&ciHL3Ca3 zc>Vy(z2necjTnRAL5=64oZ;A%W5skZ9&}|rOIwjy5?jRy?x)x*Q5j})MwDC&Xg#ke zZ&-`Tcg}^w601&c3ub7PUVOOKfQpY*S(ozS_an+Cw? zqgJeD42V!aWSEzydMU#(QTa;aEsg>_v1+^(L{?v%yA;++ftFXQ&?F-TET-#TK#^G% zbnEp)Bb7iWVO{?Kqixtg2l+Q__&8dLa$-?U>R*+9)qu~{ zNYAzGyfhoJ2}}6e(ZK#6ecYnb;dd+7>~NyKk1I&|b6;1G$zvQMyc)2K$YfIhx?FI2 zamvtJ8jxN%3M9Z15se@h zzWwK5CK}xfjiC5>#FBTOI@NOO6sz&|ij{lTbr$~?Ki61>?#);QH1Q}Dv|3Ge`WbwO zP_=u6a^jseSPbO%Mp3aX28u|5@6ClBV26Xc!5~r-HNza zhq(;F>`E!meNGqFeNq>uIY>h^q|HJr@bmg5q?GiAr!8yuX2aa`_bPAhm~eSr-5YRB zh&I>a4uM-rc{B^H_Z6p5mwb6a*DC#XZ`Z5RucHoW-{8{vor`xwK=MXEx*(*UkEHn; zq@H`EtP4QujfKP`lx7ToRiP#$C?L{;?yb5_8r<#$x=94rFDz1DY)|+_M&jjRE#w-s zDWnmPb)*!^1087rj~37G{;keYRn`5eu5CUKcl5Lt_GkmVg1RF%WrfGAa(HWPgOE4MLEg|$9pYQ= zq3_tWdLfDvTK0K${D!9=-<*EKxUu_r4kW?y;`|QX?{r2UQ;Lu0-P2TniLpoghjkuz zL|LiI5Z?iYp@`_w#N(0t3Nc((qu0~@B8X&zSc$b7QGUN zaIXh$jG+9D5`&gVnF=+OZ*XnmL zU-GEsQY)BfWKqgR3#0&nNU7%w6xJb~?g@EEUVuw<4}yMlm zo%-23dA6qE<7jix!#MhhPm`B{-$;kc&PDW~4o$EMs+KRR+~)X$Cr zB){ihUGXbll?0WKFO7gJqn{lV$hYpTej1G^-wPdlq^7UhFdM*%XgIle0;e5uKP66R zZIx@4xj-|!5@#)XUYRRiEguiI>2+3gY^i6dcYeXOc(S=p@rSbv6N^5eXbLa@I9=B& zK-=IuTjB8f!_1}0%79=m024`Y*p*csLb2hD;Amp zS>#%ALeEmdU#^Wz4-8C?WUnl0owR_31z{c(6~vL*OUnMR?gJYxY130-Mr^#Yi{1fSle;c zL#z~JdNa~0GNZ}1V6?x>_bVF*cKI%Kzlzz&Vc=heGvp1J(@J6RX|JDJ_qpVll}r!y|Q=viMZ9CdALP{rOsq zTqJc(;19*KJ&hR=85Ezn_;Su?eBvU{@s}Ff)Wx^gqn|?J+v%_5f+TXTcQNf^r$!{NMIRGsP zdVxB&lNQHYNFCxSuBVZY)(dpqt*zbq1zYvyU2j!#YH!%!ehxGB&EvGOUeSY82vC4X zomEEc1^RVe!zzdA|K7D~fs)rXZoF%QAc8}b)hI=O;$^FvpDhF7ZBvY#2^JV+Mdv#& zF4$^ZSu^}xyM}|hUNCO_IHe|hZR>*2)Vlm$)gW6@A4kpbu1|-lHR=mZ)k0{_&2iK8 zkPL+D^-^Z@{CVGgJAZ!nj0IbDn=zA^?!^sS2`J=p0XJwPnTXxD5UUv2gCOtEdaGV@ zBCYzNMks(?Y?nNQjkQ4Ahz^(kApa!-VPIn;GEcUhJlS^pR&x+77Cie$gk)hs0nm3w z2{mXt9$(Xa8X6+vgnmF8wWjMSnyuRFB9+k3Zkplj)V4{Gci&M}t-G>&&jJqYyYGA&*b5F(1J44}R}@S!rzOpHhx;i7 zV>)$0nk`lquAyV8L~98qCKOGUeB*21>b8iT`^XQ0pM3I_A0inQ-S>zXXibbybvhhH zX$eUdYf?g5p~K-!jZ0L0QN z#ARldH)y};J1jaj%J2>E_ch>*30M;zjtEq+#2`d^cW^F@@l9QKAN~cv+GGE$EUBj$A zgcAB~P{23hNwWK3-Dd&kdBA}ec6}c>{-K%NXZk~}6o>W><2WAjL%%{EmG}1!(5ERL1`IrNg2%uW*5X578?Jc@(=nf0GV& zy{|Q%v!OIUuWWRoqpDybxQnFaXf_Uils>(wf1`FGSnp zV-q4s_BhkQ#ED5@Zgki5^7`hOC`)1-i6<_5EJ#x1P#D*2I1V{%|Jq=SjSll=!us;e z%(!^pJ0zrNe}j9w#i5{Y5KQ5D@)qvbs{TE-PtTnGvjojI3gs>?N{FX7sZ^T@szqjm zfNY9%?*9!28Hj{FB!xGBqUP}km1104C|zBV92X^Ux|4*vFM)jpOjKe*TKwZgZco<>KWR~JbNI)Zco6wTm2S)m70)fwg}r$8u=0!op6;DL<0}40 z6z&w)BkmXFB08v1FInB9%a+KU_@Gn(!JwI>gI+xL5T#z{&fBLEU5xZ>AHGIlJ-aU%{S?*bI8X%XEJe2l~{w;Zi+8I_+o zs9;o!xW-ij6O)V@2vT@W7cXa9q!ImT?QhFiGJJRmy~$P-Z}IY~!on(g7pKI>r>4fo zrvSr^;>{>Mi1vWk&$BlXZ}!@mcrS=5D%WsM1&eRQL6e7+7<+p_uiKyzK=4WqQ0>#N;KHu@rppcA`=V z_QNY6@~y^sA9~pot)N=&aEnsk)C0CcX?#j@LTpM(S7~l;DZLBhqGF@t zY*9pb;Z;ux*oxJ^adh)KPnB5Pr(2yVSPzu~(tBMqg<@CFCQE{bC zdzm$MNc!-Sou#(m@Yv~dR}8-YGPtc z#m?f)gz}Vt_*`pLJb4~--^@~lM8_HybQqbCUhAI*9fBO;x7I5SI#_(-x3`DsU}NF;yPW^l z`i?<2l>gRxhCzpFAic)j23@84n@coUTMgsCHR>94*c?N8jbaAfC`dd=HK_nn?N9xC z+C`qo(S6(@6l9Q_}L6(|9sqryfa)E+xdE26&PnTW)m&qISJFTA?bdz~M)cT4+ z2k%#SuJs0kZVLas7c`?DV9;Tk5YIKfH|Q?qzrFmeyR6Uesr>gwm2(ZcY5ey#QQ=F2 zZo2wh;Vpyia`m^u83rA!5p{H?ufu8IiGOb!H-@F+-rO3t` zaTUsW7Ej5>PScJ2B#JcF)zZ{QSCUwJ`!Y?SXy1@g>!3e;BrQiT#44S?29bd>aH3;c z9St~jQ#UTTe3`hWz8rzAlFI9sty}jaxk>Ky=AO6g@+AZ3egtJF_Ai@{RkS)lhkY={ z_kvoH8xRs)T9aKEV6yvwtPBbc46evX4vqnf^gY)*Yk z4bEy5*R&Xt9MMtXFpVwBN_N<=+*wm3u1D=NGg14;BV!^%Lt`wN`M5}=Zz^#aw8Cp7 zY9mCz(@ zm0^9r^`LZ35u#avVlK=c&kYCa-PxLFe5g>WJ)ga0V`cS#AGs6#Mpx412fw+@P4qf`(szypQh@}*$?O9 zq^!g^vdJzOlsqUQmKZNj3aY3`j*rLU$i|S!kgyP=F+CR-;lXr4+#>~vb2wf5@Y}uf zW-rqCjnmT0Z^#kv&EdmuuPkd@B44JqBvIctM>=wZl0BlI-tEI~Tk=hz!<&=SO{O%B z+oY@WOo3tLsqw)!Q)-(JH0XalkYK3;a+^vSjop4R08!+Ru3dBO730QB_x7jB#zl)7 zuu z(`;qVl(>ZvxshA9Zr$c+j9wC1lpx{WJH{xp7+Ex#s?MIuPL1J`lm zljURLSUj20h-rr4MC|5tX#ubwq@DDnGa%l`$yTd+9t4VkVns*`#W))YFUiVrv_*7E z!JI$7uz37nGhH8<5|K`V+!0aQLEkPMWq2;eeyH%0tei2`jv{-yY9)1Kf&Za4*+XY7ESb~Qc{k!8NP$bFZ8IzYft zJaPpJAUF%N&<8qT1i&E)fkGm^4Y6F3pv$k(NvC(njfS=^^QH=}*#&(i_q)=|kyrU5YMCSFPKq+oap9 z+p629dsWw=`%>4V*XtAX>H0kV5dCm{qrO=`O+QzEjsDO2SM^8q-y3X(WJ7_W($HXN zGE6fpGrVLtWH@O!ZxoFqjF%YiHa=v0-1w~VZ^rG$oyNV!&y0tRCynP#l4*u%zG;bR zg=xL%R?|JE%>f|+tpT$F76$wy;EXxTyvqE7`89Kg`TfAWz#)M(f&U16FYsSM=|R5; z+8DGY=&7J%K|chi1?L8r1Xl$&1UCg=8r&BAc<{5qe+%9oyfb)j@Mpo_gbWKA72*oH zI^@-mw?lS^d=hdnG$C|k=-AN7p)*3~hb{?S5xPF~*3jRFJ`?)a(7%U8hoy#PhZTiY zh1G|R4{HsZ6}B+!y0BGY8^Uf2yD#jKus?)t3wt%}?eLoL(cu%qkA$C%7!k1{;?9VN zBLgBMBI6?GN4{@KvRr5Rhh?|r-utB$?ze5RJsqu&4vmhB zu8tlPy(oHV^qT0$qyH5BQuLeAyQAfp2{AXu+!}LF%;uOUV~)gpA3H3zK6ZR;YwWDp zg|XMgu8Q3ddt2;%v5&<5Auce^8kZQC5tkoV7B@VuG45~i`uNcJ==cZYk0p#uxI5wP zg!dCZNjR8TpV*XmY2r7DClb4prY5aQdL(IAk~?`^a!c}!$+srole{_k$>isfUrK&6 zg{1_i*iuqbvQmmtDpTrG9!z;G<>{1nQ^Ql^Qqxj%Q%h18rQVVHVCrM3PpAGh_3x=W zQ}?ERmU=eTV>iKj!xi=i?T^_%u^+U5Z+EAKrj1M+o7R$cYuXt{k|Wbm;3#*@aLjis zajbCM>bS?T+3}=fm*c~9tO%#iNne|OfBIk3-^~y+Dl@Lncq7x88J0Oc^XbgLWWJvH z&LCmXxIr5R?H=^+thB7$tPNQoWPO!&JX^>v%C5|=%f3GQ^Bhx7curwXWzOuJ$8%oG z>B#vc=U~pUTq!pw*P7d!J1h5&+&|{Nm3uJv++fGx=E1)l{9#^9UTWTzd4J8@p0_LS zU->clbMt?je=`4kK|?`P!KDRl1veMmS@2-NV+EZB9;eBf{4W##pit1Ew5 zd3)ua%45Sahs_=Kt6{sVVyX(Owp1Oj>ZzVq{ZRF(nuwa@nu#?lYyMdC+3=9zt;2sm z{7=I_sBNy@T>E70Uuxf~-Cg_X2=j=t5qFF@GLnt7@xSDegGQE)tR6XT);&}A;i!mF&Qa4xJy~z4kFT$* zchx^p|9t)H^*if7tpB|JQ2ojJt_FR>BMo0ReAjTgp?kD`bm{1&quWQ{I{N<6?nYzd zmd2;X#E<#QC1IER`V#lpyT^r%d&#xQb$EQ)_@~CdF#f~wXPV-h(wiEZnwn-eUCaMg zHr?d?`)We=giR9-6Wb>4Y7TCm*!+j)uO~%KN|{tPY1Aawq&p`)IqCJuqbC1m^2aTa zEn{0|w_Me7N6Vg;uUkA*(xx;_xpvCKQ(m6Z(Hhd4*gCBBrPfbdyDrVXwD!`Om)?Bo z(aRi{m0tF{sSQ(Gran3K+iB_e%bPZP+LP11m~I;IuYCIdslTbywZGZZFZ_4a^sA;X z!{6HJH&4Iw|Nm1daB%v;>4z^5y8Jhnch88J@xqKBX4cRA?aY^F?wGl6=HZz=vn;c& znss}du`RUCj=$=*y*__u+vF>TUh(qm^>dz>n>5!sciP;S=I);R$=s9klIE4qyJFtT zc`wZSZ2qkI>*xPz{_zEs3)U~VXTehozE~K(@Y02MEPQj}(JM2rbY401$}6sX^vb8M z{9uu^C}>f^qDhOcUv$r+zb@K-mF=o+SI@ip_N!mH`q(x3*SxTJ!s0(KKDDHN$>Jps zEO~Xw(Q9L`t-p4~wd=2a?ArIP{nvFft`EBY*wUz_mo9y5+1O?O{>8ZENz2D9zijyx z%a<%)zx>wa4=sOZ`Pa+O+`w*#ydmX=;u{)nSa8FwH|)IO-z(UP$Q3CoYFA8Oam$Ja zR_t7HZlz(RWo6>ZjFtH-%T^9w*|>7z%Bd@7ue@sIvXyIB-n{b9EBCHEu=3<8aaGi+ ztW{%HUA5|ut6p5Sf7O}QY<2SLiq)f6FJJxm>StH~ZT0rmJ6G>r{n_eoR-agXZVg*w zUK710bIr6hzg+X&n)7R$*3MtMZtY*!3F`{h&04p$J)k|ky|(@O_BZ+8&UWSRgZ2-q zh1Z2OBJ8A+p*un676Ky@4ji`zpZxZ)#qDVq#P%Bl!@`79r%H2^6O(gG+QSa*ONsgP zTU%P<{!Wi5$WkCuz<+sY=;v?#?eBkk>+^O6o~YRe4rhNF`u3fthd~<5w5r8;$_{^F9ts8du@ab+A#MrSPM02>! zW;^^Jw|5*c$A(03kibO#f-(<-B3+*6tM9+^n2vmU*c80h>^L6zsSp$-9CtW^4t!#c z$KP2~RN&d3wdN1QzQ_?i`9wJP;fELEj?pM%bTWJjgon##Pn|mTefQd!p3c*FojQG_ z#|(;@dyX9O1Vu+jo8=?z?SV2Add{CabNc)9Zh2k!XP)8DCo$MBj=4)yWQR% zZ3CK!yd~0?_94Pkh-mwo1trBNW+ufYCR+8~iJmXN{L+)Sf4^s)$zw2_In%8-NoxZ# zGh>21--Vz3?q3SdRlu+s7$%9vkZ`<0jH29i?p$(mi1@>Ic>N%TCMTae*Cn^F({*>6 z^=uvUc-97nrlqAt26P_Xw{PF+bppH55=r>bO9VCHc>+@w#v;!j{R*$6=S|kc10jHU zAkk`Cqt^$RJAde2Ywqd%>b_)7ijxF8Ixvn3$QBix|nt$>E{FCd_NX zVt%v=Ce!!dfB!=l)9cq_b5gGtbtcnAtL5zM6mY85Aar*J21mr90ir_%tx^JNm3ZL5 zX#q7u-GtKz4uJBecEjQG=g)VY_pA-*?Cf#(oI7*!@Zq&;rPoFFoa;oj-+S-iS#v@` zK|z8U)xYtl*Pmv%xv0N2BI4}nlPB;xdHU?(vm&~Jjh#K*-mdq^I6c7D27Lbc=Vt^@ z5Ij@0TMr(Lj826cr_9vo$fQWmQM^2nNl4st_Ecz)er*7v@T7;H`sB?w-&7@LAd=nUD~nmeS-d| zIURp%bbG?~5B}+`*1u*y=g$A;2!IugpE+t)fPQ3~5#JqvnDVJHXU?35us?IUv(sYf z>^yc%dAIi;4%Qjd(vBSq58t=%#`q&&A2@K}T#xZI3kV31gn)pfN6qH+bmiUNe-v0} z+_NVvZ2$hjgD=>ZAm{1ijvk^CFP%j={=-q7$9_6W&>af3huU?Xx1#n5N}JXrZEdmu zYo3cp#bl%LTtCSerb$M~?$d(Ba`NO_h(~x-S6`ZV)B^`*(L{+?KAL?6WS}A-ohRbW zs)Xzv%MISK{J-a3uWm39yuN)R{5#tT+jnb(lWUnp(0`rsMcfxDYlP&r>>GuC;h-OO zXiP>jeW%x2y^=)=J*i|`tK||cKKc6hioPX>Muna_dP={~!5rv~hYlW!Nr=(s?-q9F z|5tirZ=HMT&>t7NqiICu3u;8ZsV=NHRRR|F=?CZ~p`lSxp`oWv9X)#Ll(&~edX*+& z-#!Oo|2Q1fP0pTxBo__gJ%N#tk-_H3$U}z?9z1j?CMF>vCZ^rmPgxT3^LOuFEA8H$ zpMSxA;z(w+4jmMTQ3PW+{fjKn?DNAM5_9U5J2)mL_|&O20bQL(p{AU*3uo7uI}h3I z5ywCK3>XA@JO*;lu4~42+#Ti4xbc zh=?15zWzETrDsp1GxU8=N=o}WmYBF!z@vi)FIWc?;F_>BO}$Ojf7ZE%?GwbKnff&h ztFRmwYH@1IHNq*hq!7@q&I>MdzdtwhrtBsN(HaEeeOR{(?NVsyp+oB>^Qq3zbquYw z7O~PgJDtwZ(DpU3UVC#LD=$}TP>npW`Viv7!oK$OxMi7n;!mE$kRD+c+=nef&-cfn zi?y#a?EM_ypMTIk907ly6mBxLWLorkOU8uNHNqC*nH%Fj|2*7eVsh8nvnNthp>Uo& ze(YH2iI9+xP`r@eAO?m9iu(58*LHmH(cTX_J3sjF!}s5Q?M6-$_)e#D-$J;>@?~&H zI9TfF(WLLsoH%yuSo=EZpYJ@oq1rRQU3AvWslkf%rW?Z#9Eka$^9+hfOgv-`4CY1X zD(Wx4dQrRX&6l6r@_Pktf7<<&JJdsnCb4JEh@n>NnbXI?>yeRPhJ;2~EEeE&)+4sB zF@E~#rw31ID7CXE9~|yk?wR5lyH-4PrfYqy*{tt8a6m!M2i-)AuDg9rKvh*$RxHP~ zU36V`ZH>?_tX+%41-c8)5~-zz1FJQO+Q=ZBKTT@b=`O)cN?3r@Yyqt&f!5h(vpoa4zS(THBnm%9cOh{d3kY2+ zSz;h3F4_j!$BqRC1qKEV88Rd#%tx&sxIKi=Zj$t8KKtx{r(OED)Wz<2XGxtpuw-;> zT$H{q-41chC$HkP|Rl3pjSQ^^+(7DieosT21;yzD%*pC%iT_VlQ} zR1DUgk})^)VB@I|dz)x*(%Vv!qSx`c5g0vz7~LrM9Pg3>`P_a$jvoQ8z&5*J54D~; z(zjOqdg1zua)ABlX-i07oY51{e2o`+VjNyU?dvrJ|I0mbJaKd~_I#O6YEPGRjOk3^ z>aMQuzB_T^yYITX@WZ5IXS(ri?mlw_O5|rpAPJa^Jvh%VjmgO;Plknk`Q=T)2M(M# zZwyaNObj)i|9`l9*C0o->r5;Y`2aE#K;r$XDio?v-Cfh&(>?5NPLnfDjwp&EwOWys zy+8b8Ed@n6f|6%A(#&Xv zGt)Die$@;001EGC;*kK--$?+4s;=q>No}md=tct#Br@;4dG5LAeCIpo*0cKj9L`A( ztko<}78ge-0Uq?vT&V>U+-Q|5-@gw~}I+=TZz=0H`iGzJeSW)klTGXnx)^(p>Hs({8iTblL-8hFU<407T(F zXbnRlrM0}=dhno?k($NbO_;>hjkm{ZFzs#uDhdO0CzoT)2K0NE$>A+2QiaLsnINRj z7&0PO76ux>!$?s5dZbiZU3Gebc&|FqgGvsIK)$ky<8h$Z#gJe#7#la!f*Uc>l*Cc~ z>$uvvx!6M7#kzt(U*bU*+pFM`xpJe%%J{V^v-InF2WvC}tr=lx)K!_!gjuIrZ<|AA zV`IOrCV&LYsrCI0{aj(c-ye<}Uuu{P??tPSYn5bLck!q*K61M~`WoY07aW3M4n~>q z$TS5fjN|K|(3pqsz4zWBX2SJJJBiKuDYP>h2n>hhIu*9+i(;Wr7Z;wlgK!IMXQ!i=C<|eRFwO`%=0`XI= zAb%6B1YeE0$cmup?C*D259W%?ls$MzJTquE5($ZE(L6GXB>;L|OV6A~&nv);4%=LG zE*w%lGLM1<9LM?4fw08XD*$MW?r{C$pi?@4G3mFem;!qxQoI|x)vhZVxqrXVA*|8M zl?A*6L|wZ;vuK{s6vZkY-2Eh5Z4Gc<(=c{1xLf7E8cwe)`rQ1p+av!2`u9Jgf1f)8 zXZmrvd?w`d%){`xGw`P$XJpQVqW&F>)|W9_#3D`v0s*g+YeDw6a+uDQTHP>A7jBcw z)Pxk*g&1RE1-(MXb#YXy);p#-%6K8BrJjgM--3OV2(B-~4mxP`{eG)4B+te@Y_M#n zh{Fnzmk%6--qfyPNjWwwovfx#wyx`w<=+2?DM6z&<2>x|Fr7_yUNR##(k zK3|Z-tCLwMqm|%A@lcx%2M7GN%%!a~!)5DglKX-6gR#bZ)Ekx!I#Q^sbgW>=bhHpE z9UXt#&i*W}V_Vgvg0RRi!(q8pAhe}ygu~EJCXD@KLhGI4q)a+(S?Tn8LKJf4E*RNk+UCd_dbyZC!XV9n5V5ZO~^MfB))(?Jg%vYQG(BwDK3UeN9I*&W#XI01# zM8w2kMk19;rLJr2z|chF5YzwA&{$)*zUJ$owHV(3QyIT;;V7q96V-)l*RCz#rg^1f zSNri1Eb{E=S8G2(#N_1FK94gI?`Og3ym;ltjT->i=gytc%M&*1sU9!DMxEKIr+a^7 znf{fI!fDz0$vz>Q=a(@C=a1W>lN;S;;sklu+$XHfA7ed?qfc@4$(;-o9MBO+LXTB;;a|Uf zXDhpP=j~VB+qrXI5ewVM*odd`Mf#Pm{^D0(S((HUzl7g|`p2w<)f^%c=5WM0MYS=) zPT7Lft*W7VDJ)AO$6AAK2MfN)o5gI=)$KU@k=FGFrkSTf} z^@RL8g+h142ZHm}Qgazzvcs%YwqX_FZovB8hUu#@q9%rdE6=Y4g6q-JX62HIz|gSU z`zWv+`jOcmju?S^jtnVH{LJ+iKl|eK&j4E0#J~LD{rBE~|D8$emoTzR7+IKM>Omh` zn-hfuu(a{-visTXo&Br^W6Yb)mM(XC3`xYtA?U6(rm2Zv|H@Ke=__B?nCa^AEHeLW zqwy?fdX{5mYk+NP3*wSsZ1#k^E6frQQR9z$(wAi6+MCRKFFg)*dzP#G3dZrPDWue5 zb6~$;;V?}V)+pqCewWpTW)6iCb8}(IhtC-b6b^MwVJ$LO85L%#sxelE9Sk+q>2$l8 z{rzeeYc@Y>@9XiH9k(QR1)c(lE%k#Vhb307)vU`Jske17r=X7-felx=fQ9$#uBty0kL5d(o ztl8B7vqH zeRz#-9=?@PhG|?g&0%H^=SD0G{%G02)N+_occayk{rH(*)>#LqM_q3C%myz702Q|ku4F}v!uPlq1xzWIcZwvR{VW7hnBYS~N%Om`3C{M<8CT+7>`U@DtuV4&U z%7@$AtwMq9zfxg)J731ta7mUN+K|HHt3m;wDkq_JIxi=ajjrw&a3Kml$RSwk5xHI1 z&{rt(!H%QH8RyJvaO*tEy0ZEw%dO>y3inelh)^(}Y`#0-ETyQr$JvA;^=HjY)e zDAHg}BMr09M<+i2J2?LDpw%yMoQDi8up^9Cqf7%hdP+x*S^h^1i3x~$X6LwCtv}2> zhj;_*mN4dMKzd4d&vZ$r?1;05;MsNZkt_uX8VZGi*jFNgjVdaYNCcpI)KaioMHFj% z?{v*!nS#!D8_A@s2eMhO1X(JyZ7?Myw@Z+v+yUJ=Ja%_K1jd<2;1vNjtA?AqS+l%! zBQZ-jQ89W@Ckvm9Z5E|=tAymWPCCGO!h zE*>lowb0=!ZvY00f-G5%z8+cJ^rvg zU~bkl+lJJ1rX(#IaW|RE^9%D~k9_lHIwbX>#Dq}#=6GgMg#71I@R2Ua*^T8z0!kN` zv1`!9)r%J$j*Ayl*g(jexQIu>>j3)Gbm;#x-#Z#=Cx*Jx7yKAMztFF2=+Vg78bHX7 z3<5G|@eejVikNB+_C;=U^WBH{l+AZHH?4d3thqU$#!3gV7YsS{ne(FD`B6t6%L;iM zU&TnT1_=*TAqUILu}CadtHokiGav`xTg4y;bZ6TXlshR4kuzk$*J$|QaU5XeviQ~h z{zto*zVmq9--kR<zkfe(@ZuA+_D^PQoc}WJH z`=e1f9L8XU0 zAtoPg@%DB+6kX^`WUqs82;>zv8(;mo?j&2txo`oYmdRaTK5^I8fO^EITzT~VpYH#W z%#IN?;C4=HP&)92Bnx~pJP1(3r~8<<0MtAH)W|XcBCQJOvya*^!P7h*FX3rv%T`*L zSoNWIA-P`}T4OjZ;<88yMj*!u&V*mW20FZV@7{p{jq9^VZ;Yl51|vB(Mbj?g4qe0@ z!a9JMVJPGrv|0mF`>htag2Kv*WvNoe1-LP$TGqrHq2Mq-7VLk*RVWCWCoyX0VLC8Jl<$$*wHW} zkRutC*CS-gExfp}u$Y`nBoegp4n0I`yv;T`8P=$4V(H=AZ@;}`Jc3}XszJ zfih`}jlS9}S*7H{aCQBi_g3t}x+@kNHZxZ-4(F$dS~t4cH;9#s-7y zZjx5V$Kg+hKLUz@uYy61={=FHG@Us!c}<}wDfGl^^f=gxp%9cn0j41wjb5#Uj_{={ z6v?_*6-cYuT}daw@X>f>VfCGNG=BB!r$7DaW70pBg3v_PkIUro&ragkvvHs~!bGMc zO^E#}+NYmtpiOsrq?MXamLF}X&44zD0UrC66YGDiowgz#A{Ejl%kcd|p+Wjzw!Ac%g@2Z8sVND4)J*zXF)j#7=2zYpVz(x>K~@Ovd#RT1u-7 zDAI)jlv(LfWrllKYD{z)mK5l+@WH{tS*mRPm@2c~hMDL0li*rYiJI9pLBwM3OAq6`+WI)X=ev52dsieRbS&ESQTxeeD!e`xY3ZYUQLQ3*Rn0$p$99@-rn5Y z4VeAOIpQw`96fzau?bZZZEUM&-l!9u>M^+57gH?rb2NgXsrDd9(54T-_-EIGP8F*+ zQ5?XAWH1j5INhPqXxMT)Nx>+sA;Q6t^O3@R5UM6-FEb78Gj($L>x_!APpkUk2q?R& z+a2PE!*0jrD6a4@V7A9-@s@u%#T&H z%?%m*TgOLzzHfrFlg%2;S)-qc%PJE}o_P=CogEk+wl)fAPrV<^MuuTCX$tNC`?@o; zu{k|jr$0GjRoNiYg>#ER@lpO!d(g861ElZ_24}IVhCBi_$5~bQ;K2eYqTe+5S*hhzx-ABSCUutS>^Tv7Y(M zmnE+vx|}>fg`wFKu!@9*UWH(sN)6f}EL*i2fSi8Y1*dF+xJo?MUZV_^Ppf-oVS>1B zZIulQgKyv7cgBbz_rOkJlQRX6WR<3Ux?sFaqOnA-#kaXxAQU2G+ zCT}JEgtgYjSSvR$Ks1`-t1K^TE`x*m^MR_6SvbO1kwr5`Rq>_Mc@klrdS>TnMS`j( z4h9~@V(DOe8@OtLbSQix#)eZ{SnPnKc65hej`ScQt096@4TVz8qKW}H^&Bl&1f#~r zKx!-&#s3$Vm#4}VfXec+SH}X@&+y&0jPV0*p{d3gP|Y3zs$+YO;!0n~om!1X!I`b> z@As-zdRwpV@0XDlhet#7VQG&0M0{1P_I1Y4@b{^}?`pBQyqrufFJGsyz=aDdcwHbs z1`m;f=Gl%I0?KhAgpGtda2%cj0FT>Cn4%r2jQ~jmh8PUlE*?RPZbB9x_3wDFjlC|N z1+vI>0C#0PVDK3V$Z_egVw8a?Zf@>;xU&OS)Ar|bxt$$AiiyOd&K$bTf+hoxx82RK z{l>cI2vnqbdt)+hFQa|74dO#m%uX)ftkog$;LJFOO|0*@!?NrLc*uf#W(#TvM#%1N zG`gBdEH0nNoW&F<4HckAxQ7HYT7deEEM=%o{i$c0gQxZ7e~PxD<`{FiZ34-Auu*P% zeXtZ_i5|sE#16PH&ABxB zp9{)dy;g3NyI{)em;03mckYI~e1A~GsMZXI=mNz~$8&COYroRz2+&*-V}2G4OEhX0=jnn{@it;o&YB3cW70&??XVPNa%?>hSXiXf=q(1&Cs z2pKI((daNg-Vhvv;gu-?=f@kBSL$_hg!>5&oapipH7O|ncms6=)W0}OWBf_R?zCLY zyb6W93j8ykYyUCEk1!Qvg9KEU!!jVrjh?nJAl^s2WAyt>5FH6H;GudTNIpl0FoQLR zBswylL4N?8sfoB`pF#3$@WF%o2W=j+6=xYpA&5;#TEC3NGS`6qhrG`R;g-a3!iaOI zC=TP`;GpHe($T`3T9+Mj%qmSYbbkVz<9->So2s!fd z_1i$R&Yin0oI~^ApGI7x`SWznY^g-F93qL~A0)sKv5rHF-?=TkgEk-es=tUUpr{lB zbnMYNr1{Ud;IWx93s{|O#JMx3!dY!P68PhJyJxlWv_zjvu{MK^NYb_`4Hw2Ci?j;2 z6|55Gnl$J${mo7Mg8)z+5=N^gONtMW7MOx#>eeFYbc;k_6aT9Hzte4g$|p8fbQAr$ znPU7tu**qB&U)t?ca7y0C7%cHSPTf`4r+q!AArs?z|RoJvB4#{(e%pt&~N_ZKl&qJ z8EL-JXyy()l9;%DJt5-03mX!rF`O;EGaX^$Yo)1s6m9@-Tsih+2x}^3KLisRVSkgg2m-ii#Yb3(LxSaw~`20%#<`*_C@>zu`2s_(~mo zIhf5>5I_FL*RHHw`RX?`@f%-#K7Hlu-_XVHeeeDI?|<)m6D|3Z+9an(=qkp8GTr%j zB3^K0REL9!Anpq_jFA~Jhp_7{P0a2WOT~lix|o~~2gCEp^-zBI@H`D4I&wF%5PQI) z<(9^rCqF^>0r?1qjGi_}KQ%h| za>!tPBi~78Z1zB@SkrZ92gkN>Mf-G6keCI17%990t3&#ywg$bDVwoE$#_NIdL-q{* zk{We*P*q~s?+a)Su5GTl4OLKa9g0^QhEIi}rDN?tIB8CmE=9>NsGVXkXq77X!iHdk zed(}KgV7s4q4j1+@+Dj!1!iqCU~)d_WZvy-$gc_K5S?lcHSR&a?Tzm3 z%_F49%Vaf1WMNKdBbL|}=Jbs8=9>UZy^7@IG#9L(nA5;lW87>yvu4*mk%bG_evLiH zIO@XlYwVj78)f>NnYNX1UnNY&F%Mpj8(9s%;_7b+&ujRZ-AkIWSJ5ZzS?N|Ib8|_A z;B&IvYVCSF{dNmeNq{2T+%0JA_V&8Cy`4@M4tDg&5GETS&Wgvwaew~jpZ)C0g9pp7 z$#D4f>z}&(+(nJOetliMe*OLTFJ1feBN}zqtC_^ka>b`D3M2S;&`{NCRf$&)D-j8~ z2x^;D2nX&u@z>$Y@*3-Q({nvMy4w$f9HuC2!LjVfv5L>A59aLI4i{CUCo|L_3-p}m z58{!KS9L`uMp>uPmqCkLh#+}M2?JOO%4Vq)3i;i(f!gSeM!hC1V8fwnb41-DOf=sm z+BJ;orh_8bF-khixVxxKLiTgD-R}+7ugH#Wvw8LTnB2iFHbM4M7+^mmW${xND=o(D zkKn3tpUdTm!W54p^bo}slJY#QPM!gbUVJJvcVO8Tsqq;FRyt3`064+LkJsp#-M#c~-U9#Fm8dgcq(uUr3(<9EORp8hk;|H}QhUwiQy5ndGG~t|^QwV$^<`z{D0o^r7k2*LW<; z?|(<!DbBZEH1`WI9i3Bot=Ww_oy)d5|=8Kasentz6i++ z1cG4-TttGzXSCeFID&4=&9*>XEVo!UPRdCNu%NK{l>K z-qMzI?P=*SHO4FS=G1!4IyM?IrKy~+zYTg8Vja?a8+6_lA%#87#_a zK{3=BLx5Pm7SH8Sn{GtE7^2{LiPAqyjIUNhC5{Ybu&Q1v%LIMvW8FhU9$y>Z>7U0H zzln@}|Hq&FYJOax2NGzSFVKCEaGKCPH0 zdB^$^*kHhYICOphGeI68I1CbAR8E%;aai`SgfSo_BB~%^N>v@Tq$k5|Y$%c@;nU<| zr3PI*UeTwvJ_6~*qTkC)R+ePsC8P^wgdL8@D_VOK8$`Ec@>xVbR7 zkVMV0k#U+|vFD1U_K;CbwBx;0WLCq>gAzR;>?Zc*YgEQ;d`Iop;f|&`QC3inu+0(d z5kis)n0UtSuA;~y2ZI%lF7hT2T2P6cTrz^eO66GMAy0{i=IyoRE(p;`wYGDcKu4mQ zW5BYLKDom=nt{CBfPmaPt0sB5{;-ILHW;bSMcE`{DH3F#Tk<7EV8ztubWB z(!3x;mJHYlPm}e8n0iSOVR3{4L8atbW|p%YSQx8_k1R4I7{S%mYu8>_iY6~ySVbhF zCqyq?yM}rA`s*6^`s=Z925^Wbwzt6G*(^=kNbFK#g{Oy9{jOa0`O0Oy5r*Tq#gGy} zJqY5G>hB_K(<+6-ItS}P$pqY?Qj6Kz%9lbhv>_HM<+t=S=fckksS1VgM&e+2!}R7T zSu9)U!UQUZah?IFkUHmfD|{vZPVaz8rNmOW55Kq{E{Um$JRW6e`<7#%i@5~8UXRDk zEFX{aRKo)kRd910qD||RpzGtG>}VE1i_w0T7{z$3Ta*f-q3(P<}4mq&Sfawiaq*E ziy3x#S>u+McliwGOCo@e<^j>=32+7jNfD~wmv0KmQ0IN1xDShU^nx<%yCUkK*&!3)>J;nKZ#-+lL9 z>9LyQSJBR2MLSnno)m`@cZV^cEpoYoLY+$4pxywhQ2a?@ZGJEajGSqP+!+^)i1`r5 zwfdPLkAi?y3ZQB-#DqX}p^D|`0s){WS6H9*Ru#XZM*0pPMLVq7!*y{^((-`QN(B?0p%}YL?*hiX*37a0qRhKJp5>{6U z6eN+T#~u->g1kjmw&oa^tmdcXspr7Z;c!k40AtdfyStSk5$?380^TCuP1X-^*a31- zsvuc!9#oUM?f{!o!$c=ilOLA|$zXP zv~ks>nHzg}@5wU{k9dN1l|xm9yXo~JK3J#On~z3|@Kmva0mk2bcjn*yaBE)=cPYKR za2SnxJRf{;<3?(KKe@P=!ol!K(m{>Ac5Pj}cI}5hj9hy0vGOt1d^250cHwgvefW0% zO2>xIdSaPS)y^u2(Q(%^?6UT>G8CSK<0~h(`>pIaG+^wc&>xU zr{Ou#b>GDK$)8)h!bigSa*L7ZUZN1E(;tQci%25;u6#H;V8me?_tBDNs!%bM^s7UH zJ4zt8-7gy>n8S!Gqv%!w8s&UkmKB($9I|&$bOudd!)tkpXGMCLS4`?ybdF7B}S-Y|T?l zytAZp8LeN&-2i3H54;8SY-6!%u~arEZs3DI)cJGg{`g_inB;-fggx@t_>=n>gbf>J#D~0MfHi#RW4kj8Jj`LS2N=!b1GvJp_dBy=Ry9 z`UB?Mj{ov!u4;}?eepNG!2Iv1>@~N!=@CVCG%z~N_;EZq)=0QaL7&95<4yLunl_uHv8W?o~nWBX+~2WHy+ zF~Vm8w}Um!O43m3&<>!zkffqCgJNjKl8#e*B;B;Wyr_s7=NXojGqqHW6F2Qn`s(% zxo8vytBzz%4XaAalS1V~TMkH=Krt*at91TVQLQf&$$&kHQucHbuqMJgaZo#Z|TXl#P4_9Iv5COakvp+C1Tq>2TY0~cQ zZgtRiL7w%ccDqCF;2gwCdEDx+R8I zfR%$u1VOVb{1Xz9{(f#Hgp8_jUF%HvD38a)=&Ze!t})TT`Y=;EJQQ zpZ9r0hdC}vGa%0p`N?+l5JY0Y|7e+t#Cn~FU)Zs?W|PHgo!xDY z^8u3)tlwdms#3^s0cY@fZLe?(=)#dxc%-`o+{N3VV@$IlNS{6W8LgP~nO!jR81w!X zq=2f*1Oqg6pn`4n3sJy3M?eY`00EXeUGSrkf5{-r*Xe684IdMCXPiSS7!Z^hZH|JV zvJBQ1=w&BUJq}=U)^8(08j+S086QV^bW@LU&26Cp#iG|+EaHt8970rE!!a2X!5iH5 z9HkKt;AQE^US+rpuz7xfx?^q7(dj;DF#Pqjh zB^ktdh6C~#;Y&I)0ZteUQQ0Rj5GufaD#9Qz%|{~C%#K*hMM7AwRfWuo!y@t!l>zK& zl%hn;5Jd=JvSCg@xV?@R0v5(j5sl{p^Yc49u@~o1Rw#`!h|8Fqpvskub!BIV;W%VN z?NvJ5cs_m&S0cXJdH97PEL$;U!t<6SvXt6wEF~a(Bku;U&p(HbSgt~y2mpO52gb~43;0j}YW*>{cD z?VM3R%C9)RR{jDc=&zyO1jRsRpxODcx+Wo_M?^qf6gPq;bSp6x;k($SHrK+Vwv3oj zn;c1hyV#V8ycm{&n%E_pid|-sN(S!}d_t_kE&$Zk4i)9cq~%>wr!%nAAQ9DKP&xqg z4{7c)tn7o2KKkf@3c&$gJ>BAG`Ghi3me4Dwy&1xgI4_QTwR(G9ym@sgxpd`4josK- zw|B9)-$bZp#LMaH*HM~nUEKVO?|$#Qf4*sZEk8vIegQ2YK24h3w=;OXCu^2+s8=0& za?wm|+=~r1PLq2H_?Q(h<+Ahh*|A1^)(WOGyXo}E603@$7vgvvN9z!gyuR+bd36Qz zaOLWY>t5O`;(oJ>F&tSKMSQvW_Md$3d*A!N-`*Ts!Kcr9`jba3Wx*6owZ6uuwwam_ zWwz+g8vo`?%);(ZaZe`9EJkCZI{V2d8vDtQ5D?oGmo+Cm^m-g#_`1ey>B2AmwM61; zU&nVZkA9#zfAE7h!?~AUe)$of=t<*tx`(GfxrwnQ-90yn;J{EeFg2>?V&6ew1T!5}M%!Y~@r zTZL(yjPRISDWKmGI9oPcf(mLK8>-$fV3z_*b5ofz*-1=Bpx(FFB$Sul-`UvkAi^VY z68N>-dj}}X>ODBv$$GGPU^?!}f?vB%ixCy^Cxs%ww8x$lfb5;y+lPz`^j%GC?d`SZ z=b1I`)~(J^Q-+;ex0ru?tMgvx)<3rI?rgP7gC~J{loO9`_W3G(ZcIOiLC284!>q2~ zW(+*-vpnU~G>)sEIyQ+2EKQkfFC=RfDiL-%9ggvFt`X4JWiQT=W>Lep%%mLF4FDo ztb4l(gS{e6vhE>jQ>yf9KCdt`_T>kiP9K0FDuy{?2-fJjyisbQdhB7fRoZwB_}*61ffNWGXu)uI31L)S{> zGtyn7{skuK?pM3WlY7V~=AfC!)}B4l=pVak17&ZqiEMWJ0eBeu4fV_Zx#d($E@q?M z!cIYsE+%A=2Um>Y9x(6ENBlrkIqA7;&pC{S;TTKzH__)YF4jRMb=74UpiBUn?=#$C zF%}3g{Z0YSN~zjI0d9y#qrj01&@;gC=!TvE` z$?Oaq?D{;Mi9LeEP-_Df>jT7-a8s@Cb19U8oapPHMSp%4_i)kYlLcoejiM~ZRbL&d zGv5*-R;gSDP8$&=pYCi|a)*WwX`Y_t|LBI?ZMJjp={AaFBI-<6Uql}G{^nbM)M`nR zM-49kC5%T0-gqp&@$lh~V#7V%8HmLEqfO+rdOqAM7-Bei4lcm83to*uK8154RgcYI zgw1GUQm|`}@)vQDXUtz5r()ZBfUI(=)x5U+l&al_b90B&Dmv>?l$%Dy^pp8eyUD(w zW1x&bKF5~y?rb$a&bTO65?&9oRqJ))0*%)B5t6D$w>`Pt>|%Tq#g{=e6fWQ^RQP-2 zyMOYhfAYs~Or(ZlO~g(_JQ|)0csGzjsH@IEkQ~5uJFR9On12=8yNUum8E1ch0?uw# zUXSnYg5&OCn`k>)9>6}rpa8If;tm5Y3@-zzTn+;Olry5>#-bokSLD+c!ciUvpa&nO zPS82(Hf&eU&bX++!SB>S5~_8M#JD2|^vfX5)ymBdYF~_4Q~<*ouo}bq2|bWHft9OQt~TNMbSek>Wn^O^ zio)5y#t9CQXtY)5z^2A2dh#6T1TUO(k4Cmd2%)#-@pRwpN)Zr)VA+BYP*4qqKlur? zVGY)lgFET8MsYN8aq->*xLWJ9VHk9t{lKf6MOxcZp^l>Q37{0R6ndZeA@i3Puj8&A z%>nXk(imigXDAmQ)zeC41Y7bTw@iag9Rm4KAi{y7UOKF%GcvM5c1Bhj@L;LOU{2#P z4|Ha3?(#w^#f~FPEb9DFBH)^%4X;KRprZO28Ch5pQQ~UcKGI7RT};6Xk;|_;u%7{dGE4JN6g?!>Ysd6bUx#0~SL|9Ylq9jsTv1CrmT&p_ z%g-YzsbIDDbk2pHzcPNx=opu}@+}`zOb9>H+Vo3kki^uvbg{l8!I5pHkcEJ zU10@~c2gikf+zk37G?*eFauHnxUDWKUEh^36Z8P~xh4Y`OEeKGX;F6g0UJVz2sHweOE9fub7;XfJU`^AhVJ~1$#!!9a!8RSGS}h~g z4;dh38B8X6&=jUf*>LH_(0_vSuexA=AnnoP z8PGY}10Hr1vcm?PT@DUO+)$<1POod~z^k;h*+{4(=2MrJ63qkPWe3f~(VL|gUKBVr zfiiF0pa)*#^Bu}2s&j!r7^8qH;(g#Cn402{3eDtdwA%<>8p_f!8uf5;SwWEi=FXk% zqD4Esc`fYNH+i#t_pab*6%{$di7uBo(b+S5-A(>MVrs8XwGV9di3NZ9lbKCFi4eqaVsu7i)|hbS1V7m&tJRnEcW@p@L*m&X)#s$AX^qq3u4#W(?Blz%c~1a;0d950a@Cs@{l3zSZil zgv1yApTFd2rw031pTVy_1NlktyeCG8^r*SF=a$LaK<4|P-F%U4UH?qGe$Nm;1l=?MdJ^)s#}^a}U!$C~Tj zJ%sHf#u`m#JMk{57Bndg8bybQGF*jHyw1xzmbI@bz$X2Q5}2tt2y0MylEYU1n!*uhyGvNuhZih!vto4c?+;q<}7*JD1CC zmjT(a;C-wwv*oQ^8hcTeX<g~Y(u<38bYi=V7NFfEI9Z^Y2(?c>`J~Q+ zk&e~KMTzqxBu_XdJtH357gOM!Sb~R^V%d-4Q(HMO=*d1B?{@@pPT?@u0+4DA%;v$a z7HtEAZ8oW>wFPh!)B-41!9dz++erCC(fK%xuxNctU0TC! zaL4B~ccb3MZkq6rpSSK|Rek{gAn7q__BY--HXy6fE!XsCe|% zfc1b*-Wc_|@V+~!D(%Pkhn%d{={Ah63CJSf9LS*Edz@oB4~l0f{;)D^hxkHf9^Y&(> zkFj&6tLx00`~TV})0J;6f%qQK5oSypW+=mn(xFJ0!7b&?hDQXK(SxmN01!1iw6Bui z)2PA^P0$hpiJ$yra)R;c@Jk0YWhMaE4f$}W{XHV;WoyJLk%`}MYV}Y(UazlZi236_C+z5UNDYH9&~GRsd^QUvodazdsN>XsH5) zkpWNy6_L-c$C^#c#9@e%_9IiiGBitCOw!0~M3>?~F zlx7oK_PM-XFvXy_q+SpEC(0;RZBBad10IWHUY%b3qKi>a*4tN8M^of|8LwZ6SwlgRX7 zWy5^thbE}bTBO~!$UY$6Bn$x40W8m9Hj%xbH1VTu4-x;6;&lO_P!x`#&rrb-?=g>o z-CLtf1ooYsXX2+tJ%d({s z@~zf5QW6?d8Q+y($8Ua}dU1{N{J4>VHo2W_9|KdZ3@CYU$k23fvGpOop-qjNO-3Hj zY7EwK+U$4R9Udhqsn|on3q;dsf|rl}m66xUqwFisWn_*Q6)$JCYh`ry8u=|1quz!X z4_F|eqEnUvxCX!>eAKMw56~^75JIky>7pV#k^CF%MCBByt`K0CN)xP(0VfcL3W$OL z))MjrI=zhC>-4(=2Z#K_DRY?a6Z!Uw9$&=kRzqO5VaKIDZY)SqmWbOdTJ|_XOsVSg)1ZjgDnv3@F7BHjoSZVvp~W-Arr+3dRc_m;xC; zW+6Z=pU-KR%5INPhi^O=ooJI2ZQ^97(bHe!N{-M-pVpr__Yf^k=PUd=$9Ax8-GO{QM zl8BmTShh50Jbswl-77jZq%nNUmPCrDQKdDF0@yI`9Yje~Vf&+qx`9QN*WEv^I1wQpbcDEo}ct^#fWQ{cVVDPQ+_%Sak+;Z(*WA5@;pW z$yk%A@t9h;D0G)=*r(kk+Wq1BnoPx}x_0F$3EwE8d3Y1^A!TxgBRPtrE(YX?w!NLo z(Q0a(tzhF6L=vCSr38Ylid>3`U+N|fytoM%vl|FQp>jG2vg;tD~3 zBvL3;eSU--{Jst_)rQdlk@>F1-ZeC7U}sJny}o%{$sZgf5;5Dn=)$5x!(EonCXtq# zO=^-L`^ex@C2oRf(8yDT5PSPz+fXDa0k0<1C_DX5+|urvoR*}tBp`Jji{`;WK9)$B z1j+!^rsM&bZfk)wXfRB%SZhsI z$8>@2lR`Id-i$MOc%`@bey3}O&geN=+h0b{sg|KVEzohO0L&7bM;NjTc=kCtn|<$o zcEgga8p_OIUvNacur@Ht!M%H|;=~V}%Cga*2zU-INjzCXl2?)gjwZ6utq!Lzj2?#J z8$_|~8H${tmMPkGz{Jr;BzM#eQ|Ga-83Kdj@tVe;*MXF+BYHIU4d&6>`4o2Owp)l+ zI^lRqFv1Pz_(h7lFvI9uj$IRB9CopDpmY4fbZt%d-!m-p-=W7ZH$18H3tq|TU4H(8 zb1=6Y6R~_C50rQ|&EA0NA8zdly?Y;S)VrN}_Q6h59d`N-*lVK9>ruJmi~4zN^zIZ~ zp=N%+3^mc)`(#5~+W2Izhs^%cey$O8@`zxtyg%kMr1a%9@w4%wU-wl$d2onZ-8;N{ zrz>W24HFJqW1KKT3o!4ECws2vFGO9uC`B(^3f7V9j5~r&lJ#iIU99yiYXFjBuM|ur zaTQ(+F0X37)#aeb3$9=?6)g2ST_XJgYH_#j+$$nVI4It`GqyW^4r4%(ZdO7{H@2O{ z?oCG11M3vY+jUK9)nyOTuVtU1uR#m6+lqn(i82O|x2Py>RG){21uqR>=!?xFc5KGJ z7mb1^Oiuu`s9^1lG>hIyuvP{<;v|RHG_kWSh1{LVB++`ZSq;b+Ltjkp`Dt(ENLz-& zNE3p#q;07ttM1Wv;ZU)J?;aj3$EM#+rH3&gJbpawJAd>kiBx3z=>?1hWlF3GJShd# z<+pu`db78#@u(y0r5wW)$}Sn@-G}$UYo@SmHs98qE<2bJajmcUUD)kl2qWtIe|o3N zSia{!|H`CKtCO>9PSN%uy)I3(P!F_J!ZereJ=~?LeDkTa#!Ft=Xsl~ayQX-yh{_oX zm3d0~^)>%1pMTzGG1WVN`h5mlN--Aa8sEoX#@Q(^Xg=4#s;8pn9v*H#)C$|6e8T*8 zHkSu6u9?qexAXV}cJ`oM^ZVh$V3{ga5ZlSnb_Nk&1@1V@O8y#QPwN-3T>zL12YbLN zggtvdiGwWeIPEWpWG9=gwh}@~2dwO{$O0Ax8xigbTa6aBCPB2}&StSqXGHn7Prdx| z%hqH(rY(kr3WNvyy?eBIFE&3}jKPkHc}55n)a+P6y;g4PvLK+unZ6@Z0_7Be>9m|{_<5_T&s2^U%zQ!PnI*EDpeU174W9R846Pt08 zMPXYu--f1GUA=o367ubFfB&kEIo|P#TWMPmv)1(P`-MgQ@ooQy{536ju+MIwRh|1Mqscq);eRoHvZkD z?m8nxqDX*3JR2Dr!oAi#>7s)7IM5#TqobmM=wTkd6n-xlAGgjc=kcDMoQv8^p0?t) zv&K}vztL!+z1TN&b@lxHyLaKY;PCHh)4!9mPx~nZ!(qS{I0SxTXaslag)Fr6rStqDZPzkUss9F-cp7_Jx{_TJ9 zTc-KXe(QJsjkqx|G9p2zQL*U`Y|(z3krIn{{* zR?p3!aUT0*f#3bEX@2*2x0uRs>-G1}IO(x7lTAQgH)8qTkQRppI%Ig?!uj(_A0_Hy zX`D-@;wnGV7b&>{f>H0l`KL5J)8s>Tl{`Sh*z6##FK%paKO}FU4mT4is$f5njf~Tv z@KCQ^+0#QKpa!@RDy^~Ujf`*ygxvb`Ygjch4D~XdVyT7)+&-)*(}yA_Wdp!3 zeudevk*FLJI)swGs3v0)V~A%qxyIglBZE^O)6vryDyWzCXwusI%NR{na*Lv* z665BW)#smCeW;?1=+b-dJ>L2QGtIXC5J5<%U%k*QMx(WIH2OFbkWg~0e(A@Xg6NBF z3Np8Dz46ARZp)FqHUg)Vo^~%p^n&)5aGba9>aRKqR!E;5PwN1E^XjW8)W{zHbUG4L zm5)Yzx?(&jrae98RXoO5rcdZhuf7WJVtpJ5J8B~_XXR-d|0Rz69UO_8s*RSz#TgAU zb5FY3C;x}Lc$QnJobU^gpH;07SkWJh)c5B!35m3rrpQVf5|~16J2F~fu*33sqWkzt zsr2>-?>>0%hi@a(N48^+n3oPXqe%3%H=LRNuXqq+k?O%<7b&C~%Ps zz)isW#G&r4Ejcg_h#+lw!v#$m;|y4At;N2M@XnqI!HvCRwL8YT)J+B ztzxUst9-w;5ue>(2kzRlNX6_Jk^uS@N$8XzK^(Lwl^W3zgV=WY5>TGK)ii2l>;3!I?5kVa>2n=%Q8x2Lt|c{7o?dGl~DVj-?MLWNT|T(1;-JGXm41({ld0SkzjH}z2H!ueOe z{`FAu8{bGiS#0gGm}v$|bQ^1isSbE~5KWz5R3)bhoMFy4w-kK@XD|y}d-Z+b47HAp zGaL#-qle&u=iph8+0%X8*~^TU`wC_2bQl5 zI>-y@OUpLsa4}7~!*!%QCJ;n-3_O<#kJVNsg zQ03t)Jc6I%5uKi?&7Hs_?%sjwAlS*WRmZWl>*PHAyO5Iqiew#l#j=DtgVU7@IidA- zd$w{hr+oOQ0vKmG`RW+cD3_-Tn#THqntz6AFlT@Ok3%`))1~bUkieFn-$Czwd(yjC zj`vO!J9W#N^{zf}gNX)k1@((5dK2~x0JhZ|0AGsb4$Bg&h6m>mqVn`^6A%yxjNz_w zm4E8+qXbL6RqeeCPe`PXi>EojYl;Fgusi=LI z%Tb8-X;@ZKSGPwV#n6A<7?Yf(KzHT z&epo)Yao!AC!=(0FVgCVGBgkyq!iBHKNY=8VYeZylPay0K>B(XD%pf3!23|w&w}dx zJ@oqTq1V_N-oL+*S16_>NmQ?^RBt@B$7i7XnWx=G{d#5lAQ4Ie{%<1Qj)1!#@c&ag zdPaC4^R)Xr(OCZ+ef;MWSxg+4MYv5W?ifwX{N~-eD5uOLG^vblKwXQ@=61sXPHr@I zx4_ok+I>`35oV+9i$&Um)fZNyPD)u?0Ab$5hpgnbS6ykXLYL2r>`~+9UqU5nVOs81`8>HeuN(@oW|b3_YQ6^$`g+!A z9UnDyI&9O|M+Im)eACxiSYSGg)7Qu&!+A8U_B!wpM)l)kqq_L$Xg>OXdvrg0_UJxo zl%I99pFZl-(N8{R^pEa>;Isr}R%ow?qowDLKL@SoB0bN(8?n@|P0!_vPHX&Jq&F9M zcID{V@2o8JJBfu_Iq@Xnp5C45>*Mdz^lkxAJR$tkyET0sdk>T?@k_XCuT53J<3mtB za_Y$Gd+H+h+Tx>g`?!?a-Sok|AQuC!!!xa3UqL&G=_>dT5j%6Wa<*V^**eLA`>8!{ zapIG<_E|c#HOtu%Gg-FV==eT#$m3QX{`)kLlXd66M(h6m6I+*P)nB@rhPF?_i<60v z0zw5SG*4}CCL#oqAxa&4{^I$CP%`9lFyk)Vcv2VMyt79udjs{p0*i=WuPy;FczUmp zVEOUuvJ)jj-gfnTk>#+ytGYUt_lt2BaByt{=X=WK8iaE zpddN{;Q1k)agPPgA)Fvb`w;B@v2OYqwEYWc`;sVP%QJqw!#V2k)GLuV>hO?!qXthr zQmOZ+d&(i;qbWpg4@pJ|X^rFhJH%G9y5kKVyOw8eoL~mODD9!m*XNJ+lcVf1M4iXU zWslU}`DTh`{tL7wg~FtuWk7Q1G39EE|KngmGIU_&6PQ+`?oom7f(j05HRJX)5FH&f zY5}umF8YBFBJT+dNs|E`tx|27&6Wz{wAnHQ-=L;oyC4fBYJmd}KH~wt2$&fb-e5r1 zX8@!?rbnd|%RTHh06-?_)E(fRWjv#y37>{V47}TeXeT({>=AKG5P2MhjJ3(HT)|1i zhggh%7rnX;7N_FbN2zw%Ca(in29(!qBoc@`7t5gSVar~_3F^7a1P!f^G|AnEy5=1M z7%bg?7!HTfe4fpCIDz8==T>U1ROO!pce_oS zH*Oq)DASjsk^A?H{eD@16cQ7VLdZY(w|yLg55gd|dRP`V_u{8-Y~1}MTkYO<18UrT z_ucvQ%A(I{Y3jABa|*=w-00nRx5_E7%`COE`X`zx1 zO5IrF@;;VDshbW9RR#Di_F$8BP$aw(v!Vr75CCsaw%Bf$Hc;!vr(dM_iCtb`fB&Oh zs)^O)g5QM-hh4^#I+x7m zyNnyLBoyYipYv|3lg}p4EqZ7-br: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

hkA|(TNmE{-ab;u^$V$0 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 literal 0 HcmV?d00001 diff --git a/ports/JetBrains_Mono/OFL.txt b/ports/JetBrains_Mono/OFL.txt new file mode 100644 index 0000000..5ceee00 --- /dev/null +++ b/ports/JetBrains_Mono/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/ports/JetBrains_Mono/README.txt b/ports/JetBrains_Mono/README.txt new file mode 100644 index 0000000..0a8510d --- /dev/null +++ b/ports/JetBrains_Mono/README.txt @@ -0,0 +1,79 @@ +JetBrains Mono Variable Font +============================ + +This download contains JetBrains Mono as both variable fonts and static fonts. + +JetBrains Mono is a variable font with this axis: + wght + +This means all the styles are contained in these files: + JetBrainsMono-VariableFont_wght.ttf + JetBrainsMono-Italic-VariableFont_wght.ttf + +If your app fully supports variable fonts, you can now pick intermediate styles +that aren’t available as static fonts. Not all apps support variable fonts, and +in those cases you can use the static font files for JetBrains Mono: + static/JetBrainsMono-Thin.ttf + static/JetBrainsMono-ExtraLight.ttf + static/JetBrainsMono-Light.ttf + static/JetBrainsMono-Regular.ttf + static/JetBrainsMono-Medium.ttf + static/JetBrainsMono-SemiBold.ttf + static/JetBrainsMono-Bold.ttf + static/JetBrainsMono-ExtraBold.ttf + static/JetBrainsMono-ThinItalic.ttf + static/JetBrainsMono-ExtraLightItalic.ttf + static/JetBrainsMono-LightItalic.ttf + static/JetBrainsMono-Italic.ttf + static/JetBrainsMono-MediumItalic.ttf + static/JetBrainsMono-SemiBoldItalic.ttf + static/JetBrainsMono-BoldItalic.ttf + static/JetBrainsMono-ExtraBoldItalic.ttf + +Get started +----------- + +1. Install the font files you want to use + +2. Use your app's font picker to view the font family and all the +available styles + +Learn more about variable fonts +------------------------------- + + https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts + https://variablefonts.typenetwork.com + https://medium.com/variable-fonts + +In desktop apps + + https://theblog.adobe.com/can-variable-fonts-illustrator-cc + https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts + +Online + + https://developers.google.com/fonts/docs/getting_started + https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide + https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts + +Installing fonts + + MacOS: https://support.apple.com/en-us/HT201749 + Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux + Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows + +Android Apps + + https://developers.google.com/fonts/docs/android + https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts + +License +------- +Please read the full license text (OFL.txt) to understand the permissions, +restrictions and requirements for usage, redistribution, and modification. + +You can use them in your products & projects – print or digital, +commercial or otherwise. + +This isn't legal advice, please consider consulting a lawyer and see the full +license for all details. diff --git a/ports/JetBrains_Mono/static/JetBrainsMono-Bold.ttf b/ports/JetBrains_Mono/static/JetBrainsMono-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1926c804b95bcd44835689b0ddf1ac10d0b7a805 GIT binary patch literal 114828 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 XWU{|ptmfj&Kcow!3j((UZvVdlxVf|n literal 0 HcmV?d00001 diff --git a/ports/JetBrains_Mono/static/JetBrainsMono-ExtraLight.ttf b/ports/JetBrains_Mono/static/JetBrainsMono-ExtraLight.ttf new file mode 100644 index 0000000000000000000000000000000000000000..605f79d0642caa36cc1095f98fda61dc067cf4f8 GIT binary patch literal 115072 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≷Sv{UYv1O5Gh&OX^WZFWrg*m%cOW7ArH*YH44 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 B#Ek#| literal 0 HcmV?d00001 diff --git a/ports/JetBrains_Mono/static/JetBrainsMono-ExtraLightItalic.ttf b/ports/JetBrains_Mono/static/JetBrainsMono-ExtraLightItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..befe9d20587aa7bcaa88d0e9e4a9cea9ea6fa267 GIT binary patch literal 118228 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%0DG6*irF>c#Y_n61a7pP66_vE}aj_lh^Fk zoE(bql9P*&E@QfD@tT61T%RvDr$GBfeXK~lhW&t-8CN1(@69(D%e-E%(NI2_lX4`8 z``MFHGEplWsCBb-D^@NO_a8h+?`(MYcl8~*Ewk-jw_kZD3eSuC;T4tg5q0pE)-%}d zeJih#Kfo6yLm`a4k9~X;hl0wd6z>Q6Ys8{s$56iTFv`eA878!pvYX`LyZUyl?pi^) z7cNAK5u^wzDF`|$VD^sH-RG{q3rQ9(Bq%W}-z|EO2KF(cB7)x0Vk+&29q#G1cAH9y zOJZsrPz31qB`t?H3#oKM#EDw9*q+_PE4kIPGy!6fX8)ZUHt-InpFU*kEZc z&Mk1clAWoNF>Ew9iJy<{afw|Jj?aO=(#1a#6)7&zb9UBl7r%m_b)axATInsRiEI*K zG7L5NNS7c+g1hvFkj2U*&qCYAqGF@yv{sAz+Y*vZY2kn`(POJ4O5Be8ra&Yx0CLNQ}wm+btSwB^r##yc^S{XzTzyu4u57p<(J>Ju}q zS;;QR-s>>WsbYT!rzH1A%4mn`mnX_t9V{wHKcM6M-w>PPWI#UH^p}%-Eo!@ol-APc z(6`pF8W56jenUgE#oSxvDUysiIaz*#6Mk0uRp zkA}v*+ShT9u@3iY|Hgd--D`as_t>e5d$oV!9(E+$tGyBT&HP^NdAM)k_iCTQJrLpP zd4Iq?lq=k;T#S2Ib#Sjz8u#7&UZorE=R!J*!mr@fs7-o!dLN~e8OkPj^zxG=6-#n* zax@94UQ0C^2Wh{cE^C*n*=y26oKy9s?9s8FRPD>j@zIBJ_@q+yy7VaLdyKgeZz9<<5uaZKOf&+>aL=sgB{smsX8jxnX6uc@<3QB&R6l8W$2K?_#r?9?XvCo`J3d%D{ z!FQx8;Pdbqq~J5E6ckDBkraeXbfzd$P^yXvzt{!!t3OCRVvY1gO$z>jq@dKJNWlgv zA2EJknOO=hoGJyS{Hap#+n{lJthF>LxK5LTytRlMN|4TslYOcb6wT{*-YSj1^b);$ zNW4`Xz)7VkQjk4l%SlQXNeYIm#aqLvN&l79)@6|qp`{n#z?Kij|

3@Cs@2BkAxtnhM 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 T&OtR_BdYm1q3c683c~*e?3ydV literal 0 HcmV?d00001 diff --git a/ports/JetBrains_Mono/static/JetBrainsMono-ExtraBold.ttf b/ports/JetBrains_Mono/static/JetBrainsMono-ExtraBold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0c5f863fab65ca1c0f989358eb98176a19a7cd98 GIT binary patch literal 114800 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 zΞ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≀FlC zgf*%Qq&qeJ+6j&kj})w!?trZ{H`cPD69@DpS2|q@r?40Ik?}+jqG%Q<+8C9*It_{_ z0p1>%ixQ#~dJk_KZ07e|qv+9l&@7yXGG-;Z^j_RY=w#9rc-w5`PGUL0@D=Iqi}$E} z2IFagwz^eFv??btCK|;BtVMuH%9t_+NTF5>l|y~d5VGW^|G2}G@=^J__gxKvy91U(f;hryM_AQ&fm(w*kITYPgk#NlLKXAZtcun~kf{3zzE15pl>okLKX$<{@o-_f8)0PT%J$rhoq@Eb5gMEdBb z8WgL_Ixqfuv@b>3hto z9L8zCrg1Ou``9+BPw8|Cz{uEXTuabDOYlih8=w-`tc*3|H(Y>P0hRGCcl-w| zG9$pkCu*1zr!YCif7}yRg5n#9N9gJ@%T=20bM#> z9AJ{}@A%KKDvug)!HVYJj^pof{$FtH5Pm&`(&SNylA`vF63IG2NCKAX=5ktQXdf